Add logging for authentication providers

Issue gh-159
This commit is contained in:
Steve Riesenberg
2022-11-03 14:27:33 -05:00
committed by Joe Grandja
parent 7e03795c58
commit 2c4bd29f98
14 changed files with 349 additions and 0 deletions

View File

@@ -17,6 +17,9 @@ package org.springframework.security.oauth2.server.authorization.authentication;
import java.time.Instant;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
@@ -47,6 +50,7 @@ import org.springframework.util.Assert;
*/
public final class ClientSecretAuthenticationProvider implements AuthenticationProvider {
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-3.2.1";
private final Log logger = LogFactory.getLog(getClass());
private final RegisteredClientRepository registeredClientRepository;
private final CodeVerifierAuthenticator codeVerifierAuthenticator;
private PasswordEncoder passwordEncoder;
@@ -95,6 +99,10 @@ public final class ClientSecretAuthenticationProvider implements AuthenticationP
throwInvalidClient(OAuth2ParameterNames.CLIENT_ID);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved registered client");
}
if (!registeredClient.getClientAuthenticationMethods().contains(
clientAuthentication.getClientAuthenticationMethod())) {
throwInvalidClient("authentication_method");
@@ -114,9 +122,17 @@ public final class ClientSecretAuthenticationProvider implements AuthenticationP
throwInvalidClient("client_secret_expires_at");
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Validated client authentication parameters");
}
// Validate the "code_verifier" parameter for the confidential client, if available
this.codeVerifierAuthenticator.authenticateIfAvailable(clientAuthentication, registeredClient);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Authenticated client secret");
}
return new OAuth2ClientAuthenticationToken(registeredClient,
clientAuthentication.getClientAuthenticationMethod(), clientAuthentication.getCredentials());
}

View File

@@ -21,6 +21,9 @@ import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
@@ -47,6 +50,7 @@ import org.springframework.util.StringUtils;
*/
final class CodeVerifierAuthenticator {
private static final OAuth2TokenType AUTHORIZATION_CODE_TOKEN_TYPE = new OAuth2TokenType(OAuth2ParameterNames.CODE);
private final Log logger = LogFactory.getLog(getClass());
private final OAuth2AuthorizationService authorizationService;
CodeVerifierAuthenticator(OAuth2AuthorizationService authorizationService) {
@@ -81,6 +85,10 @@ final class CodeVerifierAuthenticator {
throwInvalidGrant(OAuth2ParameterNames.CODE);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved authorization with authorization code");
}
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(
OAuth2AuthorizationRequest.class.getName());
@@ -90,10 +98,17 @@ final class CodeVerifierAuthenticator {
if (registeredClient.getClientSettings().isRequireProofKey()) {
throwInvalidGrant(PkceParameterNames.CODE_CHALLENGE);
} else {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Did not authenticate code verifier since requireProofKey=false");
}
return false;
}
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Validated code verifier parameters");
}
String codeChallengeMethod = (String) authorizationRequest.getAdditionalParameters()
.get(PkceParameterNames.CODE_CHALLENGE_METHOD);
String codeVerifier = (String) parameters.get(PkceParameterNames.CODE_VERIFIER);
@@ -101,6 +116,10 @@ final class CodeVerifierAuthenticator {
throwInvalidGrant(PkceParameterNames.CODE_VERIFIER);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Authenticated code verifier");
}
return true;
}

View File

@@ -15,6 +15,9 @@
*/
package org.springframework.security.oauth2.server.authorization.authentication;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
@@ -50,6 +53,7 @@ public final class JwtClientAssertionAuthenticationProvider implements Authentic
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-3.2.1";
private static final ClientAuthenticationMethod JWT_CLIENT_ASSERTION_AUTHENTICATION_METHOD =
new ClientAuthenticationMethod("urn:ietf:params:oauth:client-assertion-type:jwt-bearer");
private final Log logger = LogFactory.getLog(getClass());
private final RegisteredClientRepository registeredClientRepository;
private final CodeVerifierAuthenticator codeVerifierAuthenticator;
private JwtDecoderFactory<RegisteredClient> jwtDecoderFactory;
@@ -84,6 +88,10 @@ public final class JwtClientAssertionAuthenticationProvider implements Authentic
throwInvalidClient(OAuth2ParameterNames.CLIENT_ID);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved registered client");
}
if (!registeredClient.getClientAuthenticationMethods().contains(ClientAuthenticationMethod.PRIVATE_KEY_JWT) &&
!registeredClient.getClientAuthenticationMethods().contains(ClientAuthenticationMethod.CLIENT_SECRET_JWT)) {
throwInvalidClient("authentication_method");
@@ -101,6 +109,10 @@ public final class JwtClientAssertionAuthenticationProvider implements Authentic
throwInvalidClient(OAuth2ParameterNames.CLIENT_ASSERTION, ex);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Validated client authentication parameters");
}
// Validate the "code_verifier" parameter for the confidential client, if available
this.codeVerifierAuthenticator.authenticateIfAvailable(clientAuthentication, registeredClient);
@@ -109,6 +121,10 @@ public final class JwtClientAssertionAuthenticationProvider implements Authentic
ClientAuthenticationMethod.PRIVATE_KEY_JWT :
ClientAuthenticationMethod.CLIENT_SECRET_JWT;
if (this.logger.isTraceEnabled()) {
this.logger.trace("Authenticated client assertion");
}
return new OAuth2ClientAuthenticationToken(registeredClient, clientAuthenticationMethod, jwtAssertion);
}

View File

@@ -20,6 +20,10 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.log.LogMessage;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
@@ -72,6 +76,7 @@ public final class OAuth2AuthorizationCodeAuthenticationProvider implements Auth
new OAuth2TokenType(OAuth2ParameterNames.CODE);
private static final OAuth2TokenType ID_TOKEN_TOKEN_TYPE =
new OAuth2TokenType(OidcParameterNames.ID_TOKEN);
private final Log logger = LogFactory.getLog(getClass());
private final OAuth2AuthorizationService authorizationService;
private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator;
@@ -99,11 +104,20 @@ public final class OAuth2AuthorizationCodeAuthenticationProvider implements Auth
getAuthenticatedClientElseThrowInvalidClient(authorizationCodeAuthentication);
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved registered client");
}
OAuth2Authorization authorization = this.authorizationService.findByToken(
authorizationCodeAuthentication.getCode(), AUTHORIZATION_CODE_TOKEN_TYPE);
if (authorization == null) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_GRANT);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved authorization with authorization code");
}
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode =
authorization.getToken(OAuth2AuthorizationCode.class);
@@ -115,6 +129,9 @@ public final class OAuth2AuthorizationCodeAuthenticationProvider implements Auth
// Invalidate the authorization code given that a different client is attempting to use it
authorization = OAuth2AuthenticationProviderUtils.invalidate(authorization, authorizationCode.getToken());
this.authorizationService.save(authorization);
if (this.logger.isWarnEnabled()) {
this.logger.warn(LogMessage.format("Invalidated authorization code used by registered client '%s'", registeredClient.getId()));
}
}
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_GRANT);
}
@@ -128,6 +145,10 @@ public final class OAuth2AuthorizationCodeAuthenticationProvider implements Auth
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_GRANT);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Validated token request parameters");
}
// @formatter:off
DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
.registeredClient(registeredClient)
@@ -149,6 +170,11 @@ public final class OAuth2AuthorizationCodeAuthenticationProvider implements Auth
"The token generator failed to generate the access token.", ERROR_URI);
throw new OAuth2AuthenticationException(error);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Generated access token");
}
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
@@ -172,6 +198,11 @@ public final class OAuth2AuthorizationCodeAuthenticationProvider implements Auth
"The token generator failed to generate the refresh token.", ERROR_URI);
throw new OAuth2AuthenticationException(error);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Generated refresh token");
}
refreshToken = (OAuth2RefreshToken) generatedRefreshToken;
authorizationBuilder.refreshToken(refreshToken);
}
@@ -191,6 +222,11 @@ public final class OAuth2AuthorizationCodeAuthenticationProvider implements Auth
"The token generator failed to generate the ID token.", ERROR_URI);
throw new OAuth2AuthenticationException(error);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Generated id token");
}
idToken = new OidcIdToken(generatedIdToken.getTokenValue(), generatedIdToken.getIssuedAt(),
generatedIdToken.getExpiresAt(), ((Jwt) generatedIdToken).getClaims());
authorizationBuilder.token(idToken, (metadata) ->
@@ -206,12 +242,20 @@ public final class OAuth2AuthorizationCodeAuthenticationProvider implements Auth
this.authorizationService.save(authorization);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Saved authorization");
}
Map<String, Object> additionalParameters = Collections.emptyMap();
if (idToken != null) {
additionalParameters = new HashMap<>();
additionalParameters.put(OidcParameterNames.ID_TOKEN, idToken.getTokenValue());
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Authenticated token request");
}
return new OAuth2AccessTokenAuthenticationToken(
registeredClient, clientPrincipal, accessToken, refreshToken, additionalParameters);
}

View File

@@ -20,6 +20,9 @@ import java.util.Base64;
import java.util.Set;
import java.util.function.Consumer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
@@ -69,6 +72,7 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen
private static final String PKCE_ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc7636#section-4.4.1";
private static final StringKeyGenerator DEFAULT_STATE_GENERATOR =
new Base64StringKeyGenerator(Base64.getUrlEncoder());
private final Log logger = LogFactory.getLog(getClass());
private final RegisteredClientRepository registeredClientRepository;
private final OAuth2AuthorizationService authorizationService;
private final OAuth2AuthorizationConsentService authorizationConsentService;
@@ -105,6 +109,10 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen
authorizationCodeRequestAuthentication, null);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved registered client");
}
OAuth2AuthorizationCodeRequestAuthenticationContext authenticationContext =
OAuth2AuthorizationCodeRequestAuthenticationContext.with(authorizationCodeRequestAuthentication)
.registeredClient(registeredClient)
@@ -129,12 +137,19 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen
authorizationCodeRequestAuthentication, registeredClient, null);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Validated authorization code request parameters");
}
// ---------------
// The request is valid - ensure the resource owner is authenticated
// ---------------
Authentication principal = (Authentication) authorizationCodeRequestAuthentication.getPrincipal();
if (!isPrincipalAuthenticated(principal)) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Did not authenticate authorization code request since principal not authenticated");
}
// Return the authorization request as-is where isAuthenticated() is false
return authorizationCodeRequestAuthentication;
}
@@ -156,11 +171,20 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen
OAuth2Authorization authorization = authorizationBuilder(registeredClient, principal, authorizationRequest)
.attribute(OAuth2ParameterNames.STATE, state)
.build();
if (this.logger.isTraceEnabled()) {
logger.trace("Generated authorization consent state");
}
this.authorizationService.save(authorization);
Set<String> currentAuthorizedScopes = currentAuthorizationConsent != null ?
currentAuthorizationConsent.getScopes() : null;
if (this.logger.isTraceEnabled()) {
this.logger.trace("Saved authorization");
}
return new OAuth2AuthorizationConsentAuthenticationToken(authorizationRequest.getAuthorizationUri(),
registeredClient.getClientId(), principal, state, currentAuthorizedScopes, null);
}
@@ -174,17 +198,29 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen
throw new OAuth2AuthorizationCodeRequestAuthenticationException(error, null);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Generated authorization code");
}
OAuth2Authorization authorization = authorizationBuilder(registeredClient, principal, authorizationRequest)
.authorizedScopes(authorizationRequest.getScopes())
.token(authorizationCode)
.build();
this.authorizationService.save(authorization);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Saved authorization");
}
String redirectUri = authorizationRequest.getRedirectUri();
if (!StringUtils.hasText(redirectUri)) {
redirectUri = registeredClient.getRedirectUris().iterator().next();
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Authenticated authorization code request");
}
return new OAuth2AuthorizationCodeRequestAuthenticationToken(authorizationRequest.getAuthorizationUri(),
registeredClient.getClientId(), principal, authorizationCode, redirectUri,
authorizationRequest.getState(), authorizationRequest.getScopes());

View File

@@ -20,6 +20,9 @@ import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
@@ -62,6 +65,7 @@ import org.springframework.util.StringUtils;
public final class OAuth2AuthorizationConsentAuthenticationProvider implements AuthenticationProvider {
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1";
private static final OAuth2TokenType STATE_TOKEN_TYPE = new OAuth2TokenType(OAuth2ParameterNames.STATE);
private final Log logger = LogFactory.getLog(getClass());
private final RegisteredClientRepository registeredClientRepository;
private final OAuth2AuthorizationService authorizationService;
private final OAuth2AuthorizationConsentService authorizationConsentService;
@@ -97,6 +101,10 @@ public final class OAuth2AuthorizationConsentAuthenticationProvider implements A
authorizationConsentAuthentication, null, null);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved authorization with authorization consent state");
}
// The 'in-flight' authorization must be associated to the current principal
Authentication principal = (Authentication) authorizationConsentAuthentication.getPrincipal();
if (!isPrincipalAuthenticated(principal) || !principal.getName().equals(authorization.getPrincipalName())) {
@@ -111,6 +119,10 @@ public final class OAuth2AuthorizationConsentAuthenticationProvider implements A
authorizationConsentAuthentication, registeredClient, null);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved registered client");
}
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(OAuth2AuthorizationRequest.class.getName());
Set<String> requestedScopes = authorizationRequest.getScopes();
Set<String> authorizedScopes = new HashSet<>(authorizationConsentAuthentication.getScopes());
@@ -119,6 +131,10 @@ public final class OAuth2AuthorizationConsentAuthenticationProvider implements A
authorizationConsentAuthentication, registeredClient, authorizationRequest);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Validated authorization consent request parameters");
}
OAuth2AuthorizationConsent currentAuthorizationConsent = this.authorizationConsentService.findById(
authorization.getRegisteredClientId(), authorization.getPrincipalName());
Set<String> currentAuthorizedScopes = currentAuthorizationConsent != null ?
@@ -139,6 +155,9 @@ public final class OAuth2AuthorizationConsentAuthenticationProvider implements A
OAuth2AuthorizationConsent.Builder authorizationConsentBuilder;
if (currentAuthorizationConsent != null) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved existing authorization consent");
}
authorizationConsentBuilder = OAuth2AuthorizationConsent.from(currentAuthorizationConsent);
} else {
authorizationConsentBuilder = OAuth2AuthorizationConsent.withId(
@@ -157,6 +176,9 @@ public final class OAuth2AuthorizationConsentAuthenticationProvider implements A
.build();
// @formatter:on
this.authorizationConsentCustomizer.accept(authorizationConsentAuthenticationContext);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Customized authorization consent");
}
}
Set<GrantedAuthority> authorities = new HashSet<>();
@@ -166,8 +188,14 @@ public final class OAuth2AuthorizationConsentAuthenticationProvider implements A
// Authorization consent denied (or revoked)
if (currentAuthorizationConsent != null) {
this.authorizationConsentService.remove(currentAuthorizationConsent);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Revoked authorization consent");
}
}
this.authorizationService.remove(authorization);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Removed authorization");
}
throwError(OAuth2ErrorCodes.ACCESS_DENIED, OAuth2ParameterNames.CLIENT_ID,
authorizationConsentAuthentication, registeredClient, authorizationRequest);
}
@@ -175,6 +203,9 @@ public final class OAuth2AuthorizationConsentAuthenticationProvider implements A
OAuth2AuthorizationConsent authorizationConsent = authorizationConsentBuilder.build();
if (!authorizationConsent.equals(currentAuthorizationConsent)) {
this.authorizationConsentService.save(authorizationConsent);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Saved authorization consent");
}
}
OAuth2TokenContext tokenContext = createAuthorizationCodeTokenContext(
@@ -186,6 +217,10 @@ public final class OAuth2AuthorizationConsentAuthenticationProvider implements A
throw new OAuth2AuthorizationCodeRequestAuthenticationException(error, null);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Generated authorization code");
}
OAuth2Authorization updatedAuthorization = OAuth2Authorization.from(authorization)
.authorizedScopes(authorizedScopes)
.token(authorizationCode)
@@ -195,11 +230,19 @@ public final class OAuth2AuthorizationConsentAuthenticationProvider implements A
.build();
this.authorizationService.save(updatedAuthorization);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Saved authorization");
}
String redirectUri = authorizationRequest.getRedirectUri();
if (!StringUtils.hasText(redirectUri)) {
redirectUri = registeredClient.getRedirectUris().iterator().next();
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Authenticated authorization consent request");
}
return new OAuth2AuthorizationCodeRequestAuthenticationToken(
authorizationRequest.getAuthorizationUri(), registeredClient.getClientId(), principal, authorizationCode,
redirectUri, authorizationRequest.getState(), authorizedScopes);

View File

@@ -19,6 +19,9 @@ import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
@@ -57,6 +60,7 @@ import static org.springframework.security.oauth2.server.authorization.authentic
*/
public final class OAuth2ClientCredentialsAuthenticationProvider implements AuthenticationProvider {
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
private final Log logger = LogFactory.getLog(getClass());
private final OAuth2AuthorizationService authorizationService;
private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator;
@@ -84,6 +88,10 @@ public final class OAuth2ClientCredentialsAuthenticationProvider implements Auth
getAuthenticatedClientElseThrowInvalidClient(clientCredentialsAuthentication);
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved registered client");
}
if (!registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.CLIENT_CREDENTIALS)) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT);
}
@@ -98,6 +106,10 @@ public final class OAuth2ClientCredentialsAuthenticationProvider implements Auth
authorizedScopes = new LinkedHashSet<>(clientCredentialsAuthentication.getScopes());
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Validated token request parameters");
}
// @formatter:off
OAuth2TokenContext tokenContext = DefaultOAuth2TokenContext.builder()
.registeredClient(registeredClient)
@@ -116,6 +128,11 @@ public final class OAuth2ClientCredentialsAuthenticationProvider implements Auth
"The token generator failed to generate the access token.", ERROR_URI);
throw new OAuth2AuthenticationException(error);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Generated access token");
}
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
@@ -137,6 +154,12 @@ public final class OAuth2ClientCredentialsAuthenticationProvider implements Auth
this.authorizationService.save(authorization);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Saved authorization");
// This log is kept separate for consistency with other providers
this.logger.trace("Authenticated token request");
}
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken);
}

View File

@@ -21,6 +21,9 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
@@ -65,6 +68,7 @@ import static org.springframework.security.oauth2.server.authorization.authentic
public final class OAuth2RefreshTokenAuthenticationProvider implements AuthenticationProvider {
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
private static final OAuth2TokenType ID_TOKEN_TOKEN_TYPE = new OAuth2TokenType(OidcParameterNames.ID_TOKEN);
private final Log logger = LogFactory.getLog(getClass());
private final OAuth2AuthorizationService authorizationService;
private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator;
@@ -92,12 +96,20 @@ public final class OAuth2RefreshTokenAuthenticationProvider implements Authentic
getAuthenticatedClientElseThrowInvalidClient(refreshTokenAuthentication);
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved registered client");
}
OAuth2Authorization authorization = this.authorizationService.findByToken(
refreshTokenAuthentication.getRefreshToken(), OAuth2TokenType.REFRESH_TOKEN);
if (authorization == null) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_GRANT);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved authorization with refresh token");
}
if (!registeredClient.getId().equals(authorization.getRegisteredClientId())) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
}
@@ -122,6 +134,11 @@ public final class OAuth2RefreshTokenAuthenticationProvider implements Authentic
if (!authorizedScopes.containsAll(scopes)) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_SCOPE);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Validated token request parameters");
}
if (scopes.isEmpty()) {
scopes = authorizedScopes;
}
@@ -147,6 +164,11 @@ public final class OAuth2RefreshTokenAuthenticationProvider implements Authentic
"The token generator failed to generate the access token.", ERROR_URI);
throw new OAuth2AuthenticationException(error);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Generated access token");
}
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
@@ -169,6 +191,11 @@ public final class OAuth2RefreshTokenAuthenticationProvider implements Authentic
"The token generator failed to generate the refresh token.", ERROR_URI);
throw new OAuth2AuthenticationException(error);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Generated refresh token");
}
currentRefreshToken = (OAuth2RefreshToken) generatedRefreshToken;
authorizationBuilder.refreshToken(currentRefreshToken);
}
@@ -188,6 +215,11 @@ public final class OAuth2RefreshTokenAuthenticationProvider implements Authentic
"The token generator failed to generate the ID token.", ERROR_URI);
throw new OAuth2AuthenticationException(error);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Generated id token");
}
idToken = new OidcIdToken(generatedIdToken.getTokenValue(), generatedIdToken.getIssuedAt(),
generatedIdToken.getExpiresAt(), ((Jwt) generatedIdToken).getClaims());
authorizationBuilder.token(idToken, (metadata) ->
@@ -200,12 +232,20 @@ public final class OAuth2RefreshTokenAuthenticationProvider implements Authentic
this.authorizationService.save(authorization);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Saved authorization");
}
Map<String, Object> additionalParameters = Collections.emptyMap();
if (idToken != null) {
additionalParameters = new HashMap<>();
additionalParameters.put(OidcParameterNames.ID_TOKEN, idToken.getTokenValue());
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Authenticated token request");
}
return new OAuth2AccessTokenAuthenticationToken(
registeredClient, clientPrincipal, accessToken, currentRefreshToken, additionalParameters);
}

View File

@@ -20,6 +20,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
@@ -53,6 +56,7 @@ public final class OAuth2TokenIntrospectionAuthenticationProvider implements Aut
private static final TypeDescriptor OBJECT_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Object.class);
private static final TypeDescriptor LIST_STRING_TYPE_DESCRIPTOR =
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class));
private final Log logger = LogFactory.getLog(getClass());
private final RegisteredClientRepository registeredClientRepository;
private final OAuth2AuthorizationService authorizationService;
@@ -81,13 +85,23 @@ public final class OAuth2TokenIntrospectionAuthenticationProvider implements Aut
OAuth2Authorization authorization = this.authorizationService.findByToken(
tokenIntrospectionAuthentication.getToken(), null);
if (authorization == null) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Did not authenticate token introspection request since token was not found");
}
// Return the authentication request when token not found
return tokenIntrospectionAuthentication;
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved authorization with token");
}
OAuth2Authorization.Token<OAuth2Token> authorizedToken =
authorization.getToken(tokenIntrospectionAuthentication.getToken());
if (!authorizedToken.isActive()) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Did not introspect token since not active");
}
return new OAuth2TokenIntrospectionAuthenticationToken(tokenIntrospectionAuthentication.getToken(),
clientPrincipal, OAuth2TokenIntrospection.builder().build());
}
@@ -95,6 +109,10 @@ public final class OAuth2TokenIntrospectionAuthenticationProvider implements Aut
RegisteredClient authorizedClient = this.registeredClientRepository.findById(authorization.getRegisteredClientId());
OAuth2TokenIntrospection tokenClaims = withActiveTokenClaims(authorizedToken, authorizedClient);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Authenticated token introspection request");
}
return new OAuth2TokenIntrospectionAuthenticationToken(authorizedToken.getToken().getTokenValue(),
clientPrincipal, tokenClaims);
}

View File

@@ -15,6 +15,9 @@
*/
package org.springframework.security.oauth2.server.authorization.authentication;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
@@ -39,6 +42,7 @@ import static org.springframework.security.oauth2.server.authorization.authentic
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc7009#section-2.1">Section 2.1 Revocation Request</a>
*/
public final class OAuth2TokenRevocationAuthenticationProvider implements AuthenticationProvider {
private final Log logger = LogFactory.getLog(getClass());
private final OAuth2AuthorizationService authorizationService;
/**
@@ -63,6 +67,9 @@ public final class OAuth2TokenRevocationAuthenticationProvider implements Authen
OAuth2Authorization authorization = this.authorizationService.findByToken(
tokenRevocationAuthentication.getToken(), null);
if (authorization == null) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Did not authenticate token revocation request since token was not found");
}
// Return the authentication request when token not found
return tokenRevocationAuthentication;
}
@@ -75,6 +82,12 @@ public final class OAuth2TokenRevocationAuthenticationProvider implements Authen
authorization = OAuth2AuthenticationProviderUtils.invalidate(authorization, token.getToken());
this.authorizationService.save(authorization);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Saved authorization with revoked token");
// This log is kept separate for consistency with other providers
this.logger.trace("Authenticated token revocation request");
}
return new OAuth2TokenRevocationAuthenticationToken(token.getToken(), clientPrincipal);
}

View File

@@ -15,6 +15,9 @@
*/
package org.springframework.security.oauth2.server.authorization.authentication;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
@@ -42,6 +45,7 @@ import org.springframework.util.Assert;
*/
public final class PublicClientAuthenticationProvider implements AuthenticationProvider {
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-3.2.1";
private final Log logger = LogFactory.getLog(getClass());
private final RegisteredClientRepository registeredClientRepository;
private final CodeVerifierAuthenticator codeVerifierAuthenticator;
@@ -74,14 +78,26 @@ public final class PublicClientAuthenticationProvider implements AuthenticationP
throwInvalidClient(OAuth2ParameterNames.CLIENT_ID);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved registered client");
}
if (!registeredClient.getClientAuthenticationMethods().contains(
clientAuthentication.getClientAuthenticationMethod())) {
throwInvalidClient("authentication_method");
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Validated client authentication parameters");
}
// Validate the "code_verifier" parameter for the public client
this.codeVerifierAuthenticator.authenticateRequired(clientAuthentication, registeredClient);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Authenticated public client");
}
return new OAuth2ClientAuthenticationToken(registeredClient,
clientAuthentication.getClientAuthenticationMethod(), null);
}

View File

@@ -19,6 +19,9 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
@@ -52,6 +55,7 @@ import org.springframework.util.StringUtils;
*/
public final class OidcClientConfigurationAuthenticationProvider implements AuthenticationProvider {
static final String DEFAULT_CLIENT_CONFIGURATION_AUTHORIZED_SCOPE = "client.read";
private final Log logger = LogFactory.getLog(getClass());
private final RegisteredClientRepository registeredClientRepository;
private final OAuth2AuthorizationService authorizationService;
private final Converter<RegisteredClient, OidcClientRegistration> clientRegistrationConverter;
@@ -98,6 +102,10 @@ public final class OidcClientConfigurationAuthenticationProvider implements Auth
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_TOKEN);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved authorization with access token");
}
OAuth2Authorization.Token<OAuth2AccessToken> authorizedAccessToken = authorization.getAccessToken();
if (!authorizedAccessToken.isActive()) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_TOKEN);
@@ -125,8 +133,16 @@ public final class OidcClientConfigurationAuthenticationProvider implements Auth
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Validated client configuration request parameters");
}
OidcClientRegistration clientRegistration = this.clientRegistrationConverter.convert(registeredClient);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Authenticated client configuration request");
}
return new OidcClientRegistrationAuthenticationToken(
(Authentication) clientRegistrationAuthentication.getPrincipal(), clientRegistration);
}

View File

@@ -27,6 +27,9 @@ import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
@@ -81,6 +84,7 @@ import org.springframework.util.StringUtils;
public final class OidcClientRegistrationAuthenticationProvider implements AuthenticationProvider {
private static final String ERROR_URI = "https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationError";
private static final String DEFAULT_CLIENT_REGISTRATION_AUTHORIZED_SCOPE = "client.create";
private final Log logger = LogFactory.getLog(getClass());
private final RegisteredClientRepository registeredClientRepository;
private final OAuth2AuthorizationService authorizationService;
private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator;
@@ -134,6 +138,10 @@ public final class OidcClientRegistrationAuthenticationProvider implements Authe
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_TOKEN);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved authorization with initial access token");
}
OAuth2Authorization.Token<OAuth2AccessToken> authorizedAccessToken = authorization.getAccessToken();
if (!authorizedAccessToken.isActive()) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_TOKEN);
@@ -170,9 +178,17 @@ public final class OidcClientRegistrationAuthenticationProvider implements Authe
throwInvalidClientRegistration("invalid_client_metadata", OidcClientMetadataClaimNames.TOKEN_ENDPOINT_AUTH_METHOD);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Validated client registration request parameters");
}
RegisteredClient registeredClient = this.registeredClientConverter.convert(clientRegistrationAuthentication.getClientRegistration());
this.registeredClientRepository.save(registeredClient);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Saved registered client");
}
OAuth2Authorization registeredClientAuthorization = registerAccessToken(registeredClient);
// Invalidate the "initial" access token as it can only be used once
@@ -182,11 +198,19 @@ public final class OidcClientRegistrationAuthenticationProvider implements Authe
}
this.authorizationService.save(authorization);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Saved authorization with invalidated initial access token");
}
Map<String, Object> clientRegistrationClaims = this.clientRegistrationConverter.convert(registeredClient).getClaims();
OidcClientRegistration clientRegistration = OidcClientRegistration.withClaims(clientRegistrationClaims)
.registrationAccessToken(registeredClientAuthorization.getAccessToken().getToken().getTokenValue())
.build();
if (this.logger.isTraceEnabled()) {
this.logger.trace("Authenticated client registration request");
}
return new OidcClientRegistrationAuthenticationToken(
(Authentication) clientRegistrationAuthentication.getPrincipal(), clientRegistration);
}
@@ -216,6 +240,11 @@ public final class OidcClientRegistrationAuthenticationProvider implements Authe
"The token generator failed to generate the registration access token.", ERROR_URI);
throw new OAuth2AuthenticationException(error);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Generated registration access token");
}
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
registrationAccessToken.getTokenValue(), registrationAccessToken.getIssuedAt(),
registrationAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
@@ -237,6 +266,10 @@ public final class OidcClientRegistrationAuthenticationProvider implements Authe
this.authorizationService.save(authorization);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Saved authorization with registration access token");
}
return authorization;
}

View File

@@ -23,6 +23,9 @@ import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
@@ -48,6 +51,7 @@ import org.springframework.util.Assert;
* @see <a href="https://openid.net/specs/openid-connect-core-1_0.html#UserInfo">5.3. UserInfo Endpoint</a>
*/
public final class OidcUserInfoAuthenticationProvider implements AuthenticationProvider {
private final Log logger = LogFactory.getLog(getClass());
private final OAuth2AuthorizationService authorizationService;
private Function<OidcUserInfoAuthenticationContext, OidcUserInfo> userInfoMapper = new DefaultOidcUserInfoMapper();
@@ -82,6 +86,10 @@ public final class OidcUserInfoAuthenticationProvider implements AuthenticationP
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_TOKEN);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved authorization with access token");
}
OAuth2Authorization.Token<OAuth2AccessToken> authorizedAccessToken = authorization.getAccessToken();
if (!authorizedAccessToken.isActive()) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_TOKEN);
@@ -96,6 +104,10 @@ public final class OidcUserInfoAuthenticationProvider implements AuthenticationP
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_TOKEN);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Validated user info request");
}
OidcUserInfoAuthenticationContext authenticationContext =
OidcUserInfoAuthenticationContext.with(userInfoAuthentication)
.accessToken(authorizedAccessToken.getToken())
@@ -103,6 +115,10 @@ public final class OidcUserInfoAuthenticationProvider implements AuthenticationP
.build();
OidcUserInfo userInfo = this.userInfoMapper.apply(authenticationContext);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Authenticated user info request");
}
return new OidcUserInfoAuthenticationToken(accessTokenAuthentication, userInfo);
}