Skip to content

Commit 73f2210

Browse files
committed
Polish Authorization Consent Deny Request
Issue spring-projectsgh-470
1 parent 7b00c75 commit 73f2210

File tree

2 files changed

+66
-15
lines changed

2 files changed

+66
-15
lines changed

oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProvider.java

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.springframework.security.authentication.AuthenticationProvider;
3333
import org.springframework.security.core.Authentication;
3434
import org.springframework.security.core.AuthenticationException;
35+
import org.springframework.security.core.GrantedAuthority;
3536
import org.springframework.security.crypto.keygen.Base64StringKeyGenerator;
3637
import org.springframework.security.crypto.keygen.StringKeyGenerator;
3738
import org.springframework.security.oauth2.core.AuthorizationGrantType;
@@ -329,19 +330,6 @@ private Authentication authenticateAuthorizationConsent(Authentication authentic
329330
Set<String> currentAuthorizedScopes = currentAuthorizationConsent != null ?
330331
currentAuthorizationConsent.getScopes() : Collections.emptySet();
331332

332-
if (authorizedScopes.isEmpty() && currentAuthorizedScopes.isEmpty() &&
333-
authorizationCodeRequestAuthentication.getAdditionalParameters().isEmpty()) {
334-
// Authorization consent denied
335-
this.authorizationService.remove(authorization);
336-
throwError(OAuth2ErrorCodes.ACCESS_DENIED, OAuth2ParameterNames.CLIENT_ID,
337-
authorizationCodeRequestAuthentication, registeredClient, authorizationRequest);
338-
}
339-
340-
if (requestedScopes.contains(OidcScopes.OPENID)) {
341-
// 'openid' scope is auto-approved as it does not require consent
342-
authorizedScopes.add(OidcScopes.OPENID);
343-
}
344-
345333
if (!currentAuthorizedScopes.isEmpty()) {
346334
for (String requestedScope : requestedScopes) {
347335
if (currentAuthorizedScopes.contains(requestedScope)) {
@@ -350,6 +338,11 @@ private Authentication authenticateAuthorizationConsent(Authentication authentic
350338
}
351339
}
352340

341+
if (!authorizedScopes.isEmpty() && requestedScopes.contains(OidcScopes.OPENID)) {
342+
// 'openid' scope is auto-approved as it does not require consent
343+
authorizedScopes.add(OidcScopes.OPENID);
344+
}
345+
353346
OAuth2AuthorizationConsent.Builder authorizationConsentBuilder;
354347
if (currentAuthorizationConsent != null) {
355348
authorizationConsentBuilder = OAuth2AuthorizationConsent.from(currentAuthorizationConsent);
@@ -371,6 +364,19 @@ private Authentication authenticateAuthorizationConsent(Authentication authentic
371364
this.authorizationConsentCustomizer.accept(authorizationConsentAuthenticationContext);
372365
}
373366

367+
Set<GrantedAuthority> authorities = new HashSet<>();
368+
authorizationConsentBuilder.authorities(authorities::addAll);
369+
370+
if (authorities.isEmpty()) {
371+
// Authorization consent denied (or revoked)
372+
if (currentAuthorizationConsent != null) {
373+
this.authorizationConsentService.remove(currentAuthorizationConsent);
374+
}
375+
this.authorizationService.remove(authorization);
376+
throwError(OAuth2ErrorCodes.ACCESS_DENIED, OAuth2ParameterNames.CLIENT_ID,
377+
authorizationCodeRequestAuthentication, registeredClient, authorizationRequest);
378+
}
379+
374380
OAuth2AuthorizationConsent authorizationConsent = authorizationConsentBuilder.build();
375381
if (!authorizationConsent.equals(currentAuthorizationConsent)) {
376382
this.authorizationConsentService.save(authorizationConsent);

oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProviderTests.java

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,52 @@ private void assertAuthorizationConsentRequestWithAuthorizationCodeResult(
868868
}
869869

870870
@Test
871-
public void authenticateWhenConsentRequestWithPreviouslyApprovedThenAuthorizationConsentUpdated() {
871+
public void authenticateWhenConsentRequestApproveNoneAndRevokePreviouslyApprovedThenAuthorizationConsentRemoved() {
872+
String previouslyApprovedScope = "message.read";
873+
String requestedScope = "message.write";
874+
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
875+
.scopes(scopes -> {
876+
scopes.clear();
877+
scopes.add(previouslyApprovedScope);
878+
scopes.add(requestedScope);
879+
})
880+
.build();
881+
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
882+
.thenReturn(registeredClient);
883+
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient)
884+
.principalName(this.principal.getName())
885+
.build();
886+
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(OAuth2AuthorizationRequest.class.getName());
887+
OAuth2AuthorizationCodeRequestAuthenticationToken authentication =
888+
authorizationConsentRequestAuthentication(registeredClient, this.principal)
889+
.scopes(new HashSet<>()) // No scopes approved
890+
.build();
891+
when(this.authorizationService.findByToken(eq(authentication.getState()), eq(STATE_TOKEN_TYPE)))
892+
.thenReturn(authorization);
893+
OAuth2AuthorizationConsent previousAuthorizationConsent =
894+
OAuth2AuthorizationConsent.withId(authorization.getRegisteredClientId(), authorization.getPrincipalName())
895+
.scope(previouslyApprovedScope)
896+
.build();
897+
when(this.authorizationConsentService.findById(eq(authorization.getRegisteredClientId()), eq(authorization.getPrincipalName())))
898+
.thenReturn(previousAuthorizationConsent);
899+
900+
// Revoke all (including previously approved)
901+
this.authenticationProvider.setAuthorizationConsentCustomizer((authorizationConsentContext) ->
902+
authorizationConsentContext.getAuthorizationConsent().authorities(Set::clear));
903+
904+
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
905+
.isInstanceOf(OAuth2AuthorizationCodeRequestAuthenticationException.class)
906+
.satisfies(ex ->
907+
assertAuthenticationException((OAuth2AuthorizationCodeRequestAuthenticationException) ex,
908+
OAuth2ErrorCodes.ACCESS_DENIED, OAuth2ParameterNames.CLIENT_ID, authorizationRequest.getRedirectUri())
909+
);
910+
911+
verify(this.authorizationConsentService).remove(eq(previousAuthorizationConsent));
912+
verify(this.authorizationService).remove(eq(authorization));
913+
}
914+
915+
@Test
916+
public void authenticateWhenConsentRequestApproveSomeAndPreviouslyApprovedThenAuthorizationConsentUpdated() {
872917
String previouslyApprovedScope = "message.read";
873918
String requestedScope = "message.write";
874919
String otherPreviouslyApprovedScope = "other.scope";
@@ -923,7 +968,7 @@ public void authenticateWhenConsentRequestWithPreviouslyApprovedThenAuthorizatio
923968
}
924969

925970
@Test
926-
public void authenticateWhenConsentRequestApproveNoneButPreviouslyApprovedThenAuthorizationConsentNotUpdated() {
971+
public void authenticateWhenConsentRequestApproveNoneAndPreviouslyApprovedThenAuthorizationConsentNotUpdated() {
927972
String previouslyApprovedScope = "message.read";
928973
String requestedScope = "message.write";
929974
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()

0 commit comments

Comments
 (0)