Apply Spring formatting to 1.2.x

Issue gh-1616
This commit is contained in:
Joe Grandja
2024-05-16 06:11:50 -04:00
parent f94964c6d6
commit 9be1438c25
23 changed files with 292 additions and 243 deletions

View File

@@ -75,8 +75,9 @@ public class JdbcOAuth2AuthorizationConsentService implements OAuth2Authorizatio
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.resources().registerResource(new ClassPathResource(
"org/springframework/security/oauth2/server/authorization/oauth2-authorization-consent-schema.sql"));
hints.resources()
.registerResource(new ClassPathResource(
"org/springframework/security/oauth2/server/authorization/oauth2-authorization-consent-schema.sql"));
}
}

View File

@@ -101,8 +101,9 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.resources().registerResource(new ClassPathResource(
"org/springframework/security/oauth2/server/authorization/oauth2-authorization-schema.sql"));
hints.resources()
.registerResource(new ClassPathResource(
"org/springframework/security/oauth2/server/authorization/oauth2-authorization-schema.sql"));
}
}

View File

@@ -51,19 +51,22 @@ import org.springframework.security.web.savedrequest.DefaultSavedRequest;
import org.springframework.util.ClassUtils;
/**
* {@link BeanRegistrationAotProcessor} that detects specific registered beans and contributes the required {@link RuntimeHints}.
* Statically registered via META-INF/spring/aot.factories.
* {@link BeanRegistrationAotProcessor} that detects specific registered beans and
* contributes the required {@link RuntimeHints}. Statically registered via
* META-INF/spring/aot.factories.
*
* @author Joe Grandja
* @author Josh Long
* @since 1.2
*/
class OAuth2AuthorizationServerBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor {
private boolean jackson2Contributed;
@Override
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
String beanClassName = registeredBean.getBeanClass().getName();
// @formatter:off
if ((beanClassName.equals("org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService") ||
beanClassName.equals("org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository")) &&
!jackson2Contributed) {
@@ -72,10 +75,13 @@ class OAuth2AuthorizationServerBeanRegistrationAotProcessor implements BeanRegis
jackson2Contributed = true;
return jackson2Contribution;
}
// @formatter:on
return null;
}
private static class Jackson2ConfigurationBeanRegistrationAotContribution implements BeanRegistrationAotContribution {
private static class Jackson2ConfigurationBeanRegistrationAotContribution
implements BeanRegistrationAotContribution {
private final BindingReflectionHintsRegistrar reflectionHintsRegistrar = new BindingReflectionHintsRegistrar();
@Override
@@ -84,50 +90,40 @@ class OAuth2AuthorizationServerBeanRegistrationAotProcessor implements BeanRegis
}
private void registerHints(RuntimeHints hints) {
// Collections -> UnmodifiableSet, UnmodifiableList, UnmodifiableMap, UnmodifiableRandomAccessList, etc.
hints.reflection().registerType(Collections.class,
MemberCategory.DECLARED_CLASSES);
// Collections -> UnmodifiableSet, UnmodifiableList, UnmodifiableMap,
// UnmodifiableRandomAccessList, etc.
hints.reflection().registerType(Collections.class, MemberCategory.DECLARED_CLASSES);
// HashSet
hints.reflection().registerType(HashSet.class,
MemberCategory.DECLARED_FIELDS, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_DECLARED_METHODS);
hints.reflection()
.registerType(HashSet.class, MemberCategory.DECLARED_FIELDS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS);
// Spring Security and Spring Authorization Server
hints.reflection().registerTypes(
Arrays.asList(
TypeReference.of(AbstractAuthenticationToken.class),
TypeReference.of(DefaultSavedRequest.Builder.class),
TypeReference.of(WebAuthenticationDetails.class),
TypeReference.of(UsernamePasswordAuthenticationToken.class),
TypeReference.of(User.class),
TypeReference.of(DefaultOidcUser.class),
TypeReference.of(DefaultOAuth2User.class),
TypeReference.of(OidcUserAuthority.class),
TypeReference.of(OAuth2UserAuthority.class),
TypeReference.of(SimpleGrantedAuthority.class),
TypeReference.of(OidcIdToken.class),
TypeReference.of(AbstractOAuth2Token.class),
TypeReference.of(OidcUserInfo.class),
TypeReference.of(OAuth2AuthorizationRequest.class),
TypeReference.of(AuthorizationGrantType.class),
TypeReference.of(OAuth2AuthorizationResponseType.class),
TypeReference.of(OAuth2TokenFormat.class)
), builder ->
builder.withMembers(MemberCategory.DECLARED_FIELDS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS)
);
hints.reflection()
.registerTypes(Arrays.asList(TypeReference.of(AbstractAuthenticationToken.class),
TypeReference.of(DefaultSavedRequest.Builder.class),
TypeReference.of(WebAuthenticationDetails.class),
TypeReference.of(UsernamePasswordAuthenticationToken.class), TypeReference.of(User.class),
TypeReference.of(DefaultOidcUser.class), TypeReference.of(DefaultOAuth2User.class),
TypeReference.of(OidcUserAuthority.class), TypeReference.of(OAuth2UserAuthority.class),
TypeReference.of(SimpleGrantedAuthority.class), TypeReference.of(OidcIdToken.class),
TypeReference.of(AbstractOAuth2Token.class), TypeReference.of(OidcUserInfo.class),
TypeReference.of(OAuth2AuthorizationRequest.class),
TypeReference.of(AuthorizationGrantType.class),
TypeReference.of(OAuth2AuthorizationResponseType.class),
TypeReference.of(OAuth2TokenFormat.class)),
builder -> builder.withMembers(MemberCategory.DECLARED_FIELDS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS));
// Jackson Modules - Spring Security and Spring Authorization Server
hints.reflection().registerTypes(
Arrays.asList(
TypeReference.of(CoreJackson2Module.class),
TypeReference.of(WebServletJackson2Module.class),
TypeReference.of(OAuth2AuthorizationServerJackson2Module.class)
), builder ->
builder.withMembers(MemberCategory.DECLARED_FIELDS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS)
);
hints.reflection()
.registerTypes(
Arrays.asList(TypeReference.of(CoreJackson2Module.class),
TypeReference.of(WebServletJackson2Module.class),
TypeReference.of(OAuth2AuthorizationServerJackson2Module.class)),
builder -> builder.withMembers(MemberCategory.DECLARED_FIELDS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS));
// Jackson Mixins - Spring Security and Spring Authorization Server
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
@@ -136,8 +132,8 @@ class OAuth2AuthorizationServerBeanRegistrationAotProcessor implements BeanRegis
loadClass("org.springframework.security.jackson2.UnmodifiableListMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.jackson2.UnmodifiableMapMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.oauth2.server.authorization.jackson2.UnmodifiableMapMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), loadClass(
"org.springframework.security.oauth2.server.authorization.jackson2.UnmodifiableMapMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.oauth2.server.authorization.jackson2.HashSetMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
@@ -150,28 +146,29 @@ class OAuth2AuthorizationServerBeanRegistrationAotProcessor implements BeanRegis
loadClass("org.springframework.security.jackson2.UserMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.jackson2.SimpleGrantedAuthorityMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationRequestMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.oauth2.server.authorization.jackson2.OAuth2TokenFormatMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), loadClass(
"org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationRequestMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), loadClass(
"org.springframework.security.oauth2.server.authorization.jackson2.OAuth2TokenFormatMixin"));
// Check if Spring Security OAuth2 Client is on classpath
if (ClassUtils.isPresent("org.springframework.security.oauth2.client.registration.ClientRegistration",
ClassUtils.getDefaultClassLoader())) {
// Jackson Module (and required types) - Spring Security OAuth2 Client
hints.reflection().registerTypes(
Arrays.asList(
TypeReference.of("org.springframework.security.oauth2.client.jackson2.OAuth2ClientJackson2Module"),
TypeReference.of("org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken")
), builder ->
builder.withMembers(MemberCategory.DECLARED_FIELDS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS)
);
hints.reflection()
.registerTypes(Arrays.asList(
TypeReference
.of("org.springframework.security.oauth2.client.jackson2.OAuth2ClientJackson2Module"),
TypeReference
.of("org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken")),
builder -> builder.withMembers(MemberCategory.DECLARED_FIELDS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_DECLARED_METHODS));
// Jackson Mixins - Spring Security OAuth2 Client
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.oauth2.client.jackson2.OAuth2AuthenticationTokenMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), loadClass(
"org.springframework.security.oauth2.client.jackson2.OAuth2AuthenticationTokenMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.oauth2.client.jackson2.DefaultOidcUserMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
@@ -190,7 +187,8 @@ class OAuth2AuthorizationServerBeanRegistrationAotProcessor implements BeanRegis
private static Class<?> loadClass(String className) {
try {
return Class.forName(className);
} catch (ClassNotFoundException ex) {
}
catch (ClassNotFoundException ex) {
throw new RuntimeException(ex);
}
}

View File

@@ -123,8 +123,9 @@ public final class ClientSecretAuthenticationProvider implements AuthenticationP
String clientSecret = clientAuthentication.getCredentials().toString();
if (!this.passwordEncoder.matches(clientSecret, registeredClient.getClientSecret())) {
if (this.logger.isDebugEnabled()) {
this.logger.debug(LogMessage.format("Invalid request: client_secret does not match" +
" for registered client '%s'", registeredClient.getId()));
this.logger.debug(LogMessage.format(
"Invalid request: client_secret does not match" + " for registered client '%s'",
registeredClient.getId()));
}
throwInvalidClient(OAuth2ParameterNames.CLIENT_SECRET);
}

View File

@@ -98,11 +98,11 @@ final class CodeVerifierAuthenticator {
.get(PkceParameterNames.CODE_CHALLENGE);
String codeVerifier = (String) parameters.get(PkceParameterNames.CODE_VERIFIER);
if (!StringUtils.hasText(codeChallenge)) {
if (registeredClient.getClientSettings().isRequireProofKey() ||
StringUtils.hasText(codeVerifier)) {
if (registeredClient.getClientSettings().isRequireProofKey() || StringUtils.hasText(codeVerifier)) {
if (this.logger.isDebugEnabled()) {
this.logger.debug(LogMessage.format("Invalid request: code_challenge is required" +
" for registered client '%s'", registeredClient.getId()));
this.logger.debug(LogMessage.format(
"Invalid request: code_challenge is required" + " for registered client '%s'",
registeredClient.getId()));
}
throwInvalidGrant(PkceParameterNames.CODE_CHALLENGE);
}
@@ -122,8 +122,9 @@ final class CodeVerifierAuthenticator {
.get(PkceParameterNames.CODE_CHALLENGE_METHOD);
if (!codeVerifierValid(codeVerifier, codeChallenge, codeChallengeMethod)) {
if (this.logger.isDebugEnabled()) {
this.logger.debug(LogMessage.format("Invalid request: code_verifier is missing or invalid" +
" for registered client '%s'", registeredClient.getId()));
this.logger.debug(LogMessage.format(
"Invalid request: code_verifier is missing or invalid" + " for registered client '%s'",
registeredClient.getId()));
}
throwInvalidGrant(PkceParameterNames.CODE_VERIFIER);
}

View File

@@ -56,6 +56,7 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationValidator
implements Consumer<OAuth2AuthorizationCodeRequestAuthenticationContext> {
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1";
private static final Log LOGGER = LogFactory.getLog(OAuth2AuthorizationCodeRequestAuthenticationValidator.class);
/**
@@ -87,8 +88,9 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationValidator
Set<String> allowedScopes = registeredClient.getScopes();
if (!requestedScopes.isEmpty() && !allowedScopes.containsAll(requestedScopes)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(LogMessage.format("Invalid request: requested scope is not allowed" +
" for registered client '%s'", registeredClient.getId()));
LOGGER.debug(LogMessage.format(
"Invalid request: requested scope is not allowed" + " for registered client '%s'",
registeredClient.getId()));
}
throwError(OAuth2ErrorCodes.INVALID_SCOPE, OAuth2ParameterNames.SCOPE,
authorizationCodeRequestAuthentication, registeredClient);
@@ -113,8 +115,8 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationValidator
}
if (requestedRedirect == null || requestedRedirect.getFragment() != null) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(LogMessage.format("Invalid request: redirect_uri is missing or contains a fragment" +
" for registered client '%s'", registeredClient.getId()));
LOGGER.debug(LogMessage.format("Invalid request: redirect_uri is missing or contains a fragment"
+ " for registered client '%s'", registeredClient.getId()));
}
throwError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.REDIRECT_URI,
authorizationCodeRequestAuthentication, registeredClient);
@@ -148,8 +150,9 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationValidator
}
if (!validRedirectUri) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(LogMessage.format("Invalid request: redirect_uri does not match" +
" for registered client '%s'", registeredClient.getId()));
LOGGER.debug(LogMessage.format(
"Invalid request: redirect_uri does not match" + " for registered client '%s'",
registeredClient.getId()));
}
throwError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.REDIRECT_URI,
authorizationCodeRequestAuthentication, registeredClient);

View File

@@ -86,8 +86,9 @@ public class JdbcRegisteredClientRepository implements RegisteredClientRepositor
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.resources().registerResource(new ClassPathResource(
"org/springframework/security/oauth2/server/authorization/client/oauth2-registered-client-schema.sql"));
hints.resources()
.registerResource(new ClassPathResource(
"org/springframework/security/oauth2/server/authorization/client/oauth2-registered-client-schema.sql"));
}
}

View File

@@ -86,12 +86,14 @@ public final class OidcClientConfigurationAuthenticationProvider implements Auth
}
/**
* Sets the {@link Converter} used for converting a {@link RegisteredClient} to an {@link OidcClientRegistration}.
*
* @param clientRegistrationConverter the {@link Converter} used for converting a {@link RegisteredClient} to an {@link OidcClientRegistration}
* Sets the {@link Converter} used for converting a {@link RegisteredClient} to an
* {@link OidcClientRegistration}.
* @param clientRegistrationConverter the {@link Converter} used for converting a
* {@link RegisteredClient} to an {@link OidcClientRegistration}
* @since 1.2.0
*/
public void setClientRegistrationConverter(Converter<RegisteredClient, OidcClientRegistration> clientRegistrationConverter) {
public void setClientRegistrationConverter(
Converter<RegisteredClient, OidcClientRegistration> clientRegistrationConverter) {
Assert.notNull(clientRegistrationConverter, "clientRegistrationConverter cannot be null");
this.clientRegistrationConverter = clientRegistrationConverter;
}

View File

@@ -185,12 +185,14 @@ public final class OidcClientRegistrationAuthenticationProvider implements Authe
}
/**
* Sets the {@link Converter} used for converting a {@link RegisteredClient} to an {@link OidcClientRegistration}.
*
* @param clientRegistrationConverter the {@link Converter} used for converting a {@link RegisteredClient} to an {@link OidcClientRegistration}
* Sets the {@link Converter} used for converting a {@link RegisteredClient} to an
* {@link OidcClientRegistration}.
* @param clientRegistrationConverter the {@link Converter} used for converting a
* {@link RegisteredClient} to an {@link OidcClientRegistration}
* @since 1.2.0
*/
public void setClientRegistrationConverter(Converter<RegisteredClient, OidcClientRegistration> clientRegistrationConverter) {
public void setClientRegistrationConverter(
Converter<RegisteredClient, OidcClientRegistration> clientRegistrationConverter) {
Assert.notNull(clientRegistrationConverter, "clientRegistrationConverter cannot be null");
this.clientRegistrationConverter = clientRegistrationConverter;
}

View File

@@ -34,15 +34,19 @@ import org.springframework.security.oauth2.server.authorization.settings.TokenSe
import org.springframework.util.CollectionUtils;
/**
* A {@link Converter} that converts the provided {@link OidcClientRegistration} to a {@link RegisteredClient}.
* A {@link Converter} that converts the provided {@link OidcClientRegistration} to a
* {@link RegisteredClient}.
*
* @author Joe Grandja
* @author Dmitriy Dubson
* @since 1.2.0
*/
public final class OidcClientRegistrationRegisteredClientConverter implements Converter<OidcClientRegistration, RegisteredClient> {
public final class OidcClientRegistrationRegisteredClientConverter
implements Converter<OidcClientRegistration, RegisteredClient> {
private static final StringKeyGenerator CLIENT_ID_GENERATOR = new Base64StringKeyGenerator(
Base64.getUrlEncoder().withoutPadding(), 32);
private static final StringKeyGenerator CLIENT_SECRET_GENERATOR = new Base64StringKeyGenerator(
Base64.getUrlEncoder().withoutPadding(), 48);
@@ -125,4 +129,3 @@ public final class OidcClientRegistrationRegisteredClientConverter implements Co
}
}

View File

@@ -28,12 +28,14 @@ import org.springframework.util.CollectionUtils;
import org.springframework.web.util.UriComponentsBuilder;
/**
* A {@link Converter} that converts the provided {@link RegisteredClient} to an {@link OidcClientRegistration}.
* A {@link Converter} that converts the provided {@link RegisteredClient} to an
* {@link OidcClientRegistration}.
*
* @author Joe Grandja
* @since 1.2.0
*/
public final class RegisteredClientOidcClientRegistrationConverter implements Converter<RegisteredClient, OidcClientRegistration> {
public final class RegisteredClientOidcClientRegistrationConverter
implements Converter<RegisteredClient, OidcClientRegistration> {
@Override
public OidcClientRegistration convert(RegisteredClient registeredClient) {

View File

@@ -99,27 +99,27 @@ public final class OidcProviderConfigurationEndpointFilter extends OncePerReques
.getAuthorizationServerSettings();
OidcProviderConfiguration.Builder providerConfiguration = OidcProviderConfiguration.builder()
.issuer(issuer)
.authorizationEndpoint(asUrl(issuer, authorizationServerSettings.getAuthorizationEndpoint()))
.deviceAuthorizationEndpoint(asUrl(issuer, authorizationServerSettings.getDeviceAuthorizationEndpoint()))
.tokenEndpoint(asUrl(issuer, authorizationServerSettings.getTokenEndpoint()))
.tokenEndpointAuthenticationMethods(clientAuthenticationMethods())
.jwkSetUrl(asUrl(issuer, authorizationServerSettings.getJwkSetEndpoint()))
.userInfoEndpoint(asUrl(issuer, authorizationServerSettings.getOidcUserInfoEndpoint()))
.endSessionEndpoint(asUrl(issuer, authorizationServerSettings.getOidcLogoutEndpoint()))
.responseType(OAuth2AuthorizationResponseType.CODE.getValue())
.grantType(AuthorizationGrantType.AUTHORIZATION_CODE.getValue())
.grantType(AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
.grantType(AuthorizationGrantType.REFRESH_TOKEN.getValue())
.grantType(AuthorizationGrantType.DEVICE_CODE.getValue())
.tokenRevocationEndpoint(asUrl(issuer, authorizationServerSettings.getTokenRevocationEndpoint()))
.tokenRevocationEndpointAuthenticationMethods(clientAuthenticationMethods())
.tokenIntrospectionEndpoint(asUrl(issuer, authorizationServerSettings.getTokenIntrospectionEndpoint()))
.tokenIntrospectionEndpointAuthenticationMethods(clientAuthenticationMethods())
.codeChallengeMethod("S256")
.subjectType("public")
.idTokenSigningAlgorithm(SignatureAlgorithm.RS256.getName())
.scope(OidcScopes.OPENID);
.issuer(issuer)
.authorizationEndpoint(asUrl(issuer, authorizationServerSettings.getAuthorizationEndpoint()))
.deviceAuthorizationEndpoint(asUrl(issuer, authorizationServerSettings.getDeviceAuthorizationEndpoint()))
.tokenEndpoint(asUrl(issuer, authorizationServerSettings.getTokenEndpoint()))
.tokenEndpointAuthenticationMethods(clientAuthenticationMethods())
.jwkSetUrl(asUrl(issuer, authorizationServerSettings.getJwkSetEndpoint()))
.userInfoEndpoint(asUrl(issuer, authorizationServerSettings.getOidcUserInfoEndpoint()))
.endSessionEndpoint(asUrl(issuer, authorizationServerSettings.getOidcLogoutEndpoint()))
.responseType(OAuth2AuthorizationResponseType.CODE.getValue())
.grantType(AuthorizationGrantType.AUTHORIZATION_CODE.getValue())
.grantType(AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
.grantType(AuthorizationGrantType.REFRESH_TOKEN.getValue())
.grantType(AuthorizationGrantType.DEVICE_CODE.getValue())
.tokenRevocationEndpoint(asUrl(issuer, authorizationServerSettings.getTokenRevocationEndpoint()))
.tokenRevocationEndpointAuthenticationMethods(clientAuthenticationMethods())
.tokenIntrospectionEndpoint(asUrl(issuer, authorizationServerSettings.getTokenIntrospectionEndpoint()))
.tokenIntrospectionEndpointAuthenticationMethods(clientAuthenticationMethods())
.codeChallengeMethod("S256")
.subjectType("public")
.idTokenSigningAlgorithm(SignatureAlgorithm.RS256.getName())
.scope(OidcScopes.OPENID);
this.providerConfigurationCustomizer.accept(providerConfiguration);

View File

@@ -57,10 +57,12 @@ public final class OAuth2RefreshTokenGenerator implements OAuth2TokenGenerator<O
}
private static boolean isPublicClientForAuthorizationCodeGrant(OAuth2TokenContext context) {
// @formatter:off
if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(context.getAuthorizationGrantType()) &&
(context.getAuthorizationGrant().getPrincipal() instanceof OAuth2ClientAuthenticationToken clientPrincipal)) {
return clientPrincipal.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.NONE);
}
// @formatter:on
return false;
}

View File

@@ -35,8 +35,9 @@ import org.springframework.security.web.authentication.AuthenticationFailureHand
import org.springframework.util.Assert;
/**
* An implementation of an {@link AuthenticationFailureHandler} used for handling an {@link OAuth2AuthenticationException}
* and returning the {@link OAuth2Error OAuth 2.0 Error Response}.
* An implementation of an {@link AuthenticationFailureHandler} used for handling an
* {@link OAuth2AuthenticationException} and returning the {@link OAuth2Error OAuth 2.0
* Error Response}.
*
* @author Dmitriy Dubson
* @see AuthenticationFailureHandler
@@ -44,7 +45,9 @@ import org.springframework.util.Assert;
* @since 1.2
*/
public final class OAuth2ErrorAuthenticationFailureHandler implements AuthenticationFailureHandler {
private final Log logger = LogFactory.getLog(getClass());
private HttpMessageConverter<OAuth2Error> errorResponseConverter = new OAuth2ErrorHttpMessageConverter();
@Override
@@ -56,19 +59,21 @@ public final class OAuth2ErrorAuthenticationFailureHandler implements Authentica
if (authenticationException instanceof OAuth2AuthenticationException) {
OAuth2Error error = ((OAuth2AuthenticationException) authenticationException).getError();
this.errorResponseConverter.write(error, null, httpResponse);
} else {
}
else {
if (this.logger.isWarnEnabled()) {
this.logger.warn(AuthenticationException.class.getSimpleName() + " must be of type " +
OAuth2AuthenticationException.class.getName() +
" but was " + authenticationException.getClass().getName());
this.logger.warn(AuthenticationException.class.getSimpleName() + " must be of type "
+ OAuth2AuthenticationException.class.getName() + " but was "
+ authenticationException.getClass().getName());
}
}
}
/**
* Sets the {@link HttpMessageConverter} used for converting an {@link OAuth2Error} to an HTTP response.
*
* @param errorResponseConverter the {@link HttpMessageConverter} used for converting an {@link OAuth2Error} to an HTTP response
* Sets the {@link HttpMessageConverter} used for converting an {@link OAuth2Error} to
* an HTTP response.
* @param errorResponseConverter the {@link HttpMessageConverter} used for converting
* an {@link OAuth2Error} to an HTTP response
*/
public void setErrorResponseConverter(HttpMessageConverter<OAuth2Error> errorResponseConverter) {
Assert.notNull(errorResponseConverter, "errorResponseConverter cannot be null");

View File

@@ -406,8 +406,8 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests {
doAnswer(answer -> {
OAuth2TokenContext context = answer.getArgument(0);
if (OAuth2TokenType.REFRESH_TOKEN.equals(context.getTokenType())) {
return new OAuth2AccessToken(
OAuth2AccessToken.TokenType.BEARER, "access-token", Instant.now(), Instant.now().plusSeconds(300));
return new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "access-token", Instant.now(),
Instant.now().plusSeconds(300));
}
else {
return answer.callRealMethod();
@@ -415,12 +415,13 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests {
}).when(this.tokenGenerator).generate(any());
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
.isInstanceOf(OAuth2AuthenticationException.class)
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
.satisfies(error -> {
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.SERVER_ERROR);
assertThat(error.getDescription()).contains("The token generator failed to generate a valid refresh token.");
});
.isInstanceOf(OAuth2AuthenticationException.class)
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
.satisfies(error -> {
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.SERVER_ERROR);
assertThat(error.getDescription())
.contains("The token generator failed to generate a valid refresh token.");
});
}
@Test

View File

@@ -467,46 +467,52 @@ public class OAuth2AuthorizationCodeGrantTests {
this.spring.register(AuthorizationServerConfigurationWithCustomRefreshTokenGenerator.class).autowire();
RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient()
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.build();
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.build();
this.registeredClientRepository.save(registeredClient);
MvcResult mvcResult = this.mvc.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI)
MvcResult mvcResult = this.mvc
.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI)
.queryParams(getAuthorizationRequestParameters(registeredClient))
.queryParam(PkceParameterNames.CODE_CHALLENGE, S256_CODE_CHALLENGE)
.queryParam(PkceParameterNames.CODE_CHALLENGE_METHOD, "S256")
.with(user("user")))
.andExpect(status().is3xxRedirection())
.andReturn();
.andExpect(status().is3xxRedirection())
.andReturn();
String redirectedUrl = mvcResult.getResponse().getRedirectedUrl();
assertThat(redirectedUrl).matches("https://example.com\\?code=.{15,}&state=" + STATE_URL_ENCODED);
String authorizationCode = extractParameterFromRedirectUri(redirectedUrl, "code");
OAuth2Authorization authorizationCodeAuthorization = this.authorizationService.findByToken(authorizationCode, AUTHORIZATION_CODE_TOKEN_TYPE);
OAuth2Authorization authorizationCodeAuthorization = this.authorizationService.findByToken(authorizationCode,
AUTHORIZATION_CODE_TOKEN_TYPE);
assertThat(authorizationCodeAuthorization).isNotNull();
assertThat(authorizationCodeAuthorization.getAuthorizationGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);
assertThat(authorizationCodeAuthorization.getAuthorizationGrantType())
.isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);
this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
this.mvc
.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
.params(getTokenRequestParameters(registeredClient, authorizationCodeAuthorization))
.param(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId())
.param(PkceParameterNames.CODE_VERIFIER, S256_CODE_VERIFIER))
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, containsString("no-store")))
.andExpect(header().string(HttpHeaders.PRAGMA, containsString("no-cache")))
.andExpect(status().isOk())
.andExpect(jsonPath("$.access_token").isNotEmpty())
.andExpect(jsonPath("$.token_type").isNotEmpty())
.andExpect(jsonPath("$.expires_in").isNotEmpty())
.andExpect(jsonPath("$.refresh_token").isNotEmpty())
.andExpect(jsonPath("$.scope").isNotEmpty());
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, containsString("no-store")))
.andExpect(header().string(HttpHeaders.PRAGMA, containsString("no-cache")))
.andExpect(status().isOk())
.andExpect(jsonPath("$.access_token").isNotEmpty())
.andExpect(jsonPath("$.token_type").isNotEmpty())
.andExpect(jsonPath("$.expires_in").isNotEmpty())
.andExpect(jsonPath("$.refresh_token").isNotEmpty())
.andExpect(jsonPath("$.scope").isNotEmpty());
OAuth2Authorization authorization = this.authorizationService.findById(authorizationCodeAuthorization.getId());
assertThat(authorization).isNotNull();
assertThat(authorization.getAccessToken()).isNotNull();
assertThat(authorization.getRefreshToken()).isNotNull();
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCodeToken = authorization.getToken(OAuth2AuthorizationCode.class);
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCodeToken = authorization
.getToken(OAuth2AuthorizationCode.class);
assertThat(authorizationCodeToken).isNotNull();
assertThat(authorizationCodeToken.getMetadata().get(OAuth2Authorization.Token.INVALIDATED_METADATA_NAME)).isEqualTo(true);
assertThat(authorizationCodeToken.getMetadata().get(OAuth2Authorization.Token.INVALIDATED_METADATA_NAME))
.isEqualTo(true);
}
@Test
@@ -1032,7 +1038,8 @@ public class OAuth2AuthorizationCodeGrantTests {
@EnableWebSecurity
@Import(OAuth2AuthorizationServerConfiguration.class)
static class AuthorizationServerConfigurationWithCustomRefreshTokenGenerator extends AuthorizationServerConfiguration {
static class AuthorizationServerConfigurationWithCustomRefreshTokenGenerator
extends AuthorizationServerConfiguration {
@Bean
JwtEncoder jwtEncoder() {
@@ -1048,8 +1055,9 @@ public class OAuth2AuthorizationCodeGrantTests {
}
private static final class CustomRefreshTokenGenerator implements OAuth2TokenGenerator<OAuth2RefreshToken> {
private final StringKeyGenerator refreshTokenGenerator =
new Base64StringKeyGenerator(Base64.getUrlEncoder().withoutPadding(), 96);
private final StringKeyGenerator refreshTokenGenerator = new Base64StringKeyGenerator(
Base64.getUrlEncoder().withoutPadding(), 96);
@Nullable
@Override
@@ -1058,7 +1066,8 @@ public class OAuth2AuthorizationCodeGrantTests {
return null;
}
Instant issuedAt = Instant.now();
Instant expiresAt = issuedAt.plus(context.getRegisteredClient().getTokenSettings().getRefreshTokenTimeToLive());
Instant expiresAt = issuedAt
.plus(context.getRegisteredClient().getTokenSettings().getRefreshTokenTimeToLive());
return new OAuth2RefreshToken(this.refreshTokenGenerator.generateKey(), issuedAt, expiresAt);
}

View File

@@ -248,24 +248,24 @@ public class OAuth2RefreshTokenGrantTests {
this.spring.register(AuthorizationServerConfigurationWithPublicClientAuthentication.class).autowire();
RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient()
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.build();
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.build();
this.registeredClientRepository.save(registeredClient);
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient).build();
this.authorizationService.save(authorization);
this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
.params(getRefreshTokenRequestParameters(authorization))
this.mvc
.perform(post(DEFAULT_TOKEN_ENDPOINT_URI).params(getRefreshTokenRequestParameters(authorization))
.param(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId()))
.andExpect(status().isOk())
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, containsString("no-store")))
.andExpect(header().string(HttpHeaders.PRAGMA, containsString("no-cache")))
.andExpect(jsonPath("$.access_token").isNotEmpty())
.andExpect(jsonPath("$.token_type").isNotEmpty())
.andExpect(jsonPath("$.expires_in").isNotEmpty())
.andExpect(jsonPath("$.refresh_token").isNotEmpty())
.andExpect(jsonPath("$.scope").isNotEmpty());
.andExpect(status().isOk())
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, containsString("no-store")))
.andExpect(header().string(HttpHeaders.PRAGMA, containsString("no-cache")))
.andExpect(jsonPath("$.access_token").isNotEmpty())
.andExpect(jsonPath("$.token_type").isNotEmpty())
.andExpect(jsonPath("$.expires_in").isNotEmpty())
.andExpect(jsonPath("$.refresh_token").isNotEmpty())
.andExpect(jsonPath("$.scope").isNotEmpty());
}
private static MultiValueMap<String, String> getRefreshTokenRequestParameters(OAuth2Authorization authorization) {
@@ -365,7 +365,9 @@ public class OAuth2RefreshTokenGrantTests {
@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
static class AuthorizationServerConfigurationWithPublicClientAuthentication extends AuthorizationServerConfiguration {
static class AuthorizationServerConfigurationWithPublicClientAuthentication
extends AuthorizationServerConfiguration {
// @formatter:off
@Bean
SecurityFilterChain authorizationServerSecurityFilterChain(
@@ -393,6 +395,7 @@ public class OAuth2RefreshTokenGrantTests {
return http.build();
}
// @formatter:on
}
@Transient
@@ -431,6 +434,7 @@ public class OAuth2RefreshTokenGrantTests {
}
private static final class PublicClientRefreshTokenAuthenticationProvider implements AuthenticationProvider {
private final RegisteredClientRepository registeredClientRepository;
private PublicClientRefreshTokenAuthenticationProvider(RegisteredClientRepository registeredClientRepository) {
@@ -440,8 +444,7 @@ public class OAuth2RefreshTokenGrantTests {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
PublicClientRefreshTokenAuthenticationToken publicClientAuthentication =
(PublicClientRefreshTokenAuthenticationToken) authentication;
PublicClientRefreshTokenAuthenticationToken publicClientAuthentication = (PublicClientRefreshTokenAuthenticationToken) authentication;
if (!ClientAuthenticationMethod.NONE.equals(publicClientAuthentication.getClientAuthenticationMethod())) {
return null;
@@ -453,8 +456,8 @@ public class OAuth2RefreshTokenGrantTests {
throwInvalidClient(OAuth2ParameterNames.CLIENT_ID);
}
if (!registeredClient.getClientAuthenticationMethods().contains(
publicClientAuthentication.getClientAuthenticationMethod())) {
if (!registeredClient.getClientAuthenticationMethods()
.contains(publicClientAuthentication.getClientAuthenticationMethod())) {
throwInvalidClient("authentication_method");
}
@@ -467,11 +470,8 @@ public class OAuth2RefreshTokenGrantTests {
}
private static void throwInvalidClient(String parameterName) {
OAuth2Error error = new OAuth2Error(
OAuth2ErrorCodes.INVALID_CLIENT,
"Public client authentication failed: " + parameterName,
null
);
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_CLIENT,
"Public client authentication failed: " + parameterName, null);
throw new OAuth2AuthenticationException(error);
}

View File

@@ -683,7 +683,7 @@ public class OidcClientRegistrationTests {
// @formatter:on
private Consumer<List<AuthenticationProvider>> configureClientRegistrationConverters() {
// @formatter:off
// @formatter:off
return (authenticationProviders) ->
authenticationProviders.forEach(authenticationProvider -> {
List<String> supportedCustomClientMetadata = List.of("custom-metadata-name-1", "custom-metadata-name-2");
@@ -769,9 +769,11 @@ public class OidcClientRegistrationTests {
}
private static class CustomRegisteredClientConverter implements Converter<OidcClientRegistration, RegisteredClient> {
private final OidcClientRegistrationRegisteredClientConverter delegate =
new OidcClientRegistrationRegisteredClientConverter();
private static class CustomRegisteredClientConverter
implements Converter<OidcClientRegistration, RegisteredClient> {
private final OidcClientRegistrationRegisteredClientConverter delegate = new OidcClientRegistrationRegisteredClientConverter();
private final List<String> supportedCustomClientMetadata;
private CustomRegisteredClientConverter(List<String> supportedCustomClientMetadata) {
@@ -783,7 +785,7 @@ public class OidcClientRegistrationTests {
RegisteredClient registeredClient = this.delegate.convert(clientRegistration);
ClientSettings.Builder clientSettingsBuilder = ClientSettings
.withSettings(registeredClient.getClientSettings().getSettings());
.withSettings(registeredClient.getClientSettings().getSettings());
if (!CollectionUtils.isEmpty(this.supportedCustomClientMetadata)) {
clientRegistration.getClaims().forEach((claim, value) -> {
if (this.supportedCustomClientMetadata.contains(claim)) {
@@ -797,9 +799,11 @@ public class OidcClientRegistrationTests {
}
private static class CustomClientRegistrationConverter implements Converter<RegisteredClient, OidcClientRegistration> {
private final RegisteredClientOidcClientRegistrationConverter delegate =
new RegisteredClientOidcClientRegistrationConverter();
private static class CustomClientRegistrationConverter
implements Converter<RegisteredClient, OidcClientRegistration> {
private final RegisteredClientOidcClientRegistrationConverter delegate = new RegisteredClientOidcClientRegistrationConverter();
private final List<String> supportedCustomClientMetadata;
private CustomClientRegistrationConverter(List<String> supportedCustomClientMetadata) {
@@ -822,6 +826,7 @@ public class OidcClientRegistrationTests {
return OidcClientRegistration.withClaims(clientMetadata).build();
}
}
}

View File

@@ -472,81 +472,85 @@ public class OidcTests {
// gh-1422
@Test
public void requestWhenAuthenticationRequestWithOfflineAccessScopeThenTokenResponseIncludesRefreshToken() throws Exception {
public void requestWhenAuthenticationRequestWithOfflineAccessScopeThenTokenResponseIncludesRefreshToken()
throws Exception {
this.spring.register(AuthorizationServerConfigurationWithCustomRefreshTokenGenerator.class).autowire();
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
.scope(OidcScopes.OPENID)
.scope("offline_access")
.build();
.scope(OidcScopes.OPENID)
.scope("offline_access")
.build();
this.registeredClientRepository.save(registeredClient);
MultiValueMap<String, String> authorizationRequestParameters = getAuthorizationRequestParameters(registeredClient);
MvcResult mvcResult = this.mvc.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI)
.queryParams(authorizationRequestParameters)
.with(user("user")))
.andExpect(status().is3xxRedirection())
.andReturn();
MultiValueMap<String, String> authorizationRequestParameters = getAuthorizationRequestParameters(
registeredClient);
MvcResult mvcResult = this.mvc
.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI).queryParams(authorizationRequestParameters)
.with(user("user")))
.andExpect(status().is3xxRedirection())
.andReturn();
String redirectedUrl = mvcResult.getResponse().getRedirectedUrl();
String expectedRedirectUri = authorizationRequestParameters.getFirst(OAuth2ParameterNames.REDIRECT_URI);
assertThat(redirectedUrl).matches(expectedRedirectUri + "\\?code=.{15,}&state=state");
String authorizationCode = extractParameterFromRedirectUri(redirectedUrl, "code");
OAuth2Authorization authorization = this.authorizationService.findByToken(authorizationCode, AUTHORIZATION_CODE_TOKEN_TYPE);
OAuth2Authorization authorization = this.authorizationService.findByToken(authorizationCode,
AUTHORIZATION_CODE_TOKEN_TYPE);
this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
.params(getTokenRequestParameters(registeredClient, authorization))
.header(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth(
registeredClient.getClientId(), registeredClient.getClientSecret())))
.andExpect(status().isOk())
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, containsString("no-store")))
.andExpect(header().string(HttpHeaders.PRAGMA, containsString("no-cache")))
.andExpect(jsonPath("$.access_token").isNotEmpty())
.andExpect(jsonPath("$.token_type").isNotEmpty())
.andExpect(jsonPath("$.expires_in").isNotEmpty())
.andExpect(jsonPath("$.refresh_token").isNotEmpty())
.andExpect(jsonPath("$.scope").isNotEmpty())
.andExpect(jsonPath("$.id_token").isNotEmpty())
.andReturn();
this.mvc
.perform(post(DEFAULT_TOKEN_ENDPOINT_URI).params(getTokenRequestParameters(registeredClient, authorization))
.header(HttpHeaders.AUTHORIZATION,
"Basic " + encodeBasicAuth(registeredClient.getClientId(), registeredClient.getClientSecret())))
.andExpect(status().isOk())
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, containsString("no-store")))
.andExpect(header().string(HttpHeaders.PRAGMA, containsString("no-cache")))
.andExpect(jsonPath("$.access_token").isNotEmpty())
.andExpect(jsonPath("$.token_type").isNotEmpty())
.andExpect(jsonPath("$.expires_in").isNotEmpty())
.andExpect(jsonPath("$.refresh_token").isNotEmpty())
.andExpect(jsonPath("$.scope").isNotEmpty())
.andExpect(jsonPath("$.id_token").isNotEmpty())
.andReturn();
}
// gh-1422
@Test
public void requestWhenAuthenticationRequestWithoutOfflineAccessScopeThenTokenResponseDoesNotIncludeRefreshToken() throws Exception {
public void requestWhenAuthenticationRequestWithoutOfflineAccessScopeThenTokenResponseDoesNotIncludeRefreshToken()
throws Exception {
this.spring.register(AuthorizationServerConfigurationWithCustomRefreshTokenGenerator.class).autowire();
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
.scope(OidcScopes.OPENID)
.build();
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().scope(OidcScopes.OPENID).build();
this.registeredClientRepository.save(registeredClient);
MultiValueMap<String, String> authorizationRequestParameters = getAuthorizationRequestParameters(registeredClient);
MvcResult mvcResult = this.mvc.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI)
.queryParams(authorizationRequestParameters)
.with(user("user")))
.andExpect(status().is3xxRedirection())
.andReturn();
MultiValueMap<String, String> authorizationRequestParameters = getAuthorizationRequestParameters(
registeredClient);
MvcResult mvcResult = this.mvc
.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI).queryParams(authorizationRequestParameters)
.with(user("user")))
.andExpect(status().is3xxRedirection())
.andReturn();
String redirectedUrl = mvcResult.getResponse().getRedirectedUrl();
String expectedRedirectUri = authorizationRequestParameters.getFirst(OAuth2ParameterNames.REDIRECT_URI);
assertThat(redirectedUrl).matches(expectedRedirectUri + "\\?code=.{15,}&state=state");
String authorizationCode = extractParameterFromRedirectUri(redirectedUrl, "code");
OAuth2Authorization authorization = this.authorizationService.findByToken(authorizationCode, AUTHORIZATION_CODE_TOKEN_TYPE);
OAuth2Authorization authorization = this.authorizationService.findByToken(authorizationCode,
AUTHORIZATION_CODE_TOKEN_TYPE);
this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
.params(getTokenRequestParameters(registeredClient, authorization))
.header(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth(
registeredClient.getClientId(), registeredClient.getClientSecret())))
.andExpect(status().isOk())
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, containsString("no-store")))
.andExpect(header().string(HttpHeaders.PRAGMA, containsString("no-cache")))
.andExpect(jsonPath("$.access_token").isNotEmpty())
.andExpect(jsonPath("$.token_type").isNotEmpty())
.andExpect(jsonPath("$.expires_in").isNotEmpty())
.andExpect(jsonPath("$.refresh_token").doesNotExist())
.andExpect(jsonPath("$.scope").isNotEmpty())
.andExpect(jsonPath("$.id_token").isNotEmpty())
.andReturn();
this.mvc
.perform(post(DEFAULT_TOKEN_ENDPOINT_URI).params(getTokenRequestParameters(registeredClient, authorization))
.header(HttpHeaders.AUTHORIZATION,
"Basic " + encodeBasicAuth(registeredClient.getClientId(), registeredClient.getClientSecret())))
.andExpect(status().isOk())
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, containsString("no-store")))
.andExpect(header().string(HttpHeaders.PRAGMA, containsString("no-cache")))
.andExpect(jsonPath("$.access_token").isNotEmpty())
.andExpect(jsonPath("$.token_type").isNotEmpty())
.andExpect(jsonPath("$.expires_in").isNotEmpty())
.andExpect(jsonPath("$.refresh_token").doesNotExist())
.andExpect(jsonPath("$.scope").isNotEmpty())
.andExpect(jsonPath("$.id_token").isNotEmpty())
.andReturn();
}
private static MultiValueMap<String, String> getAuthorizationRequestParameters(RegisteredClient registeredClient) {
@@ -728,7 +732,8 @@ public class OidcTests {
@EnableWebSecurity
@Configuration
static class AuthorizationServerConfigurationWithCustomRefreshTokenGenerator extends AuthorizationServerConfiguration {
static class AuthorizationServerConfigurationWithCustomRefreshTokenGenerator
extends AuthorizationServerConfiguration {
// @formatter:off
@Bean
@@ -763,13 +768,14 @@ public class OidcTests {
}
private static final class CustomRefreshTokenGenerator implements OAuth2TokenGenerator<OAuth2RefreshToken> {
private final OAuth2RefreshTokenGenerator delegate = new OAuth2RefreshTokenGenerator();
@Nullable
@Override
public OAuth2RefreshToken generate(OAuth2TokenContext context) {
if (context.getAuthorizedScopes().contains(OidcScopes.OPENID) &&
!context.getAuthorizedScopes().contains("offline_access")) {
if (context.getAuthorizedScopes().contains(OidcScopes.OPENID)
&& !context.getAuthorizedScopes().contains("offline_access")) {
return null;
}
return this.delegate.generate(context);

View File

@@ -119,8 +119,8 @@ public class OidcClientConfigurationAuthenticationProviderTests {
@Test
public void setClientRegistrationConverterWhenNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.authenticationProvider.setClientRegistrationConverter(null))
.withMessage("clientRegistrationConverter cannot be null");
.isThrownBy(() -> this.authenticationProvider.setClientRegistrationConverter(null))
.withMessage("clientRegistrationConverter cannot be null");
}
@Test

View File

@@ -172,8 +172,8 @@ public class OidcClientRegistrationAuthenticationProviderTests {
@Test
public void setClientRegistrationConverterWhenNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.authenticationProvider.setClientRegistrationConverter(null))
.withMessage("clientRegistrationConverter cannot be null");
.isThrownBy(() -> this.authenticationProvider.setClientRegistrationConverter(null))
.withMessage("clientRegistrationConverter cannot be null");
}
@Test

View File

@@ -131,11 +131,16 @@ public class OidcProviderConfigurationEndpointFilterTests {
assertThat(providerConfigurationResponse).contains("\"jwks_uri\":\"https://example.com/oauth2/v1/jwks\"");
assertThat(providerConfigurationResponse).contains("\"scopes_supported\":[\"openid\"]");
assertThat(providerConfigurationResponse).contains("\"response_types_supported\":[\"code\"]");
assertThat(providerConfigurationResponse).contains("\"grant_types_supported\":[\"authorization_code\",\"client_credentials\",\"refresh_token\",\"urn:ietf:params:oauth:grant-type:device_code\"]");
assertThat(providerConfigurationResponse).contains("\"revocation_endpoint\":\"https://example.com/oauth2/v1/revoke\"");
assertThat(providerConfigurationResponse).contains("\"revocation_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"client_secret_jwt\",\"private_key_jwt\"]");
assertThat(providerConfigurationResponse).contains("\"introspection_endpoint\":\"https://example.com/oauth2/v1/introspect\"");
assertThat(providerConfigurationResponse).contains("\"introspection_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"client_secret_jwt\",\"private_key_jwt\"]");
assertThat(providerConfigurationResponse).contains(
"\"grant_types_supported\":[\"authorization_code\",\"client_credentials\",\"refresh_token\",\"urn:ietf:params:oauth:grant-type:device_code\"]");
assertThat(providerConfigurationResponse)
.contains("\"revocation_endpoint\":\"https://example.com/oauth2/v1/revoke\"");
assertThat(providerConfigurationResponse).contains(
"\"revocation_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"client_secret_jwt\",\"private_key_jwt\"]");
assertThat(providerConfigurationResponse)
.contains("\"introspection_endpoint\":\"https://example.com/oauth2/v1/introspect\"");
assertThat(providerConfigurationResponse).contains(
"\"introspection_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"client_secret_jwt\",\"private_key_jwt\"]");
assertThat(providerConfigurationResponse).contains("\"code_challenge_methods_supported\":[\"S256\"]");
assertThat(providerConfigurationResponse).contains("\"subject_types_supported\":[\"public\"]");
assertThat(providerConfigurationResponse).contains("\"id_token_signing_alg_values_supported\":[\"RS256\"]");

View File

@@ -39,6 +39,7 @@ import static org.mockito.Mockito.verifyNoInteractions;
* @author Dmitriy Dubson
*/
public class OAuth2ErrorAuthenticationFailureHandlerTests {
private final OAuth2ErrorAuthenticationFailureHandler authenticationFailureHandler = new OAuth2ErrorAuthenticationFailureHandler();
@Test