Skip to content

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

Conversation

Kehrlann
Copy link
Contributor

@Kehrlann Kehrlann commented Apr 12, 2021

Fixes gh-283

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Apr 12, 2021
@Kehrlann Kehrlann force-pushed the feature/extend-user-consent-#177645165 branch 9 times, most recently from c8362e3 to 966ed3a Compare April 19, 2021 13:54
@Kehrlann Kehrlann force-pushed the feature/extend-user-consent-#177645165 branch 4 times, most recently from 36e65fb to 97148c8 Compare April 20, 2021 12:29
@Kehrlann Kehrlann marked this pull request as ready for review April 20, 2021 13:10
@Kehrlann Kehrlann force-pushed the feature/extend-user-consent-#177645165 branch 2 times, most recently from 1d888d5 to 8950a8c Compare April 26, 2021 15:31
@jgrandja jgrandja self-assigned this Apr 27, 2021
@jgrandja jgrandja added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged labels Apr 27, 2021
@jgrandja jgrandja added this to the 0.1.1 milestone Apr 27, 2021
@Kehrlann Kehrlann force-pushed the feature/extend-user-consent-#177645165 branch 7 times, most recently from 5ef9c73 to fe329ea Compare May 3, 2021 09:24
@jgrandja jgrandja modified the milestones: 0.1.1, 0.1.2 May 7, 2021
Copy link
Collaborator

@jgrandja jgrandja left a 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.

@@ -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())) {
Copy link
Collaborator

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?

Copy link
Contributor Author

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());
Copy link
Collaborator

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

Copy link
Contributor Author

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.

Copy link
Contributor Author

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:

@jgrandja
Copy link
Collaborator

jgrandja commented May 26, 2021

@Kehrlann The current implementation stores authorized scopes in OAuth2Authorization.attributes using key OAuth2Authorization.AUTHORIZED_SCOPE_ATTRIBUTE_NAME. We need to account for this in the PR since the storage is moving.

I wonder if we remove the key or possibly keep it? If we keep it then the OAuth2AuthorizationService would need to use the OAuth2AuthorizationConsentService to load the consents into the OAuth2Authorization attribute. Thoughts?

@Kehrlann Kehrlann force-pushed the feature/extend-user-consent-#177645165 branch 8 times, most recently from 20dbae4 to 71cf160 Compare May 27, 2021 08:36
@Kehrlann
Copy link
Contributor Author

Kehrlann commented May 27, 2021

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();

(code is here)

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 ConsentService is only used at authorization time, to determine:

  • if consent is required
  • which scopes should we ask consent for

However, I believe you have found a bug in the current implementation! Imagine we have previously approved scopes:

  • banana.eat
  • milk.drink

And the authorization request has the following requested scopes:

  • apple.eat
  • banana.eat

If the user consents to apple.eat, I believe the token will have:

  • apple.eat
  • banana.eat
  • milk.drink -> 💥 the authorization request never asked for this scope

@Kehrlann Kehrlann force-pushed the feature/extend-user-consent-#177645165 branch 2 times, most recently from ffea88e to c8167b5 Compare May 31, 2021 06:36
@Kehrlann Kehrlann force-pushed the feature/extend-user-consent-#177645165 branch from c8167b5 to 44b6b54 Compare May 31, 2021 09:08
@Kehrlann
Copy link
Contributor Author

Kehrlann commented May 31, 2021

Fixed the issue, ready for review.

Re: ProviderSettings, as discussed, I'm leaving userConsentUri out.

@Kehrlann Kehrlann requested a review from jgrandja May 31, 2021 09:10
@jgrandja jgrandja added the status: duplicate A duplicate of another issue label Jun 4, 2021
jgrandja added a commit that referenced this pull request Jun 4, 2021
@jgrandja
Copy link
Collaborator

jgrandja commented Jun 4, 2021

Thanks for all the updates @Kehrlann ! This is now in main.

@jgrandja jgrandja closed this Jun 4, 2021
@Kehrlann Kehrlann deleted the feature/extend-user-consent-#177645165 branch June 23, 2021 06:32
jgrandja added a commit that referenced this pull request Jul 6, 2021
doba16 pushed a commit to doba16/spring-authorization-server that referenced this pull request Apr 21, 2023
doba16 pushed a commit to doba16/spring-authorization-server that referenced this pull request Apr 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: duplicate A duplicate of another issue type: enhancement A general enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Provide configuration for custom Authorization Consent page
3 participants