|
@@ -19,6 +19,7 @@ import java.security.Principal;
|
|
import java.util.Base64;
|
|
import java.util.Base64;
|
|
import java.util.Set;
|
|
import java.util.Set;
|
|
import java.util.function.Consumer;
|
|
import java.util.function.Consumer;
|
|
|
|
+import java.util.function.Predicate;
|
|
|
|
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.LogFactory;
|
|
import org.apache.commons.logging.LogFactory;
|
|
@@ -80,6 +81,7 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen
|
|
private OAuth2TokenGenerator<OAuth2AuthorizationCode> authorizationCodeGenerator = new OAuth2AuthorizationCodeGenerator();
|
|
private OAuth2TokenGenerator<OAuth2AuthorizationCode> authorizationCodeGenerator = new OAuth2AuthorizationCodeGenerator();
|
|
private Consumer<OAuth2AuthorizationCodeRequestAuthenticationContext> authenticationValidator =
|
|
private Consumer<OAuth2AuthorizationCodeRequestAuthenticationContext> authenticationValidator =
|
|
new OAuth2AuthorizationCodeRequestAuthenticationValidator();
|
|
new OAuth2AuthorizationCodeRequestAuthenticationValidator();
|
|
|
|
+ private Predicate<OAuth2AuthorizationCodeRequestAuthenticationContext> requiresAuthorizationConsent;
|
|
|
|
|
|
/**
|
|
/**
|
|
* Constructs an {@code OAuth2AuthorizationCodeRequestAuthenticationProvider} using the provided parameters.
|
|
* Constructs an {@code OAuth2AuthorizationCodeRequestAuthenticationProvider} using the provided parameters.
|
|
@@ -96,6 +98,7 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen
|
|
this.registeredClientRepository = registeredClientRepository;
|
|
this.registeredClientRepository = registeredClientRepository;
|
|
this.authorizationService = authorizationService;
|
|
this.authorizationService = authorizationService;
|
|
this.authorizationConsentService = authorizationConsentService;
|
|
this.authorizationConsentService = authorizationConsentService;
|
|
|
|
+ this.requiresAuthorizationConsent = this::requireAuthorizationConsent;
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
@@ -171,7 +174,19 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen
|
|
OAuth2AuthorizationConsent currentAuthorizationConsent = this.authorizationConsentService.findById(
|
|
OAuth2AuthorizationConsent currentAuthorizationConsent = this.authorizationConsentService.findById(
|
|
registeredClient.getId(), principal.getName());
|
|
registeredClient.getId(), principal.getName());
|
|
|
|
|
|
- if (requireAuthorizationConsent(registeredClient, authorizationRequest, currentAuthorizationConsent)) {
|
|
|
|
|
|
+ OAuth2AuthorizationCodeRequestAuthenticationContext.Builder authenticationContextBuilder =
|
|
|
|
+ OAuth2AuthorizationCodeRequestAuthenticationContext.with(authorizationCodeRequestAuthentication)
|
|
|
|
+ .registeredClient(registeredClient)
|
|
|
|
+ .authorizationRequest(authorizationRequest);
|
|
|
|
+
|
|
|
|
+ if (currentAuthorizationConsent != null) {
|
|
|
|
+ authenticationContextBuilder.authorizationConsent(currentAuthorizationConsent);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ OAuth2AuthorizationCodeRequestAuthenticationContext contextWithAuthorizationRequestAndAuthorizationConsent =
|
|
|
|
+ authenticationContextBuilder.build();
|
|
|
|
+
|
|
|
|
+ if (requiresAuthorizationConsent.test(contextWithAuthorizationRequestAndAuthorizationConsent)) {
|
|
String state = DEFAULT_STATE_GENERATOR.generateKey();
|
|
String state = DEFAULT_STATE_GENERATOR.generateKey();
|
|
OAuth2Authorization authorization = authorizationBuilder(registeredClient, principal, authorizationRequest)
|
|
OAuth2Authorization authorization = authorizationBuilder(registeredClient, principal, authorizationRequest)
|
|
.attribute(OAuth2ParameterNames.STATE, state)
|
|
.attribute(OAuth2ParameterNames.STATE, state)
|
|
@@ -264,7 +279,48 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen
|
|
this.authenticationValidator = authenticationValidator;
|
|
this.authenticationValidator = authenticationValidator;
|
|
}
|
|
}
|
|
|
|
|
|
- private static OAuth2Authorization.Builder authorizationBuilder(RegisteredClient registeredClient, Authentication principal,
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Sets the {@link Predicate} used to determine if authorization consent is required.
|
|
|
|
+ *
|
|
|
|
+ * <p>
|
|
|
|
+ * The {@link OAuth2AuthorizationCodeRequestAuthenticationContext} gives the predicate access to the {@link OAuth2AuthorizationCodeRequestAuthenticationToken},
|
|
|
|
+ * as well as, the following context attributes:
|
|
|
|
+ * {@link OAuth2AuthorizationCodeRequestAuthenticationContext#getRegisteredClient()} containing {@link RegisteredClient} used to make the request.
|
|
|
|
+ * {@link OAuth2AuthorizationCodeRequestAuthenticationContext#getOAuth2AuthorizationRequest()} containing {@link OAuth2AuthorizationRequest}.
|
|
|
|
+ * {@link OAuth2AuthorizationCodeRequestAuthenticationContext#getOAuth2AuthorizationConsent()} containing {@link OAuth2AuthorizationConsent} granted in the request.
|
|
|
|
+ *
|
|
|
|
+ * @param requiresAuthorizationConsent the {@link Predicate} that determines if authorization consent is required.
|
|
|
|
+ * @since 1.3.0
|
|
|
|
+ */
|
|
|
|
+ public void setRequiresAuthorizationConsent(Predicate<OAuth2AuthorizationCodeRequestAuthenticationContext> requiresAuthorizationConsent) {
|
|
|
|
+ Assert.notNull(requiresAuthorizationConsent, "requiresAuthorizationConsent cannot be null");
|
|
|
|
+ this.requiresAuthorizationConsent = requiresAuthorizationConsent;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private boolean requireAuthorizationConsent(OAuth2AuthorizationCodeRequestAuthenticationContext context) {
|
|
|
|
+ RegisteredClient registeredClient = context.getRegisteredClient();
|
|
|
|
+ if (!registeredClient.getClientSettings().isRequireAuthorizationConsent()) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ OAuth2AuthorizationRequest authorizationRequest = context.getOAuth2AuthorizationRequest();
|
|
|
|
+ // 'openid' scope does not require consent
|
|
|
|
+ if (authorizationRequest.getScopes().contains(OidcScopes.OPENID) &&
|
|
|
|
+ authorizationRequest.getScopes().size() == 1) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ OAuth2AuthorizationConsent authorizationConsent = context.getOAuth2AuthorizationConsent();
|
|
|
|
+ if (authorizationConsent != null &&
|
|
|
|
+ authorizationConsent.getScopes().containsAll(authorizationRequest.getScopes())) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static OAuth2Authorization.Builder authorizationBuilder(RegisteredClient registeredClient,
|
|
|
|
+ Authentication principal,
|
|
OAuth2AuthorizationRequest authorizationRequest) {
|
|
OAuth2AuthorizationRequest authorizationRequest) {
|
|
return OAuth2Authorization.withRegisteredClient(registeredClient)
|
|
return OAuth2Authorization.withRegisteredClient(registeredClient)
|
|
.principalName(principal.getName())
|
|
.principalName(principal.getName())
|
|
@@ -295,26 +351,6 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen
|
|
return tokenContextBuilder.build();
|
|
return tokenContextBuilder.build();
|
|
}
|
|
}
|
|
|
|
|
|
- private static boolean requireAuthorizationConsent(RegisteredClient registeredClient,
|
|
|
|
- OAuth2AuthorizationRequest authorizationRequest, OAuth2AuthorizationConsent authorizationConsent) {
|
|
|
|
-
|
|
|
|
- if (!registeredClient.getClientSettings().isRequireAuthorizationConsent()) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- // 'openid' scope does not require consent
|
|
|
|
- if (authorizationRequest.getScopes().contains(OidcScopes.OPENID) &&
|
|
|
|
- authorizationRequest.getScopes().size() == 1) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (authorizationConsent != null &&
|
|
|
|
- authorizationConsent.getScopes().containsAll(authorizationRequest.getScopes())) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
private static boolean isPrincipalAuthenticated(Authentication principal) {
|
|
private static boolean isPrincipalAuthenticated(Authentication principal) {
|
|
return principal != null &&
|
|
return principal != null &&
|
|
!AnonymousAuthenticationToken.class.isAssignableFrom(principal.getClass()) &&
|
|
!AnonymousAuthenticationToken.class.isAssignableFrom(principal.getClass()) &&
|