Skip to content

OAuth2Login should process authenticated requests #6890

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

Closed
wangzw opened this issue May 20, 2019 · 11 comments
Closed

OAuth2Login should process authenticated requests #6890

wangzw opened this issue May 20, 2019 · 11 comments
Assignees
Labels
in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) status: backported An issue that has been backported to maintenance branches type: bug A general bug
Milestone

Comments

@wangzw
Copy link
Contributor

wangzw commented May 20, 2019

Use case:

We have a system A use OAuth2Login to implement user login(Code flow). And another system B works as OAuth2 provider.

Step 1: A supervisor login system A. Everything works well.
Step 2: Supervisor close browser without logout. System A session is still available.
Step 3: A non-privilege user login system B to do something, Everything works well. Session of system B is reset to non-privilege user.
Step 4: The non-privilege user login system A from login page, but found that the login user is actually supervisor. (Reuse the previous supervisor session)

Expected: At step 4, since non-privilege user start a new login process from login page, we expected non-privilege user login finally.

After debug, we found that at step 4, the login process of system A have got the oauth2 code (Code flow) and redirected to the redirect url, but the redirect url is not processed correctly and skipped since the following code.

PathPatternParserServerWebExchangeMatcher loginPathMatcher = new PathPatternParserServerWebExchangeMatcher("/login/oauth2/code/{registrationId}");
ServerWebExchangeMatcher notAuthenticatedMatcher = e -> ReactiveSecurityContextHolder.getContext()
.flatMap(p -> ServerWebExchangeMatcher.MatchResult.notMatch())
.switchIfEmpty(ServerWebExchangeMatcher.MatchResult.match());
return new AndServerWebExchangeMatcher(loginPathMatcher, notAuthenticatedMatcher);

Since the existence of the previous session, the process of redirect url is skipped. And the previous session is reused incorrectly.

AFAIK the process of redirect url is used to validate oauth2 code and retrieve user/token info and cannot be skipped. So it looks a security issue.

And since the process of redirect url is skipped, the saved authentication request cannot be removed from (in memory) session and potential run out server memory.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label May 20, 2019
@rwinch
Copy link
Member

rwinch commented May 20, 2019

Thanks @wangzw! @jgrandja will take a look soon

@jgrandja
Copy link
Contributor

jgrandja commented Jun 5, 2019

@wangzw The one thing that I would like to point out (in case you are not aware) is that when a user authenticates via oauth2Login(), 2 sessions are created. The first session is with the provider and the second session is with the application.

Given your use case, if supervisor logs out of the application (but not with the provider) and a non-privilege user attempts to authenticate via the application than authentication will automatically happen given that there is an existing session cookie (in the browser) with the provider. This session cookie (created for supervisor) is used to authenticate the non-privilege user which than follows up with the auth-code flow to complete OpenID Connect authentication.

NOTE: This only happens when using the same browser session/window. I believe in your scenario, you are also testing this using the same browser/window session? Can you please test your scenario using a different browser (or new session window) and let me know your results?

FYI, we also introduced support (in 5.2.0.M2) for RP (Client) initiated logout via #5350, which would allow you to configure the application to logout at the provider whenever the user logs out of the application.

@jgrandja jgrandja removed their assignment Jun 5, 2019
@jgrandja jgrandja added in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) status: waiting-for-feedback We need additional information before we can continue and removed status: waiting-for-triage An issue we've not yet triaged labels Jun 5, 2019
@wangzw
Copy link
Contributor Author

wangzw commented Jun 5, 2019

@jgrandja

Thanks for your reply. I'm aware that two different sessions exist for application and provider.

At Step 3, a non-privilege user login system B (Provider), so the session of provider is for non-privilege user.

a non-privilege user attempts to authenticate via the application than authentication will automatically happen given that there is an existing session cookie (in the browser) with the provider.

Yes, it is expected.

But finally application shows that the login user is supervisor.

The reason is that since the session of system A (application) for supervisor still available during login process, the login process is aborted due to following code.

PathPatternParserServerWebExchangeMatcher loginPathMatcher = new PathPatternParserServerWebExchangeMatcher("/login/oauth2/code/{registrationId}");
ServerWebExchangeMatcher notAuthenticatedMatcher = e -> ReactiveSecurityContextHolder.getContext()
.flatMap(p -> ServerWebExchangeMatcher.MatchResult.notMatch())
.switchIfEmpty(ServerWebExchangeMatcher.MatchResult.match());
return new AndServerWebExchangeMatcher(loginPathMatcher, notAuthenticatedMatcher);

Since at step 4, the non-privilege user start a new login process to application, the login process should not be aborted no matter a previous session exists or not.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Jun 5, 2019
@wangzw
Copy link
Contributor Author

wangzw commented Jun 5, 2019

Let me make the issue clear.

OAuth2 login has 3 steps (code flow):

  1. Authenticate and get code from provider.
  2. validate code and get access token.
  3. validate token and get token/user information.

Current issue is that since there is a previous session, step 2 and 3 is skipped. And the existence session is reused.

I do not think that step 2 can be skipped in any case.

Two consequences:

  1. If pervious session is for user A and user B start login process in same browser/window. Login process finish successfully but the session is still for user A. The action of reset session happen in step 2/3, but skipped.

  2. At step 1, an authorization request is stored in (in-memory) session and expected be removed at step 2. But since step 2 is skipped, the authorization request is not removed from session. So it can be used to blow up server's memory.

@jgrandja
Copy link
Contributor

jgrandja commented Jun 6, 2019

@wangzw

The reason is that since the session of system A (application) for supervisor still available during login process, the login process is aborted due to following code.

In this scenario the login process is never started (or aborted) given that there is an established session from the supervisor on the previous step. Please keep in mind that the authentication process will not initiate if there is already an authenticated session.

Since at step 4, the non-privilege user start a new login process to application, the login process should not be aborted no matter a previous session exists or not.

Can you please provide details on exactly how you start a new login process with the non-privilege user? The fact that there is already an established session from supervisor and you do not log out, how do you start a new login process with non-privilege user without logging out supervisor first?

Also, this really isn't a valid real world use-case IMO. If a supervisor logs into an application and performs some tasks but than wants to log into the application with lesser privileges than they would typically logout first and than log back in using the non-privilege user.

At this point, I do not see any issues with the current implementation. This will likely get closed as Works as Designed but I'll wait for your reply.

@jgrandja jgrandja added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Jun 6, 2019
@wangzw
Copy link
Contributor Author

wangzw commented Jun 7, 2019

In this scenario the login process is never started (or aborted) given that there is an established session from the supervisor on the previous step. Please keep in mind that the authentication process will not initiate if there is already an authenticated session.

That is not true.

From the view of user at step 4, non-privilege user start a new login process of application by open the login URL, redirected to authentication page and type in non-privilege user name and password (since provider's session is cleaned by logout of provider), non-privilege user will think that I have login. But not, supervisor's session of application is actually reused.

From the view of OAuth2 protocol at step 4, authorization code is granted by provider for non-privilege user, that means the oauth2 login process has started. But OAuth2Login skip validate authorization code and reuse existing session. It violate the OAuth2 protocol. Application must validate authorization code unconditionally.

The fact that there is already an established session from supervisor and you do not log out, how do you start a new login process with non-privilege user without logging out supervisor first?

It is a common use case that user can start a new login process by open login URL no matter a previous session exists or not. It is spring-security default form login behavior, previous session will be reset after a new successful login.

Currently issue is that OAuth2Login skip validating authorization code if a previous session exists.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Jun 7, 2019
@wangzw
Copy link
Contributor Author

wangzw commented Jun 7, 2019

Compare FormLogin and OAuth2Login

FormLogin: A new user login with a pervious session exists, new user login successfully and session is reset for new user. Expected.

OAuth2Login: A new user login with a pervious application session exists (provider session not exist), new user type in new user name and password and no error throws but previous session is reused. Not Expected, new user feels login successfully but actually previous session is reused.

@wangzw
Copy link
Contributor Author

wangzw commented Jun 7, 2019

how do you start a new login process with non-privilege user without logging out supervisor first?

To start a new oauth2 login from application, open browser with http://application.example.com/oauth2/authorization/demo

If provider's session has expired, or supervisor has logout from provider(not application). non-privilege user is required to authenticated first.

If any provider session exists, authentication will be skipped.

I found that webflux and servlet have different behavior at this case.

when start a new oauth2 login with previous application session exist. (code flow)

  1. Servlet: when the browser call the redirect url, 404 is returned.
  2. WebFlux: when the browser call the redirect url, 2xx/3xx is returned (means new user login successfully), but previous session is reused.

Both behaviors are not expected.
Expected: Application session is reset for new user, just like form login.

@wangzw
Copy link
Contributor Author

wangzw commented Jun 7, 2019

I have filed a pull request to fix this issue. With this fix, OAuth2Login behave the same as FormLogin when a new user login with a previous session exist. New user login will success and session will reset for new user.

@wangzw
Copy link
Contributor Author

wangzw commented Jun 7, 2019

I have setup a repo to reproduce the issue. https://github.com/wangzw/oauth2-login-6890

@jgrandja
Copy link
Contributor

@wangzw Thanks for providing a sample that reproduces the issue. After inspecting the code in more detail, I have noticed some inconsistencies between servlet and reactive.

I'm currently working on another task but I will get to this later this week. I'll update you when I get back to this. Thanks for your patience.

@jgrandja jgrandja removed the status: feedback-provided Feedback has been provided label Jun 18, 2019
@jgrandja jgrandja added this to the 5.2.0.RC1 milestone Jun 18, 2019
@jgrandja jgrandja added the type: bug A general bug label Jun 18, 2019
@jgrandja jgrandja changed the title OAuth2Login redirect url is not processed correctly and cause incorrect user login OAuth2Login should process authenticated requests Jun 19, 2019
@spring-projects-issues spring-projects-issues added status: backported An issue that has been backported to maintenance branches and removed for: backport-to-5.1.x labels Jun 19, 2019
jgrandja added a commit that referenced this issue Jun 19, 2019
Issue #5856
Commit 385bdfc

NOTE: This commit 'partially' reverts #5856. Only the ServerWebExchangeMatcher for OAuth2LoginSpec is reverted.

Fixes gh-6890
jgrandja added a commit that referenced this issue Jun 19, 2019
Issue #5856
Commit 385bdfc

NOTE: This commit 'partially' reverts #5856. Only the ServerWebExchangeMatcher for OAuth2LoginSpec is reverted.

Fixes gh-6890
kostya05983 pushed a commit to kostya05983/spring-security that referenced this issue Aug 26, 2019
kostya05983 pushed a commit to kostya05983/spring-security that referenced this issue Aug 26, 2019
Issue spring-projects#5856
Commit 385bdfc

NOTE: This commit 'partially' reverts spring-projects#5856. Only the ServerWebExchangeMatcher for OAuth2LoginSpec is reverted.

Fixes spring-projectsgh-6890
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) status: backported An issue that has been backported to maintenance branches type: bug A general bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants