123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- # encoding: utf-8
- require 'warden/hooks'
- require 'warden/config'
- module Warden
- # The middleware for Rack Authentication
- # The middlware requires that there is a session upstream
- # The middleware injects an authentication object into
- # the rack environment hash
- class Manager
- extend Warden::Hooks
- attr_accessor :config
- # Initialize the middleware. If a block is given, a Warden::Config is yielded so you can properly
- # configure the Warden::Manager.
- # :api: public
- def initialize(app, options={})
- default_strategies = options.delete(:default_strategies)
- @app, @config = app, Warden::Config.new(options)
- @config.default_strategies *default_strategies if default_strategies
- yield @config if block_given?
- self
- end
- # Invoke the application guarding for throw :warden.
- # If this is downstream from another warden instance, don't do anything.
- # :api: private
- def call(env) # :nodoc:
- return @app.call(env) if env['warden'] && env['warden'].manager != self
- env['warden'] = Proxy.new(env, self)
- result = catch(:warden) do
- @app.call(env)
- end
- result ||= {}
- case result
- when Array
- if result.first == 401 && intercept_401?(env)
- process_unauthenticated(env)
- else
- result
- end
- when Hash
- process_unauthenticated(env, result)
- end
- end
- # :api: private
- 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.
- #
- # You can supply different methods of serialization for different scopes by passing a scope symbol
- #
- # Example:
- # Warden::Manager.serialize_into_session{ |user| user.id }
- # # With Scope:
- # Warden::Manager.serialize_into_session(:admin) { |user| user.id }
- #
- # :api: public
- def serialize_into_session(scope = nil, &block)
- method_name = scope.nil? ? :serialize : "#{scope}_serialize"
- Warden::SessionSerializer.send :define_method, method_name, &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
- # You can supply different methods of de-serialization for different scopes by passing a scope symbol
- #
- # Example:
- # Warden::Manager.serialize_from_session{ |id| User.get(id) }
- # # With Scope:
- # Warden::Manager.serialize_from_session(:admin) { |id| AdminUser.get(id) }
- #
- # :api: public
- def serialize_from_session(scope = nil, &block)
- method_name = scope.nil? ? :deserialize : "#{scope}_deserialize"
- Warden::SessionSerializer.send :define_method, method_name, &block
- end
- end
- private
- def intercept_401?(env)
- config[:intercept_401] && !env['warden'].custom_failure?
- end
- # When a request is unauthenticated, here's where the processing occurs.
- # It looks at the result of the proxy to see if it's been executed and what action to take.
- # :api: private
- def process_unauthenticated(env, options={})
- options[:action] ||= begin
- opts = config[:scope_defaults][config.default_scope] || {}
- opts[:action] || 'unauthenticated'
- end
- proxy = env['warden']
- result = options[:result] || proxy.result
- case result
- when :redirect
- body = proxy.message || "You are being redirected to #{proxy.headers['Location']}"
- [proxy.status, proxy.headers, [body]]
- when :custom
- proxy.custom_response
- else
- call_failure_app(env, options)
- end
- end
- # Calls the failure app.
- # The before_failure hooks are run on each failure
- # :api: private
- def call_failure_app(env, options = {})
- if config.failure_app
- options.merge!(:attempted_path => ::Rack::Request.new(env).fullpath)
- env["PATH_INFO"] = "/#{options[:action]}"
- env["warden.options"] = options
- _run_callbacks(:before_failure, env, options)
- config.failure_app.call(env).to_a
- else
- raise "No Failure App provided"
- end
- end # call_failure_app
- end
- end # Warden
|