-
Notifications
You must be signed in to change notification settings - Fork 978
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
Conversation
lib/galaxy/authnz/managers.py
Outdated
@@ -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"} |
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.
The galaxy.util.asbool
function is a potential replacement for this:
galaxy/lib/galaxy/util/__init__.py
Line 925 in 0204c9b
def asbool(obj): |
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.
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 |
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.
Are the return values for this documented somewhere?
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.
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') |
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.
Should this be a per provider logout as well?
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 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.
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.
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.
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.
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.
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.
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
.
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.
@machristie Thanks for the changes, looks great to me!
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. |
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 So, you could check for and read Anyway, thank you again for the enhancement. |
Thanks @dannon
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. |
@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. |
Add support for logging out of OIDC Identity Provider
[WIP] Backporting PR #9162 into 20.01
Add support for logging out of OIDC Identity Provider
[20.01] Backporting PR #9162 into 20.01 branch
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).