warden 0.8.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,8 +1,10 @@
1
1
  require 'rubygems'
2
+ gem 'rspec'
2
3
  require 'spec/rake/spectask'
3
4
  require File.join(File.dirname(__FILE__), "lib", "warden", "version")
4
5
 
5
6
  begin
7
+ gem 'jeweler'
6
8
  require 'jeweler'
7
9
  Jeweler::Tasks.new do |gem|
8
10
  gem.name = "warden"
@@ -13,8 +15,9 @@ begin
13
15
  gem.authors = ["Daniel Neighman"]
14
16
  gem.rubyforge_project = "warden"
15
17
  gem.add_dependency "rack", ">= 1.0.0"
18
+ gem.add_development_dependency "rspec", ">= 1.0.0"
16
19
  end
17
-
20
+
18
21
  Jeweler::GemcutterTasks.new
19
22
  rescue LoadError
20
23
  puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
@@ -1,17 +1,13 @@
1
1
  # encoding: utf-8
2
2
  require 'forwardable'
3
- $:.unshift File.join(File.dirname(__FILE__))
4
3
 
5
4
  require 'warden/mixins/common'
6
5
  require 'warden/proxy'
7
6
  require 'warden/manager'
8
7
  require 'warden/errors'
8
+ require 'warden/session_serializer'
9
9
  require 'warden/strategies'
10
10
  require 'warden/strategies/base'
11
- require 'warden/serializers'
12
- require 'warden/serializers/base'
13
- require 'warden/serializers/cookie'
14
- require 'warden/serializers/session'
15
11
 
16
12
  module Warden
17
13
  class NotAuthenticated < StandardError; end
@@ -34,10 +34,8 @@ module Warden
34
34
 
35
35
  def initialize(other={})
36
36
  merge!(other)
37
-
38
37
  self[:default_scope] ||= :default
39
38
  self[:default_strategies] ||= []
40
- self[:default_serializers] ||= [ :session ]
41
39
  end
42
40
 
43
41
  # Do not raise an error if a missing strategy is given by default.
@@ -50,16 +48,6 @@ module Warden
50
48
  !!self[:silence_missing_strategies]
51
49
  end
52
50
 
53
- # Do not raise an error if a missing serializer is given by default.
54
- # :api: plugin
55
- def silence_missing_serializers!
56
- self[:silence_missing_serializers] = true
57
- end
58
-
59
- def silence_missing_serializers? #:nodoc:
60
- !!self[:silence_missing_serializers]
61
- end
62
-
63
51
  # Set the default strategies to use.
64
52
  # :api: public
65
53
  def default_strategies(*strategies)
@@ -70,26 +58,22 @@ module Warden
70
58
  end
71
59
  end
72
60
 
73
- # Set the default serializers to use. By default, only session is enabled.
61
+ # Quick accessor to strategies from manager
74
62
  # :api: public
75
- def default_serializers(*serializers)
76
- if serializers.empty?
77
- self[:default_serializers]
78
- else
79
- self[:default_serializers] = serializers.flatten
80
- end
63
+ def strategies
64
+ Warden::Strategies
81
65
  end
82
66
 
83
- # Quick accessor to strategies from manager
67
+ # Hook from configuration to serialize_into_session.
84
68
  # :api: public
85
- def serializers
86
- Warden::Serializers
69
+ def serialize_into_session(*args, &block)
70
+ Warden::Manager.serialize_into_session(*args, &block)
87
71
  end
88
72
 
89
- # Quick accessor to strategies from manager
73
+ # Hook from configuration to serialize_from_session.
90
74
  # :api: public
91
- def strategies
92
- Warden::Strategies
75
+ def serialize_from_session(*args, &block)
76
+ Warden::Manager.serialize_from_session(*args, &block)
93
77
  end
94
78
  end
95
79
  end
@@ -16,8 +16,8 @@ module Warden
16
16
  end
17
17
 
18
18
  # A callback hook set to run every time after a user is set.
19
- # This callback is triggered the first time one of those three events happens during a request:
20
- # :authentication, :fetch (from one of the serializers, like session) and :set_user (when manually set).
19
+ # This callback is triggered the first time one of those three events happens
20
+ # during a request: :authentication, :fetch (from session) and :set_user (when manually set).
21
21
  # You can supply as many hooks as you like, and they will be run in order of decleration.
22
22
  #
23
23
  # If you want to run the callbacks for a given scope and/or event, you can specify them as options.
@@ -37,10 +37,10 @@ module Warden
37
37
  result ||= {}
38
38
  case result
39
39
  when Array
40
- if result.first != 401
41
- return result
42
- else
40
+ if result.first == 401
43
41
  process_unauthenticated({:original_response => result, :action => :unauthenticated}, env)
42
+ else
43
+ result
44
44
  end
45
45
  when Hash
46
46
  result[:action] ||= :unauthenticated
@@ -53,6 +53,32 @@ module Warden
53
53
  self.class._run_callbacks(*args)
54
54
  end
55
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
+ # Example:
63
+ # Warden::Manager.serialize_into_session{ |user| user.id }
64
+ #
65
+ # :api: public
66
+ def serialize_into_session(&block)
67
+ Warden::SessionSerializer.send :define_method, :serialize, &block
68
+ end
69
+
70
+ # Reconstitues the user from the session.
71
+ # Use the results of user_session_key to reconstitue the user from the session on requests after the initial login
72
+ #
73
+ # Example:
74
+ # Warden::Manager.serialize_from_session{ |id| User.get(id) }
75
+ #
76
+ # :api: public
77
+ def serialize_from_session(&block)
78
+ Warden::SessionSerializer.send :define_method, :deserialize, &block
79
+ end
80
+ end
81
+
56
82
  private
57
83
 
58
84
  # When a request is unauthentiated, here's where the processing occurs.
@@ -63,7 +89,7 @@ module Warden
63
89
 
64
90
  case action
65
91
  when :redirect
66
- [env['warden']._status, env['warden'].headers, [env['warden'].message || "You are being redirected to #{env['warden'].headers['Location']}"]]
92
+ [env['warden'].status, env['warden'].headers, [env['warden'].message || "You are being redirected to #{env['warden'].headers['Location']}"]]
67
93
  when :custom
68
94
  env['warden'].custom_response
69
95
  else
@@ -1,5 +1,22 @@
1
1
  module Warden
2
2
  module ManagerDeprecation
3
+ class Dummy
4
+ def update(type, &block)
5
+ if type == :session
6
+ warn "[DEPRECATION] warden.serializers.update(:session) is deprecated. " <<
7
+ "Please use Warden::Manager.serialize_from_session and Warden::Manager.serialize_into_session"
8
+ Warden::SessionSerializer.class_eval(&block)
9
+ else
10
+ method_missing(update)
11
+ end
12
+ end
13
+
14
+ def method_missing(method, *args)
15
+ warn "[DEPRECATION] warden.serializers.#{method} is deprecated."
16
+ nil
17
+ end
18
+ end
19
+
3
20
  # Read the default scope from Warden
4
21
  def default_scope
5
22
  warn "[DEPRECATION] Warden::Manager.default_scope is deprecated. It's now accessible in the Warden::Manager instance."
@@ -10,53 +27,9 @@ module Warden
10
27
  warn "[DEPRECATION] Warden::Manager.default_scope= is deprecated. Please set it in the Warden::Manager instance."
11
28
  end
12
29
 
13
- # Prepares the user to serialize into the session.
14
- # Any object that can be serialized into the session in some way can be used as a "user" object
15
- # Generally however complex object should not be stored in the session.
16
- # If possible store only a "key" of the user object that will allow you to reconstitute it.
17
- #
18
- # Example:
19
- # Warden::Manager.serialize_into_session{ |user| user.id }
20
- #
21
- # Deprecation:
22
- # This method was deprecated in favor of serializer in Session. You can set it while setting the middleware:
23
- #
24
- # use Warden::Manager do |manager|
25
- # manager.serializers.update(:session) do
26
- # def serialize(user)
27
- # user.id
28
- # end
29
- # end
30
- # end
31
- #
32
- # :api: public
33
- def serialize_into_session(&block)
34
- warn "[DEPRECATION] serialize_into_session is deprecated. Please overwrite the serialize method in Warden::Serializers::Session."
35
- Warden::Serializers::Session.send :define_method, :serialize, &block
30
+ def serializers
31
+ warn "[DEPRECATION] warden.serializers is deprecated since Warden::Serializers were merged into Warden::Strategies."
32
+ Dummy.new
36
33
  end
37
-
38
- # Reconstitues the user from the session.
39
- # Use the results of user_session_key to reconstitue the user from the session on requests after the initial login
40
- #
41
- # Example:
42
- # Warden::Manager.serialize_from_session{ |id| User.get(id) }
43
- #
44
- # Deprecation:
45
- # This method was deprecated in favor of serializer in Session. You can set it while setting the middleware:
46
- #
47
- # use Warden::Manager do |manager|
48
- # manager.serializers.update(:session) do
49
- # def deserialize(id)
50
- # User.get(id)
51
- # end
52
- # end
53
- # end
54
- #
55
- # :api: public
56
- def serialize_from_session(&block)
57
- warn "[DEPRECATION] serialize_from_session is deprecated. Please overwrite the deserialize method in Warden::Serializers::Session."
58
- Warden::Serializers::Session.send :define_method, :deserialize, &block
59
- end
60
-
61
34
  end
62
35
  end
@@ -18,11 +18,11 @@ module Warden
18
18
  @request ||= Rack::Request.new(@env)
19
19
  end # request
20
20
 
21
- # Convenience method to access the rack response. This should be replaced by the
22
- # actual response returned to the client.
21
+ # Provides a warden repository for cookies. Those are sent to the client
22
+ # when the response is streamed back from the app.
23
23
  # :api: public
24
- def response
25
- @response ||= Rack::Response.new(@env)
24
+ def warden_cookies
25
+ env['warden.cookies'] ||= {}
26
26
  end # response
27
27
 
28
28
  # Convenience method to access the rack request params
@@ -3,7 +3,7 @@ module Warden
3
3
  class UserNotSet < RuntimeError; end
4
4
 
5
5
  class Proxy
6
- # An accessor to the wining strategy
6
+ # An accessor to the winning strategy
7
7
  # :api: private
8
8
  attr_accessor :winning_strategy
9
9
 
@@ -15,56 +15,77 @@ module Warden
15
15
  include ::Warden::Mixins::Common
16
16
 
17
17
  # :api: private
18
- def_delegators :winning_strategy, :headers, :_status, :custom_response
18
+ def_delegators :winning_strategy, :headers, :status, :custom_response
19
19
 
20
20
  def initialize(env, manager) #:nodoc:
21
21
  @env, @users = env, {}
22
+ @strategies = Hash.new { |h,k| h[k] = {} }
22
23
  @manager, @config = manager, manager.config
23
24
  errors # setup the error object in the session
24
25
  end
25
26
 
26
- # Check to see if there is an authenticated user for the given scope.
27
- # When scope is not specified, Warden::Manager.default_scope is assumed.
28
- # This will not try to reconstitute the user from the session and will simply check for the
29
- # existance of a session key
27
+ # Points to a SessionSerializer instance responsible for handling
28
+ # everything related with storing, fetching and removing the user
29
+ # session.
30
+ # :api: public
31
+ def session_serializer
32
+ @session_serializer ||= Warden::SessionSerializer.new(@env)
33
+ end
34
+
35
+ # Clear the cache of performed strategies so far. It has the same API
36
+ # as authenticate, allowing you to clear an specific strategies for
37
+ # given scope:
30
38
  #
31
39
  # Parameters:
32
- # scope - the scope to check for authentication. Defaults to :default
40
+ # args - a list of symbols (labels) that name the strategies to attempt
41
+ # opts - an options hash that contains the :scope of the user to check
33
42
  #
34
43
  # Example:
35
- # env['warden'].authenticated?(:admin)
44
+ # # Clear all strategies for the configured default_scope
45
+ # env['warden'].clear_strategies_cache!
46
+ #
47
+ # # Clear all strategies for the :admin scope
48
+ # env['warden'].clear_strategies_cache!(:scope => :admin)
49
+ #
50
+ # # Clear password strategy for the :admin scope
51
+ # env['warden'].clear_strategies_cache!(:password, :scope => :admin)
36
52
  #
37
53
  # :api: public
38
- def authenticated?(scope = @config.default_scope)
39
- result = !!user(scope)
40
- yield if block_given? && result
41
- result
42
- end
54
+ def clear_strategies_cache!(*args)
55
+ scope, opts = _retrieve_scope_and_opts(args)
43
56
 
44
- # Same API as authenticated, but returns false when authenticated.
45
- # :api: public
46
- def unauthenticated?(scope = @config.default_scope)
47
- result = !authenticated?(scope)
48
- yield if block_given? && result
49
- result
57
+ @strategies[scope].each do |k, v|
58
+ v.clear! if args.empty? || args.include?(k)
59
+ end
50
60
  end
51
61
 
52
62
  # Run the authentiation strategies for the given strategies.
53
63
  # If there is already a user logged in for a given scope, the strategies are not run
54
64
  # This does not halt the flow of control and is a passive attempt to authenticate only
55
- # When scope is not specified, Warden::Manager.default_scope is assumed.
65
+ # When scope is not specified, the default_scope is assumed.
56
66
  #
57
67
  # Parameters:
58
68
  # args - a list of symbols (labels) that name the strategies to attempt
59
69
  # opts - an options hash that contains the :scope of the user to check
60
70
  #
61
71
  # Example:
62
- # env['auth'].authenticate(:password, :basic, :scope => :sudo)
72
+ # env['warden'].authenticate(:password, :basic, :scope => :sudo)
63
73
  #
64
74
  # :api: public
65
75
  def authenticate(*args)
66
- scope, opts = _perform_authentication(*args)
67
- user(scope)
76
+ user, opts = _perform_authentication(*args)
77
+ user
78
+ end
79
+
80
+ # Same API as authenticated, but returns a boolean instead of a user.
81
+ # The difference between this method (authenticate?) and authenticated?
82
+ # is that the former will run strategies if the user has not yet been authenticated,
83
+ # and the second relies on already performed ones.
84
+ # :api: public
85
+ def authenticate?(*args)
86
+ result = !!authenticate(*args)
87
+ yield if result && block_given?
88
+ result
68
89
  end
69
90
 
70
91
  # The same as +authenticate+ except on failure it will throw an :warden symbol causing the request to be halted
@@ -75,28 +96,34 @@ module Warden
75
96
  #
76
97
  # :api: public
77
98
  def authenticate!(*args)
78
- scope, opts = _perform_authentication(*args)
79
- throw(:warden, opts) if !user(scope)
80
- user(scope)
99
+ user, opts = _perform_authentication(*args)
100
+ throw(:warden, opts) unless user
101
+ user
81
102
  end
82
103
 
83
- # Checks if the given scope is stored in session. Different from authenticated?, this method
84
- # does not serialize values from session.
104
+ # Check to see if there is an authenticated user for the given scope.
105
+ # This brings the user from the session, but does not run strategies before doing so.
106
+ # If you want strategies to be run, please check authenticate?.
85
107
  #
86
- # Example
87
- # env['warden'].set_user(@user)
88
- # env['warden'].stored? #=> true
89
- # env['warden'].stored?(:default) #=> true
90
- # env['warden'].stored?(:default, :session) #=> true
91
- # env['warden'].stored?(:default, :cookie) #=> false
108
+ # Parameters:
109
+ # scope - the scope to check for authentication. Defaults to default_scope
110
+ #
111
+ # Example:
112
+ # env['warden'].authenticated?(:admin)
92
113
  #
93
114
  # :api: public
94
- def stored?(scope = @config.default_scope, serializer = nil)
95
- if serializer
96
- _find_serializer(serializer).stored?(scope)
97
- else
98
- serializers.any? { |s| s.stored?(scope) }
99
- end
115
+ def authenticated?(scope = @config.default_scope)
116
+ result = !!user(scope)
117
+ yield if block_given? && result
118
+ result
119
+ end
120
+
121
+ # Same API as authenticated?, but returns false when authenticated.
122
+ # :api: public
123
+ def unauthenticated?(scope = @config.default_scope)
124
+ result = !authenticated?(scope)
125
+ yield if block_given? && result
126
+ result
100
127
  end
101
128
 
102
129
  # Manually set the user into the session and auth proxy
@@ -109,8 +136,9 @@ module Warden
109
136
  def set_user(user, opts = {})
110
137
  return unless user
111
138
  scope = (opts[:scope] ||= @config.default_scope)
112
- _store_user(user, scope) unless opts[:store] == false
139
+
113
140
  @users[scope] = user
141
+ session_serializer.store(user, scope) unless opts[:store] == false
114
142
 
115
143
  opts[:event] ||= :set_user
116
144
  manager._run_callbacks(:after_set_user, user, self, opts)
@@ -118,7 +146,8 @@ module Warden
118
146
  end
119
147
 
120
148
  # Provides acccess to the user object in a given scope for a request.
121
- # will be nil if not logged in
149
+ # Will be nil if not logged in. Please notice that this method does not
150
+ # perform strategies.
122
151
  #
123
152
  # Example:
124
153
  # # without scope (default user)
@@ -129,7 +158,8 @@ module Warden
129
158
  #
130
159
  # :api: public
131
160
  def user(scope = @config.default_scope)
132
- @users[scope] ||= set_user(_fetch_user(scope), :scope => scope, :event => :fetch)
161
+ @users[scope] ||= set_user(session_serializer.fetch(scope),
162
+ :scope => scope, :event => :fetch)
133
163
  end
134
164
 
135
165
  # Provides a scoped session data for authenticated users.
@@ -176,7 +206,7 @@ module Warden
176
206
  manager._run_callbacks(:before_logout, user, self, :scope => scope)
177
207
 
178
208
  raw_session.delete("warden.user.#{scope}.session")
179
- _delete_user(user, scope)
209
+ session_serializer.delete(scope, user)
180
210
  end
181
211
 
182
212
  reset_session! if reset_session
@@ -207,97 +237,56 @@ module Warden
207
237
  !!@custom_failure
208
238
  end
209
239
 
210
- # Retrieve and initializer serializers.
211
- # :api: private
212
- def serializers # :nodoc:
213
- @serializers ||= begin
214
- @config.default_serializers.inject([]) do |array, s|
215
- unless klass = Warden::Serializers[s]
216
- raise "Invalid serializer #{s}" unless @config.silence_missing_serializers?
217
- array
218
- else
219
- array << klass.new(@env)
220
- end
221
- end
222
- end
223
- end
224
-
225
240
  private
226
241
 
227
- # :api: private
228
242
  def _perform_authentication(*args)
229
- scope = scope_from_args(args)
230
- opts = opts_from_args(args)
243
+ scope, opts = _retrieve_scope_and_opts(args)
244
+ user = nil
231
245
 
232
246
  # Look for an existing user in the session for this scope.
233
- # If there was no user in the session. See if we can get one from the request
234
- return scope, opts if user(scope)
235
-
247
+ # If there was no user in the session. See if we can get one from the request.
248
+ return user, opts if user = user(scope)
236
249
  _run_strategies_for(scope, args)
237
250
 
238
251
  if winning_strategy && winning_strategy.user
239
252
  set_user(winning_strategy.user, opts.merge!(:event => :authentication))
240
253
  end
241
254
 
242
- [scope, opts]
255
+ [@users[scope], opts]
243
256
  end
244
257
 
245
- # :api: private
246
- def scope_from_args(args) # :nodoc:
247
- Hash === args.last ? args.last.fetch(:scope, @config.default_scope) : @config.default_scope
248
- end
249
-
250
- # :api: private
251
- def opts_from_args(args) # :nodoc:
252
- Hash === args.last ? args.pop : {}
258
+ def _retrieve_scope_and_opts(args) #:nodoc:
259
+ opts = args.last.is_a?(Hash) ? args.pop : {}
260
+ scope = opts[:scope] || @config.default_scope
261
+ [scope, opts]
253
262
  end
254
263
 
255
- # :api: private
264
+ # Run the strategies for a given scope
256
265
  def _run_strategies_for(scope, args) #:nodoc:
257
266
  strategies = args.empty? ? @config.default_strategies : args
258
- raise "No Strategies Found" if strategies.empty?
259
267
 
260
- strategies.each do |s|
261
- unless klass = Warden::Strategies[s]
262
- raise "Invalid strategy #{s}" unless args.empty? && @config.silence_missing_strategies?
263
- next
264
- end
268
+ strategies.each do |name|
269
+ strategy = _fetch_strategy(name, scope)
270
+ next unless strategy && !strategy.performed? && strategy.valid?
265
271
 
266
- strategy = klass.new(@env, scope)
267
272
  self.winning_strategy = strategy
268
- next unless strategy.valid?
269
-
270
273
  strategy._run!
271
274
  break if strategy.halted?
272
275
  end
273
276
  end
274
277
 
275
- # Does the work of storing the user in stores.
276
- # :api: private
277
- def _store_user(user, scope) # :nodoc:
278
- return unless user
279
- serializers.each { |s| s.store(user, scope) }
280
- end
278
+ # Fetchs strategies and keep them in a hash cache.
279
+ def _fetch_strategy(name, scope)
280
+ return @strategies[scope][name] if @strategies[scope].key?(name)
281
281
 
282
- # Does the work of fetching the user from the first store.
283
- # :api: private
284
- def _fetch_user(scope) # :nodoc:
285
- serializers.each do |s|
286
- user = s.fetch(scope)
287
- return user if user
282
+ @strategies[scope][name] = if klass = Warden::Strategies[name]
283
+ klass.new(@env, scope)
284
+ elsif @config.silence_missing_strategies?
285
+ nil
286
+ else
287
+ raise "Invalid strategy #{name}"
288
288
  end
289
- nil
290
- end
291
-
292
- # Does the work of deleteing the user in all stores.
293
- # :api: private
294
- def _delete_user(user, scope) # :nodoc:
295
- serializers.each { |s| s.delete(scope, user) }
296
289
  end
297
290
 
298
- # :api: private
299
- def _find_serializer(name) # :nodoc:
300
- serializers.find { |s| s.class == ::Warden::Serializers[name] }
301
- end
302
291
  end # Proxy
303
292
  end # Warden