loyal_warden 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +11 -0
- data/History.rdoc +150 -0
- data/LICENSE +20 -0
- data/README.textile +9 -0
- data/Rakefile +12 -0
- data/lib/loyal_warden.rb +2 -0
- data/lib/warden.rb +45 -0
- data/lib/warden/config.rb +112 -0
- data/lib/warden/errors.rb +66 -0
- data/lib/warden/hooks.rb +211 -0
- data/lib/warden/manager.rb +136 -0
- data/lib/warden/mixins/common.rb +44 -0
- data/lib/warden/proxy.rb +371 -0
- data/lib/warden/session_serializer.rb +52 -0
- data/lib/warden/strategies.rb +47 -0
- data/lib/warden/strategies/base.rb +175 -0
- data/lib/warden/test/helpers.rb +36 -0
- data/lib/warden/test/warden_helpers.rb +43 -0
- data/lib/warden/version.rb +4 -0
- data/loyal_warden.gemspec +26 -0
- data/spec/helpers/request_helper.rb +51 -0
- data/spec/helpers/strategies/failz.rb +8 -0
- data/spec/helpers/strategies/invalid.rb +8 -0
- data/spec/helpers/strategies/pass.rb +8 -0
- data/spec/helpers/strategies/pass_with_message.rb +8 -0
- data/spec/helpers/strategies/password.rb +13 -0
- data/spec/helpers/strategies/single.rb +12 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/warden/authenticated_data_store_spec.rb +114 -0
- data/spec/warden/config_spec.rb +48 -0
- data/spec/warden/errors_spec.rb +47 -0
- data/spec/warden/hooks_spec.rb +373 -0
- data/spec/warden/manager_spec.rb +316 -0
- data/spec/warden/proxy_spec.rb +1041 -0
- data/spec/warden/scoped_session_serializer.rb +123 -0
- data/spec/warden/session_serializer_spec.rb +53 -0
- data/spec/warden/strategies/base_spec.rb +313 -0
- data/spec/warden/strategies_spec.rb +93 -0
- data/spec/warden/test/helpers_spec.rb +93 -0
- data/spec/warden/test/test_mode_spec.rb +76 -0
- data/warden.gemspec +24 -0
- metadata +105 -0
@@ -0,0 +1,136 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'warden/hooks'
|
3
|
+
require 'warden/config'
|
4
|
+
|
5
|
+
module Warden
|
6
|
+
# The middleware for Rack Authentication
|
7
|
+
# The middlware requires that there is a session upstream
|
8
|
+
# The middleware injects an authentication object into
|
9
|
+
# the rack environment hash
|
10
|
+
class Manager
|
11
|
+
extend Warden::Hooks
|
12
|
+
|
13
|
+
attr_accessor :config
|
14
|
+
|
15
|
+
# Initialize the middleware. If a block is given, a Warden::Config is yielded so you can properly
|
16
|
+
# configure the Warden::Manager.
|
17
|
+
# :api: public
|
18
|
+
def initialize(app, options={})
|
19
|
+
default_strategies = options.delete(:default_strategies)
|
20
|
+
|
21
|
+
@app, @config = app, Warden::Config.new(options)
|
22
|
+
@config.default_strategies *default_strategies if default_strategies
|
23
|
+
yield @config if block_given?
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
# Invoke the application guarding for throw :warden.
|
28
|
+
# If this is downstream from another warden instance, don't do anything.
|
29
|
+
# :api: private
|
30
|
+
def call(env) # :nodoc:
|
31
|
+
return @app.call(env) if env['warden'] && env['warden'].manager != self
|
32
|
+
|
33
|
+
env['warden'] = Proxy.new(env, self)
|
34
|
+
result = catch(:warden) do
|
35
|
+
@app.call(env)
|
36
|
+
end
|
37
|
+
|
38
|
+
result ||= {}
|
39
|
+
case result
|
40
|
+
when Array
|
41
|
+
if result.first == 401 && intercept_401?(env)
|
42
|
+
process_unauthenticated(env)
|
43
|
+
else
|
44
|
+
result
|
45
|
+
end
|
46
|
+
when Hash
|
47
|
+
process_unauthenticated(env, result)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# :api: private
|
52
|
+
def _run_callbacks(*args) #:nodoc:
|
53
|
+
self.class._run_callbacks(*args)
|
54
|
+
end
|
55
|
+
|
56
|
+
class << self
|
57
|
+
# Prepares the user to serialize into the session.
|
58
|
+
# Any object that can be serialized into the session in some way can be used as a "user" object
|
59
|
+
# Generally however complex object should not be stored in the session.
|
60
|
+
# If possible store only a "key" of the user object that will allow you to reconstitute it.
|
61
|
+
#
|
62
|
+
# You can supply different methods of serialization for different scopes by passing a scope symbol
|
63
|
+
#
|
64
|
+
# Example:
|
65
|
+
# Warden::Manager.serialize_into_session{ |user| user.id }
|
66
|
+
# # With Scope:
|
67
|
+
# Warden::Manager.serialize_into_session(:admin) { |user| user.id }
|
68
|
+
#
|
69
|
+
# :api: public
|
70
|
+
def serialize_into_session(scope = nil, &block)
|
71
|
+
method_name = scope.nil? ? :serialize : "#{scope}_serialize"
|
72
|
+
Warden::SessionSerializer.send :define_method, method_name, &block
|
73
|
+
end
|
74
|
+
|
75
|
+
# Reconstitues the user from the session.
|
76
|
+
# Use the results of user_session_key to reconstitue the user from the session on requests after the initial login
|
77
|
+
# You can supply different methods of de-serialization for different scopes by passing a scope symbol
|
78
|
+
#
|
79
|
+
# Example:
|
80
|
+
# Warden::Manager.serialize_from_session{ |id| User.get(id) }
|
81
|
+
# # With Scope:
|
82
|
+
# Warden::Manager.serialize_from_session(:admin) { |id| AdminUser.get(id) }
|
83
|
+
#
|
84
|
+
# :api: public
|
85
|
+
def serialize_from_session(scope = nil, &block)
|
86
|
+
method_name = scope.nil? ? :deserialize : "#{scope}_deserialize"
|
87
|
+
Warden::SessionSerializer.send :define_method, method_name, &block
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def intercept_401?(env)
|
94
|
+
config[:intercept_401] && !env['warden'].custom_failure?
|
95
|
+
end
|
96
|
+
|
97
|
+
# When a request is unauthenticated, here's where the processing occurs.
|
98
|
+
# It looks at the result of the proxy to see if it's been executed and what action to take.
|
99
|
+
# :api: private
|
100
|
+
def process_unauthenticated(env, options={})
|
101
|
+
options[:action] ||= begin
|
102
|
+
opts = config[:scope_defaults][config.default_scope] || {}
|
103
|
+
opts[:action] || 'unauthenticated'
|
104
|
+
end
|
105
|
+
|
106
|
+
proxy = env['warden']
|
107
|
+
result = options[:result] || proxy.result
|
108
|
+
|
109
|
+
case result
|
110
|
+
when :redirect
|
111
|
+
body = proxy.message || "You are being redirected to #{proxy.headers['Location']}"
|
112
|
+
[proxy.status, proxy.headers, [body]]
|
113
|
+
when :custom
|
114
|
+
proxy.custom_response
|
115
|
+
else
|
116
|
+
call_failure_app(env, options)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Calls the failure app.
|
121
|
+
# The before_failure hooks are run on each failure
|
122
|
+
# :api: private
|
123
|
+
def call_failure_app(env, options = {})
|
124
|
+
if config.failure_app
|
125
|
+
options.merge!(:attempted_path => ::Rack::Request.new(env).fullpath)
|
126
|
+
env["PATH_INFO"] = "/#{options[:action]}"
|
127
|
+
env["warden.options"] = options
|
128
|
+
|
129
|
+
_run_callbacks(:before_failure, env, options)
|
130
|
+
config.failure_app.call(env).to_a
|
131
|
+
else
|
132
|
+
raise "No Failure App provided"
|
133
|
+
end
|
134
|
+
end # call_failure_app
|
135
|
+
end
|
136
|
+
end # Warden
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Warden
|
3
|
+
module Mixins
|
4
|
+
module Common
|
5
|
+
|
6
|
+
# Convinience method to access the session
|
7
|
+
# :api: public
|
8
|
+
def session
|
9
|
+
env['rack.session']
|
10
|
+
end # session
|
11
|
+
|
12
|
+
# Alias :session to :raw_session since the former will be user API for storing scoped data.
|
13
|
+
alias :raw_session :session
|
14
|
+
|
15
|
+
# Convenience method to access the rack request.
|
16
|
+
# :api: public
|
17
|
+
def request
|
18
|
+
@request ||= Rack::Request.new(@env)
|
19
|
+
end # request
|
20
|
+
|
21
|
+
# Provides a warden repository for cookies. Those are sent to the client
|
22
|
+
# when the response is streamed back from the app.
|
23
|
+
# :api: public
|
24
|
+
def warden_cookies
|
25
|
+
warn "warden_cookies was never functional and is going to be removed in next versions"
|
26
|
+
env['warden.cookies'] ||= {}
|
27
|
+
end # warden_cookies
|
28
|
+
|
29
|
+
# Convenience method to access the rack request params
|
30
|
+
# :api: public
|
31
|
+
def params
|
32
|
+
request.params
|
33
|
+
end # params
|
34
|
+
|
35
|
+
# Resets the session. By using this non-hash like sessions can
|
36
|
+
# be cleared by overwriting this method in a plugin
|
37
|
+
# @api overwritable
|
38
|
+
def reset_session!
|
39
|
+
raw_session.clear
|
40
|
+
end # reset_session!
|
41
|
+
|
42
|
+
end # Common
|
43
|
+
end # Mixins
|
44
|
+
end # Warden
|
data/lib/warden/proxy.rb
ADDED
@@ -0,0 +1,371 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Warden
|
4
|
+
class UserNotSet < RuntimeError; end
|
5
|
+
|
6
|
+
class Proxy
|
7
|
+
# An accessor to the winning strategy
|
8
|
+
# :api: private
|
9
|
+
attr_accessor :winning_strategy
|
10
|
+
|
11
|
+
# An accessor to the rack env hash, the proxy owner and its config
|
12
|
+
# :api: public
|
13
|
+
attr_reader :env, :manager, :config, :winning_strategies
|
14
|
+
|
15
|
+
extend ::Forwardable
|
16
|
+
include ::Warden::Mixins::Common
|
17
|
+
|
18
|
+
ENV_WARDEN_ERRORS = 'warden.errors'.freeze
|
19
|
+
ENV_SESSION_OPTIONS = 'rack.session.options'.freeze
|
20
|
+
|
21
|
+
# :api: private
|
22
|
+
def_delegators :winning_strategy, :headers, :status, :custom_response
|
23
|
+
|
24
|
+
# :api: public
|
25
|
+
def_delegators :config, :default_strategies
|
26
|
+
|
27
|
+
def initialize(env, manager) #:nodoc:
|
28
|
+
@env, @users, @winning_strategies, @locked = env, {}, {}, false
|
29
|
+
@manager, @config = manager, manager.config.dup
|
30
|
+
@strategies = Hash.new { |h,k| h[k] = {} }
|
31
|
+
manager._run_callbacks(:on_request, self)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Lazily initiate errors object in session.
|
35
|
+
# :api: public
|
36
|
+
def errors
|
37
|
+
@env[ENV_WARDEN_ERRORS] ||= Errors.new
|
38
|
+
end
|
39
|
+
|
40
|
+
# Points to a SessionSerializer instance responsible for handling
|
41
|
+
# everything related with storing, fetching and removing the user
|
42
|
+
# session.
|
43
|
+
# :api: public
|
44
|
+
def session_serializer
|
45
|
+
@session_serializer ||= Warden::SessionSerializer.new(@env)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Clear the cache of performed strategies so far. Warden runs each
|
49
|
+
# strategy just once during the request lifecycle. You can clear the
|
50
|
+
# strategies cache if you want to allow a strategy to be run more than
|
51
|
+
# once.
|
52
|
+
#
|
53
|
+
# This method has the same API as authenticate, allowing you to clear
|
54
|
+
# specific strategies for given scope:
|
55
|
+
#
|
56
|
+
# Parameters:
|
57
|
+
# args - a list of symbols (labels) that name the strategies to attempt
|
58
|
+
# opts - an options hash that contains the :scope of the user to check
|
59
|
+
#
|
60
|
+
# Example:
|
61
|
+
# # Clear all strategies for the configured default_scope
|
62
|
+
# env['warden'].clear_strategies_cache!
|
63
|
+
#
|
64
|
+
# # Clear all strategies for the :admin scope
|
65
|
+
# env['warden'].clear_strategies_cache!(:scope => :admin)
|
66
|
+
#
|
67
|
+
# # Clear password strategy for the :admin scope
|
68
|
+
# env['warden'].clear_strategies_cache!(:password, :scope => :admin)
|
69
|
+
#
|
70
|
+
# :api: public
|
71
|
+
def clear_strategies_cache!(*args)
|
72
|
+
scope, opts = _retrieve_scope_and_opts(args)
|
73
|
+
|
74
|
+
@winning_strategies.delete(scope)
|
75
|
+
@strategies[scope].each do |k, v|
|
76
|
+
v.clear! if args.empty? || args.include?(k)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Locks the proxy so new users cannot authenticate during the
|
81
|
+
# request lifecycle. This is useful when the request cannot
|
82
|
+
# be verified (for example, using a CSRF verification token).
|
83
|
+
# Notice that already authenticated users are kept as so.
|
84
|
+
#
|
85
|
+
# :api: public
|
86
|
+
def lock!
|
87
|
+
@locked = true
|
88
|
+
end
|
89
|
+
|
90
|
+
# Run the authentiation strategies for the given strategies.
|
91
|
+
# If there is already a user logged in for a given scope, the strategies are not run
|
92
|
+
# This does not halt the flow of control and is a passive attempt to authenticate only
|
93
|
+
# When scope is not specified, the default_scope is assumed.
|
94
|
+
#
|
95
|
+
# Parameters:
|
96
|
+
# args - a list of symbols (labels) that name the strategies to attempt
|
97
|
+
# opts - an options hash that contains the :scope of the user to check
|
98
|
+
#
|
99
|
+
# Example:
|
100
|
+
# env['warden'].authenticate(:password, :basic, :scope => :sudo)
|
101
|
+
#
|
102
|
+
# :api: public
|
103
|
+
def authenticate(*args)
|
104
|
+
user, opts = _perform_authentication(*args)
|
105
|
+
user
|
106
|
+
end
|
107
|
+
|
108
|
+
# Same API as authenticated, but returns a boolean instead of a user.
|
109
|
+
# The difference between this method (authenticate?) and authenticated?
|
110
|
+
# is that the former will run strategies if the user has not yet been
|
111
|
+
# authenticated, and the second relies on already performed ones.
|
112
|
+
# :api: public
|
113
|
+
def authenticate?(*args)
|
114
|
+
result = !!authenticate(*args)
|
115
|
+
yield if result && block_given?
|
116
|
+
result
|
117
|
+
end
|
118
|
+
|
119
|
+
# The same as +authenticate+ except on failure it will throw an :warden symbol causing the request to be halted
|
120
|
+
# and rendered through the +failure_app+
|
121
|
+
#
|
122
|
+
# Example
|
123
|
+
# env['warden'].authenticate!(:password, :scope => :publisher) # throws if it cannot authenticate
|
124
|
+
#
|
125
|
+
# :api: public
|
126
|
+
def authenticate!(*args)
|
127
|
+
user, opts = _perform_authentication(*args)
|
128
|
+
throw(:warden, opts) unless user
|
129
|
+
user
|
130
|
+
end
|
131
|
+
|
132
|
+
# Check to see if there is an authenticated user for the given scope.
|
133
|
+
# This brings the user from the session, but does not run strategies before doing so.
|
134
|
+
# If you want strategies to be run, please check authenticate?.
|
135
|
+
#
|
136
|
+
# Parameters:
|
137
|
+
# scope - the scope to check for authentication. Defaults to default_scope
|
138
|
+
#
|
139
|
+
# Example:
|
140
|
+
# env['warden'].authenticated?(:admin)
|
141
|
+
#
|
142
|
+
# :api: public
|
143
|
+
def authenticated?(scope = @config.default_scope)
|
144
|
+
result = !!user(scope)
|
145
|
+
yield if block_given? && result
|
146
|
+
result
|
147
|
+
end
|
148
|
+
|
149
|
+
# Same API as authenticated?, but returns false when authenticated.
|
150
|
+
# :api: public
|
151
|
+
def unauthenticated?(scope = @config.default_scope)
|
152
|
+
result = !authenticated?(scope)
|
153
|
+
yield if block_given? && result
|
154
|
+
result
|
155
|
+
end
|
156
|
+
|
157
|
+
# Manually set the user into the session and auth proxy
|
158
|
+
#
|
159
|
+
# Parameters:
|
160
|
+
# user - An object that has been setup to serialize into and out of the session.
|
161
|
+
# opts - An options hash. Use the :scope option to set the scope of the user, set the :store option to false to skip serializing into the session, set the :run_callbacks to false to skip running the callbacks (the default is true).
|
162
|
+
#
|
163
|
+
# :api: public
|
164
|
+
def set_user(user, opts = {})
|
165
|
+
scope = (opts[:scope] ||= @config.default_scope)
|
166
|
+
|
167
|
+
# Get the default options from the master configuration for the given scope
|
168
|
+
opts = (@config[:scope_defaults][scope] || {}).merge(opts)
|
169
|
+
opts[:event] ||= :set_user
|
170
|
+
@users[scope] = user
|
171
|
+
|
172
|
+
if opts[:store] != false && opts[:event] != :fetch
|
173
|
+
options = env[ENV_SESSION_OPTIONS]
|
174
|
+
options[:renew] = true if options
|
175
|
+
session_serializer.store(user, scope)
|
176
|
+
end
|
177
|
+
|
178
|
+
run_callbacks = opts.fetch(:run_callbacks, true)
|
179
|
+
manager._run_callbacks(:after_set_user, user, self, opts) if run_callbacks
|
180
|
+
|
181
|
+
@users[scope]
|
182
|
+
end
|
183
|
+
|
184
|
+
# Provides acccess to the user object in a given scope for a request.
|
185
|
+
# Will be nil if not logged in. Please notice that this method does not
|
186
|
+
# perform strategies.
|
187
|
+
#
|
188
|
+
# Example:
|
189
|
+
# # without scope (default user)
|
190
|
+
# env['warden'].user
|
191
|
+
#
|
192
|
+
# # with scope
|
193
|
+
# env['warden'].user(:admin)
|
194
|
+
#
|
195
|
+
# # as a Hash
|
196
|
+
# env['warden'].user(:scope => :admin)
|
197
|
+
#
|
198
|
+
# # with default scope and run_callbacks option
|
199
|
+
# env['warden'].user(:run_callbacks => false)
|
200
|
+
#
|
201
|
+
# # with a scope and run_callbacks option
|
202
|
+
# env['warden'].user(:scope => :admin, :run_callbacks => true)
|
203
|
+
#
|
204
|
+
# :api: public
|
205
|
+
def user(argument = {})
|
206
|
+
opts = argument.is_a?(Hash) ? argument : { :scope => argument }
|
207
|
+
scope = (opts[:scope] ||= @config.default_scope)
|
208
|
+
|
209
|
+
if @users.has_key?(scope)
|
210
|
+
@users[scope]
|
211
|
+
else
|
212
|
+
unless user = session_serializer.fetch(scope)
|
213
|
+
run_callbacks = opts.fetch(:run_callbacks, true)
|
214
|
+
manager._run_callbacks(:after_failed_fetch, user, self, :scope => scope) if run_callbacks
|
215
|
+
end
|
216
|
+
|
217
|
+
@users[scope] = user ? set_user(user, opts.merge(:event => :fetch)) : nil
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Provides a scoped session data for authenticated users.
|
222
|
+
# Warden manages clearing out this data when a user logs out
|
223
|
+
#
|
224
|
+
# Example
|
225
|
+
# # default scope
|
226
|
+
# env['warden'].session[:foo] = "bar"
|
227
|
+
#
|
228
|
+
# # :sudo scope
|
229
|
+
# env['warden'].session(:sudo)[:foo] = "bar"
|
230
|
+
#
|
231
|
+
# :api: public
|
232
|
+
def session(scope = @config.default_scope)
|
233
|
+
raise NotAuthenticated, "#{scope.inspect} user is not logged in" unless authenticated?(scope)
|
234
|
+
raw_session["warden.user.#{scope}.session"] ||= {}
|
235
|
+
end
|
236
|
+
|
237
|
+
# Provides logout functionality.
|
238
|
+
# The logout also manages any authenticated data storage and clears it when a user logs out.
|
239
|
+
#
|
240
|
+
# Parameters:
|
241
|
+
# scopes - a list of scopes to logout
|
242
|
+
#
|
243
|
+
# Example:
|
244
|
+
# # Logout everyone and clear the session
|
245
|
+
# env['warden'].logout
|
246
|
+
#
|
247
|
+
# # Logout the default user but leave the rest of the session alone
|
248
|
+
# env['warden'].logout(:default)
|
249
|
+
#
|
250
|
+
# # Logout the :publisher and :admin user
|
251
|
+
# env['warden'].logout(:publisher, :admin)
|
252
|
+
#
|
253
|
+
# :api: public
|
254
|
+
def logout(*scopes)
|
255
|
+
if scopes.empty?
|
256
|
+
scopes = @users.keys
|
257
|
+
reset_session = true
|
258
|
+
end
|
259
|
+
|
260
|
+
scopes.each do |scope|
|
261
|
+
user = @users.delete(scope)
|
262
|
+
manager._run_callbacks(:before_logout, user, self, :scope => scope)
|
263
|
+
|
264
|
+
raw_session.delete("warden.user.#{scope}.session") unless raw_session.nil?
|
265
|
+
session_serializer.delete(scope, user)
|
266
|
+
end
|
267
|
+
|
268
|
+
reset_session! if reset_session
|
269
|
+
end
|
270
|
+
|
271
|
+
# proxy methods through to the winning strategy
|
272
|
+
# :api: private
|
273
|
+
def result # :nodoc:
|
274
|
+
winning_strategy && winning_strategy.result
|
275
|
+
end
|
276
|
+
|
277
|
+
# Proxy through to the authentication strategy to find out the message that was generated.
|
278
|
+
# :api: public
|
279
|
+
def message
|
280
|
+
winning_strategy && winning_strategy.message
|
281
|
+
end
|
282
|
+
|
283
|
+
# Provides a way to return a 401 without warden defering to the failure app
|
284
|
+
# The result is a direct passthrough of your own response
|
285
|
+
# :api: public
|
286
|
+
def custom_failure!
|
287
|
+
@custom_failure = true
|
288
|
+
end
|
289
|
+
|
290
|
+
# Check to see if the custom failure flag has been set
|
291
|
+
# :api: public
|
292
|
+
def custom_failure?
|
293
|
+
!!@custom_failure
|
294
|
+
end
|
295
|
+
|
296
|
+
# Check to see if this is an asset request
|
297
|
+
# :api: public
|
298
|
+
def asset_request?
|
299
|
+
::Warden::asset_paths.any? { |r| env['PATH_INFO'].to_s.match(r) }
|
300
|
+
end
|
301
|
+
|
302
|
+
def inspect(*args)
|
303
|
+
"Warden::Proxy:#{object_id} @config=#{@config.inspect}"
|
304
|
+
end
|
305
|
+
|
306
|
+
def to_s(*args)
|
307
|
+
inspect(*args)
|
308
|
+
end
|
309
|
+
|
310
|
+
private
|
311
|
+
|
312
|
+
def _perform_authentication(*args)
|
313
|
+
scope, opts = _retrieve_scope_and_opts(args)
|
314
|
+
user = nil
|
315
|
+
|
316
|
+
# Look for an existing user in the session for this scope.
|
317
|
+
# If there was no user in the session. See if we can get one from the request.
|
318
|
+
return user, opts if user = user(opts.merge(:scope => scope))
|
319
|
+
_run_strategies_for(scope, args)
|
320
|
+
|
321
|
+
if winning_strategy && winning_strategy.user
|
322
|
+
opts[:store] = opts.fetch(:store, winning_strategy.store?)
|
323
|
+
set_user(winning_strategy.user, opts.merge!(:event => :authentication))
|
324
|
+
end
|
325
|
+
|
326
|
+
[@users[scope], opts]
|
327
|
+
end
|
328
|
+
|
329
|
+
def _retrieve_scope_and_opts(args) #:nodoc:
|
330
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
331
|
+
scope = opts[:scope] || @config.default_scope
|
332
|
+
opts = (@config[:scope_defaults][scope] || {}).merge(opts)
|
333
|
+
[scope, opts]
|
334
|
+
end
|
335
|
+
|
336
|
+
# Run the strategies for a given scope
|
337
|
+
def _run_strategies_for(scope, args) #:nodoc:
|
338
|
+
self.winning_strategy = @winning_strategies[scope]
|
339
|
+
return if winning_strategy && winning_strategy.halted?
|
340
|
+
|
341
|
+
# Do not run any strategy if locked
|
342
|
+
return if @locked
|
343
|
+
|
344
|
+
if args.empty?
|
345
|
+
defaults = @config[:default_strategies]
|
346
|
+
strategies = defaults[scope] || defaults[:_all]
|
347
|
+
end
|
348
|
+
|
349
|
+
(strategies || args).each do |name|
|
350
|
+
strategy = _fetch_strategy(name, scope)
|
351
|
+
next unless strategy && !strategy.performed? && strategy.valid?
|
352
|
+
|
353
|
+
self.winning_strategy = @winning_strategies[scope] = strategy
|
354
|
+
strategy._run!
|
355
|
+
break if strategy.halted?
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
# Fetchs strategies and keep them in a hash cache.
|
360
|
+
def _fetch_strategy(name, scope)
|
361
|
+
@strategies[scope][name] ||= if klass = Warden::Strategies[name]
|
362
|
+
klass.new(@env, scope)
|
363
|
+
elsif @config.silence_missing_strategies?
|
364
|
+
nil
|
365
|
+
else
|
366
|
+
raise "Invalid strategy #{name}"
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end # Proxy
|
370
|
+
|
371
|
+
end # Warden
|