This is an automated email from the ASF dual-hosted git repository.
etudenhoefner pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg.git
The following commit(s) were added to refs/heads/main by this push:
new 17c7815d43 GCS: Allow no-auth for testing purposes (#9061)
17c7815d43 is described below
commit 17c7815d433ae075e16351f264ecf17598169dc9
Author: Robert Stupp <[email protected]>
AuthorDate: Fri Nov 17 14:52:17 2023 +0100
GCS: Allow no-auth for testing purposes (#9061)
Although there is no "official" Google Cloud Storage emulator available
yet, there is [one available](https://github.com/oittaa/gcp-storage-emulator)
that allows at least some basic testing. To use an emulator, the client needs
to be configured to use no authentication, otherwise it will fallback to
"automatic credential detection".
---
.../java/org/apache/iceberg/gcp/GCPProperties.java | 14 ++++++
.../java/org/apache/iceberg/gcp/gcs/GCSFileIO.java | 9 ++++
.../org/apache/iceberg/gcp/GCPPropertiesTest.java | 50 ++++++++++++++++++++++
3 files changed, 73 insertions(+)
diff --git a/gcp/src/main/java/org/apache/iceberg/gcp/GCPProperties.java
b/gcp/src/main/java/org/apache/iceberg/gcp/GCPProperties.java
index 55a8fdcfee..4465ee2901 100644
--- a/gcp/src/main/java/org/apache/iceberg/gcp/GCPProperties.java
+++ b/gcp/src/main/java/org/apache/iceberg/gcp/GCPProperties.java
@@ -22,6 +22,7 @@ import java.io.Serializable;
import java.util.Date;
import java.util.Map;
import java.util.Optional;
+import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
import org.apache.iceberg.util.PropertyUtil;
public class GCPProperties implements Serializable {
@@ -40,6 +41,8 @@ public class GCPProperties implements Serializable {
public static final String GCS_OAUTH2_TOKEN = "gcs.oauth2.token";
public static final String GCS_OAUTH2_TOKEN_EXPIRES_AT =
"gcs.oauth2.token-expires-at";
+ // Boolean to explicitly configure "no authentication" for testing purposes
using a GCS emulator
+ public static final String GCS_NO_AUTH = "gcs.no-auth";
/** Configure the batch size used when deleting multiple files from a given
GCS bucket */
public static final String GCS_DELETE_BATCH_SIZE = "gcs.delete.batch-size";
@@ -60,6 +63,7 @@ public class GCPProperties implements Serializable {
private Integer gcsChannelReadChunkSize;
private Integer gcsChannelWriteChunkSize;
+ private boolean gcsNoAuth;
private String gcsOAuth2Token;
private Date gcsOAuth2TokenExpiresAt;
@@ -90,6 +94,12 @@ public class GCPProperties implements Serializable {
gcsOAuth2TokenExpiresAt =
new
Date(Long.parseLong(properties.get(GCS_OAUTH2_TOKEN_EXPIRES_AT)));
}
+ gcsNoAuth = Boolean.parseBoolean(properties.getOrDefault(GCS_NO_AUTH,
"false"));
+ Preconditions.checkState(
+ !(gcsOAuth2Token != null && gcsNoAuth),
+ "Invalid auth settings: must not configure %s and %s",
+ GCS_NO_AUTH,
+ GCS_OAUTH2_TOKEN);
gcsDeleteBatchSize =
PropertyUtil.propertyAsInt(
@@ -132,6 +142,10 @@ public class GCPProperties implements Serializable {
return Optional.ofNullable(gcsOAuth2Token);
}
+ public boolean noAuth() {
+ return gcsNoAuth;
+ }
+
public Optional<Date> oauth2TokenExpiresAt() {
return Optional.ofNullable(gcsOAuth2TokenExpiresAt);
}
diff --git a/gcp/src/main/java/org/apache/iceberg/gcp/gcs/GCSFileIO.java
b/gcp/src/main/java/org/apache/iceberg/gcp/gcs/GCSFileIO.java
index 09eb4a7400..2201c876bd 100644
--- a/gcp/src/main/java/org/apache/iceberg/gcp/gcs/GCSFileIO.java
+++ b/gcp/src/main/java/org/apache/iceberg/gcp/gcs/GCSFileIO.java
@@ -20,6 +20,7 @@ package org.apache.iceberg.gcp.gcs;
import com.google.auth.oauth2.AccessToken;
import com.google.auth.oauth2.OAuth2Credentials;
+import com.google.cloud.NoCredentials;
import com.google.cloud.storage.Blob;
import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.Storage;
@@ -141,10 +142,18 @@ public class GCSFileIO implements DelegateFileIO {
gcpProperties.clientLibToken().ifPresent(builder::setClientLibToken);
gcpProperties.serviceHost().ifPresent(builder::setHost);
+ // Google Cloud APIs default to automatically detect the credentials
to use, which is
+ // in most cases the convenient way, especially in GCP.
+ // See javadoc of
com.google.auth.oauth2.GoogleCredentials.getApplicationDefault().
+ if (gcpProperties.noAuth()) {
+ // Explicitly allow "no credentials" for testing purposes.
+ builder.setCredentials(NoCredentials.getInstance());
+ }
gcpProperties
.oauth2Token()
.ifPresent(
token -> {
+ // Explicitly configure an OAuth token.
AccessToken accessToken =
new AccessToken(token,
gcpProperties.oauth2TokenExpiresAt().orElse(null));
builder.setCredentials(OAuth2Credentials.create(accessToken));
diff --git a/gcp/src/test/java/org/apache/iceberg/gcp/GCPPropertiesTest.java
b/gcp/src/test/java/org/apache/iceberg/gcp/GCPPropertiesTest.java
new file mode 100644
index 0000000000..f7c770dbb5
--- /dev/null
+++ b/gcp/src/test/java/org/apache/iceberg/gcp/GCPPropertiesTest.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.iceberg.gcp;
+
+import static org.apache.iceberg.gcp.GCPProperties.GCS_NO_AUTH;
+import static org.apache.iceberg.gcp.GCPProperties.GCS_OAUTH2_TOKEN;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.iceberg.relocated.com.google.common.collect.ImmutableMap;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class GCPPropertiesTest {
+
+ @Test
+ public void testOAuthWithNoAuth() {
+ Assertions.assertThatIllegalStateException()
+ .isThrownBy(
+ () ->
+ new GCPProperties(ImmutableMap.of(GCS_OAUTH2_TOKEN, "oauth",
GCS_NO_AUTH, "true")))
+ .withMessage(
+ String.format(
+ "Invalid auth settings: must not configure %s and %s",
+ GCS_NO_AUTH, GCS_OAUTH2_TOKEN));
+
+ GCPProperties gcpProperties =
+ new GCPProperties(ImmutableMap.of(GCS_OAUTH2_TOKEN, "oauth",
GCS_NO_AUTH, "false"));
+ assertThat(gcpProperties.noAuth()).isFalse();
+ assertThat(gcpProperties.oauth2Token()).get().isEqualTo("oauth");
+ gcpProperties = new GCPProperties(ImmutableMap.of(GCS_NO_AUTH, "true"));
+ assertThat(gcpProperties.noAuth()).isTrue();
+ assertThat(gcpProperties.oauth2Token()).isNotPresent();
+ }
+}