Skip to content

Commit 9cf908e

Browse files
committed
Set global lock for session renewal and persistent session token fetch
1 parent fe62118 commit 9cf908e

File tree

5 files changed

+40
-13
lines changed

5 files changed

+40
-13
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
## v1.0.18 (TBA)
44

5+
### Enhancements
6+
7+
* [`Pow.Plug.Session`] Now sets a global lock when renewing the session
8+
* [`PowPersistentSession.Plug.Cookie`] Now sets a global lock when authenticating the user
9+
510
### Bug fixes
611

712
* [`Pow.Phoenix.Routes`] Fixed bug where callback route methods is not using the overridden method

lib/extensions/persistent_session/plug/cookie.ex

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,11 @@ defmodule PowPersistentSession.Plug.Cookie do
174174
If a persistent session cookie exists, it'll fetch the credentials from the
175175
persistent session cache.
176176
177-
If credentials was fetched successfully, the token in the cache is deleted, a
178-
new session is created, and `create/2` is called to create a new persistent
179-
session cookie.
177+
If credentials was fetched successfully, a global lock is set and the token
178+
in the cache is deleted, a new session is created, and `create/2` is called
179+
to create a new persistent session cookie. If setting the lock failed, the
180+
user will fetched will be set for the `conn` with
181+
`Pow.Plug.assign_current_user/3`.
180182
181183
If a `:session_metadata` keyword list is fetched from the persistent session
182184
metadata, all the values will be merged into the private
@@ -205,9 +207,7 @@ defmodule PowPersistentSession.Plug.Cookie do
205207
conn
206208

207209
{token, {user, metadata}} ->
208-
expire_token_in_store(token, config)
209-
210-
auth_user(conn, user, metadata, config)
210+
lock_auth_user(conn, token, user, metadata, config)
211211
end
212212
end
213213

@@ -228,6 +228,18 @@ defmodule PowPersistentSession.Plug.Cookie do
228228
defp filter_invalid!([id: _value] = clauses), do: clauses
229229
defp filter_invalid!(clauses), do: raise "Invalid get_by clauses stored: #{inspect clauses}"
230230

231+
defp lock_auth_user(conn, token, user, metadata, config) do
232+
nodes = Node.list() ++ [node()]
233+
234+
case :global.set_lock({[__MODULE__, token], self()}, nodes, 0) do
235+
true ->
236+
auth_user(conn, user, metadata, config)
237+
238+
false ->
239+
Plug.assign_current_user(conn, user, config)
240+
end
241+
end
242+
231243
defp auth_user(conn, user, metadata, config) do
232244
conn
233245
|> update_persistent_session_metadata(metadata)

lib/pow/plug/session.ex

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,9 @@ defmodule Pow.Plug.Session do
115115
116116
This will fetch a session from the credentials cache with the session id
117117
fetched through `Plug.Conn.get_session/2` session. If the credentials are
118-
stale (timestamp is older than the `:session_ttl_renewal` value), the session
119-
will be regenerated with `create/3`.
118+
stale (timestamp is older than the `:session_ttl_renewal` value), a global
119+
lock will be set, and the session will be regenerated with `create/3`.
120+
Nothing happens if setting the lock failed.
120121
121122
The metadata of the session will be assigned as a private
122123
`:pow_session_metadata` key in the conn so it may be used in `create/3`.
@@ -228,17 +229,26 @@ defmodule Pow.Plug.Session do
228229
defp convert_old_session_value(any), do: any
229230

230231
defp handle_fetched_session_value({_session_id, :not_found}, conn, _config), do: {conn, nil}
231-
defp handle_fetched_session_value({_session_id, {user, metadata}}, conn, config) when is_list(metadata) do
232+
defp handle_fetched_session_value({session_id, {user, metadata}}, conn, config) when is_list(metadata) do
232233
conn
233234
|> Conn.put_private(:pow_session_metadata, metadata)
234-
|> renew_stale_session(user, metadata, config)
235+
|> renew_stale_session(session_id, user, metadata, config)
235236
end
236237

237-
defp renew_stale_session(conn, user, metadata, config) do
238+
defp renew_stale_session(conn, session_id, user, metadata, config) do
238239
metadata
239240
|> Keyword.get(:inserted_at)
240241
|> session_stale?(config)
241242
|> case do
243+
true -> lock_create(conn, session_id, user, config)
244+
false -> {conn, user}
245+
end
246+
end
247+
248+
defp lock_create(conn, session_id, user, config) do
249+
nodes = Node.list() ++ [node()]
250+
251+
case :global.set_lock({[__MODULE__, session_id], self()}, nodes, 0) do
242252
true -> create(conn, user, config)
243253
false -> {conn, user}
244254
end

test/extensions/persistent_session/plug/cookie_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ defmodule PowPersistentSession.Plug.CookieTest do
5858
assert Plug.current_user(conn_1) == user
5959
assert %{value: _id, max_age: @max_age, path: "/"} = conn_1.resp_cookies[@cookie_key]
6060

61-
refute Plug.current_user(conn_2)
61+
assert Plug.current_user(conn_2) == user
6262
refute conn_2.resp_cookies[@cookie_key]
6363
end
6464

test/pow/plug/session_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ defmodule Pow.Plug.SessionTest do
146146
refute get_session_id(conn_1) == session_id
147147
assert {@user, _metadata} = CredentialsCache.get(@store_config, get_session_id(conn_1))
148148

149-
refute Plug.current_user(conn_2)
149+
assert Plug.current_user(conn_2) == @user
150150
refute conn_2.resp_cookies["foobar"]
151151
assert get_session_id(conn_2) == session_id
152152
assert CredentialsCache.get(@store_config, get_session_id(conn_2)) == :not_found

0 commit comments

Comments
 (0)