-
-
Notifications
You must be signed in to change notification settings - Fork 1
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
Support for live views #11
Comments
I plan to look at this after #7. |
Interesting. Given the example, you go through your plugs before mounting the liveview, including Plugoid if configured. So you know your user is authenticated. That said as far as I remember you have to check again when mounting the liveview that the user is authenticated for security reasons (because you can make the websocket request bypassing the plugs or something like that). Now one problem I see is that session data is passed to the callback, but Plugoid uses its own session cookie separated from the default session (for security reasons: the authentication cookie has stricter settings). Another is that https://hexdocs.pm/plugoid/Plugoid.html#module-session will not work inside a liveview. Plugoid has an internal max session lifetime, after which it redirects to the OpenID Provider (OP). If the user is already authenticated on the OP, he's redirected back immediately to the page he was browsing (with new tokens, but it's semaless). In a liveview where a user would stay a long time, this mechanisms would not work. |
Not getting the session information might be a problem. Not sure, can't think of a solution off hand. I have seen live view sessions expire. But I have no idea how this works. The docs talk about logging out: https://hexdocs.pm/phoenix_live_view/security-model.html#disconnecting-all-instances-of-a-live-user but not expiring sessions. |
Thanks to your callback in #12, can now add the following line to the callback (as per Pheonix docs cited above):
Am starting to think that live view logic is mostly application specific and should be left to the application. But we probably can add documentation/sample code on how to do this. Haven't yet got a logout URL, about to look at that now. |
For reference, here is the current live view setup I have: Token call back, as per #12: defmodule RoboticaFaceWeb.TokenCallback do
import Plug.Conn
@spec callback(
Plug.Conn.t(),
OIDC.Auth.OPResponseSuccess.t(),
String.t(),
String.t(),
keyword()
) :: Plug.Conn.t()
def callback(conn, response, _issuer, _client_id, _opts) do
sub = response.id_token_claims["sub"]
claims = Map.take(response.id_token_claims, ["groups", "name", "sub"])
conn
|> fetch_session()
|> put_session(:live_socket_id, "users_socket:#{sub}")
|> put_session(:claims, claims)
end
end Logout controller function: def logout(conn, _params) do
user = RoboticaFaceWeb.Auth.current_user(conn)
if user != nil do
sub = user["sub"]
RoboticaFaceWeb.Endpoint.broadcast("users_socket:#{sub}", "disconnect", %{})
end
conn
|> Plugoid.logout()
|> put_session(:claims, nil)
|> put_flash(:danger, "You are now logged out.")
|> redirect(to: Routes.page_path(conn, :index))
end Obviously this requires anonymous access to the path it redirects too (or it could get very confusing for the user if the get redirected to the login page and only see the message after they log in). Where defmodule RoboticaFaceWeb.Auth do
@moduledoc """
Helper functions for authorization
"""
@spec current_user(Plug.Conn.t()) :: map()
def current_user(conn) do
Plug.Conn.get_session(conn, :claims)
end
@spec user_is_admin?(map()) :: boolean()
def user_is_admin?(user) do
case user do
%{"groups" => groups} -> Enum.member?(groups, "admin")
_ -> false
end
end
end And the LiveView InitAssigns hook code: defmodule RoboticaFaceWeb.InitAssigns do
import Phoenix.LiveView
alias RoboticaFaceWeb.Router.Helpers, as: Routes
def mount(_params, session, socket) do
user = session["claims"]
if user == nil do
socket = put_flash(socket, :danger, "Your session has expired.")
socket = redirect(socket, to: Routes.page_path(socket, :index))
{:halt, socket}
else
socket = assign(socket, :user, user)
{:cont, socket}
end
end
end I am a bit puzzled here, I had to define a Ideally would like to redirect to the same URL, so that the user goes back to the same place after logging in again. |
In typical fashion, my website stops working immediately after I turn my computer off for night... So might be an error in the code I quoted, will check tomorrow. Later: I suspect that might be an unrelated issue, will file #13. |
I am seeing some unexpected behaviour with Firefox/android. It seems Firefox is quite happy to reconnect to a previous live session. Including one that has been idle for hours - i.e. Firefox in the background for hours. Not 100% sure but I suspect Firefox on Android doesn't support web sockets in the background. So I would have expected the live session to have disconnected some time ago. But if I click any buttons, including live_patch links to the same live view, it will force a login. The behaviour has recently changed. Before Firefox would force a reload of the page when I first reopen it. Which would typically force a login. But clicking back several times would get me to a live view that would work without a login (huh?). But now it just connects to the previous live view. Still trying to work this out. |
Thanks for reporting! Couldn't be due to a change in Liveview? Have you updated it recently? |
I have been consistently making changes, so I can't rule that out. But not changed anything significant that I can think of regarding live views, sessions or authentication. Not for a while now. I do have a theory that maybe the plugoid session is somehow expiring before the plugoid session. Looking at the plugoid code again, it looks like it has a default session time it imposes of session_lifetime=1 hour, and I think Phoenix might not have any session time-outs by default (???). So if I revisit a page that is already open (i.e. by reopening Firefox), it creates a new live view, which calls my mount function. Which checks the phoenix session. But when I click a link, it is causing the page to be reloaded, which causes the plugoid auth to check its session which has expired, so it requires the user login. One flaw in this theory is that live_patch links shouldn't require the page to be reloaded. But maybe this is not working on Firefox/Android. Another flaw is that I only have really noticed this issue on Firefox/Android. Firefox on Linux doesn't seem to follow the same pattern. I probably should retest though. I miss not having convenient debug tools on Firefox/Android. I had this theory, discarded it, and coming back to it again. If this is the case, I guess there are several possible solutions, depending on paranoia level:
|
For that matter, I really have not noticed any session time-outs on Firefox on Linux. Wonder if the default 1 hour isn't working for some reason here. Might try to debug when I get a chance. LATER: never mind, this is working perfectly on Firefox, except for live views, which was expected. |
Thinking this through a bit more:
That would then allow the application to put the expiration time into the Phoenix session (maybe in a custom plug - or maybe in yet another callback), which will get passed to the life view, and the live view then has an indication of when the session is going to expire, and take appropriate action when the session does expire. Hmmm. But the session expiration the live view has has might be old, the session might have been renewed. So correct behaviour might be to disconnect and force a reload the live view if the session expiration time has expired, rather then actively reject the user. |
It should be done through cookie lifetime. To have Liveview's expiration meet, indeed you need to transmit how long the cookie is valid and manually force a redirect to the same URL. That has been a long time since then, and I only started working with Liveview recently. I think putting user id in the session ( |
No, I think one should use the |
Live views do not get the
conn
value, only the session.I imagine this would be implemented through the
on_mount
LiveView server lifecycle hooks that was introduced in Pheonix 1.6.https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#on_mount/1
The text was updated successfully, but these errors were encountered: