Permalink
Browse files

Beggining of work in merging serializer and strategies.

  • Loading branch information...
1 parent 0eba8a3 commit 8a4dd51fbf8327cf2d9f471f19eb2dda45add3a3 @josevalim josevalim committed Jan 13, 2010
View
1 lib/warden.rb
@@ -6,6 +6,7 @@
require 'warden/proxy'
require 'warden/manager'
require 'warden/errors'
+require 'warden/session_serializer'
require 'warden/strategies'
require 'warden/strategies/base'
require 'warden/serializers'
View
28 lib/warden/manager.rb
@@ -52,6 +52,32 @@ def _run_callbacks(*args) #:nodoc:
self.class._run_callbacks(*args)
end
+ class << self
+ # Prepares the user to serialize into the session.
+ # Any object that can be serialized into the session in some way can be used as a "user" object
+ # Generally however complex object should not be stored in the session.
+ # If possible store only a "key" of the user object that will allow you to reconstitute it.
+ #
+ # Example:
+ # Warden::Manager.serialize_into_session{ |user| user.id }
+ #
+ # :api: public
+ def serialize_into_session(&block)
+ Warden::SessionSerializer.send :define_method, :serialize, &block
+ end
+
+ # Reconstitues the user from the session.
+ # Use the results of user_session_key to reconstitue the user from the session on requests after the initial login
+ #
+ # Example:
+ # Warden::Manager.serialize_from_session{ |id| User.get(id) }
+ #
+ # :api: public
+ def serialize_from_session(&block)
+ Warden::SessionSerializer.send :define_method, :deserialize, &block
+ end
+ end
+
private
# When a request is unauthentiated, here's where the processing occurs.
@@ -62,7 +88,7 @@ def process_unauthenticated(result, env)
case action
when :redirect
- [env['warden']._status, env['warden'].headers, [env['warden'].message || "You are being redirected to #{env['warden'].headers['Location']}"]]
+ [env['warden'].status, env['warden'].headers, [env['warden'].message || "You are being redirected to #{env['warden'].headers['Location']}"]]
when :custom
env['warden'].custom_response
else
View
49 lib/warden/manager_deprecation.rb
@@ -9,54 +9,5 @@ def default_scope
def default_scope=(scope)
warn "[DEPRECATION] Warden::Manager.default_scope= is deprecated. Please set it in the Warden::Manager instance."
end
-
- # Prepares the user to serialize into the session.
- # Any object that can be serialized into the session in some way can be used as a "user" object
- # Generally however complex object should not be stored in the session.
- # If possible store only a "key" of the user object that will allow you to reconstitute it.
- #
- # Example:
- # Warden::Manager.serialize_into_session{ |user| user.id }
- #
- # Deprecation:
- # This method was deprecated in favor of serializer in Session. You can set it while setting the middleware:
- #
- # use Warden::Manager do |manager|
- # manager.serializers.update(:session) do
- # def serialize(user)
- # user.id
- # end
- # end
- # end
- #
- # :api: public
- def serialize_into_session(&block)
- warn "[DEPRECATION] serialize_into_session is deprecated. Please overwrite the serialize method in Warden::Serializers::Session."
- Warden::Serializers::Session.send :define_method, :serialize, &block
- end
-
- # Reconstitues the user from the session.
- # Use the results of user_session_key to reconstitue the user from the session on requests after the initial login
- #
- # Example:
- # Warden::Manager.serialize_from_session{ |id| User.get(id) }
- #
- # Deprecation:
- # This method was deprecated in favor of serializer in Session. You can set it while setting the middleware:
- #
- # use Warden::Manager do |manager|
- # manager.serializers.update(:session) do
- # def deserialize(id)
- # User.get(id)
- # end
- # end
- # end
- #
- # :api: public
- def serialize_from_session(&block)
- warn "[DEPRECATION] serialize_from_session is deprecated. Please overwrite the deserialize method in Warden::Serializers::Session."
- Warden::Serializers::Session.send :define_method, :deserialize, &block
- end
-
end
end
View
127 lib/warden/proxy.rb
@@ -3,7 +3,7 @@ module Warden
class UserNotSet < RuntimeError; end
class Proxy
- # An accessor to the wining strategy
+ # An accessor to the winning strategy
# :api: private
attr_accessor :winning_strategy
@@ -15,27 +15,21 @@ class Proxy
include ::Warden::Mixins::Common
# :api: private
- def_delegators :winning_strategy, :headers, :_status, :custom_response
+ def_delegators :winning_strategy, :headers, :status, :custom_response
def initialize(env, manager) #:nodoc:
@env, @users = env, {}
+ @strategies = Hash.new { |h,k| h[k] = {} }
@manager, @config = manager, manager.config
errors # setup the error object in the session
end
- # Add warden cookies to the response streamed back.
- def respond!(args)
- return args if warden_cookies.empty?
- response = Rack::Response.new(args[2], args[0], args[1])
-
- warden_cookies.each do |key, value|
- if value.is_a?(Hash)
- response.set_cookie key, value
- else
- response.delete_cookie key
- end
- end
- response.to_a
+ # Points to a SessionSerializer instance repsonsible for handling
+ # everything related with storing, fetching and removing the user
+ # session.
+ # :api: public
+ def session_serializer
+ @session_serializer ||= Warden::SessionSerializer.new(@env)
end
# Check to see if there is an authenticated user for the given scope.
@@ -102,16 +96,10 @@ def authenticate!(*args)
# env['warden'].set_user(@user)
# env['warden'].stored? #=> true
# env['warden'].stored?(:default) #=> true
- # env['warden'].stored?(:default, :session) #=> true
- # env['warden'].stored?(:default, :cookie) #=> false
#
# :api: public
- def stored?(scope = @config.default_scope, serializer = nil)
- if serializer
- _find_serializer(serializer).stored?(scope)
- else
- serializers.any? { |s| s.stored?(scope) }
- end
+ def stored?(scope = @config.default_scope)
+ session_serializer.stored?(scope)
end
# Manually set the user into the session and auth proxy
@@ -124,8 +112,9 @@ def stored?(scope = @config.default_scope, serializer = nil)
def set_user(user, opts = {})
return unless user
scope = (opts[:scope] ||= @config.default_scope)
- _store_user(user, scope) unless opts[:store] == false
+
@users[scope] = user
+ session_serializer.store(user, scope) unless opts[:store] == false
opts[:event] ||= :set_user
manager._run_callbacks(:after_set_user, user, self, opts)
@@ -144,7 +133,8 @@ def set_user(user, opts = {})
#
# :api: public
def user(scope = @config.default_scope)
- @users[scope] ||= set_user(_fetch_user(scope), :scope => scope, :event => :fetch)
+ @users[scope] ||= set_user(session_serializer.fetch(scope),
+ :scope => scope, :event => :fetch)
end
# Provides a scoped session data for authenticated users.
@@ -191,7 +181,7 @@ def logout(*scopes)
manager._run_callbacks(:before_logout, user, self, :scope => scope)
raw_session.delete("warden.user.#{scope}.session")
- _delete_user(user, scope)
+ session_serializer.delete(scope, user)
end
reset_session! if reset_session
@@ -222,32 +212,32 @@ def custom_failure?
!!@custom_failure
end
- # Retrieve and initializer serializers.
+ # Add warden cookies to the response streamed back.
# :api: private
- def serializers # :nodoc:
- @serializers ||= begin
- @config.default_serializers.inject([]) do |array, s|
- unless klass = Warden::Serializers[s]
- raise "Invalid serializer #{s}" unless @config.silence_missing_serializers?
- array
- else
- array << klass.new(@env)
- end
+ # TODO Test me since I was removed.
+ def respond!(args)
+ return args if warden_cookies.empty?
+ response = Rack::Response.new(args[2], args[0], args[1])
+
+ warden_cookies.each do |key, value|
+ if value.is_a?(Hash)
+ response.set_cookie key, value
+ else
+ response.delete_cookie key
end
end
+ response.to_a
end
private
- # :api: private
def _perform_authentication(*args)
- scope = scope_from_args(args)
- opts = opts_from_args(args)
+ opts = args.last.is_a?(Hash) ? args.pop : {}
+ scope = opts[:scope] || @config.default_scope
# Look for an existing user in the session for this scope.
- # If there was no user in the session. See if we can get one from the request
+ # If there was no user in the session. See if we can get one from the request.
return scope, opts if user(scope)
-
_run_strategies_for(scope, args)
if winning_strategy && winning_strategy.user
@@ -257,61 +247,32 @@ def _perform_authentication(*args)
[scope, opts]
end
- # :api: private
- def scope_from_args(args) # :nodoc:
- Hash === args.last ? args.last.fetch(:scope, @config.default_scope) : @config.default_scope
- end
-
- # :api: private
- def opts_from_args(args) # :nodoc:
- Hash === args.last ? args.pop : {}
- end
-
- # :api: private
+ # Run the strategies for a given scope
def _run_strategies_for(scope, args) #:nodoc:
strategies = args.empty? ? @config.default_strategies : args
- strategies.each do |s|
- unless klass = Warden::Strategies[s]
- raise "Invalid strategy #{s}" unless args.empty? && @config.silence_missing_strategies?
- next
- end
+ strategies.each do |name|
+ strategy = _fetch_strategy(name, scope)
+ next unless strategy && strategy.valid?
- strategy = klass.new(@env, scope)
self.winning_strategy = strategy
- next unless strategy.valid?
-
strategy._run!
break if strategy.halted?
end
end
- # Does the work of storing the user in stores.
- # :api: private
- def _store_user(user, scope) # :nodoc:
- return unless user
- serializers.each { |s| s.store(user, scope) }
- end
+ # Fetchs strategies and keep them in a hash cache.
+ def _fetch_strategy(name, scope)
+ return @strategies[scope][name] if @strategies[scope].key?(name)
- # Does the work of fetching the user from the first store.
- # :api: private
- def _fetch_user(scope) # :nodoc:
- serializers.each do |s|
- user = s.fetch(scope)
- return user if user
+ @strategies[scope][name] = if klass = Warden::Strategies[name]
+ klass.new(@env, scope)
+ elsif @config.silence_missing_strategies?
+ nil
+ else
+ raise "Invalid strategy #{name}"
end
- nil
- end
-
- # Does the work of deleteing the user in all stores.
- # :api: private
- def _delete_user(user, scope) # :nodoc:
- serializers.each { |s| s.delete(scope, user) }
end
- # :api: private
- def _find_serializer(name) # :nodoc:
- serializers.find { |s| s.class == ::Warden::Serializers[name] }
- end
end # Proxy
end # Warden
View
20 lib/warden/serializers.rb
@@ -1,20 +0,0 @@
-# encoding: utf-8
-require 'warden/declarable'
-
-module Warden
- module Serializers
- extend Warden::Declarable
-
- class << self
- def check_validity!(label, serializer)
- [:fetch, :store, :stored?, :delete].each do |method|
- next if serializer.method_defined?(method)
- raise NoMethodError, "#{method} is not declared in the #{label.inspect} serializer"
- end
- end
-
- alias :_serializers :_declarations
- end # << self
-
- end # Serializers
-end # Warden
View
38 lib/warden/serializers/base.rb
@@ -1,38 +0,0 @@
-# encoding: utf-8
-module Warden
- module Serializers
- # A serializer is a place where you put the logic to serializing and deserializing an user. All serializers
- # inherits from Warden::Serializers::Base.
- #
- # The Warden::Serializers.add method is a simple way to provide custom serializers. In order to do so,
- # you _must_ declare @store@, @fetch@, @delete@ and @stored?@ methods.
- #
- # The parameters for Warden::Serializers.add method is:
- # <label: Symbol> The label is the name given to a serializer. Use the label to refer to the serializer when authenticating
- # <serializer: Class|nil> The optional serializer argument if set _must_ be a class that inherits from Warden::Serializers::Base
- # <block> The block acts as a convinient way to declare your serializer. Inside is the class definition of a serializer.
- #
- # Check Session and Cookie serializers for more information.
- #
- class Base
- attr_accessor :env
- include ::Warden::Mixins::Common
-
- def initialize(env)
- @env = env
- end
-
- def key_for(scope)
- "warden.user.#{scope}.key"
- end
-
- def serialize(user)
- user
- end
-
- def deserialize(key)
- key
- end
- end # Base
- end # Serializers
-end # Warden
View
34 lib/warden/serializers/cookie.rb
@@ -1,34 +0,0 @@
-# encoding: utf-8
-module Warden
- module Serializers
- # A cookie serializer provided by Warden. You need to implement the serialize and deserialize
- # methods in order to use it.
- class Cookie < Base
- def store(user, scope)
- warden_cookies[key_for(scope)] = default_options(user)
- end
-
- def fetch(scope)
- key = request.cookies[key_for(scope)]
- return nil unless key
- user = deserialize(key)
- delete(scope) unless user
- user
- end
-
- def stored?(scope)
- !!request.cookies[key_for(scope)]
- end
-
- def delete(scope, user=nil)
- warden_cookies[key_for(scope)] = nil
- end
-
- def default_options(user)
- { :value => serialize(user), :expires => (Time.now + 7 * 24 * 3600), :path => "/" }
- end
- end # Cookie
-
- Serializers.add(:cookie, Cookie)
- end # Serializers
-end # Warden
View
30 lib/warden/serializers/session.rb
@@ -1,30 +0,0 @@
-# encoding: utf-8
-module Warden
- module Serializers
- # A session serializer provided by Warden. You need to implement the serialize and deserialize
- # methods in order to use it.
- class Session < Base
- def store(user, scope)
- session[key_for(scope)] = serialize(user)
- end
-
- def fetch(scope)
- key = session[key_for(scope)]
- return nil unless key
- user = deserialize(key)
- delete(scope) unless user
- user
- end
-
- def stored?(scope)
- !!session[key_for(scope)]
- end
-
- def delete(scope, user=nil)
- session.delete(key_for(scope))
- end
- end # Session
-
- Serializers.add(:session, Session)
- end # Serializers
-end # Warden
View
44 lib/warden/session_serializer.rb
@@ -0,0 +1,44 @@
+# encoding: utf-8
+module Warden
+ class SessionSerializer
+ attr_reader :env
+ include ::Warden::Mixins::Common
+
+ def initialize(env)
+ @env = env
+ end
+
+ def key_for(scope)
+ "warden.user.#{scope}.key"
+ end
+
+ def serialize(user)
+ user
+ end
+
+ def deserialize(key)
+ key
+ end
+
+ def store(user, scope)
+ return unless user
+ session[key_for(scope)] = serialize(user)
+ end
+
+ def fetch(scope)
+ key = session[key_for(scope)]
+ return nil unless key
+ user = deserialize(key)
+ delete(scope) unless user
+ user
+ end
+
+ def stored?(scope)
+ !!session[key_for(scope)]
+ end
+
+ def delete(scope, user=nil)
+ session.delete(key_for(scope))
+ end
+ end # SessionSerializer
+end # Warden
View
10 lib/warden/strategies/base.rb
@@ -34,13 +34,9 @@ class Base
#:api: private
attr_accessor :result, :custom_response
- # Setup for redirection
- # :api: private
- attr_reader :_status
-
- # Accessor for the rack env
+ # Accessors for the rack env
# :api: public
- attr_reader :env, :scope
+ attr_reader :env, :scope, :status
include ::Warden::Mixins::Common
# :api: private
@@ -127,7 +123,7 @@ def fail!(message = "Failed to Login")
# :api: public
def redirect!(url, params = {}, opts = {})
halt!
- @_status = opts[:permanent] ? 301 : 302
+ @status = opts[:permanent] ? 301 : 302
headers["Location"] = url
headers["Location"] << "?" << Rack::Utils.build_query(params) unless params.empty?
headers["Content-Type"] = opts[:content_type] || 'text/plain'
View
53 spec/warden/proxy_spec.rb
@@ -226,30 +226,6 @@
end
setup_rack(app).call(@env)
end
-
- it "returns based on the given store" do
- @env['rack.session'].delete("warden.user.default.key")
- @env["HTTP_COOKIE"] = "warden.user.default.key=user;"
- app = lambda do |env|
- env['warden'].stored?(:default, :session).should be_false
- env['warden'].stored?(:default, :cookie).should be_true
- valid_response
- end
- setup_rack(app, :default_serializers => [:session, :cookie]).call(@env)
- end
- end
-
- it "should not raise errors with missing serializers" do
- env = env_with_params('/')
- app = lambda do |env|
- env['warden'].authenticate
- env['warden'].serializers.size.should == 1
- env['warden'].serializers.first.should be_kind_of(Warden::Serializers[:session])
- valid_response
- end
- lambda {
- setup_rack(app, :silence_missing_serializers => true, :default_serializers => [:session, :unknown]).call(env)
- }.should_not raise_error
end
describe "set user" do
@@ -265,18 +241,6 @@
setup_rack(app).call(env)
end
- it "should store the user into cookies" do
- env = env_with_params("/")
- app = lambda do |env|
- env['warden'].authenticate(:pass)
- env['warden'].should be_authenticated
- env['warden'].user.should == "Valid User"
- valid_response
- end
- response = setup_rack(app, :default_serializers => [:cookie]).call(env)
- response[1]['Set-Cookie'].split(";").first.should == "warden.user.default.key=Valid+User"
- end
-
it "should not store the user if the :store option is set to false" do
env = env_with_params("/")
app = lambda do |e|
@@ -313,17 +277,7 @@
setup_rack(app).call(@env)
end
- it "should load user from others serializers" do
- @env["HTTP_COOKIE"] = "warden.user.default.key=user;"
- app = lambda do |env|
- env['warden'].user.should == "user"
- valid_response
- end
- setup_rack(app, :default_serializers => [:session, :cookie]).call(@env)
- end
-
describe "previously logged in" do
-
before(:each) do
@env['rack.session']['warden.user.default.key'] = "A Previous User"
@env['warden.spec.strategies'] = []
@@ -411,13 +365,6 @@
setup_rack(app).call(@env)
end
- it "should clear the cookie serializer when logging out" do
- @app = setup_rack(@app, :default_serializers => [:cookie])
- @env['warden.spec.which_logout'] = :default
- response = @app.call(@env)
- response[1]['Set-Cookie'].first.split(";").first.should == "warden.user.default.key="
- end
-
it "should clear out the session by calling reset_session! so that plugins can setup their own session clearing" do
@env['rack.session'].should_not be_nil
app = lambda do |e|
View
65 spec/warden/serializers/cookie_spec.rb
@@ -1,65 +0,0 @@
-require File.dirname(__FILE__) + '/../../spec_helper'
-
-describe Warden::Serializers::Cookie do
- before(:each) do
- @env = env_with_params
- @cookie = Warden::Serializers::Cookie.new(@env)
- end
-
- def set_cookie!
- response = Rack::Response.new
- @cookie.warden_cookies.each do |key, value|
- if value.is_a?(Hash)
- response.set_cookie key, value
- else
- response.delete_cookie key
- end
- end
- @env['HTTP_COOKIE'] = response.headers['Set-Cookie']
- end
-
- it "should store data for the default scope" do
- @cookie.store("user", :default)
- @cookie.warden_cookies.should have_key("warden.user.default.key")
- @cookie.warden_cookies["warden.user.default.key"][:value].should == "user"
- end
-
- it "should check if a data is stored or not" do
- @cookie.should_not be_stored(:default)
- @cookie.store("user", :default)
- set_cookie!
- @cookie.should be_stored(:default)
- end
-
- it "should load an user from store" do
- @cookie.fetch(:default).should be_nil
- @cookie.store("user", :default)
- set_cookie!
- @cookie.fetch(:default).should == "user"
- end
-
- it "should store data based on the scope" do
- @cookie.store("user", :default)
- set_cookie!
- @cookie.fetch(:default).should == "user"
- @cookie.fetch(:another).should be_nil
- end
-
- it "should delete data from store" do
- @cookie.store("user", :default)
- set_cookie!
- @cookie.fetch(:default).should == "user"
- @cookie.delete(:default)
- @cookie.warden_cookies.should have_key("warden.user.default.key")
- @cookie.warden_cookies["warden.user.default.key"].should be_nil
- end
-
- it "should delete information from store if user cannot be retrieved" do
- @cookie.store("user", :default)
- set_cookie!
- @cookie.instance_eval "def deserialize(key); nil; end"
- @cookie.fetch(:default)
- @cookie.warden_cookies.should have_key("warden.user.default.key")
- @cookie.warden_cookies["warden.user.default.key"].should be_nil
- end
-end
View
102 spec/warden/serializers_spec.rb
@@ -1,102 +0,0 @@
-require File.dirname(__FILE__) + '/../spec_helper'
-
-describe Warden::Serializers do
- it "should let me add a serializer via a block" do
- Warden::Serializers.add(:serializer1) do
- def fetch; end
- def store; end
- def stored?; end
- def delete; end
- end
- Warden::Serializers[:serializer1].ancestors.should include(Warden::Serializers::Base)
- end
-
- it "should raise an error if I add a serializer via a block, that does not have an autheniticate! method" do
- lambda do
- Warden::Serializers.add(:serializer2) do
- end
- end.should raise_error
- end
-
- it "should allow me to get access to a particular serializer" do
- Warden::Serializers.add(:serializer3) do
- def fetch; end
- def store; end
- def stored?; end
- def delete; end
- end
- serializer = Warden::Serializers[:serializer3]
- serializer.should_not be_nil
- serializer.ancestors.should include(Warden::Serializers::Base)
- end
-
- it "should allow me to add a serializer with the required methods" do
- class MySerializer < Warden::Serializers::Base
- def fetch; end
- def store; end
- def stored?; end
- def delete; end
- end
- lambda do
- Warden::Serializers.add(:serializer4, MySerializer)
- end.should_not raise_error
- end
-
- it "should not allow a serializer that does not have any required method" do
- class MyOtherSerializer
- end
- lambda do
- Warden::Serializers.add(:serializer5, MyOtherSerializer)
- end.should raise_error
- end
-
- it "should allow me to change a class when providing a block and class" do
- class MySerializer < Warden::Serializers::Base
- end
-
- Warden::Serializers.add(:foo, MySerializer) do
- def fetch; end
- def store; end
- def stored?; end
- def delete; end
- end
-
- Warden::Serializers[:foo].ancestors.should include(MySerializer)
- end
-
- it "should allow me to update a previously given serializer" do
- class MySerializer < Warden::Serializers::Base
- def fetch; end
- def store; end
- def stored?; end
- def delete; end
- end
-
- Warden::Serializers.add(:serializer6, MySerializer)
-
- new_module = Module.new
- Warden::Serializers.update(:serializer6) do
- include new_module
- end
-
- Warden::Serializers[:serializer6].ancestors.should include(new_module)
- end
-
- it "should allow me to clear the Serializers" do
- old_serializers = Warden::Serializers._serializers.dup
-
- begin
- Warden::Serializers.add(:foobar) do
- def fetch; end
- def store; end
- def stored?; end
- def delete; end
- end
- Warden::Serializers[:foobar].should_not be_nil
- Warden::Serializers.clear!
- Warden::Serializers[:foobar].should be_nil
- else
- Warden::Serializers._serializers.replace(old_serializers)
- end
- end
-end
View
6 spec/warden/serializers/session_spec.rb → spec/warden/session_serializer_spec.rb
@@ -1,10 +1,10 @@
-require File.dirname(__FILE__) + '/../../spec_helper'
+require File.dirname(__FILE__) + '/../spec_helper'
-describe Warden::Serializers::Session do
+describe Warden::SessionSerializer do
before(:each) do
@env = env_with_params
@env['rack.session'] ||= {}
- @session = Warden::Serializers::Session.new(@env)
+ @session = Warden::SessionSerializer.new(@env)
end
it "should store data for the default scope" do

0 comments on commit 8a4dd51

Please sign in to comment.