Skip to content

Commit 149aaa6

Browse files
authored
Auth: reorganize internal authentication components (#2634)
This PR contains no functional and no user-facing change. It is merely a refactor to better organize auth code. Summary of changes: - Moved all internal authentication components to the `org.apache.polaris.service.auth.internal` package and subpackages - Reduced visibility of utility classes - Renamed `TokenBroker` class hierarchy to stick to the naming standard: `<Algorithm>JWTBroker` - Introduced `@PolarisImmutable` whenever appropriate - Removed unused `NoneTokenBrokerFactory` (we already have `DisabledOAuth2ApiService`) - Removed unused `TokenBrokerFactoryConfig`
1 parent 7110592 commit 149aaa6

33 files changed

+298
-436
lines changed

runtime/service/src/main/java/org/apache/polaris/service/auth/AuthenticationRealmConfiguration.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import java.nio.file.Path;
2323
import java.time.Duration;
2424
import java.util.Optional;
25+
import org.apache.polaris.service.auth.internal.broker.TokenBrokerFactory;
26+
import org.apache.polaris.service.catalog.api.IcebergRestOAuth2ApiService;
2527

2628
public interface AuthenticationRealmConfiguration {
2729

@@ -38,10 +40,7 @@ public interface AuthenticationRealmConfiguration {
3840

3941
interface AuthenticatorConfiguration {
4042

41-
/**
42-
* The type of the identity provider. Must be a registered {@link
43-
* org.apache.polaris.service.auth.Authenticator} identifier.
44-
*/
43+
/** The type of the identity provider. Must be a registered {@link Authenticator} identifier. */
4544
@WithDefault("default")
4645
String type();
4746
}
@@ -54,8 +53,8 @@ interface AuthenticatorConfiguration {
5453

5554
interface TokenServiceConfiguration {
5655
/**
57-
* The type of the OAuth2 service. Must be a registered {@link
58-
* org.apache.polaris.service.catalog.api.IcebergRestOAuth2ApiService} identifier.
56+
* The type of the OAuth2 service. Must be a registered {@link IcebergRestOAuth2ApiService}
57+
* identifier.
5958
*/
6059
@WithDefault("default")
6160
String type();
@@ -75,8 +74,8 @@ interface TokenBrokerConfiguration {
7574
Duration maxTokenGeneration();
7675

7776
/**
78-
* The type of the token broker factory. Must be a registered {@link
79-
* org.apache.polaris.service.auth.TokenBrokerFactory} identifier.
77+
* The type of the token broker factory. Must be a registered {@link TokenBrokerFactory}
78+
* identifier.
8079
*/
8180
@WithDefault("rsa-key-pair")
8281
String type();

runtime/service/src/main/java/org/apache/polaris/service/auth/NoneTokenBrokerFactory.java

Lines changed: 0 additions & 76 deletions
This file was deleted.

runtime/service/src/main/java/org/apache/polaris/service/auth/OAuthTokenErrorResponse.java

Lines changed: 0 additions & 72 deletions
This file was deleted.

runtime/service/src/main/java/org/apache/polaris/service/auth/TokenResponse.java

Lines changed: 0 additions & 59 deletions
This file was deleted.

runtime/service/src/main/java/org/apache/polaris/service/auth/internal/InternalAuthenticationMechanism.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
import org.apache.polaris.service.auth.AuthenticationRealmConfiguration;
4040
import org.apache.polaris.service.auth.AuthenticationType;
4141
import org.apache.polaris.service.auth.PolarisCredential;
42-
import org.apache.polaris.service.auth.TokenBroker;
42+
import org.apache.polaris.service.auth.internal.broker.TokenBroker;
4343

4444
/**
4545
* A custom {@link HttpAuthenticationMechanism} that handles internal token authentication, that is,

runtime/service/src/main/java/org/apache/polaris/service/auth/InternalPolarisToken.java renamed to runtime/service/src/main/java/org/apache/polaris/service/auth/internal/broker/InternalPolarisToken.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@
1616
* specific language governing permissions and limitations
1717
* under the License.
1818
*/
19-
package org.apache.polaris.service.auth;
19+
package org.apache.polaris.service.auth.internal.broker;
2020

2121
import com.google.common.base.Splitter;
2222
import jakarta.annotation.Nonnull;
2323
import java.util.Set;
2424
import java.util.stream.Collectors;
2525
import org.apache.polaris.immutables.PolarisImmutable;
26+
import org.apache.polaris.service.auth.PolarisCredential;
2627
import org.immutables.value.Value;
2728

2829
/**

runtime/service/src/main/java/org/apache/polaris/service/auth/JWTBroker.java renamed to runtime/service/src/main/java/org/apache/polaris/service/auth/internal/broker/JWTBroker.java

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
* specific language governing permissions and limitations
1717
* under the License.
1818
*/
19-
package org.apache.polaris.service.auth;
19+
package org.apache.polaris.service.auth.internal.broker;
2020

2121
import com.auth0.jwt.JWT;
2222
import com.auth0.jwt.algorithms.Algorithm;
@@ -32,7 +32,10 @@
3232
import org.apache.polaris.core.entity.PrincipalEntity;
3333
import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
3434
import org.apache.polaris.core.persistence.dao.entity.EntityResult;
35-
import org.apache.polaris.service.auth.OAuthTokenErrorResponse.Error;
35+
import org.apache.polaris.core.persistence.dao.entity.PrincipalSecretsResult;
36+
import org.apache.polaris.service.auth.DefaultAuthenticator;
37+
import org.apache.polaris.service.auth.PolarisCredential;
38+
import org.apache.polaris.service.auth.internal.service.OAuthError;
3639
import org.apache.polaris.service.types.TokenType;
3740
import org.slf4j.Logger;
3841
import org.slf4j.LoggerFactory;
@@ -88,35 +91,35 @@ public TokenResponse generateFromToken(
8891
PolarisCallContext polarisCallContext,
8992
TokenType requestedTokenType) {
9093
if (requestedTokenType != null && !TokenType.ACCESS_TOKEN.equals(requestedTokenType)) {
91-
return new TokenResponse(OAuthTokenErrorResponse.Error.invalid_request);
94+
return TokenResponse.of(OAuthError.invalid_request);
9295
}
9396
if (!TokenType.ACCESS_TOKEN.equals(subjectTokenType)) {
94-
return new TokenResponse(OAuthTokenErrorResponse.Error.invalid_request);
97+
return TokenResponse.of(OAuthError.invalid_request);
9598
}
9699
if (subjectToken == null || subjectToken.isBlank()) {
97-
return new TokenResponse(OAuthTokenErrorResponse.Error.invalid_request);
100+
return TokenResponse.of(OAuthError.invalid_request);
98101
}
99102
InternalPolarisToken decodedToken;
100103
try {
101104
decodedToken = verifyInternal(subjectToken);
102105
} catch (NotAuthorizedException e) {
103106
LOGGER.error("Failed to verify the token", e.getCause());
104-
return new TokenResponse(Error.invalid_client);
107+
return TokenResponse.of(OAuthError.invalid_client);
105108
}
106109
EntityResult principalLookup =
107110
metaStoreManager.loadEntity(
108111
polarisCallContext, 0L, decodedToken.getPrincipalId(), PolarisEntityType.PRINCIPAL);
109112
if (!principalLookup.isSuccess()
110113
|| principalLookup.getEntity().getType() != PolarisEntityType.PRINCIPAL) {
111-
return new TokenResponse(OAuthTokenErrorResponse.Error.unauthorized_client);
114+
return TokenResponse.of(OAuthError.unauthorized_client);
112115
}
113116
String tokenString =
114117
generateTokenString(
115118
decodedToken.getPrincipalName(),
116119
decodedToken.getPrincipalId(),
117120
decodedToken.getClientId(),
118121
decodedToken.getScope());
119-
return new TokenResponse(
122+
return TokenResponse.of(
120123
tokenString, TokenType.ACCESS_TOKEN.getValue(), maxTokenGenerationInSeconds);
121124
}
122125

@@ -130,21 +133,20 @@ public TokenResponse generateFromClientSecrets(
130133
TokenType requestedTokenType) {
131134
// Initial sanity checks
132135
TokenRequestValidator validator = new TokenRequestValidator();
133-
Optional<OAuthTokenErrorResponse.Error> initialValidationResponse =
136+
Optional<OAuthError> initialValidationResponse =
134137
validator.validateForClientCredentialsFlow(clientId, clientSecret, grantType, scope);
135138
if (initialValidationResponse.isPresent()) {
136-
return new TokenResponse(initialValidationResponse.get());
139+
return TokenResponse.of(initialValidationResponse.get());
137140
}
138141

139142
Optional<PrincipalEntity> principal =
140-
TokenBroker.findPrincipalEntity(
141-
metaStoreManager, clientId, clientSecret, polarisCallContext);
143+
findPrincipalEntity(clientId, clientSecret, polarisCallContext);
142144
if (principal.isEmpty()) {
143-
return new TokenResponse(OAuthTokenErrorResponse.Error.unauthorized_client);
145+
return TokenResponse.of(OAuthError.unauthorized_client);
144146
}
145147
String tokenString =
146148
generateTokenString(principal.get().getName(), principal.get().getId(), clientId, scope);
147-
return new TokenResponse(
149+
return TokenResponse.of(
148150
tokenString, TokenType.ACCESS_TOKEN.getValue(), maxTokenGenerationInSeconds);
149151
}
150152

@@ -177,4 +179,27 @@ public boolean supportsRequestedTokenType(TokenType tokenType) {
177179
private String scopes(String scope) {
178180
return scope == null || scope.isBlank() ? DefaultAuthenticator.PRINCIPAL_ROLE_ALL : scope;
179181
}
182+
183+
private Optional<PrincipalEntity> findPrincipalEntity(
184+
String clientId, String clientSecret, PolarisCallContext polarisCallContext) {
185+
// Validate the principal is present and secrets match
186+
PrincipalSecretsResult principalSecrets =
187+
metaStoreManager.loadPrincipalSecrets(polarisCallContext, clientId);
188+
if (!principalSecrets.isSuccess()) {
189+
return Optional.empty();
190+
}
191+
if (!principalSecrets.getPrincipalSecrets().matchesSecret(clientSecret)) {
192+
return Optional.empty();
193+
}
194+
EntityResult result =
195+
metaStoreManager.loadEntity(
196+
polarisCallContext,
197+
0L,
198+
principalSecrets.getPrincipalSecrets().getPrincipalId(),
199+
PolarisEntityType.PRINCIPAL);
200+
if (!result.isSuccess() || result.getEntity().getType() != PolarisEntityType.PRINCIPAL) {
201+
return Optional.empty();
202+
}
203+
return Optional.of(PrincipalEntity.of(result.getEntity()));
204+
}
180205
}

0 commit comments

Comments
 (0)