loyal_warden 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|