From 511d702ee031812b993e9ef2d1b34640d14d565f Mon Sep 17 00:00:00 2001 From: Joe Grandja Date: Mon, 30 Oct 2017 11:31:19 -0400 Subject: [PATCH] Remove JwtDecoderRegistry Fixes gh-4754 --- .../oauth2/client/OAuth2LoginConfigurer.java | 5 +- .../oauth2/client/jwt/JwtDecoderRegistry.java | 33 ----------- .../client/jwt/NimbusJwtDecoderRegistry.java | 59 ------------------- ...thorizationCodeAuthenticationProvider.java | 37 ++++++++---- 4 files changed, 27 insertions(+), 107 deletions(-) delete mode 100644 oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jwt/JwtDecoderRegistry.java delete mode 100644 oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jwt/NimbusJwtDecoderRegistry.java diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java index 64fa97232c..8e999553ff 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java @@ -27,8 +27,6 @@ import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuth import org.springframework.security.oauth2.client.endpoint.NimbusAuthorizationCodeTokenResponseClient; import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient; import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest; -import org.springframework.security.oauth2.client.jwt.JwtDecoderRegistry; -import org.springframework.security.oauth2.client.jwt.NimbusJwtDecoderRegistry; import org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeAuthenticationProvider; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService; @@ -252,11 +250,10 @@ public final class OAuth2LoginConfigurer> exten if (oidcUserService == null) { oidcUserService = new OidcUserService(); } - JwtDecoderRegistry jwtDecoderRegistry = new NimbusJwtDecoderRegistry(); OidcAuthorizationCodeAuthenticationProvider oidcAuthorizationCodeAuthenticationProvider = new OidcAuthorizationCodeAuthenticationProvider( - accessTokenResponseClient, oidcUserService, jwtDecoderRegistry); + accessTokenResponseClient, oidcUserService); if (this.userInfoEndpointConfig.userAuthoritiesMapper != null) { oidcAuthorizationCodeAuthenticationProvider.setAuthoritiesMapper( this.userInfoEndpointConfig.userAuthoritiesMapper); diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jwt/JwtDecoderRegistry.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jwt/JwtDecoderRegistry.java deleted file mode 100644 index c548915464..0000000000 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jwt/JwtDecoderRegistry.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed 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.springframework.security.oauth2.client.jwt; - -import org.springframework.security.oauth2.jwt.JwtDecoder; -import org.springframework.security.oauth2.client.registration.ClientRegistration; - -/** - * A registry of {@link JwtDecoder}'s that are associated to a {@link ClientRegistration}. - * - * @author Joe Grandja - * @since 5.0 - * @see JwtDecoder - * @see ClientRegistration - */ -public interface JwtDecoderRegistry { - - JwtDecoder getJwtDecoder(ClientRegistration registration); - -} diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jwt/NimbusJwtDecoderRegistry.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jwt/NimbusJwtDecoderRegistry.java deleted file mode 100644 index aa22e30ac2..0000000000 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jwt/NimbusJwtDecoderRegistry.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed 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.springframework.security.oauth2.client.jwt; - -import org.springframework.security.oauth2.jwt.JwtDecoder; -import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport; -import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * A {@link JwtDecoderRegistry} that creates/manages instances of - * {@link NimbusJwtDecoderJwkSupport}, which uses the Nimbus JOSE + JWT SDK internally. - * - * @author Joe Grandja - * @since 5.0 - * @see JwtDecoderRegistry - * @see NimbusJwtDecoderJwkSupport - * @see Nimbus JOSE + JWT SDK - */ -public class NimbusJwtDecoderRegistry implements JwtDecoderRegistry { - private final Map jwtDecoders = new ConcurrentHashMap<>(); - - @Override - public JwtDecoder getJwtDecoder(ClientRegistration registration) { - Assert.notNull(registration, "registration cannot be null"); - if (!this.jwtDecoders.containsKey(registration.getRegistrationId())) { - JwtDecoder jwtDecoder = this.createJwtDecoder(registration); - if (jwtDecoder != null) { - this.jwtDecoders.put(registration.getRegistrationId(), jwtDecoder); - } - } - return this.jwtDecoders.get(registration.getRegistrationId()); - } - - private JwtDecoder createJwtDecoder(ClientRegistration registration) { - JwtDecoder jwtDecoder = null; - if (StringUtils.hasText(registration.getProviderDetails().getJwkSetUri())) { - jwtDecoder = new NimbusJwtDecoderJwkSupport(registration.getProviderDetails().getJwkSetUri()); - } - return jwtDecoder; - } -} diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProvider.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProvider.java index 17b87e1ea4..ebf19135b7 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProvider.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProvider.java @@ -23,7 +23,6 @@ import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMap import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken; import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient; import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest; -import org.springframework.security.oauth2.client.jwt.JwtDecoderRegistry; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService; import org.springframework.security.oauth2.client.registration.ClientRegistration; @@ -40,13 +39,17 @@ import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames import org.springframework.security.oauth2.core.oidc.user.OidcUser; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtDecoder; +import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import java.net.URL; import java.time.Instant; import java.util.Collection; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * An implementation of an {@link AuthenticationProvider} @@ -74,22 +77,20 @@ public class OidcAuthorizationCodeAuthenticationProvider implements Authenticati private static final String INVALID_STATE_PARAMETER_ERROR_CODE = "invalid_state_parameter"; private static final String INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE = "invalid_redirect_uri_parameter"; private static final String INVALID_ID_TOKEN_ERROR_CODE = "invalid_id_token"; + private static final String MISSING_SIGNATURE_VERIFIER_ERROR_CODE = "missing_signature_verifier"; private final OAuth2AccessTokenResponseClient accessTokenResponseClient; private final OAuth2UserService userService; - private final JwtDecoderRegistry jwtDecoderRegistry; + private final Map jwtDecoders = new ConcurrentHashMap<>(); private GrantedAuthoritiesMapper authoritiesMapper = (authorities -> authorities); public OidcAuthorizationCodeAuthenticationProvider( OAuth2AccessTokenResponseClient accessTokenResponseClient, - OAuth2UserService userService, - JwtDecoderRegistry jwtDecoderRegistry) { + OAuth2UserService userService) { Assert.notNull(accessTokenResponseClient, "accessTokenResponseClient cannot be null"); Assert.notNull(userService, "userService cannot be null"); - Assert.notNull(jwtDecoderRegistry, "jwtDecoderRegistry cannot be null"); this.accessTokenResponseClient = accessTokenResponseClient; this.userService = userService; - this.jwtDecoderRegistry = jwtDecoderRegistry; } @Override @@ -142,11 +143,7 @@ public class OidcAuthorizationCodeAuthenticationProvider implements Authenticati "Missing (required) ID Token in Token Response for Client Registration: " + clientRegistration.getRegistrationId()); } - JwtDecoder jwtDecoder = this.jwtDecoderRegistry.getJwtDecoder(clientRegistration); - if (jwtDecoder == null) { - throw new IllegalArgumentException("Failed to find a registered JwtDecoder for Client Registration: '" + - clientRegistration.getRegistrationId() + "'. Check to ensure you have configured the JwkSet URI."); - } + JwtDecoder jwtDecoder = this.getJwtDecoder(clientRegistration); Jwt jwt = jwtDecoder.decode((String) accessTokenResponse.getAdditionalParameters().get(OidcParameterNames.ID_TOKEN)); OidcIdToken idToken = new OidcIdToken(jwt.getTokenValue(), jwt.getIssuedAt(), jwt.getExpiresAt(), jwt.getClaims()); @@ -179,6 +176,24 @@ public class OidcAuthorizationCodeAuthenticationProvider implements Authenticati return OAuth2LoginAuthenticationToken.class.isAssignableFrom(authentication); } + private JwtDecoder getJwtDecoder(ClientRegistration clientRegistration) { + JwtDecoder jwtDecoder = this.jwtDecoders.get(clientRegistration.getRegistrationId()); + if (jwtDecoder == null) { + if (!StringUtils.hasText(clientRegistration.getProviderDetails().getJwkSetUri())) { + OAuth2Error oauth2Error = new OAuth2Error( + MISSING_SIGNATURE_VERIFIER_ERROR_CODE, + "Failed to find a Signature Verifier for Client Registration: '" + + clientRegistration.getRegistrationId() + "'. Check to ensure you have configured the JwkSet URI.", + null + ); + throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); + } + jwtDecoder = new NimbusJwtDecoderJwkSupport(clientRegistration.getProviderDetails().getJwkSetUri()); + this.jwtDecoders.put(clientRegistration.getRegistrationId(), jwtDecoder); + } + return jwtDecoder; + } + private void validateIdToken(OidcIdToken idToken, ClientRegistration clientRegistration) { // 3.1.3.7 ID Token Validation // http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation