This is an automated email from the ASF dual-hosted git repository.
amoghj 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 67e181ea9b Core: Introduce AuthConfig (#10161)
67e181ea9b is described below
commit 67e181ea9b706afc8ff9d1bcd0f9e9c240f173cd
Author: Eduard Tudenhoefner <[email protected]>
AuthorDate: Mon Jun 3 16:58:16 2024 +0200
Core: Introduce AuthConfig (#10161)
---
.../aws/s3/signer/S3V4RestSignerClient.java | 26 ++--
.../apache/iceberg/rest/RESTSessionCatalog.java | 9 +-
.../org/apache/iceberg/rest/auth/AuthConfig.java | 72 ++++++++++
.../org/apache/iceberg/rest/auth/OAuth2Util.java | 151 ++++++++++-----------
4 files changed, 166 insertions(+), 92 deletions(-)
diff --git
a/aws/src/main/java/org/apache/iceberg/aws/s3/signer/S3V4RestSignerClient.java
b/aws/src/main/java/org/apache/iceberg/aws/s3/signer/S3V4RestSignerClient.java
index cdbdfb3d86..806c52420f 100644
---
a/aws/src/main/java/org/apache/iceberg/aws/s3/signer/S3V4RestSignerClient.java
+++
b/aws/src/main/java/org/apache/iceberg/aws/s3/signer/S3V4RestSignerClient.java
@@ -42,6 +42,7 @@ import org.apache.iceberg.rest.ErrorHandlers;
import org.apache.iceberg.rest.HTTPClient;
import org.apache.iceberg.rest.RESTClient;
import org.apache.iceberg.rest.ResourcePaths;
+import org.apache.iceberg.rest.auth.AuthConfig;
import org.apache.iceberg.rest.auth.OAuth2Properties;
import org.apache.iceberg.rest.auth.OAuth2Util;
import org.apache.iceberg.rest.auth.OAuth2Util.AuthSession;
@@ -213,12 +214,13 @@ public abstract class S3V4RestSignerClient
expiresAtMillis(properties()),
new AuthSession(
ImmutableMap.of(),
- token,
- null,
- credential(),
- SCOPE,
- oauth2ServerUri(),
- optionalOAuthParams())));
+ AuthConfig.builder()
+ .token(token)
+ .credential(credential())
+ .scope(SCOPE)
+ .oauth2ServerUri(oauth2ServerUri())
+ .optionalOAuthParams(optionalOAuthParams())
+ .build())));
}
if (credentialProvided()) {
@@ -229,12 +231,12 @@ public abstract class S3V4RestSignerClient
AuthSession session =
new AuthSession(
ImmutableMap.of(),
- null,
- null,
- credential(),
- SCOPE,
- oauth2ServerUri(),
- optionalOAuthParams());
+ AuthConfig.builder()
+ .credential(credential())
+ .scope(SCOPE)
+ .oauth2ServerUri(oauth2ServerUri())
+ .optionalOAuthParams(optionalOAuthParams())
+ .build());
long startTimeMillis = System.currentTimeMillis();
OAuthTokenResponse authResponse =
OAuth2Util.fetchToken(
diff --git a/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java
b/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java
index dcf92289df..da40d4c3ae 100644
--- a/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java
+++ b/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java
@@ -70,6 +70,7 @@ import
org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableMap;
import org.apache.iceberg.relocated.com.google.common.collect.Lists;
import org.apache.iceberg.relocated.com.google.common.collect.Maps;
+import org.apache.iceberg.rest.auth.AuthConfig;
import org.apache.iceberg.rest.auth.OAuth2Properties;
import org.apache.iceberg.rest.auth.OAuth2Util;
import org.apache.iceberg.rest.auth.OAuth2Util.AuthSession;
@@ -219,7 +220,13 @@ public class RESTSessionCatalog extends
BaseViewSessionCatalog
String token = mergedProps.get(OAuth2Properties.TOKEN);
this.catalogAuth =
new AuthSession(
- baseHeaders, null, null, credential, scope, oauth2ServerUri,
optionalOAuthParams);
+ baseHeaders,
+ AuthConfig.builder()
+ .credential(credential)
+ .scope(scope)
+ .oauth2ServerUri(oauth2ServerUri)
+ .optionalOAuthParams(optionalOAuthParams)
+ .build());
if (authResponse != null) {
this.catalogAuth =
AuthSession.fromTokenResponse(
diff --git a/core/src/main/java/org/apache/iceberg/rest/auth/AuthConfig.java
b/core/src/main/java/org/apache/iceberg/rest/auth/AuthConfig.java
new file mode 100644
index 0000000000..275884e118
--- /dev/null
+++ b/core/src/main/java/org/apache/iceberg/rest/auth/AuthConfig.java
@@ -0,0 +1,72 @@
+/*
+ * 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.rest.auth;
+
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.apache.iceberg.rest.ResourcePaths;
+import org.immutables.value.Value;
+
+/**
+ * The purpose of this class is to hold configuration options for {@link
+ * org.apache.iceberg.rest.auth.OAuth2Util.AuthSession}.
+ */
[email protected](redactedMask = "****")
+@SuppressWarnings("ImmutablesStyle")
[email protected]
+public interface AuthConfig {
+ @Nullable
+ @Value.Redacted
+ String token();
+
+ @Nullable
+ String tokenType();
+
+ @Nullable
+ @Value.Redacted
+ String credential();
+
+ @Value.Default
+ default String scope() {
+ return OAuth2Properties.CATALOG_SCOPE;
+ }
+
+ @Value.Lazy
+ @Nullable
+ default Long expiresAtMillis() {
+ return OAuth2Util.expiresAtMillis(token());
+ }
+
+ @Value.Default
+ default boolean keepRefreshed() {
+ return true;
+ }
+
+ @Nullable
+ @Value.Default
+ default String oauth2ServerUri() {
+ return ResourcePaths.tokens();
+ }
+
+ Map<String, String> optionalOAuthParams();
+
+ static ImmutableAuthConfig.Builder builder() {
+ return ImmutableAuthConfig.builder();
+ }
+}
diff --git a/core/src/main/java/org/apache/iceberg/rest/auth/OAuth2Util.java
b/core/src/main/java/org/apache/iceberg/rest/auth/OAuth2Util.java
index 9e36694508..2283aba7d0 100644
--- a/core/src/main/java/org/apache/iceberg/rest/auth/OAuth2Util.java
+++ b/core/src/main/java/org/apache/iceberg/rest/auth/OAuth2Util.java
@@ -458,32 +458,11 @@ public class OAuth2Util {
private static final long MAX_REFRESH_WINDOW_MILLIS = 300_000; // 5 minutes
private static final long MIN_REFRESH_WAIT_MILLIS = 10;
private volatile Map<String, String> headers;
- private volatile String token;
- private volatile String tokenType;
- private volatile Long expiresAtMillis;
- private final String credential;
- private final String scope;
- private volatile boolean keepRefreshed = true;
- private final String oauth2ServerUri;
+ private volatile AuthConfig config;
- private Map<String, String> optionalOAuthParams = ImmutableMap.of();
-
- public AuthSession(
- Map<String, String> baseHeaders,
- String token,
- String tokenType,
- String credential,
- String scope,
- String oauth2ServerUri,
- Map<String, String> optionalOAuthParams) {
- this.headers = RESTUtil.merge(baseHeaders, authHeaders(token));
- this.token = token;
- this.tokenType = tokenType;
- this.expiresAtMillis = OAuth2Util.expiresAtMillis(token);
- this.credential = credential;
- this.scope = scope;
- this.oauth2ServerUri = oauth2ServerUri;
- this.optionalOAuthParams = optionalOAuthParams;
+ public AuthSession(Map<String, String> baseHeaders, AuthConfig config) {
+ this.headers = RESTUtil.merge(baseHeaders, authHeaders(config.token()));
+ this.config = config;
}
/** @deprecated since 1.5.0, will be removed in 1.6.0 */
@@ -494,13 +473,14 @@ public class OAuth2Util {
String tokenType,
String credential,
String scope) {
- this.headers = RESTUtil.merge(baseHeaders, authHeaders(token));
- this.token = token;
- this.tokenType = tokenType;
- this.expiresAtMillis = OAuth2Util.expiresAtMillis(token);
- this.credential = credential;
- this.scope = scope;
- this.oauth2ServerUri = ResourcePaths.tokens();
+ this(
+ baseHeaders,
+ AuthConfig.builder()
+ .token(token)
+ .tokenType(tokenType)
+ .credential(credential)
+ .scope(scope)
+ .build());
}
/** @deprecated since 1.6.0, will be removed in 1.7.0 */
@@ -512,14 +492,15 @@ public class OAuth2Util {
String credential,
String scope,
String oauth2ServerUri) {
- this.headers = RESTUtil.merge(baseHeaders, authHeaders(token));
- this.token = token;
- this.tokenType = tokenType;
- this.expiresAtMillis = OAuth2Util.expiresAtMillis(token);
- this.credential = credential;
- this.scope = scope;
- this.oauth2ServerUri = oauth2ServerUri;
- this.optionalOAuthParams = ImmutableMap.of();
+ this(
+ baseHeaders,
+ AuthConfig.builder()
+ .token(token)
+ .tokenType(tokenType)
+ .credential(credential)
+ .scope(scope)
+ .oauth2ServerUri(oauth2ServerUri)
+ .build());
}
public Map<String, String> headers() {
@@ -527,35 +508,39 @@ public class OAuth2Util {
}
public String token() {
- return token;
+ return config.token();
}
public String tokenType() {
- return tokenType;
+ return config.tokenType();
}
public Long expiresAtMillis() {
- return expiresAtMillis;
+ return config.expiresAtMillis();
}
public String scope() {
- return scope;
+ return config.scope();
}
- public void stopRefreshing() {
- this.keepRefreshed = false;
+ public synchronized void stopRefreshing() {
+ this.config =
ImmutableAuthConfig.copyOf(config).withKeepRefreshed(false);
}
public String credential() {
- return credential;
+ return config.credential();
}
public String oauth2ServerUri() {
- return oauth2ServerUri;
+ return config.oauth2ServerUri();
}
public Map<String, String> optionalOAuthParams() {
- return optionalOAuthParams;
+ return config.optionalOAuthParams();
+ }
+
+ public AuthConfig config() {
+ return config;
}
@VisibleForTesting
@@ -569,14 +554,7 @@ public class OAuth2Util {
* @return A new {@link AuthSession} with empty headers.
*/
public static AuthSession empty() {
- return new AuthSession(
- ImmutableMap.of(),
- null,
- null,
- null,
- OAuth2Properties.CATALOG_SCOPE,
- null,
- ImmutableMap.of());
+ return new AuthSession(ImmutableMap.of(), AuthConfig.builder().build());
}
/**
@@ -586,7 +564,7 @@ public class OAuth2Util {
* @return interval to wait before calling refresh again, or null if no
refresh is needed
*/
public Pair<Integer, TimeUnit> refresh(RESTClient client) {
- if (token != null && keepRefreshed) {
+ if (token() != null && config.keepRefreshed()) {
AtomicReference<OAuthTokenResponse> ref = new AtomicReference<>(null);
boolean isSuccessful =
Tasks.foreach(ref)
@@ -612,10 +590,13 @@ public class OAuth2Util {
}
OAuthTokenResponse response = ref.get();
- this.token = response.token();
- this.tokenType = response.issuedTokenType();
- this.expiresAtMillis = OAuth2Util.expiresAtMillis(token);
- this.headers = RESTUtil.merge(headers, authHeaders(token));
+ this.config =
+ AuthConfig.builder()
+ .from(config())
+ .token(response.token())
+ .tokenType(response.issuedTokenType())
+ .build();
+ this.headers = RESTUtil.merge(headers, authHeaders(config.token()));
if (response.expiresInSeconds() != null) {
return Pair.of(response.expiresInSeconds(), TimeUnit.SECONDS);
@@ -626,21 +607,34 @@ public class OAuth2Util {
}
private OAuthTokenResponse refreshCurrentToken(RESTClient client) {
- if (null != expiresAtMillis && expiresAtMillis <=
System.currentTimeMillis()) {
+ if (null != expiresAtMillis() && expiresAtMillis() <=
System.currentTimeMillis()) {
// the token has already expired, attempt to refresh using the
credential
return refreshExpiredToken(client);
} else {
// attempt a normal refresh
return refreshToken(
- client, headers(), token, tokenType, scope, oauth2ServerUri,
optionalOAuthParams);
+ client,
+ headers(),
+ token(),
+ tokenType(),
+ scope(),
+ oauth2ServerUri(),
+ optionalOAuthParams());
}
}
private OAuthTokenResponse refreshExpiredToken(RESTClient client) {
- if (credential != null) {
- Map<String, String> basicHeaders = RESTUtil.merge(headers(),
basicAuthHeaders(credential));
+ if (credential() != null) {
+ Map<String, String> basicHeaders =
+ RESTUtil.merge(headers(), basicAuthHeaders(credential()));
return refreshToken(
- client, basicHeaders, token, tokenType, scope, oauth2ServerUri,
optionalOAuthParams);
+ client,
+ basicHeaders,
+ token(),
+ tokenType(),
+ scope(),
+ oauth2ServerUri(),
+ optionalOAuthParams());
}
return null;
@@ -693,12 +687,11 @@ public class OAuth2Util {
AuthSession session =
new AuthSession(
parent.headers(),
- token,
- OAuth2Properties.ACCESS_TOKEN_TYPE,
- parent.credential(),
- parent.scope(),
- parent.oauth2ServerUri(),
- parent.optionalOAuthParams());
+ AuthConfig.builder()
+ .from(parent.config())
+ .token(token)
+ .tokenType(OAuth2Properties.ACCESS_TOKEN_TYPE)
+ .build());
long startTimeMillis = System.currentTimeMillis();
Long expiresAtMillis = session.expiresAtMillis();
@@ -766,12 +759,12 @@ public class OAuth2Util {
AuthSession session =
new AuthSession(
parent.headers(),
- response.token(),
- response.issuedTokenType(),
- credential,
- parent.scope(),
- parent.oauth2ServerUri(),
- parent.optionalOAuthParams());
+ AuthConfig.builder()
+ .from(parent.config())
+ .token(response.token())
+ .tokenType(response.issuedTokenType())
+ .credential(credential)
+ .build());
Long expiresAtMillis = session.expiresAtMillis();
if (null == expiresAtMillis && response.expiresInSeconds() != null) {