Skip to content

Add hard expiration to Flask session - #5907

Merged
ThiefMaster merged 12 commits into
indico:masterfrom
cbartz:multipass-session-expiry
Oct 27, 2023
Merged

Add hard expiration to Flask session#5907
ThiefMaster merged 12 commits into
indico:masterfrom
cbartz:multipass-session-expiry

Conversation

@cbartz

@cbartz cbartz commented Aug 25, 2023

Copy link
Copy Markdown
Contributor

This PR adds the ability to set a hard expiration for the Flask session. This can be used in conjunction with a Flask Multipass identity provider that specifies the session expiration. See this post for more details on use cases and implementation considerations.

Comment thread indico/web/flask/session.py Outdated
Comment thread indico/web/flask/session.py Outdated
Comment thread indico/web/flask/session_test.py Outdated
Comment thread indico/web/flask/session_test.py Outdated
Comment thread CHANGES.rst Outdated
@cbartz
cbartz marked this pull request as ready for review August 28, 2023 07:57
Comment thread indico/modules/auth/auth_test.py Outdated
Comment thread indico/modules/auth/auth_test.py Outdated
Comment thread indico/web/flask/session.py
@cbartz
cbartz force-pushed the multipass-session-expiry branch from 74a845a to 30f8cec Compare August 30, 2023 11:51
@ThiefMaster

Copy link
Copy Markdown
Member

Just wondering... should there some kind of indicator that the session will expire soon when someone uses this feature? It'd be a bit disruptive if someone is e.g. writing an abstract or minutes for an event and does not realize that the session will expire in a few minutes!

@cbartz

cbartz commented Aug 30, 2023

Copy link
Copy Markdown
Contributor Author

Just wondering... should there some kind of indicator that the session will expire soon when someone uses this feature? It'd be a bit disruptive if someone is e.g. writing an abstract or minutes for an event and does not realize that the session will expire in a few minutes!

This may make sense. Would a flash inside session.py be the right approach or is there a better way?

@ThiefMaster

Copy link
Copy Markdown
Member

We do use flash messages in a few places, but IMHO it would be nicer to actually expose the session expiry to the client, and show a warning dialog client-side that the session will soon expire (with the option to refresh it (by going through the login again)) when getting close to the expiry.

@SegiNyn

SegiNyn commented Oct 2, 2023

Copy link
Copy Markdown
Contributor

but IMHO it would be nicer to actually expose the session expiry to the client, and show a warning dialog client-side that the session will soon expire (with the option to refresh it (by going through the login again)) when getting close to the expiry.

Hi @ThiefMaster, we were also proposing an expiration dialog of this nature to warn users when the session is about to expire and give them the opportunity to refresh:
Screenshot 2023-10-02 at 17 10 40
Screenshot 2023-10-02 at 17 10 54

is this something we can coordinate with this pr?

cc @OmeGak

@ThiefMaster

Copy link
Copy Markdown
Member

Maybe it's best for @SegiNyn to send a PR to @cbartz's branch used for this PR? Alterantively, @cbartz could give her access to his fork of Indico in order to push directly on top of his changes.

At least i'd prefer those options over first merging it and then having a separate PR to improve it...

@SegiNyn

SegiNyn commented Oct 10, 2023

Copy link
Copy Markdown
Contributor

Sending a pr to @cbartz's branch sounds good to me.

Comment thread indico/modules/auth/__init__.py Outdated
def process_identity(identity_info):
logger.info('Received identity info: %s', identity_info)

if session_expiry := identity_info.multipass_data.get('session_expiry'):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hi @cbartz, please does this work when logging in with a local account? I'm getting a AttributeError: 'NoneType' object has no attribute 'get' when logging in with a local account.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

the multipass_data is None for local accounts. so this is currently a bug in the PR

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Okay, thanks

@SegiNyn

SegiNyn commented Oct 20, 2023

Copy link
Copy Markdown
Contributor

Hi @ThiefMaster, I have sent a PR to @cbartz's branch here: cbartz#1 There are still some problems with it like some resources being fetched when opening the dialog which refreshes the session. You won't see this if you run indico with the -q flag because those requests will be silenced in the logs but they still reach the app and refresh the session.

@ThiefMaster

ThiefMaster commented Oct 20, 2023

Copy link
Copy Markdown
Member

Try this to prevent those requests from refreshing the session:

diff --git a/indico/web/flask/session.py b/indico/web/flask/session.py
index 8637f295c4..1d7fc785dd 100644
--- a/indico/web/flask/session.py
+++ b/indico/web/flask/session.py
@@ -162,6 +162,9 @@ class IndicoSessionInterface(SessionInterface):
             return self.temporary_session_lifetime

     def should_refresh_session(self, app, session):
+        if (request.blueprint == 'assets' or
+                (request.blueprint.startswith('plugin_') and request.endpoint.endswith('.static'))):
+            return False
         if session.new or '_expires' not in session:
             return False
         threshold = self.get_storage_lifetime(app, session) / 2

Or replace that whole if condition with re.match(r'assets\.|plugin_.*\.static$', request.endpoint) (you may want to re.compile() that regex since it's used on every single request)

{{ render_announcements() }}
{% endblock %}
{% block body %}{% endblock %}
{% block session_expiration %}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@SegiNyn do you override that block on your side? or is it a leftover that's no longer needed?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes, sorry this is a leftover that's not being used

@ThiefMaster
ThiefMaster force-pushed the multipass-session-expiry branch from d8018b1 to 8ee74d9 Compare October 26, 2023 15:08
@ThiefMaster

Copy link
Copy Markdown
Member

I forcepushed some cleanups and also getting rid of those merge commits while rebasing

@ThiefMaster

Copy link
Copy Markdown
Member

@SegiNyn some feedback after testing this:

  • I think the RequestConfirm component is not a good choice here. It's meant for confirmation of possibly destructive actions. For example, it has no option to only show one button (OK and Cancel doing the same is bad UX) nor to not close when clicking outside the dialog.
  • Sending the user back to the login page only makes sense if there's a hard expiry date set for the session (and thus no possibility of refreshing it). Otherwise a request to an endpoint that simply refreshes its lifetime (as is the case during regular Indico usage) should be made which is much less intrusive (imagine you're writing minutes or an abstract and get this message - you do not expect a redirect, and in most cases it would not be necessary).

@ThiefMaster

Copy link
Copy Markdown
Member

Also, considering that the dialog still needs a bit of work and is not as straightforward as I originally thought, I'm thinking about merging this PR without the dialog stuff tomorrow (3.3 is under development so having no indicator of a soon-expiring session for the time being is fine). That way we avoid the indirection of PRs to a fork, and reviewing the dialog stuff properly will be easier...

@SegiNyn

SegiNyn commented Oct 26, 2023

Copy link
Copy Markdown
Contributor

hi @ThiefMaster, Yes I did notice the issue with the buttons which basically do the same thing but I had not thought of how disruptive it would be to refresh the page while the user is filling in an abstract. So I can add a custom dialog for this part. It's ok for me if you merge this pr with the hard expiry and then I create a different one for the dialog. I'm not going to be in tomorrow so I cannot work on it until Monday anyway.

@ThiefMaster
ThiefMaster force-pushed the multipass-session-expiry branch from d213be1 to 8e9778d Compare October 27, 2023 09:39
@ThiefMaster
ThiefMaster force-pushed the multipass-session-expiry branch from df4cdde to 6d27d38 Compare October 27, 2023 10:07
@ThiefMaster
ThiefMaster merged commit 3689c09 into indico:master Oct 27, 2023
@ThiefMaster

Copy link
Copy Markdown
Member

@SegiNyn I pushed a branch containing your changes, rebased on top of the latest master, to session-expiry-with-dialog in my indico fork. It contains some fixes I did on top of your code so it might be good for you to reset your local branch to that one.

@cbartz

cbartz commented Oct 27, 2023

Copy link
Copy Markdown
Contributor Author

Thanks for merging the PR @ThiefMaster

@cbartz
cbartz deleted the multipass-session-expiry branch October 27, 2023 13:27
@ThiefMaster

Copy link
Copy Markdown
Member

@cbartz Did you ever end up using it in production? Because I just tried to pass a datetime object from a multipass provider, and it fails when trying to save it as part of the multipass_data in the DB (JSONB column, and datetime is not json-serializable)...

I thought I had tested it back when I merged it, but nothing related to this changed so I'm a bit surprised that it doesn't work as expected...

@ThiefMaster

Copy link
Copy Markdown
Member

I'll probably just replace the multipass_data.get('session_expiry') with multipass_data.pop('session_expiry', None) since this does not need to be stored as part of the multipass_data anyway.

@cbartz

cbartz commented Aug 19, 2025

Copy link
Copy Markdown
Contributor Author

@ThiefMaster I moved on to other projects shortly after working on this, so I may have missed some context, but I don't think it's used. The mechanism we use to expire the session is shown here: canonical/flask-multipass-saml-groups#6.

@ThiefMaster

Copy link
Copy Markdown
Member

Thanks. Considering that the support in Indico for this multipass data key was broken and thus we can be pretty sure nobody was using it, I will remove it altogether.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants