warden 0.8.1 → 0.9.0

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/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