This is an automated email from the ASF dual-hosted git repository. collado pushed a commit to branch mcollado-support-tokenexchange in repository https://gitbox.apache.org/repos/asf/polaris.git
commit 5cc5c1e431d5592b7f71ad4bb73eca237e257f2e Author: Michael Collado <[email protected]> AuthorDate: Fri Feb 7 11:41:10 2025 -0800 Update TokenBroker interface to accept requestedTokenType --- .../service/quarkus/auth/JWTRSAKeyPairTest.java | 7 ++- .../quarkus/auth/JWTSymmetricKeyGeneratorTest.java | 7 ++- .../service/auth/DefaultOAuth2ApiService.java | 10 ++-- .../org/apache/polaris/service/auth/JWTBroker.java | 14 ++++- .../service/auth/NoneTokenBrokerFactory.java | 12 +++- .../apache/polaris/service/auth/TokenBroker.java | 70 +++++++++++++++++++++- .../service/auth/DefaultOAuth2ApiServiceTest.java | 22 ++++--- 7 files changed, 122 insertions(+), 20 deletions(-) diff --git a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/auth/JWTRSAKeyPairTest.java b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/auth/JWTRSAKeyPairTest.java index 6627fbf9..8eb89fb4 100644 --- a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/auth/JWTRSAKeyPairTest.java +++ b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/auth/JWTRSAKeyPairTest.java @@ -41,6 +41,7 @@ import org.apache.polaris.service.auth.PemUtils; import org.apache.polaris.service.auth.TokenBroker; import org.apache.polaris.service.auth.TokenRequestValidator; import org.apache.polaris.service.auth.TokenResponse; +import org.apache.polaris.service.types.TokenType; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -76,7 +77,11 @@ public class JWTRSAKeyPairTest { new JWTRSAKeyPair(metastoreManager, session, 420, publicFileLocation, privateFileLocation); TokenResponse token = tokenBroker.generateFromClientSecrets( - clientId, mainSecret, TokenRequestValidator.CLIENT_CREDENTIALS, scope); + clientId, + mainSecret, + TokenRequestValidator.CLIENT_CREDENTIALS, + scope, + TokenType.ACCESS_TOKEN); assertThat(token).isNotNull(); assertThat(token.getExpiresIn()).isEqualTo(420); diff --git a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/auth/JWTSymmetricKeyGeneratorTest.java b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/auth/JWTSymmetricKeyGeneratorTest.java index 039e575c..787e329e 100644 --- a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/auth/JWTSymmetricKeyGeneratorTest.java +++ b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/auth/JWTSymmetricKeyGeneratorTest.java @@ -34,6 +34,7 @@ import org.apache.polaris.service.auth.JWTSymmetricKeyBroker; import org.apache.polaris.service.auth.TokenBroker; import org.apache.polaris.service.auth.TokenRequestValidator; import org.apache.polaris.service.auth.TokenResponse; +import org.apache.polaris.service.types.TokenType; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -64,7 +65,11 @@ public class JWTSymmetricKeyGeneratorTest { new JWTSymmetricKeyBroker(metastoreManager, metaStoreSession, 666, () -> "polaris"); TokenResponse token = generator.generateFromClientSecrets( - clientId, mainSecret, TokenRequestValidator.CLIENT_CREDENTIALS, "PRINCIPAL_ROLE:TEST"); + clientId, + mainSecret, + TokenRequestValidator.CLIENT_CREDENTIALS, + "PRINCIPAL_ROLE:TEST", + TokenType.ACCESS_TOKEN); assertThat(token).isNotNull(); JWTVerifier verifier = JWT.require(Algorithm.HMAC256("polaris")).withIssuer("polaris").build(); diff --git a/service/common/src/main/java/org/apache/polaris/service/auth/DefaultOAuth2ApiService.java b/service/common/src/main/java/org/apache/polaris/service/auth/DefaultOAuth2ApiService.java index 5855e36a..4055d6e5 100644 --- a/service/common/src/main/java/org/apache/polaris/service/auth/DefaultOAuth2ApiService.java +++ b/service/common/src/main/java/org/apache/polaris/service/auth/DefaultOAuth2ApiService.java @@ -96,12 +96,14 @@ public class DefaultOAuth2ApiService implements IcebergRestOAuth2ApiService { } } TokenResponse tokenResponse; - if (subjectToken != null) { + if (clientSecret != null) { tokenResponse = - tokenBroker.generateFromToken(subjectTokenType, subjectToken, grantType, scope); - } else if (clientSecret != null) { + tokenBroker.generateFromClientSecrets( + clientId, clientSecret, grantType, scope, requestedTokenType); + } else if (subjectToken != null) { tokenResponse = - tokenBroker.generateFromClientSecrets(clientId, clientSecret, grantType, scope); + tokenBroker.generateFromToken( + subjectTokenType, subjectToken, grantType, scope, requestedTokenType); } else { return OAuthUtils.getResponseFromError(OAuthTokenErrorResponse.Error.invalid_request); } diff --git a/service/common/src/main/java/org/apache/polaris/service/auth/JWTBroker.java b/service/common/src/main/java/org/apache/polaris/service/auth/JWTBroker.java index cd4b24d1..ef7151ff 100644 --- a/service/common/src/main/java/org/apache/polaris/service/auth/JWTBroker.java +++ b/service/common/src/main/java/org/apache/polaris/service/auth/JWTBroker.java @@ -98,8 +98,12 @@ public abstract class JWTBroker implements TokenBroker { @Override public TokenResponse generateFromToken( - TokenType tokenType, String subjectToken, String grantType, String scope) { - if (!TokenType.ACCESS_TOKEN.equals(tokenType)) { + TokenType subjectTokenType, + String subjectToken, + String grantType, + String scope, + TokenType requestedTokenType) { + if (!TokenType.ACCESS_TOKEN.equals(subjectTokenType)) { return new TokenResponse(OAuthTokenErrorResponse.Error.invalid_request); } if (StringUtils.isBlank(subjectToken)) { @@ -121,7 +125,11 @@ public abstract class JWTBroker implements TokenBroker { @Override public TokenResponse generateFromClientSecrets( - String clientId, String clientSecret, String grantType, String scope) { + String clientId, + String clientSecret, + String grantType, + String scope, + TokenType requestedTokenType) { // Initial sanity checks TokenRequestValidator validator = new TokenRequestValidator(); Optional<OAuthTokenErrorResponse.Error> initialValidationResponse = diff --git a/service/common/src/main/java/org/apache/polaris/service/auth/NoneTokenBrokerFactory.java b/service/common/src/main/java/org/apache/polaris/service/auth/NoneTokenBrokerFactory.java index 9f642a2b..175c2afa 100644 --- a/service/common/src/main/java/org/apache/polaris/service/auth/NoneTokenBrokerFactory.java +++ b/service/common/src/main/java/org/apache/polaris/service/auth/NoneTokenBrokerFactory.java @@ -42,13 +42,21 @@ public class NoneTokenBrokerFactory implements TokenBrokerFactory { @Override public TokenResponse generateFromClientSecrets( - String clientId, String clientSecret, String grantType, String scope) { + String clientId, + String clientSecret, + String grantType, + String scope, + TokenType requestedTokenType) { return null; } @Override public TokenResponse generateFromToken( - TokenType tokenType, String subjectToken, String grantType, String scope) { + TokenType subjectTokenType, + String subjectToken, + String grantType, + String scope, + TokenType requestedTokenType) { return null; } diff --git a/service/common/src/main/java/org/apache/polaris/service/auth/TokenBroker.java b/service/common/src/main/java/org/apache/polaris/service/auth/TokenBroker.java index 31b6c400..62969938 100644 --- a/service/common/src/main/java/org/apache/polaris/service/auth/TokenBroker.java +++ b/service/common/src/main/java/org/apache/polaris/service/auth/TokenBroker.java @@ -34,11 +34,77 @@ public interface TokenBroker { boolean supportsRequestedTokenType(TokenType tokenType); + /** + * Generate a token from client secrets without specifying the requested token type + * + * @param clientId + * @param clientSecret + * @param grantType + * @param scope + * @return the response indicating an error or the requested token + * @deprecated - use the method with the requested token type + */ + @Deprecated + default TokenResponse generateFromClientSecrets( + final String clientId, + final String clientSecret, + final String grantType, + final String scope) { + return generateFromClientSecrets( + clientId, clientSecret, grantType, scope, TokenType.ACCESS_TOKEN); + } + + /** + * Generate a token from client secrets + * + * @param clientId + * @param clientSecret + * @param grantType + * @param scope + * @param requestedTokenType + * @return the response indicating an error or the requested token + */ TokenResponse generateFromClientSecrets( - final String clientId, final String clientSecret, final String grantType, final String scope); + final String clientId, + final String clientSecret, + final String grantType, + final String scope, + TokenType requestedTokenType); + + /** + * Generate a token from an existing token of a specified type without specifying the requested + * token type + * + * @param subjectTokenType + * @param subjectToken + * @param grantType + * @param scope + * @return the response indicating an error or the requested token + * @deprecated - use the method with the requested token type + */ + @Deprecated + default TokenResponse generateFromToken( + TokenType subjectTokenType, String subjectToken, final String grantType, final String scope) { + return generateFromToken( + subjectTokenType, subjectToken, grantType, scope, TokenType.ACCESS_TOKEN); + } + /** + * Generate a token from an existing token of a specified type + * + * @param subjectTokenType + * @param subjectToken + * @param grantType + * @param scope + * @param requestedTokenType + * @return the response indicating an error or the requested token + */ TokenResponse generateFromToken( - TokenType tokenType, String subjectToken, final String grantType, final String scope); + TokenType subjectTokenType, + String subjectToken, + final String grantType, + final String scope, + TokenType requestedTokenType); DecodedToken verify(String token); diff --git a/service/common/src/test/java/org/apache/polaris/service/auth/DefaultOAuth2ApiServiceTest.java b/service/common/src/test/java/org/apache/polaris/service/auth/DefaultOAuth2ApiServiceTest.java index 097f99e9..ea119e5c 100644 --- a/service/common/src/test/java/org/apache/polaris/service/auth/DefaultOAuth2ApiServiceTest.java +++ b/service/common/src/test/java/org/apache/polaris/service/auth/DefaultOAuth2ApiServiceTest.java @@ -43,7 +43,8 @@ class DefaultOAuth2ApiServiceTest { when(tokenBrokerFactory.apply(realmContext)).thenReturn(tokenBroker); when(tokenBroker.supportsGrantType(CLIENT_CREDENTIALS)).thenReturn(false); when(tokenBroker.supportsRequestedTokenType(TokenType.ACCESS_TOKEN)).thenReturn(true); - when(tokenBroker.generateFromClientSecrets("client", "secret", CLIENT_CREDENTIALS, "scope")) + when(tokenBroker.generateFromClientSecrets( + "client", "secret", CLIENT_CREDENTIALS, "scope", TokenType.ACCESS_TOKEN)) .thenReturn(new TokenResponse("token", TokenType.ACCESS_TOKEN.getValue(), 3600)); Response response = new InvocationBuilder() @@ -70,7 +71,8 @@ class DefaultOAuth2ApiServiceTest { when(tokenBrokerFactory.apply(realmContext)).thenReturn(tokenBroker); when(tokenBroker.supportsGrantType(CLIENT_CREDENTIALS)).thenReturn(true); when(tokenBroker.supportsRequestedTokenType(TokenType.ACCESS_TOKEN)).thenReturn(false); - when(tokenBroker.generateFromClientSecrets("client", "secret", CLIENT_CREDENTIALS, "scope")) + when(tokenBroker.generateFromClientSecrets( + "client", "secret", CLIENT_CREDENTIALS, "scope", TokenType.ACCESS_TOKEN)) .thenReturn(new TokenResponse("token", TokenType.ACCESS_TOKEN.getValue(), 3600)); Response response = new InvocationBuilder() @@ -97,7 +99,8 @@ class DefaultOAuth2ApiServiceTest { when(tokenBrokerFactory.apply(realmContext)).thenReturn(tokenBroker); when(tokenBroker.supportsGrantType(CLIENT_CREDENTIALS)).thenReturn(true); when(tokenBroker.supportsRequestedTokenType(TokenType.ACCESS_TOKEN)).thenReturn(true); - when(tokenBroker.generateFromClientSecrets(null, "secret", CLIENT_CREDENTIALS, "scope")) + when(tokenBroker.generateFromClientSecrets( + null, "secret", CLIENT_CREDENTIALS, "scope", TokenType.ACCESS_TOKEN)) .thenReturn(new TokenResponse("token", TokenType.ACCESS_TOKEN.getValue(), 3600)); Response response = new InvocationBuilder() @@ -121,7 +124,8 @@ class DefaultOAuth2ApiServiceTest { when(tokenBrokerFactory.apply(realmContext)).thenReturn(tokenBroker); when(tokenBroker.supportsGrantType(CLIENT_CREDENTIALS)).thenReturn(true); when(tokenBroker.supportsRequestedTokenType(TokenType.ACCESS_TOKEN)).thenReturn(true); - when(tokenBroker.generateFromClientSecrets("client", "secret", CLIENT_CREDENTIALS, "scope")) + when(tokenBroker.generateFromClientSecrets( + "client", "secret", CLIENT_CREDENTIALS, "scope", TokenType.ACCESS_TOKEN)) .thenReturn(new TokenResponse("token", TokenType.ACCESS_TOKEN.getValue(), 3600)); Response response = new InvocationBuilder() @@ -147,7 +151,11 @@ class DefaultOAuth2ApiServiceTest { when(tokenBroker.supportsGrantType(TokenRequestValidator.TOKEN_EXCHANGE)).thenReturn(true); when(tokenBroker.supportsRequestedTokenType(TokenType.ACCESS_TOKEN)).thenReturn(true); when(tokenBroker.generateFromClientSecrets( - "client", "secret", TokenRequestValidator.TOKEN_EXCHANGE, "scope")) + "client", + "secret", + TokenRequestValidator.TOKEN_EXCHANGE, + "scope", + TokenType.ACCESS_TOKEN)) .thenReturn(new TokenResponse("token", TokenType.ACCESS_TOKEN.getValue(), 3600)); Response response = new InvocationBuilder() @@ -175,7 +183,7 @@ class DefaultOAuth2ApiServiceTest { when(tokenBroker.supportsGrantType(TokenRequestValidator.TOKEN_EXCHANGE)).thenReturn(true); when(tokenBroker.supportsRequestedTokenType(TokenType.ACCESS_TOKEN)).thenReturn(true); when(tokenBroker.generateFromClientSecrets( - null, "secret", TokenRequestValidator.TOKEN_EXCHANGE, "scope")) + null, "secret", TokenRequestValidator.TOKEN_EXCHANGE, "scope", TokenType.ACCESS_TOKEN)) .thenReturn(new TokenResponse("token", TokenType.ACCESS_TOKEN.getValue(), 3600)); Response response = new InvocationBuilder() @@ -206,7 +214,7 @@ class DefaultOAuth2ApiServiceTest { when(tokenBroker.supportsRequestedTokenType(TokenType.ACCESS_TOKEN)).thenReturn(true); when(tokenBroker.generateFromClientSecrets( - "", "secret", TokenRequestValidator.TOKEN_EXCHANGE, "scope")) + "", "secret", TokenRequestValidator.TOKEN_EXCHANGE, "scope", TokenType.ACCESS_TOKEN)) .thenReturn(new TokenResponse("token", TokenType.ACCESS_TOKEN.getValue(), 3600)); Response response = new InvocationBuilder()
