Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/warden.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ def self.test_mode!
while blk = Warden._on_next_request.shift
blk.call(proxy)
end
Warden._test_users.each_value do |(user, opts)|
opts = opts.dup
scope = opts[:scope] || proxy.config.default_scope
unless proxy.session_serializer.stored?(scope)
proxy.set_user(user, opts)
end
end
end
end
end
Expand Down
11 changes: 7 additions & 4 deletions lib/warden/test/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@ def self.included(_base)
# @see Warden::Proxy#set_user
# @api public
def login_as(user, opts = {})
Warden.on_next_request do |proxy|
opts[:event] ||= :authentication
proxy.set_user(user, opts)
end
opts[:event] ||= :authentication
Warden._test_users[opts[:scope]] = [user, opts]
end

# Logs out a user from the session.
Expand All @@ -28,6 +26,11 @@ def login_as(user, opts = {})
# @see Warden::Proxy#logout
# @api public
def logout(*scopes)
if scopes.empty?
Warden._test_users.clear
else
scopes.each { |s| Warden._test_users.delete(s) }
end
Warden.on_next_request do |proxy|
proxy.logout(*scopes)
end
Expand Down
9 changes: 9 additions & 0 deletions lib/warden/test/warden_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def on_next_request(&blk)
# @api public
def test_reset!
_on_next_request.clear
_test_users.clear
end

# A container for the on_next_request items.
Expand All @@ -39,6 +40,14 @@ def _on_next_request
@_on_next_request ||= []
@_on_next_request
end

# A persistent store of test users keyed by scope.
# Unlike _on_next_request, these survive across multiple requests,
# preventing race conditions with background requests.
# @api private
def _test_users
@_test_users ||= {}
end
end
end
end
73 changes: 73 additions & 0 deletions spec/warden/test/helpers_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,79 @@
expect($captures).to eq([:run])
end

it "should persist authentication across multiple requests" do
user = "A User"
session = {}
login_as user
app = setup_rack(lambda { |e|
$captures << e['warden'].user
valid_response
})
app.call(env_with_params("/", {}, "rack.session" => session))
app.call(env_with_params("/", {}, "rack.session" => session))
expect($captures).to eq(["A User", "A User"])
end

it "should not lose authentication when another session makes a concurrent request" do
alice = "Alice"
bob = "Bob"

alice_session = {}
bob_session = {}

app = setup_rack(lambda { |e|
$captures << e['warden'].user
valid_response
})

# 1. Alice logs in and visits a page — her session is established
login_as alice
app.call(env_with_params("/", {}, "rack.session" => alice_session))

# 2. Bob logs in
login_as bob

# 3. A background request from Alice's session (e.g. Turbo Frame fetch)
app.call(env_with_params("/turbo-frame", {}, "rack.session" => alice_session))

# 4. Bob's session makes its first request
app.call(env_with_params("/", {}, "rack.session" => bob_session))

expect($captures).to eq(["Alice", "Alice", "Bob"])
end

it "should allow switching users with logout in between" do
session = {}
app = setup_rack(lambda { |e|
$captures << e['warden'].user
valid_response
})

login_as "Alice"
app.call(env_with_params("/", {}, "rack.session" => session))

logout
login_as "Bob"
app.call(env_with_params("/", {}, "rack.session" => session))

expect($captures).to eq(["Alice", "Bob"])
end

it "should clear persistent state on logout" do
user = "A User"
login_as user
expect(Warden._test_users).not_to be_empty
logout
expect(Warden._test_users).to be_empty
end

it "should clear only the specified scope on logout" do
login_as "Default User"
login_as "Foo User", scope: :foo
logout :foo
expect(Warden._test_users.keys).to eq([nil])
end

describe "#asset_paths" do
it "should default asset_paths to anything asset path regex" do
expect(Warden.asset_paths).to eq([/^\/assets\//] )
Expand Down
7 changes: 7 additions & 0 deletions spec/warden/test/test_mode_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@
expect($captures).to eq([])
end

it "should clear _test_users when test is reset" do
Warden._test_users[:default] = ["A User", { event: :authentication }]
expect(Warden._test_users).not_to be_empty
Warden.test_reset!
expect(Warden._test_users).to be_empty
end

context "asset requests" do
it "should not execute on_next_request blocks if this is an asset request" do
app = setup_rack(@app)
Expand Down