We are using the Flask-Multipass SAML Auth Provider and the SAML Auth Responses currently have an expiration of one day.
The Indico session is renewed upon user interaction, which means that a user can still be legitimately logged in even though the SAML response is no longer valid.
We are interested in having some kind of (at best: non-interactive) refresh after the expiration of the SAML response (a bit of background: We use this plugin in order to use groups with SAML,
and group membership information is only updated on login, so a user would currently have group access if they indefinitely extend the session).
Is there a recommended way to implement this in a plugin?
One thought would be to override the IndicoSession and either redirect to the login page or to the SAML Identity Provider after expiration.
Generally we recommend against using group information that’s only available during login times, because as you correctly noticed, the Indico session is created during login and then there’s no more interaction with whatever you used to log in.
I think the only halfway decent way to do what you want to do would be to add some way to allow passing an optional hard expiry date for the Indico session from the Multipass identity provider, and then considering the session invalid (either explicitly or by never setting an expiry in redis that’s after that date).
If you are willing to contribute such a feature, great! You can probably make use of the multipass_data field of the IdentityInfo. During the login on the Indico side (in the process_identity function) you’ then check if the key exists and store this expiry date on the session. Another option would be making the max session duration a first-class citizen of flask-multipass (ie adding a new attribute to IdentityInfo directly and support in other places of flask-multipass as needed), and then checking for that in Indico.
With some effort you could do it in a plugin as well: Use the signals.users.logged_in signal, and check the identity’s multipass_data for what I explained above, and then store this data on the session. To force a logout you’d need to se e.g. the flask before_request signal to check if the session expiry has been reached and if that’s the case clear the session - you probably want session.clear() for this and not multipass.logout() because the latter would do a SSO logout, which is probably not what you want.
Instead of just clearing the session you could of course also redirect to the SSO login endpoint again so the user gets more or less transparently logged in again if they still have a valid SSO session.
Automatically redirecting to login isn’t easily possible. However, if this is your only login method, and the user is on a restricted page, they will be automatically redirected to the login and thus the SSO.
If you really want to trigger a redirect from code that’s usually not returning a response, you can try this:
raise Forbidden(response=redirect(...))
(any other exception class imported from werkzeug.exceptions will work as well - when passing a response that one will be used instead of the usual one for the exception)
Note that I have no idea if usual exception handling is applied when it happens while opening the session, so it may very well be possible that this doesn’t work at all…
Thanks, one problem would be that going to the unrestricted main page would not trigger a redirect, which could be confusing for users (they would see a login button on the top right and would certainly click on it, so it would not be so “transparent”).
So perhaps the current approach (basically your suggestion to set an expiration through the plugin and then redirect) would be better, but we will be interested in using the session expiration warning dialogue once it is implemented and would then have to see if it is usable with our current approach.