Skip to content
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

Add support for logging out of OIDC Identity Provider #9162

Merged
merged 12 commits into from
Jan 29, 2020

Conversation

machristie
Copy link
Contributor

This PR adds support for logging out of an OIDC Identity Provider when the user logs out of Galaxy. This makes sense for some IDPs that exist primarily to provide authentication for Galaxy such as a private Keycloak server. Logging out of the IDP is controlled by a new configuration option in oidc_backends_config.xml called <enable_idp_logout>.

The implementation works by creating a cookie called oidc-provider when the user logs in through an OIDC IDP to record which provider was used. Then, on logout (menu.js), /authnz/logout is called to determine if IDP logout is supported and enabled for the IDP and if so a redirect URI is returned. The user's browser is redirect to this redirect URI which terminates the user's session in the IDP. The IDP then redirects back to the Galaxy home page.

Support for IDP logout is only implemented for Custos/Keycloak since the PSA based backends don't support logout (PSA only supports disconnecting, but logout support was added for SAML recently so it may someday be available for other backends).

@galaxybot galaxybot added this to the 20.05 milestone Dec 23, 2019
@@ -126,7 +127,8 @@ def _parse_custos_config(self, config_xml):
'client_id': config_xml.find('client_id').text,
'client_secret': config_xml.find('client_secret').text,
'redirect_uri': config_xml.find('redirect_uri').text,
'realm': config_xml.find('realm').text}
'realm': config_xml.find('realm').text,
'enable_idp_logout': config_xml.findtext('enable_idp_logout', 'false').lower() == "true"}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The galaxy.util.asbool function is a potential replacement for this:

def asbool(obj):

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion, will do.

# check if logout is enabled for this idp and return false if not
unified_provider_name = self._unify_provider_name(provider)
if self.oidc_backends_config[unified_provider_name]['enable_idp_logout'] is False:
return False, "IDP logout is not enabled for {}".format(provider), None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the return values for this documented somewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I'll document.

@@ -72,6 +72,7 @@ def app_factory(global_conf, load_app_kwds={}, **kwargs):
webapp.add_route('/authnz/{provider}/login', controller='authnz', action='login', provider=None)
webapp.add_route('/authnz/{provider}/callback', controller='authnz', action='callback', provider=None)
webapp.add_route('/authnz/{provider}/disconnect', controller='authnz', action='disconnect', provider=None)
webapp.add_route('/authnz/logout', controller='authnz', action='logout')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a per provider logout as well?

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 having per provider logout could work too, but this seemed more natural to me from the perspective of the UI. For login, the user has picked a specific provider to log into. However, on logout the user has only indicated that they want to logout. /authnz/logout figures out what provider was used to authenticate (using the identity-provider cookie) and logs the user out of that provider.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UI perspective makes sense. What do you think about the API perspective? I feel as if having a per provider logout allows programmatic logout from specific providers, although I'm not sure there's a clear use case. Perhaps a programmatic global logout from a specific provider like keycloak only through the API perhaps? Is the only necessary change to read the cookie from the client side instead of the server? I also feel like authnz/logout should log the user out from all providers, not just the last logged in one? Just some thoughts, but no strong views on which may be better.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What your saying makes a lot of sense. I do like that per provider logout is consistent with the other provider methods.

Is the only necessary change to read the cookie from the client side instead of the server?

Yeah I think that's basically it. However, I think I would change it so that server side the cookie is used to determine the logout API URL and this is provided to the client. I'll work on updating the PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @nuwang , I looked into passing a value to the UI, but it seemed simpler and more in keeping with the Galaxy client design to add an API method for getting the provider specific logout url, so I did that. The frontend now calls /authnz/logout which reads the oidc-provider cookie and if it exists, redirects to /authnz/{provider}/logout.

@dannon dannon self-requested a review January 15, 2020 15:30
Copy link
Member

@nuwang nuwang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@machristie Thanks for the changes, looks great to me!

@dannon
Copy link
Member

dannon commented Jan 28, 2020

I'll get keycloak configured again for testing this morning and will merge this today when it works.

Resolved conflicts with upstream, pushed the merge here.

@dannon dannon added area/auth Authentication and authorization kind/enhancement and removed triage labels Jan 28, 2020
@dannon
Copy link
Member

dannon commented Jan 28, 2020

This is working well for me so I'm going to go ahead and merge it when the tests finish this time. I do think we might want to address the potential refactoring @nuwang mentions, and we might want to drop get_logout_url since, with teh cookie, we actually have all the information we need to call the correct method from the client side from the start.

So, you could check for and read oidc-provider, you'll know it's custos, and can then call authnz/custos/logout, right?

Anyway, thank you again for the enhancement.

@dannon dannon merged commit 299a729 into galaxyproject:dev Jan 29, 2020
@machristie
Copy link
Contributor Author

Thanks @dannon

So, you could check for and read oidc-provider, you'll know it's custos, and can then call authnz/custos/logout, right?

Yes that's right. I went with the approach I took so that only the backend needs to know about cookie instead of the front end and back end needing to know about the cookie. That makes it easier to change the code around setting the cookie, if necessary, going forward. But the approach of the client reading the cookie I think would be fine too, especially if we don't anticipate change in the logic around setting the cookie. I hope that makes sense.

I can put together a PR to do that refactor, maybe this weekend.

@nuwang
Copy link
Member

nuwang commented Jan 30, 2020

@machristie That makes sense. In any case, in future perhaps an enhancement may be to have the logout url log you out of all providers, and the provider specific logout url log you out of that provider only. For now, this seems like a pretty good way for things to work, and we can implement that pretty easily if we ever need it, so I think we may as well leave this as is if @dannon agrees.

almahmoud pushed a commit to almahmoud/galaxy that referenced this pull request Mar 2, 2020
Add support for logging out of OIDC Identity Provider
dannon added a commit that referenced this pull request Mar 3, 2020
[WIP] Backporting PR #9162 into 20.01
almahmoud pushed a commit to almahmoud/galaxy that referenced this pull request Mar 4, 2020
Add support for logging out of OIDC Identity Provider
mvdbeek added a commit that referenced this pull request Mar 4, 2020
[20.01] Backporting PR #9162 into 20.01 branch
@hexylena hexylena mentioned this pull request Jun 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/auth Authentication and authorization kind/enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants