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

Refactor and consolidate user session logic #4452

Merged
merged 13 commits into from
Aug 23, 2024
Merged

Conversation

zoldar
Copy link
Contributor

@zoldar zoldar commented Aug 19, 2024

Changes

This PR refactors and creates a groundwork for implementing persisted user sessions.

Review can be done commit-by-commit for convenience.

  • User session management and retrieval is completely abstracted behind PlausibleWeb.UserAuth. The module takes care of managing cookies (currently the defaults session when and "logged_in" cookie shared with static site). There are also extension points introduced already for supporting persisted sessions and transition from the current (legacy) cookies to the new, token based ones which will be persisted using Plausible.Auth.UserSession (currently an embedded schema - just enough to support existing cookie auth).
  • Cookies are now always renewed/reset, reducing the potential risk of session fixation attacks.
  • There's a new assign introduced, called live_socket_id. Once the token based authentication is implemented, it will allow disconnecting LV clients on either explicit logout or after revoking the relevant token(s). More details in the docs. NOTE: As Phoenix PubSub is not fully setup, we might still not be able to fully benefit from that mechanism.
  • The current_user_id value is no longer explicitly passed via live_render's session option. All existing session keys are passed through implicitly, to this was redundant.
  • PlausibleWeb.Live.AuthContext is now automatically populating current_user (and current_user_session) in LV context on mount - provided it's not provided by the AuthPlug already which is sooner in the overall pipeline.
  • Both Live.AuthContext and AuthPlug ensure the shape of the loaded user is the same, always with an active subscription preloaded if there is one.
  • Any direct references to current_user_id session value got removed from LV in favor of retrieving current_user implicitly set by the auth plug or context.
  • The current_user from the context is used more consistently in a number of spots (mostly around billing where user was refetched and set under a different key, like user).

Tests

  • Automated tests have been added

Changelog

  • This PR does not make a user-facing change

Documentation

  • This change does not need a documentation update

Dark mode

  • This PR does not change the UI

@zoldar zoldar changed the title Session cookie consolidation Refactor and consolidate user session logic Aug 19, 2024
@zoldar zoldar force-pushed the session-cookie-consolidation branch 3 times, most recently from 4302325 to 6207655 Compare August 20, 2024 10:59
@zoldar zoldar added the preview label Aug 20, 2024
Copy link

Preview environment👷🏼‍♀️🏗️
PR-4452

socket =
socket
|> assign_new(:site, fn %{current_user: current_user} ->
Plausible.Sites.get_for_user!(current_user, domain, [:owner, :admin, :super_admin])
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved site assignment under assign_new here. I think it's fine to reuse existing assign if present but maybe I'm missing something?

@@ -40,7 +34,7 @@ defmodule PlausibleWeb.Live.Shields.Countries do
current_user={@current_user}
country_rules_count={@country_rules_count}
site={@site}
id="country-rules-#{@current_user.id}"
id={"country-rules-#{@current_user.id}"}
Copy link
Contributor Author

@zoldar zoldar Aug 20, 2024

Choose a reason for hiding this comment

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

It was a literal instead of interpolated string - fixed it btw (the same goes for other instances in shields LVs).

@@ -112,10 +110,7 @@ defmodule PlausibleWeb.Live.Sites do
>
Total of <span class="font-medium"><%= @sites.total_entries %></span> sites
</.pagination>
<.invitation_modal
:if={Enum.any?(@sites.entries, &(&1.entry_type == "invitation"))}
user={@user}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This assign was completely unused in the modal component.

@zoldar zoldar force-pushed the session-cookie-consolidation branch 4 times, most recently from 9f90460 to 5c4445b Compare August 22, 2024 09:46
@zoldar zoldar marked this pull request as ready for review August 22, 2024 09:46
@zoldar zoldar requested a review from a team August 22, 2024 09:46
@zoldar zoldar mentioned this pull request Aug 22, 2024
9 tasks
Copy link
Member

@aerosol aerosol left a comment

Choose a reason for hiding this comment

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

Nice and clean ✨

@@ -622,8 +622,7 @@ defmodule PlausibleWeb.AuthController do
redirect_to = Map.get(params, "redirect", "/")

conn
|> configure_session(drop: true)
|> delete_resp_cookie("logged_in")
|> UserAuth.log_out_user()
Copy link
Member

Choose a reason for hiding this comment

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

Just to make sure - renewing is just as good as dropping the cookie now?

Copy link
Contributor Author

@zoldar zoldar Aug 23, 2024

Choose a reason for hiding this comment

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

Renewing and clearing session is basically identical as dropping it in case of using COOKIE session store. It makes more of a difference in case of other stores (ETS, there's also Redis driver) where session data is stored server-side and session ID is stored in the cookie. Renewing then is indeed necessary to avoid malicious reuse of the same session ID (so-called session fixation attacks). Defaulting to renewal + clear is fine and additionally future-proof in case we ever want to switch the session store to avoid risk of potentially forgetting to update the reset strategy. For reference here's a short discussion clearing that up a bit: phoenixframework/phoenix#5466

end
end

def on_mount(:default, _params, session, socket) do
Copy link
Member

Choose a reason for hiding this comment

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

nice 👏

@zoldar zoldar force-pushed the session-cookie-consolidation branch from 5c4445b to fbe1cdb Compare August 23, 2024 08:48
@zoldar zoldar merged commit bd93cf3 into master Aug 23, 2024
10 checks passed
@zoldar zoldar deleted the session-cookie-consolidation branch August 23, 2024 08:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants