diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2TokenExchangeAuthenticationProvider.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2TokenExchangeAuthenticationProvider.java index 9c07b63c..dc710338 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2TokenExchangeAuthenticationProvider.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2TokenExchangeAuthenticationProvider.java @@ -37,6 +37,7 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.OAuth2ErrorCodes; import org.springframework.security.oauth2.core.OAuth2Token; +import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; import org.springframework.security.oauth2.core.oidc.StandardClaimNames; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; @@ -70,15 +71,10 @@ public final class OAuth2TokenExchangeAuthenticationProvider implements Authenti private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2"; - private static final AuthorizationGrantType TOKEN_EXCHANGE = new AuthorizationGrantType( - "urn:ietf:params:oauth:grant-type:token-exchange"); - private static final String JWT_TOKEN_TYPE_VALUE = "urn:ietf:params:oauth:token-type:jwt"; private static final String MAY_ACT = "may_act"; - private static final String ISSUED_TOKEN_TYPE = "issued_token_type"; - private final Log logger = LogFactory.getLog(getClass()); private final OAuth2AuthorizationService authorizationService; @@ -112,7 +108,7 @@ public final class OAuth2TokenExchangeAuthenticationProvider implements Authenti this.logger.trace("Retrieved registered client"); } - if (!registeredClient.getAuthorizationGrantTypes().contains(TOKEN_EXCHANGE)) { + if (!registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.TOKEN_EXCHANGE)) { throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT); } @@ -218,7 +214,7 @@ public final class OAuth2TokenExchangeAuthenticationProvider implements Authenti .authorizationServerContext(AuthorizationServerContextHolder.getContext()) .authorizedScopes(authorizedScopes) .tokenType(OAuth2TokenType.ACCESS_TOKEN) - .authorizationGrantType(TOKEN_EXCHANGE) + .authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE) .authorizationGrant(tokenExchangeAuthentication); // @formatter:on @@ -242,7 +238,7 @@ public final class OAuth2TokenExchangeAuthenticationProvider implements Authenti // @formatter:off OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient) .principalName(subjectAuthorization.getPrincipalName()) - .authorizationGrantType(TOKEN_EXCHANGE) + .authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE) .authorizedScopes(authorizedScopes) .attribute(Principal.class.getName(), principal); // @formatter:on @@ -264,7 +260,7 @@ public final class OAuth2TokenExchangeAuthenticationProvider implements Authenti } Map additionalParameters = new HashMap<>(); - additionalParameters.put(ISSUED_TOKEN_TYPE, tokenExchangeAuthentication.getRequestedTokenType()); + additionalParameters.put(OAuth2ParameterNames.ISSUED_TOKEN_TYPE, tokenExchangeAuthentication.getRequestedTokenType()); if (this.logger.isTraceEnabled()) { this.logger.trace("Authenticated token request"); diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2TokenExchangeAuthenticationToken.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2TokenExchangeAuthenticationToken.java index 67efb8a2..06083a9d 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2TokenExchangeAuthenticationToken.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2TokenExchangeAuthenticationToken.java @@ -36,9 +36,6 @@ import org.springframework.util.Assert; */ public class OAuth2TokenExchangeAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken { - private static final AuthorizationGrantType TOKEN_EXCHANGE = new AuthorizationGrantType( - "urn:ietf:params:oauth:grant-type:token-exchange"); - private final List resources; private final List audiences; @@ -73,7 +70,7 @@ public class OAuth2TokenExchangeAuthenticationToken extends OAuth2AuthorizationG @Nullable Set scopes, @Nullable String requestedTokenType, String subjectToken, String subjectTokenType, @Nullable String actorToken, @Nullable String actorTokenType, Authentication clientPrincipal, @Nullable Map additionalParameters) { - super(TOKEN_EXCHANGE, clientPrincipal, additionalParameters); + super(AuthorizationGrantType.TOKEN_EXCHANGE, clientPrincipal, additionalParameters); Assert.notNull(resources, "resources cannot be null"); Assert.notNull(audiences, "audiences cannot be null"); Assert.hasText(requestedTokenType, "requestedTokenType cannot be empty"); diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2TokenExchangeTokenCustomizers.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2TokenExchangeTokenCustomizers.java index c8fcf0b7..39957414 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2TokenExchangeTokenCustomizers.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2TokenExchangeTokenCustomizers.java @@ -38,9 +38,6 @@ import org.springframework.util.CollectionUtils; */ final class OAuth2TokenExchangeTokenCustomizers { - private static final AuthorizationGrantType TOKEN_EXCHANGE = new AuthorizationGrantType( - "urn:ietf:params:oauth:grant-type:token-exchange"); - private OAuth2TokenExchangeTokenCustomizers() { } @@ -53,7 +50,7 @@ final class OAuth2TokenExchangeTokenCustomizers { } private static void customize(OAuth2TokenContext context, Map claims) { - if (!TOKEN_EXCHANGE.equals(context.getAuthorizationGrantType())) { + if (!AuthorizationGrantType.TOKEN_EXCHANGE.equals(context.getAuthorizationGrantType())) { return; } diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcProviderConfigurationEndpointFilter.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcProviderConfigurationEndpointFilter.java index c8e7b868..1b652237 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcProviderConfigurationEndpointFilter.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcProviderConfigurationEndpointFilter.java @@ -105,8 +105,7 @@ public final class OidcProviderConfigurationEndpointFilter extends OncePerReques .grantType(AuthorizationGrantType.CLIENT_CREDENTIALS.getValue()) .grantType(AuthorizationGrantType.REFRESH_TOKEN.getValue()) .grantType(AuthorizationGrantType.DEVICE_CODE.getValue()) - // TODO: Replace with constant from spring-security: - .grantType(new AuthorizationGrantType("urn:ietf:params:oauth:grant-type:token-exchange").getValue()) + .grantType(AuthorizationGrantType.TOKEN_EXCHANGE.getValue()) .tokenRevocationEndpoint(asUrl(issuer, authorizationServerSettings.getTokenRevocationEndpoint())) .tokenRevocationEndpointAuthenticationMethods(clientAuthenticationMethods()) .tokenIntrospectionEndpoint(asUrl(issuer, authorizationServerSettings.getTokenIntrospectionEndpoint())) diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/OAuth2AuthorizationServerMetadataEndpointFilter.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/OAuth2AuthorizationServerMetadataEndpointFilter.java index 7f10c809..3e1db8b2 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/OAuth2AuthorizationServerMetadataEndpointFilter.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/OAuth2AuthorizationServerMetadataEndpointFilter.java @@ -101,8 +101,7 @@ public final class OAuth2AuthorizationServerMetadataEndpointFilter extends OnceP .grantType(AuthorizationGrantType.CLIENT_CREDENTIALS.getValue()) .grantType(AuthorizationGrantType.REFRESH_TOKEN.getValue()) .grantType(AuthorizationGrantType.DEVICE_CODE.getValue()) - // TODO: Replace with constant from spring-security: - .grantType(new AuthorizationGrantType("urn:ietf:params:oauth:grant-type:token-exchange").getValue()) + .grantType(AuthorizationGrantType.TOKEN_EXCHANGE.getValue()) .tokenRevocationEndpoint(asUrl(issuer, authorizationServerSettings.getTokenRevocationEndpoint())) .tokenRevocationEndpointAuthenticationMethods(clientAuthenticationMethods()) .tokenIntrospectionEndpoint(asUrl(issuer, authorizationServerSettings.getTokenIntrospectionEndpoint())) diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/OAuth2TokenExchangeAuthenticationConverter.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/OAuth2TokenExchangeAuthenticationConverter.java index 68fb1253..6fe1b4a7 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/OAuth2TokenExchangeAuthenticationConverter.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/OAuth2TokenExchangeAuthenticationConverter.java @@ -56,23 +56,6 @@ public final class OAuth2TokenExchangeAuthenticationConverter implements Authent private static final String TOKEN_TYPE_IDENTIFIERS_URI = "https://datatracker.ietf.org/doc/html/rfc8693#section-3"; - private static final AuthorizationGrantType TOKEN_EXCHANGE = new AuthorizationGrantType( - "urn:ietf:params:oauth:grant-type:token-exchange"); - - private static final String AUDIENCE = "audience"; - - private static final String RESOURCE = "resource"; - - private static final String REQUESTED_TOKEN_TYPE = "requested_token_type"; - - private static final String SUBJECT_TOKEN = "subject_token"; - - private static final String SUBJECT_TOKEN_TYPE = "subject_token_type"; - - private static final String ACTOR_TOKEN = "actor_token"; - - private static final String ACTOR_TOKEN_TYPE = "actor_token_type"; - private static final String ACCESS_TOKEN_TYPE_VALUE = "urn:ietf:params:oauth:token-type:access_token"; private static final String JWT_TOKEN_TYPE_VALUE = "urn:ietf:params:oauth:token-type:jwt"; @@ -86,27 +69,27 @@ public final class OAuth2TokenExchangeAuthenticationConverter implements Authent // grant_type (REQUIRED) String grantType = parameters.getFirst(OAuth2ParameterNames.GRANT_TYPE); - if (!TOKEN_EXCHANGE.getValue().equals(grantType)) { + if (!AuthorizationGrantType.TOKEN_EXCHANGE.getValue().equals(grantType)) { return null; } Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication(); // resource (OPTIONAL) - List resources = parameters.getOrDefault(RESOURCE, Collections.emptyList()); + List resources = parameters.getOrDefault(OAuth2ParameterNames.RESOURCE, Collections.emptyList()); if (!CollectionUtils.isEmpty(resources)) { for (String resource : resources) { if (!isValidUri(resource)) { OAuth2EndpointUtils.throwError( OAuth2ErrorCodes.INVALID_REQUEST, - RESOURCE, + OAuth2ParameterNames.RESOURCE, OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); } } } // audience (OPTIONAL) - List audiences = parameters.getOrDefault(AUDIENCE, Collections.emptyList()); + List audiences = parameters.getOrDefault(OAuth2ParameterNames.AUDIENCE, Collections.emptyList()); // scope (OPTIONAL) String scope = parameters.getFirst(OAuth2ParameterNames.SCOPE); @@ -125,87 +108,87 @@ public final class OAuth2TokenExchangeAuthenticationConverter implements Authent } // requested_token_type (OPTIONAL) - String requestedTokenType = parameters.getFirst(REQUESTED_TOKEN_TYPE); + String requestedTokenType = parameters.getFirst(OAuth2ParameterNames.REQUESTED_TOKEN_TYPE); if (StringUtils.hasText(requestedTokenType)) { - if (parameters.get(REQUESTED_TOKEN_TYPE).size() != 1) { + if (parameters.get(OAuth2ParameterNames.REQUESTED_TOKEN_TYPE).size() != 1) { OAuth2EndpointUtils.throwError( OAuth2ErrorCodes.INVALID_REQUEST, - REQUESTED_TOKEN_TYPE, + OAuth2ParameterNames.REQUESTED_TOKEN_TYPE, OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); } - validateTokenType(REQUESTED_TOKEN_TYPE, requestedTokenType); + validateTokenType(OAuth2ParameterNames.REQUESTED_TOKEN_TYPE, requestedTokenType); } else { requestedTokenType = ACCESS_TOKEN_TYPE_VALUE; } // subject_token (REQUIRED) - String subjectToken = parameters.getFirst(SUBJECT_TOKEN); + String subjectToken = parameters.getFirst(OAuth2ParameterNames.SUBJECT_TOKEN); if (!StringUtils.hasText(subjectToken) || - parameters.get(SUBJECT_TOKEN).size() != 1) { + parameters.get(OAuth2ParameterNames.SUBJECT_TOKEN).size() != 1) { OAuth2EndpointUtils.throwError( OAuth2ErrorCodes.INVALID_REQUEST, - SUBJECT_TOKEN, + OAuth2ParameterNames.SUBJECT_TOKEN, OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); } // subject_token_type (REQUIRED) - String subjectTokenType = parameters.getFirst(SUBJECT_TOKEN_TYPE); + String subjectTokenType = parameters.getFirst(OAuth2ParameterNames.SUBJECT_TOKEN_TYPE); if (!StringUtils.hasText(subjectTokenType) || - parameters.get(SUBJECT_TOKEN_TYPE).size() != 1) { + parameters.get(OAuth2ParameterNames.SUBJECT_TOKEN_TYPE).size() != 1) { OAuth2EndpointUtils.throwError( OAuth2ErrorCodes.INVALID_REQUEST, - SUBJECT_TOKEN_TYPE, + OAuth2ParameterNames.SUBJECT_TOKEN_TYPE, OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); } else { - validateTokenType(SUBJECT_TOKEN_TYPE, subjectTokenType); + validateTokenType(OAuth2ParameterNames.SUBJECT_TOKEN_TYPE, subjectTokenType); } // actor_token (OPTIONAL, REQUIRED if actor_token_type is provided) - String actorToken = parameters.getFirst(ACTOR_TOKEN); + String actorToken = parameters.getFirst(OAuth2ParameterNames.ACTOR_TOKEN); if (StringUtils.hasText(actorToken) && - parameters.get(ACTOR_TOKEN).size() != 1) { + parameters.get(OAuth2ParameterNames.ACTOR_TOKEN).size() != 1) { OAuth2EndpointUtils.throwError( OAuth2ErrorCodes.INVALID_REQUEST, - ACTOR_TOKEN, + OAuth2ParameterNames.ACTOR_TOKEN, OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); } // actor_token_type (OPTIONAL, REQUIRED if actor_token is provided) - String actorTokenType = parameters.getFirst(ACTOR_TOKEN_TYPE); + String actorTokenType = parameters.getFirst(OAuth2ParameterNames.ACTOR_TOKEN_TYPE); if (StringUtils.hasText(actorTokenType)) { - if (parameters.get(ACTOR_TOKEN_TYPE).size() != 1) { + if (parameters.get(OAuth2ParameterNames.ACTOR_TOKEN_TYPE).size() != 1) { OAuth2EndpointUtils.throwError( OAuth2ErrorCodes.INVALID_REQUEST, - ACTOR_TOKEN_TYPE, + OAuth2ParameterNames.ACTOR_TOKEN_TYPE, OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); } - validateTokenType(ACTOR_TOKEN_TYPE, actorTokenType); + validateTokenType(OAuth2ParameterNames.ACTOR_TOKEN_TYPE, actorTokenType); } if (!StringUtils.hasText(actorToken) && StringUtils.hasText(actorTokenType)) { OAuth2EndpointUtils.throwError( OAuth2ErrorCodes.INVALID_REQUEST, - ACTOR_TOKEN, + OAuth2ParameterNames.ACTOR_TOKEN, OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); } else if (StringUtils.hasText(actorToken) && !StringUtils.hasText(actorTokenType)) { OAuth2EndpointUtils.throwError( OAuth2ErrorCodes.INVALID_REQUEST, - ACTOR_TOKEN_TYPE, + OAuth2ParameterNames.ACTOR_TOKEN_TYPE, OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); } Map additionalParameters = new HashMap<>(); parameters.forEach((key, value) -> { if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) && - !key.equals(RESOURCE) && - !key.equals(AUDIENCE) && - !key.equals(REQUESTED_TOKEN_TYPE) && - !key.equals(SUBJECT_TOKEN) && - !key.equals(SUBJECT_TOKEN_TYPE) && - !key.equals(ACTOR_TOKEN) && - !key.equals(ACTOR_TOKEN_TYPE) && + !key.equals(OAuth2ParameterNames.RESOURCE) && + !key.equals(OAuth2ParameterNames.AUDIENCE) && + !key.equals(OAuth2ParameterNames.REQUESTED_TOKEN_TYPE) && + !key.equals(OAuth2ParameterNames.SUBJECT_TOKEN) && + !key.equals(OAuth2ParameterNames.SUBJECT_TOKEN_TYPE) && + !key.equals(OAuth2ParameterNames.ACTOR_TOKEN) && + !key.equals(OAuth2ParameterNames.ACTOR_TOKEN_TYPE) && !key.equals(OAuth2ParameterNames.SCOPE)) { additionalParameters.put(key, (value.size() == 1) ? value.get(0) : value.toArray(new String[0])); }