-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Remember user consent and make consent page configurable #280
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remember user consent and make consent page configurable #280
Conversation
c8362e3
to
966ed3a
Compare
36e65fb
to
97148c8
Compare
1d888d5
to
8950a8c
Compare
5ef9c73
to
fe329ea
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR @Kehrlann ! Please see review comments.
...ava/org/springframework/security/oauth2/server/authorization/OAuth2AuthorizationConsent.java
Outdated
Show resolved
Hide resolved
...ava/org/springframework/security/oauth2/server/authorization/OAuth2AuthorizationConsent.java
Show resolved
Hide resolved
...ava/org/springframework/security/oauth2/server/authorization/OAuth2AuthorizationConsent.java
Outdated
Show resolved
Hide resolved
...ava/org/springframework/security/oauth2/server/authorization/OAuth2AuthorizationConsent.java
Outdated
Show resolved
Hide resolved
...ava/org/springframework/security/oauth2/server/authorization/OAuth2AuthorizationConsent.java
Outdated
Show resolved
Hide resolved
...ingframework/security/oauth2/server/authorization/web/OAuth2AuthorizationEndpointFilter.java
Outdated
Show resolved
Hide resolved
@@ -296,6 +385,28 @@ private void processUserConsent(HttpServletRequest request, HttpServletResponse | |||
authorizationCode, userConsentRequestContext.getAuthorizationRequest().getState()); | |||
} | |||
|
|||
private void saveAuthorizationConsent(OAuth2AuthorizationConsent previousConsent, UserConsentRequestContext userConsentRequestContext) { | |||
if (CollectionUtils.isEmpty(userConsentRequestContext.getScopes())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a valid condition?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so.
Scenario 1
Requested scopes:
- openid [REQUIRED to authenticate the user]
- notification.read [OPTIONAL, e.g. the app wants to alert users if they have notifications about X]
The user would see a consent screen with just notification.read
, which they may decide NOT to consent to ; they may "untick" the item and click submit anyway (which is what the current consent page does).
Which would mean "yes, give a token to this client, but without any of theses scopes that I can see".
Scenario 2
Requested scopes:
- message.read [REQUIRED]
- message.write [OPTIONAL]
Previously approved scopes:
- message.read
Same as above, with the user un-ticking "message.write"
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute( | ||
OAuth2AuthorizationRequest.class.getName()); | ||
Set<String> scopes = new HashSet<>(authorizationRequest.getScopes()); | ||
scopes.remove(OidcScopes.OPENID); // openid scope does not require consent | ||
if (previousConsent != null) { | ||
scopes.removeAll(previousConsent.getScopes()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should still display the previous consented scopes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could, but then they should be disabled, because otherwise the users may think they are revoking consent, or not granting consent for this particular token request, despite them having not granted consent before.
The more I think about it, the more I think it should be visible but grayed-out.
Example flow if we just keep it as is.
Token request #1:
User sees message.read
and message.write
, and only ticks the second:
-
message.read
-
message.write
Then, consent for message.write
is persisted. There is no way to revoke consent yet.
Token request #2
User sees message.read
and message.write
again, and this times ticks only the first:
-
message.read
-
message.write
The user would expect to only consent to message.read
. But they have already consented to message.write
, so despite them unticking message.write
, the client app will obtain a token with the message.write
scope as requested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, please review and/or change the "previously approved scopes" message:
You have already granted the following permissions to the above app:
...nnotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java
Outdated
Show resolved
Hide resolved
...amework/security/oauth2/server/authorization/web/OAuth2AuthorizationEndpointFilterTests.java
Show resolved
Hide resolved
@Kehrlann The current implementation stores authorized scopes in I wonder if we remove the key or possibly keep it? If we keep it then the |
20dbae4
to
71cf160
Compare
Re: OAuth2Authorization storing the authorized scopes, that's an interesting point. In this PR, we save all previously approved scopes in the OAuth2Authorization, through: Set<String> authorizedScopes = userConsentRequestContext.getScopes();
[...]
if (previousConsent != null) {
authorizedScopes.addAll(previousConsent.getScopes());
}
[...]
OAuth2Authorization authorization = OAuth2Authorization.from(userConsentRequestContext.getAuthorization())
.token(authorizationCode)
.attributes(attrs -> {
attrs.remove(OAuth2ParameterNames.STATE);
attrs.put(OAuth2Authorization.AUTHORIZED_SCOPE_ATTRIBUTE_NAME, authorizedScopes);
})
.build(); The information is duplicated, but it works and avoid re-loading the consents when issuing a token. I think I like it as is, that is the
However, I believe you have found a bug in the current implementation! Imagine we have previously approved scopes:
And the authorization request has the following requested scopes:
If the user consents to
|
ffea88e
to
c8167b5
Compare
c8167b5
to
44b6b54
Compare
Fixed the issue, ready for review. Re: ProviderSettings, as discussed, I'm leaving |
Thanks for all the updates @Kehrlann ! This is now in main. |
Fixes gh-283