FusionAuth / fusionauth-issues

FusionAuth issue submission project
https://fusionauth.io
89 stars 12 forks source link

Self-service account session revocation #2298

Open jobannon opened 1 year ago

jobannon commented 1 year ago

Self-service account session revocation

Problem

In FusionAuth version 1.45.0 the self-service themed pages no longer use the SSO session, and instead have a discrete session.

Logging out of SSO, or your own application will not necessarily log you out of the session held for the /account pages which is essentially an extension of your own application.

For example, if you are logged into application A with a client_id of 377e77a7-e066-4896-b3b4-5c2bbaec96e0 and then navigate to /account/?client_id=377e77a7-e066-4896-b3b4-5c2bbaec96e0 you will now have a new access token and refresh token for this application. This session is held in http only secure cookies.

If you then log out of SSO or your own application, the state for the /account pages is still valid.

In order to logout of the /account session, you need to make a GET request to /account/logout?client_id=377e77a7-e066-4896-b3b4-5c2bbaec96e0.

Solution

One option would be to use single logout and then when logging out of an app w/ self-service enabled, we add another URL to the list of other application logout URLs for /account/logout?client_Id=377e77a7-e066-4896-b3b4-5c2bbaec96e0.

Another option is to listen for refresh token revocation events and if a token for application 377e77a7-e066-4896-b3b4-5c2bbaec96e0is revoked, revoke the refresh token held for/account` as well.

Needs more investigation.

Observed in version

Affects versions

Workarounds

Related

Additional context

Internal:

Community guidelines

All issues filed in this repository must abide by the FusionAuth community guidelines.

How to vote

Please give us a thumbs up or thumbs down as a reaction to help us prioritize this feature. Feel free to comment if you have a particular need or comment on how this feature should work.

lyleschemmerling commented 1 year ago

Using the account jwt side-load isn't a proper workaround for this. It is going to cause confusion over what it is in the fusionauth.sso cookie which can lead the browser getting into a bad state.

lyleschemmerling commented 1 year ago

Added surrogate application workaround steps

dransome commented 11 months ago

It should be noted that the current behaviour can pose a security issue, since the self-service account feature can potentially provide a way to set a new user password without further authentication (i.e. subject to whether or not the 'Require current password' option added via https://github.com/FusionAuth/fusionauth-issues/issues/1578 is enabled or not).

There is also potential to change email address (e.g. which could enable authentication via magic link) without further authentication (as far as I can tell, the only "defence" against this aspect is to enable the Email update email template which sends a notification old + new email on change, but it doesn't prevent the attack: just notifies someone that it happened).

If a public/shared computer is used, an attacker can gain access to a previously "logged out" session (i.e. applications/SSO was logged out, but not the self-service account management session), and then take over the affected account!

dransome commented 11 months ago

Added surrogate application workaround steps

@lyleschemmerling please can you clarify

Attempting to follow your surrogate application workaround steps verbatim:

Real application: 5f921ed5-1700-4f25-8ec4-7db9b267c96a Surrogate logout application: 59e7200e-47c4-49ff-8f53-d4b461dbfbe6

My test user is registered to real application, and has an existing self-service account session. I set the logout URL of surrogate logout application to https://<MY_FUSIONAUTH_HOST>/account/logout/5f921ed5-1700-4f25-8ec4-7db9b267c96a (replacing MY_FUSIONAUTH_HOST - obviously).

Then I point my (test user) browser at the logout URL of the surrogate logout application: https://<MY_FUSIONAUTH_HOST/oauth2/logout?client_id=59e7200e-47c4-49ff-8f53-d4b461dbfbe6

I got a HTTP 500, with this in the logs:

2023-09-22 12:02:13.693 PM ERROR io.fusionauth.app.primeframework.error.ExceptionExceptionHandler - An unhandled exception was thrown
com.google.inject.ProvisionException: Unable to provision, see the following errors:

1) [Guice/ErrorInjectingConstructor]: NullPointerException: Cannot read field "oauthConfiguration" because "<parameter1>" is null
  at LogoutAction.<init>(LogoutAction.java:23)
  while locating LogoutAction
...
2023-09-22 12:02:13.714 PM ERROR org.primeframework.mvc.PrimeMVCRequestHandler - Error encountered
java.lang.NullPointerException: Cannot read field "actionURI" because "actionInvocation" is null

I thought maybe you had a typo and the Logout URL was supposed to be set to https://<MY_FUSIONAUTH_HOST>/account/logout?client_id=377e77a7-e066-4896-b3b4-5c2bbaec96e0 (rather than /account/logout/377e77a7-e066-4896-b3b4-5c2bbaec96e0) but that variant also led to a HTTP 500:

2023-09-22 12:06:07.062 PM ERROR io.fusionauth.app.primeframework.error.ExceptionExceptionHandler - An unhandled exception was thrown
com.google.inject.ProvisionException: Unable to provision, see the following errors:

1) [Guice/ErrorInjectingConstructor]: NullPointerException: Cannot read field "oauthConfiguration" because "<parameter1>" is null
  at LogoutAction.<init>(LogoutAction.java:23)
  while locating LogoutAction
...
2023-09-22 12:06:07.064 PM ERROR org.primeframework.mvc.PrimeMVCRequestHandler - Error encountered
java.lang.NullPointerException: Cannot read field "actionURI" because "actionInvocation" is null

Am I doing something wrong with my steps, or is the proposed workaround faulty?

dransome commented 11 months ago

For the record, the following workaround seems to be viable for my use case:

Assuming a single (real) application with ID: 5f921ed5-1700-4f25-8ec4-7db9b267c96a

Hope this helps someone else facing the same.

lyleschemmerling commented 11 months ago

@dransome apologies in the delayed response. I'm glad you got this working. The intent of the workaround was for the main application to call its logout endpoint like normal, and this action would trigger the side effect of invoking logout of "all applications" including the surrogate and self-service account applications.

We do have work in progress with a proper fix for this issue but I do not have an ETA for its delivery at the moment.

dransome commented 9 months ago

@lyleschemmerling seems that my workaround creates its own problem.

We noticed intermittent HTTP 500 errors from the logout URL. (https://<MY_FUSIONAUTH_HOST>/account/logout?client_id=5f921ed5-1700-4f25-8ec4-7db9b267c96a).

My working theory is this happens if the user has not visited the FusionAuth self-service pages, and as a result, maybe FusionAuth doesn't find a session for that user?

When searching for logs, I found that it was the same error that I posted earlier. Is this just a result of what I'm doing with the workaround attempt(s), or a separate FusionAuth bug in its own right?

It seems that FusionAuth ought not to explode (HTTP 500) if you attempt to log out on a non-existent(?) session?

mooreds commented 1 month ago

Another option is to listen for refresh token revocation events and if a token for application 377e77a7-e066-4896-b3b4-5c2bbaec96e0is revoked, revoke the refresh token held for /account as well.

I don't believe the refresh token for account is visible. I tried to find it but was unable to see it on either the admin screen or the API. When I deleted all the sessions for a user using the 'delete all sessions' button in the admin UI, my account session remains alive.

It seems like front channel logout to https://<MY_FUSIONAUTH_HOST>/account/logout?client_id=... is the best option.