pax_global_header00006660000000000000000000000064133734010540014512gustar00rootroot0000000000000052 comment=61b22a6ffb53f2816a414c5d256650361942db71 warden-1.2.8/000077500000000000000000000000001337340105400130025ustar00rootroot00000000000000warden-1.2.8/.gitignore000066400000000000000000000000311337340105400147640ustar00rootroot00000000000000.DS_Store pkg .*~ *.gem warden-1.2.8/.rspec000066400000000000000000000000641337340105400141170ustar00rootroot00000000000000--require spec_helper --format documentation --colorwarden-1.2.8/.travis.yml000066400000000000000000000001121337340105400151050ustar00rootroot00000000000000language: ruby install: - bundle install rvm: - 2.2 - 2.3 - 2.4.2 warden-1.2.8/CHANGELOG.md000066400000000000000000000116351337340105400146210ustar00rootroot00000000000000== Version 1.2.8 / 2018-11-15 * Bugfix: Flips two lines to allow scopes authenticating from another without stepping on each other's toes. (PR #144) * Update `rack` dependency to >= 2.0.6 due to security vulnerability * Internal: Add Rubocop Lint checking * Internal: Update RSpec to use `.rspec` file == Version 1.2.7 / 2016-10-12 * Added 'frozen_string_literal' comment, bump ruby to 2.3 == Version 1.2.6 / 2016-01-31 * Separate test helpers to encapsulate Warden object mocking inside it's own class == Version 1.2.5 / 2016-01-28 * Expands on the test helpers available to make it easier for testing gems == Version 1.2.3 / 2013-07-14 * Fix an issue with lazy loaded sessions == Version 1.2.2 / 2013-07-12 * Support nil session stores on logout * Fix strategies blowing up with undefined method base == Version 1.2.1 / 2012-06-16 * Minor caching and speed improvements * Add support to #lock in the proxy * Add support to after_failed_fetch callback == Version 1.2.0 / 2012-05-08 * Deprecate warden_cookies since it was never functional * Add support to serialize_from_session and serialize_into_session per scope == Version 1.1.1 / 2012-02-16 * Allow run_callbacks as an option to set_user and user == Version 1.1.0 / 2011-11-02 * Use the default scopes action when using a bare throw(:warden) == Version 1.0.6 * Remove gem files from the packaged gem == Version 1.0.3 * Do not renew session on user fetch == Version 1.0.2 * Added :intercept_401 to Warden::Config == Version 1.0.1 * Bug fix on strategies errors handler == Version 1.0.0 * Bump! * Allow strategies to configure if user should be stored or not * Force session id renewal when user is set == Version 0.10.7 * Performance boost. config object to use raw accessors * Add per strategy storage option == Version 0.10.6 / 0.10.7 / 2010-05-22 * Bugfix set_user was not respecting logouts in hooks == Version 0.10.4 / 0.10.5 / 2010-05-20 * Add action specifying in scope_defaults == Version 0.10.3 / 2010-03-01 * Bugfix prevent halted winning strategy from being skipped in subsequent runs == Version 0.10.2 / 2010-03-26 * Halt on fail!. Add fail to allow cascading * cache the winning strategy * Make the config object Dupable == Version 0.10.1 / 2010-03-23 * Merge previous from master * tag == Version 0.10.0 / 2010-03-22 * Allow default strategies to be set on the proxy * Provide each scope with it's own default strategies * Provide each scope with default set_user opts * depricate the Proxy#default_strategies= method == Version 0.9.5 / 2010-02-28 * Add Warden.test_mode! * Add Warden.on_next_request * Add test helpers in Warden::Test::Helpers ** login_as ** logout == Version 0.9.4 / 2010-02-23 * Fix an issue where winning_strategy was not cleaned, allowing multiple scopes to sign in, even when the second one should not == Version 0.9.3 / 2010-02-17 * Add prepend_ to all hooks (josevalim) == Version 0.9.2 / 2010-02-10 * Ruby 1.9 compatibility changes (grimen) == Version 0.9.1 / 2010-02-09 * Support for passing a custom message with Warden::Strategy::Base#success! as second optional (grimen) == Version 0.9.0 / 2010-01-21 * Remove serializers and make strategies more powerful, including cache behavior (josevalim) == Version 0.8.1 / 2010-01-06 * Fix a bug when silence missing serializers is set (josevalim) == Version 0.8.0 / 2010-01-06 * enhancements * Add conditionals to callbacks (josevalim) * Extract Warden::Config from Warden::Manager (josevalim) == Version 0.7.0 / 2010-01-04 * enhancements * Expose config in warden proxy (hassox) == Version 0.6.0 / 2009-11-16 * enhancements * added serializers, including session serializer (set by default) and a cookie serializer (josevalim) * deprecation * serializer_into_session and serializer_from_session are deprecated, overwrite serialize and deserializer in Warden::Serializers::Session instead (josevalim) == Version 0.5.3 / 2009-11-10 * bug fixes * authenticated? and unauthenticated? should return true or false, not the user or false. (hassox) == Version 0.5.2 / 2009-11-09 * enhancements * authenticated? always try to serialize the user from session (josevalim) * stored_in_session? checks if user information is stored in session, without serializing (josevalim) * 401 behaves exactly like throw :warden (staugaard) === Version 0.5.1 / 2009-10-25 * enhancements * Adds yielding to authenticated? and unauthenticated? methods (hassox) * Adds an option to silence missing strategies (josevalim) * Add an option to authenticate(!) to prevent storage of a user into the session (hassox) * allow custom :action to be thrown (josevalim) === Version 0.4.0 / 2009-10-12 * enhancements * add Content-Type header to redirects (staugaard) * Make scope available to strategies (josevalim) * bug fixes * Do not consume opts twice, otherwise just the first will parse the scope (josevalim) === Version 0.3.2 / 2009-09-15 * enhancements * add a hook for plugins to specify how they can clear the whole section warden-1.2.8/Gemfile000066400000000000000000000002431337340105400142740ustar00rootroot00000000000000# frozen_string_literal: true source 'https://rubygems.org' gemspec gem 'rake' gem 'rack', '>= 2.0.6' group :test do gem 'rspec', '~>3' gem 'rack-test' end warden-1.2.8/Gemfile.lock000066400000000000000000000013021337340105400152200ustar00rootroot00000000000000PATH remote: . specs: warden (1.2.8) rack (>= 2.0.6) GEM remote: https://rubygems.org/ specs: diff-lcs (1.3) rack (2.0.6) rack-test (0.7.0) rack (>= 1.0, < 3) rake (12.1.0) rspec (3.6.0) rspec-core (~> 3.6.0) rspec-expectations (~> 3.6.0) rspec-mocks (~> 3.6.0) rspec-core (3.6.0) rspec-support (~> 3.6.0) rspec-expectations (3.6.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.6.0) rspec-mocks (3.6.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.6.0) rspec-support (3.6.0) PLATFORMS ruby DEPENDENCIES rack (>= 2.0.6) rack-test rake rspec (~> 3) warden! BUNDLED WITH 1.17.1 warden-1.2.8/LICENSE000066400000000000000000000020471337340105400140120ustar00rootroot00000000000000Copyright (c) 2009-2017 Daniel Neighman Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.warden-1.2.8/README.md000066400000000000000000000006021337340105400142570ustar00rootroot00000000000000# Warden ## Getting Started Please see the [Warden Wiki](https://wiki.github.com/hassox/warden) for overview documentation. ## Maintainers * Daniel Neighman (hassox) * José Valim (josevalim) * Justin Smestad (jsmestad) * Whitney Smestad (whithub) [A list of all contributors is available on Github.](https://github.com/hassox/warden/contributors) ## LICENSE See `LICENSE` file. warden-1.2.8/Rakefile000066400000000000000000000002551337340105400144510ustar00rootroot00000000000000# -*- encoding: utf-8 -*- # frozen_string_literal: true require "bundler/gem_tasks" require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec) task :default => :spec warden-1.2.8/lib/000077500000000000000000000000001337340105400135505ustar00rootroot00000000000000warden-1.2.8/lib/warden.rb000066400000000000000000000025501337340105400153570ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true require 'forwardable' require 'warden/mixins/common' require 'warden/proxy' require 'warden/manager' require 'warden/errors' require 'warden/session_serializer' require 'warden/strategies' require 'warden/strategies/base' module Warden class NotAuthenticated < StandardError; end module Test autoload :WardenHelpers, 'warden/test/warden_helpers' autoload :Helpers, 'warden/test/helpers' autoload :Mock, 'warden/test/mock' end # Provides helper methods to warden for testing. # # To setup warden in test mode call the +test_mode!+ method on warden # # @example # Warden.test_mode! # # This will provide a number of methods. # Warden.on_next_request(&blk) - captures a block which is yielded the warden proxy on the next request # Warden.test_reset! - removes any captured blocks that would have been executed on the next request # # Warden.test_reset! should be called in after blocks for rspec, or teardown methods for Test::Unit def self.test_mode! unless Warden::Test::WardenHelpers === Warden Warden.extend Warden::Test::WardenHelpers Warden::Manager.on_request do |proxy| unless proxy.asset_request? while blk = Warden._on_next_request.shift blk.call(proxy) end end end end true end end warden-1.2.8/lib/warden/000077500000000000000000000000001337340105400150305ustar00rootroot00000000000000warden-1.2.8/lib/warden/config.rb000066400000000000000000000056711337340105400166330ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true module Warden # This class is yielded inside Warden::Manager. If you have a plugin and want to # add more configuration to warden, you just need to extend this class. class Config < Hash # Creates an accessor that simply sets and reads a key in the hash: # # class Config < Hash # hash_accessor :failure_app # end # # config = Config.new # config.failure_app = Foo # config[:failure_app] #=> Foo # # config[:failure_app] = Bar # config.failure_app #=> Bar # def self.hash_accessor(*names) #:nodoc: names.each do |name| class_eval <<-METHOD, __FILE__, __LINE__ + 1 def #{name} self[:#{name}] end def #{name}=(value) self[:#{name}] = value end METHOD end end hash_accessor :failure_app, :default_scope, :intercept_401 def initialize(other={}) merge!(other) self[:default_scope] ||= :default self[:scope_defaults] ||= {} self[:default_strategies] ||= {} self[:intercept_401] = true unless key?(:intercept_401) end def initialize_copy(other) super deep_dup(:scope_defaults, other) deep_dup(:default_strategies, other) end # Do not raise an error if a missing strategy is given. # :api: plugin def silence_missing_strategies! self[:silence_missing_strategies] = true end def silence_missing_strategies? #:nodoc: !!self[:silence_missing_strategies] end # Set the default strategies to use. # :api: public def default_strategies(*strategies) opts = Hash === strategies.last ? strategies.pop : {} hash = self[:default_strategies] scope = opts[:scope] || :_all hash[scope] = strategies.flatten unless strategies.empty? hash[scope] || hash[:_all] || [] end # A short hand way to set up a particular scope # :api: public def scope_defaults(scope, opts = {}) if strategies = opts.delete(:strategies) default_strategies(strategies, :scope => scope) end if opts.empty? self[:scope_defaults][scope] || {} else self[:scope_defaults][scope] ||= {} self[:scope_defaults][scope].merge!(opts) end end # Quick accessor to strategies from manager # :api: public def strategies Warden::Strategies end # Hook from configuration to serialize_into_session. # :api: public def serialize_into_session(*args, &block) Warden::Manager.serialize_into_session(*args, &block) end # Hook from configuration to serialize_from_session. # :api: public def serialize_from_session(*args, &block) Warden::Manager.serialize_from_session(*args, &block) end protected def deep_dup(key, other) self[key] = hash = other[key].dup hash.each { |k, v| hash[k] = v.dup } end end end warden-1.2.8/lib/warden/errors.rb000066400000000000000000000031631337340105400166740ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true module Warden class Proxy # Lifted from DataMapper's dm-validations plugin :) # @author Guy van den Berg # @since DM 0.9 class Errors include Enumerable # Clear existing authentication errors. def clear! errors.clear end # Add a authentication error. Use the field_name :general if the errors does # not apply to a specific field of the Resource. # # @param field_name the name of the field that caused the error # @param message the message to add def add(field_name, message) (errors[field_name] ||= []) << message end # Collect all errors into a single list. def full_messages errors.inject([]) do |list,pair| list += pair.last end end # Return authentication errors for a particular field_name. # # @param field_name the name of the field you want an error for def on(field_name) errors_for_field = errors[field_name] blank?(errors_for_field) ? nil : errors_for_field end def each errors.map.each do |_k,v| next if blank?(v) yield(v) end end def empty? entries.empty? end def method_missing(meth, *args, &block) errors.send(meth, *args, &block) end private def errors @errors ||= {} end def blank?(thing) thing.nil? || thing == "" || (thing.respond_to?(:empty?) && thing.empty?) end end # class Errors end # Proxy end # Warden warden-1.2.8/lib/warden/hooks.rb000066400000000000000000000174201337340105400165040ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true module Warden module Hooks # Hook to _run_callbacks asserting for conditions. def _run_callbacks(kind, *args) #:nodoc: options = args.last # Last callback arg MUST be a Hash send("_#{kind}").each do |callback, conditions| invalid = conditions.find do |key, value| value.is_a?(Array) ? !value.include?(options[key]) : (value != options[key]) end callback.call(*args) unless invalid end end # A callback hook set to run every time after a user is set. # This callback is triggered the first time one of those three events happens # during a request: :authentication, :fetch (from session) and :set_user (when manually set). # You can supply as many hooks as you like, and they will be run in order of declaration. # # If you want to run the callbacks for a given scope and/or event, you can specify them as options. # See parameters and example below. # # Parameters: # Some options which specify when the callback should be executed # scope - Executes the callback only if it matches the scope(s) given # only - Executes the callback only if it matches the event(s) given # except - Executes the callback except if it matches the event(s) given # A block where you can set arbitrary logic to run every time a user is set # Block Parameters: |user, auth, opts| # user - The user object that is being set # auth - The raw authentication proxy object. # opts - any options passed into the set_user call including :scope # # Example: # Warden::Manager.after_set_user do |user,auth,opts| # scope = opts[:scope] # if auth.session["#{scope}.last_access"].to_i > (Time.now - 5.minutes) # auth.logout(scope) # throw(:warden, :scope => scope, :reason => "Times Up") # end # auth.session["#{scope}.last_access"] = Time.now # end # # Warden::Manager.after_set_user :except => :fetch do |user,auth,opts| # user.login_count += 1 # end # # :api: public def after_set_user(options = {}, method = :push, &block) raise BlockNotGiven unless block_given? if options.key?(:only) options[:event] = options.delete(:only) elsif options.key?(:except) options[:event] = [:set_user, :authentication, :fetch] - Array(options.delete(:except)) end _after_set_user.send(method, [block, options]) end # Provides access to the array of after_set_user blocks to run # :api: private def _after_set_user # :nodoc: @_after_set_user ||= [] end # after_authentication is just a wrapper to after_set_user, which is only invoked # when the user is set through the authentication path. The options and yielded arguments # are the same as in after_set_user. # # :api: public def after_authentication(options = {}, method = :push, &block) after_set_user(options.merge(:event => :authentication), method, &block) end # after_fetch is just a wrapper to after_set_user, which is only invoked # when the user is fetched from session. The options and yielded arguments # are the same as in after_set_user. # # :api: public def after_fetch(options = {}, method = :push, &block) after_set_user(options.merge(:event => :fetch), method, &block) end # A callback that runs just prior to the failure application being called. # This callback occurs after PATH_INFO has been modified for the failure (default /unauthenticated) # In this callback you can mutate the environment as required by the failure application # If a Rails controller were used for the failure_app for example, you would need to set request[:params][:action] = :unauthenticated # # Parameters: # Some options which specify when the callback should be executed # scope - Executes the callback only if it matches the scope(s) given # A block to contain logic for the callback # Block Parameters: |env, opts| # env - The rack env hash # opts - any options passed into the authenticate call including :scope # # Example: # Warden::Manager.before_failure do |env, opts| # params = Rack::Request.new(env).params # params[:action] = :unauthenticated # params[:warden_failure] = opts # end # # :api: public def before_failure(options = {}, method = :push, &block) raise BlockNotGiven unless block_given? _before_failure.send(method, [block, options]) end # Provides access to the callback array for before_failure # :api: private def _before_failure @_before_failure ||= [] end # A callback that runs if no user could be fetched, meaning there is now no user logged in. # # Parameters: # Some options which specify when the callback should be executed # scope - Executes the callback only if it matches the scope(s) given # A block to contain logic for the callback # Block Parameters: |user, auth, scope| # user - The authenticated user for the current scope # auth - The warden proxy object # opts - any options passed into the authenticate call including :scope # # Example: # Warden::Manager.after_failed_fetch do |user, auth, opts| # I18n.locale = :en # end # # :api: public def after_failed_fetch(options = {}, method = :push, &block) raise BlockNotGiven unless block_given? _after_failed_fetch.send(method, [block, options]) end # Provides access to the callback array for after_failed_fetch # :api: private def _after_failed_fetch @_after_failed_fetch ||= [] end # A callback that runs just prior to the logout of each scope. # # Parameters: # Some options which specify when the callback should be executed # scope - Executes the callback only if it matches the scope(s) given # A block to contain logic for the callback # Block Parameters: |user, auth, scope| # user - The authenticated user for the current scope # auth - The warden proxy object # opts - any options passed into the authenticate call including :scope # # Example: # Warden::Manager.before_logout do |user, auth, opts| # user.forget_me! # end # # :api: public def before_logout(options = {}, method = :push, &block) raise BlockNotGiven unless block_given? _before_logout.send(method, [block, options]) end # Provides access to the callback array for before_logout # :api: private def _before_logout @_before_logout ||= [] end # A callback that runs on each request, just after the proxy is initialized # # Parameters: # A block to contain logic for the callback # Block Parameters: |proxy| # proxy - The warden proxy object for the request # # Example: # user = "A User" # Warden::Manager.on_request do |proxy| # proxy.set_user = user # end # # :api: public def on_request(options = {}, method = :push, &block) raise BlockNotGiven unless block_given? _on_request.send(method, [block, options]) end # Provides access to the callback array for before_logout # :api: private def _on_request @_on_request ||= [] end # Add prepend filters version %w(after_set_user after_authentication after_fetch on_request before_failure before_logout).each do |filter| class_eval <<-METHOD, __FILE__, __LINE__ + 1 def prepend_#{filter}(options={}, &block) #{filter}(options, :unshift, &block) end METHOD end end # Hooks end # Warden warden-1.2.8/lib/warden/manager.rb000066400000000000000000000116221337340105400167710ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true require 'warden/hooks' require 'warden/config' module Warden # The middleware for Rack Authentication # The middleware 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? 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 env['warden'].on_request @app.call(env) end result ||= {} case result when Array handle_chain_result(result.first, result, env) when Hash process_unauthenticated(env, result) when Rack::Response handle_chain_result(result.status, result, env) 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 # Reconstitutes the user from the session. # Use the results of user_session_key to reconstitute 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" if Warden::SessionSerializer.method_defined? method_name Warden::SessionSerializer.send :remove_method, method_name end Warden::SessionSerializer.send :define_method, method_name, &block end end private def handle_chain_result(status, result, env) if status == 401 && intercept_401?(env) process_unauthenticated(env) else result end end 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 options[:message] ||= proxy.message 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 warden-1.2.8/lib/warden/mixins/000077500000000000000000000000001337340105400163375ustar00rootroot00000000000000warden-1.2.8/lib/warden/mixins/common.rb000066400000000000000000000024111337340105400201520ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true module Warden module Mixins module Common # Convenience method to access the session # :api: public def session env['rack.session'] end # session # Alias :session to :raw_session since the former will be user API for storing scoped data. alias :raw_session :session # Convenience method to access the rack request. # :api: public def request @request ||= Rack::Request.new(@env) end # request # Provides a warden repository for cookies. Those are sent to the client # when the response is streamed back from the app. # :api: public def warden_cookies warn "warden_cookies was never functional and is going to be removed in next versions" env['warden.cookies'] ||= {} end # warden_cookies # Convenience method to access the rack request params # :api: public def params request.params end # params # Resets the session. By using this non-hash like sessions can # be cleared by overwriting this method in a plugin # @api overwritable def reset_session! raw_session.clear end # reset_session! end # Common end # Mixins end # Warden warden-1.2.8/lib/warden/proxy.rb000066400000000000000000000302161337340105400165400ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true module Warden class UserNotSet < RuntimeError; end class Proxy # An accessor to the winning strategy # :api: private attr_accessor :winning_strategy # An accessor to the rack env hash, the proxy owner and its config # :api: public attr_reader :env, :manager, :config, :winning_strategies extend ::Forwardable include ::Warden::Mixins::Common ENV_WARDEN_ERRORS = 'warden.errors'.freeze ENV_SESSION_OPTIONS = 'rack.session.options'.freeze # :api: private def_delegators :winning_strategy, :headers, :status, :custom_response # :api: public def_delegators :config, :default_strategies def initialize(env, manager) #:nodoc: @env, @users, @winning_strategies, @locked = env, {}, {}, false @manager, @config = manager, manager.config.dup @strategies = Hash.new { |h,k| h[k] = {} } end # Run the on_request callbacks # :api: private def on_request manager._run_callbacks(:on_request, self) end # Lazily initiate errors object in session. # :api: public def errors @env[ENV_WARDEN_ERRORS] ||= Errors.new end # Points to a SessionSerializer instance responsible for handling # everything related with storing, fetching and removing the user # session. # :api: public def session_serializer @session_serializer ||= Warden::SessionSerializer.new(@env) end # Clear the cache of performed strategies so far. Warden runs each # strategy just once during the request lifecycle. You can clear the # strategies cache if you want to allow a strategy to be run more than # once. # # This method has the same API as authenticate, allowing you to clear # specific strategies for given scope: # # Parameters: # args - a list of symbols (labels) that name the strategies to attempt # opts - an options hash that contains the :scope of the user to check # # Example: # # Clear all strategies for the configured default_scope # env['warden'].clear_strategies_cache! # # # Clear all strategies for the :admin scope # env['warden'].clear_strategies_cache!(:scope => :admin) # # # Clear password strategy for the :admin scope # env['warden'].clear_strategies_cache!(:password, :scope => :admin) # # :api: public def clear_strategies_cache!(*args) scope, _opts = _retrieve_scope_and_opts(args) @winning_strategies.delete(scope) @strategies[scope].each do |k, v| v.clear! if args.empty? || args.include?(k) end end # Locks the proxy so new users cannot authenticate during the # request lifecycle. This is useful when the request cannot # be verified (for example, using a CSRF verification token). # Notice that already authenticated users are kept as so. # # :api: public def lock! @locked = true end # Run the authentication strategies for the given strategies. # If there is already a user logged in for a given scope, the strategies are not run # This does not halt the flow of control and is a passive attempt to authenticate only # When scope is not specified, the default_scope is assumed. # # Parameters: # args - a list of symbols (labels) that name the strategies to attempt # opts - an options hash that contains the :scope of the user to check # # Example: # env['warden'].authenticate(:password, :basic, :scope => :sudo) # # :api: public def authenticate(*args) user, _opts = _perform_authentication(*args) user end # Same API as authenticated, but returns a boolean instead of a user. # The difference between this method (authenticate?) and authenticated? # is that the former will run strategies if the user has not yet been # authenticated, and the second relies on already performed ones. # :api: public def authenticate?(*args) result = !!authenticate(*args) yield if result && block_given? result end # The same as +authenticate+ except on failure it will throw an :warden symbol causing the request to be halted # and rendered through the +failure_app+ # # Example # env['warden'].authenticate!(:password, :scope => :publisher) # throws if it cannot authenticate # # :api: public def authenticate!(*args) user, opts = _perform_authentication(*args) throw(:warden, opts) unless user user end # Check to see if there is an authenticated user for the given scope. # This brings the user from the session, but does not run strategies before doing so. # If you want strategies to be run, please check authenticate?. # # Parameters: # scope - the scope to check for authentication. Defaults to default_scope # # Example: # env['warden'].authenticated?(:admin) # # :api: public def authenticated?(scope = @config.default_scope) result = !!user(scope) yield if block_given? && result result end # Same API as authenticated?, but returns false when authenticated. # :api: public def unauthenticated?(scope = @config.default_scope) result = !authenticated?(scope) yield if block_given? && result result end # Manually set the user into the session and auth proxy # # Parameters: # user - An object that has been setup to serialize into and out of the session. # 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). # # :api: public def set_user(user, opts = {}) scope = (opts[:scope] ||= @config.default_scope) # Get the default options from the master configuration for the given scope opts = (@config[:scope_defaults][scope] || {}).merge(opts) opts[:event] ||= :set_user @users[scope] = user if opts[:store] != false && opts[:event] != :fetch options = env[ENV_SESSION_OPTIONS] if options if options.frozen? env[ENV_SESSION_OPTIONS] = options.merge(:renew => true).freeze else options[:renew] = true end end session_serializer.store(user, scope) end run_callbacks = opts.fetch(:run_callbacks, true) manager._run_callbacks(:after_set_user, user, self, opts) if run_callbacks @users[scope] end # Provides access to the user object in a given scope for a request. # Will be nil if not logged in. Please notice that this method does not # perform strategies. # # Example: # # without scope (default user) # env['warden'].user # # # with scope # env['warden'].user(:admin) # # # as a Hash # env['warden'].user(:scope => :admin) # # # with default scope and run_callbacks option # env['warden'].user(:run_callbacks => false) # # # with a scope and run_callbacks option # env['warden'].user(:scope => :admin, :run_callbacks => true) # # :api: public def user(argument = {}) opts = argument.is_a?(Hash) ? argument : { :scope => argument } scope = (opts[:scope] ||= @config.default_scope) if @users.has_key?(scope) @users[scope] else unless user = session_serializer.fetch(scope) run_callbacks = opts.fetch(:run_callbacks, true) manager._run_callbacks(:after_failed_fetch, user, self, :scope => scope) if run_callbacks end @users[scope] = user ? set_user(user, opts.merge(:event => :fetch)) : nil end end # Provides a scoped session data for authenticated users. # Warden manages clearing out this data when a user logs out # # Example # # default scope # env['warden'].session[:foo] = "bar" # # # :sudo scope # env['warden'].session(:sudo)[:foo] = "bar" # # :api: public def session(scope = @config.default_scope) raise NotAuthenticated, "#{scope.inspect} user is not logged in" unless authenticated?(scope) raw_session["warden.user.#{scope}.session"] ||= {} end # Provides logout functionality. # The logout also manages any authenticated data storage and clears it when a user logs out. # # Parameters: # scopes - a list of scopes to logout # # Example: # # Logout everyone and clear the session # env['warden'].logout # # # Logout the default user but leave the rest of the session alone # env['warden'].logout(:default) # # # Logout the :publisher and :admin user # env['warden'].logout(:publisher, :admin) # # :api: public def logout(*scopes) if scopes.empty? scopes = @users.keys reset_session = true end scopes.each do |scope| user = @users.delete(scope) manager._run_callbacks(:before_logout, user, self, :scope => scope) raw_session.delete("warden.user.#{scope}.session") unless raw_session.nil? session_serializer.delete(scope, user) end reset_session! if reset_session end # proxy methods through to the winning strategy # :api: private def result # :nodoc: winning_strategy && winning_strategy.result end # Proxy through to the authentication strategy to find out the message that was generated. # :api: public def message winning_strategy && winning_strategy.message end # Provides a way to return a 401 without warden deferring to the failure app # The result is a direct passthrough of your own response # :api: public def custom_failure! @custom_failure = true end # Check to see if the custom failure flag has been set # :api: public def custom_failure? if instance_variable_defined?(:@custom_failure) !!@custom_failure else false end end # Check to see if this is an asset request # :api: public def asset_request? ::Warden::asset_paths.any? { |r| env['PATH_INFO'].to_s.match(r) } end def inspect(*args) "Warden::Proxy:#{object_id} @config=#{@config.inspect}" end def to_s(*args) inspect(*args) end private def _perform_authentication(*args) scope, opts = _retrieve_scope_and_opts(args) user = nil # 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. return user, opts if user = user(opts.merge(:scope => scope)) _run_strategies_for(scope, args) if winning_strategy && winning_strategy.successful? opts[:store] = opts.fetch(:store, winning_strategy.store?) set_user(winning_strategy.user, opts.merge!(:event => :authentication)) end [@users[scope], opts] end def _retrieve_scope_and_opts(args) #:nodoc: opts = args.last.is_a?(Hash) ? args.pop : {} scope = opts[:scope] || @config.default_scope opts = (@config[:scope_defaults][scope] || {}).merge(opts) [scope, opts] end # Run the strategies for a given scope def _run_strategies_for(scope, args) #:nodoc: self.winning_strategy = @winning_strategies[scope] return if winning_strategy && winning_strategy.halted? # Do not run any strategy if locked return if @locked if args.empty? defaults = @config[:default_strategies] strategies = defaults[scope] || defaults[:_all] end (strategies || args).each do |name| strategy = _fetch_strategy(name, scope) next unless strategy && !strategy.performed? && strategy.valid? strategy._run! self.winning_strategy = @winning_strategies[scope] = strategy break if strategy.halted? end end # Fetches strategies and keep them in a hash cache. def _fetch_strategy(name, scope) @strategies[scope][name] ||= if klass = Warden::Strategies[name] klass.new(@env, scope) elsif @config.silence_missing_strategies? nil else raise "Invalid strategy #{name}" end end end # Proxy end # Warden warden-1.2.8/lib/warden/session_serializer.rb000066400000000000000000000021401337340105400212660ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true module Warden class SessionSerializer attr_reader :env 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 method_name = "#{scope}_serialize" specialized = respond_to?(method_name) session[key_for(scope)] = specialized ? send(method_name, user) : serialize(user) end def fetch(scope) key = session[key_for(scope)] return nil unless key method_name = "#{scope}_deserialize" user = respond_to?(method_name) ? send(method_name, key) : 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 # We can't cache this result because the session can be lazy loaded def session env["rack.session"] || {} end end # SessionSerializer end # Warden warden-1.2.8/lib/warden/strategies.rb000066400000000000000000000023531337340105400175320ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true module Warden module Strategies class << self # Add a strategy and store it in a hash. def add(label, strategy = nil, &block) strategy ||= Class.new(Warden::Strategies::Base) strategy.class_eval(&block) if block_given? unless strategy.method_defined?(:authenticate!) raise NoMethodError, "authenticate! is not declared in the #{label.inspect} strategy" end base = Warden::Strategies::Base unless strategy.ancestors.include?(base) raise "#{label.inspect} is not a #{base}" end _strategies[label] = strategy end # Update a previously given strategy. def update(label, &block) strategy = _strategies[label] raise "Unknown strategy #{label.inspect}" unless strategy add(label, strategy, &block) end # Provides access to strategies by label # :api: public def [](label) _strategies[label] end # Clears all declared. # :api: public def clear! _strategies.clear end # :api: private def _strategies @strategies ||= {} end end # << self end # Strategies end # Warden warden-1.2.8/lib/warden/strategies/000077500000000000000000000000001337340105400172025ustar00rootroot00000000000000warden-1.2.8/lib/warden/strategies/base.rb000066400000000000000000000134511337340105400204450ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true module Warden module Strategies # A strategy is a place where you can put logic related to authentication. Any strategy inherits # from Warden::Strategies::Base. # # The Warden::Strategies.add method is a simple way to provide custom strategies. # You _must_ declare an @authenticate!@ method. # You _may_ provide a @valid?@ method. # The valid method should return true or false depending on if the strategy is a valid one for the request. # # The parameters for Warden::Strategies.add method are: # The label is the name given to a strategy. Use the label to refer to the strategy when authenticating # The optional strategy argument if set _must_ be a class that inherits from Warden::Strategies::Base and _must_ # implement an @authenticate!@ method # The block acts as a convenient way to declare your strategy. Inside is the class definition of a strategy. # # Examples: # # Block Declared Strategy: # Warden::Strategies.add(:foo) do # def authenticate! # # authentication logic # end # end # # Class Declared Strategy: # Warden::Strategies.add(:foo, MyStrategy) # class Base # :api: public attr_accessor :user, :message # :api: private attr_accessor :result, :custom_response # :api: public attr_reader :env, :scope, :status include ::Warden::Mixins::Common # :api: private def initialize(env, scope=nil) # :nodoc: @env, @scope = env, scope @status, @headers = nil, {} @halted, @performed = false, false end # The method that is called from above. This method calls the underlying authenticate! method # :api: private def _run! # :nodoc: @performed = true authenticate! self end # Returns if this strategy was already performed. # :api: private def performed? #:nodoc: @performed end # Marks this strategy as not performed. # :api: private def clear! @performed = false end # Acts as a guarding method for the strategy. # If #valid? responds false, the strategy will not be executed # Overwrite with your own logic # :api: overwritable def valid?; true; end # Provides access to the headers hash for setting custom headers # :api: public def headers(header = {}) @headers ||= {} @headers.merge! header @headers end # Access to the errors object. # :api: public def errors @env['warden'].errors end # Cause the processing of the strategies to stop and cascade no further # :api: public def halt! @halted = true end # Checks to see if a strategy was halted # :api: public def halted? !!@halted end # Checks to see if a strategy should result in a permanent login # :api: public def store? true end # A simple method to return from authenticate! if you want to ignore this strategy # :api: public def pass; end # Returns true only if the result is a success and a user was assigned. def successful? @result == :success && !user.nil? end # Whenever you want to provide a user object as "authenticated" use the +success!+ method. # This will halt the strategy, and set the user in the appropriate scope. # It is the "login" method # # Parameters: # user - The user object to login. This object can be anything you have setup to serialize in and out of the session # # :api: public def success!(user, message = nil) halt! @user = user @message = message @result = :success end # This causes the strategy to fail. It does not throw an :warden symbol to drop the request out to the failure application # You must throw an :warden symbol somewhere in the application to enforce this # Halts the strategies so that this is the last strategy checked # :api: public def fail!(message = "Failed to Login") halt! @message = message @result = :failure end # Causes the strategy to fail, but not halt. The strategies will cascade after this failure and warden will check the next strategy. The last strategy to fail will have it's message displayed. # :api: public def fail(message = "Failed to Login") @message = message @result = :failure end # Causes the authentication to redirect. An :warden symbol must be thrown to actually execute this redirect # # Parameters: # url - The string representing the URL to be redirected to # params - Any parameters to encode into the URL # opts - Any options to redirect with. # available options: permanent => (true || false) # # :api: public def redirect!(url, params = {}, opts = {}) halt! @status = opts[:permanent] ? 301 : 302 headers["Location"] = url.dup headers["Location"] << "?" << Rack::Utils.build_query(params) unless params.empty? headers["Content-Type"] = opts[:content_type] || 'text/plain' @message = opts[:message] || "You are being redirected to #{headers["Location"]}" @result = :redirect headers["Location"] end # Return a custom rack array. You must throw an :warden symbol to activate this # :api: public def custom!(response) halt! @custom_response = response @result = :custom end end # Base end # Strategies end # Warden warden-1.2.8/lib/warden/test/000077500000000000000000000000001337340105400160075ustar00rootroot00000000000000warden-1.2.8/lib/warden/test/helpers.rb000066400000000000000000000022431337340105400177770ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true module Warden module Test # A collection of test helpers for testing full stack rack applications using Warden # These provide the ability to login and logout on any given request # Note: During the teardown phase of your specs you should include: Warden.test_reset! module Helpers def self.included(_base) ::Warden.test_mode! end # A helper method that will perform a login of a user in warden for the next request. # Provide it the same options as you would to Warden::Proxy#set_user # @see Warden::Proxy#set_user # @api public def login_as(user, opts = {}) Warden.on_next_request do |proxy| opts[:event] ||= :authentication proxy.set_user(user, opts) end end # Logs out a user from the session. # Without arguments, all users will be logged out # Provide a list of scopes to only log out users with that scope. # @see Warden::Proxy#logout # @api public def logout(*scopes) Warden.on_next_request do |proxy| proxy.logout(*scopes) end end end end end warden-1.2.8/lib/warden/test/mock.rb000066400000000000000000000031331337340105400172650ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true require 'rack' module Warden module Test # A mock of an application to get a Warden object to test on # Note: During the teardown phase of your specs you should include: Warden.test_reset! module Mock def self.included(_base) ::Warden.test_mode! end # A helper method that provides the warden object by mocking the env variable. # @api public def warden @warden ||= begin env['warden'] end end private def env @env ||= begin request = Rack::MockRequest.env_for( "/?#{Rack::Utils.build_query({})}", { 'HTTP_VERSION' => '1.1', 'REQUEST_METHOD' => 'GET' } ) app.call(request) request end end def app @app ||= begin opts = { failure_app: lambda { |_e| [401, { 'Content-Type' => 'text/plain' }, ['You Fail!']] }, default_strategies: :password, default_serializers: :session } Rack::Builder.new do use Warden::Test::Mock::Session use Warden::Manager, opts, &proc {} run lambda { |_e| [200, { 'Content-Type' => 'text/plain' }, ['You Win']] } end end end class Session attr_accessor :app def initialize(app, _configs={}) @app = app end def call(e) e['rack.session'] ||= {} @app.call(e) end end # session end end end warden-1.2.8/lib/warden/test/warden_helpers.rb000066400000000000000000000021241337340105400213350ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true module Warden module Test module WardenHelpers # Returns list of regex objects that match paths expected to be an asset # @see Warden::Proxy#asset_request? # @api public def asset_paths @asset_paths ||= [/^\/assets\//] end # Sets list of regex objects that match paths expected to be an asset # @see Warden::Proxy#asset_request? # @api public def asset_paths=(*vals) @asset_paths = vals end # Adds a block to be executed on the next request when the stack reaches warden. # The warden proxy is yielded to the block # @api public def on_next_request(&blk) _on_next_request << blk end # resets wardens tests # any blocks queued to execute will be removed # @api public def test_reset! _on_next_request.clear end # A container for the on_next_request items. # @api private def _on_next_request @_on_next_request ||= [] @_on_next_request end end end end warden-1.2.8/lib/warden/version.rb000066400000000000000000000001261337340105400170410ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true module Warden VERSION = "1.2.8" end warden-1.2.8/spec/000077500000000000000000000000001337340105400137345ustar00rootroot00000000000000warden-1.2.8/spec/helpers/000077500000000000000000000000001337340105400153765ustar00rootroot00000000000000warden-1.2.8/spec/helpers/request_helper.rb000066400000000000000000000025441337340105400207570ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true module Warden::Spec module Helpers FAILURE_APP = lambda{|_e|[401, {"Content-Type" => "text/plain"}, ["You Fail!"]] } def env_with_params(path = "/", params = {}, env = {}) method = params.delete(:method) || "GET" env = { 'HTTP_VERSION' => '1.1', 'REQUEST_METHOD' => "#{method}" }.merge(env) Rack::MockRequest.env_for("#{path}?#{Rack::Utils.build_query(params)}", env) end def setup_rack(app = nil, opts = {}, &block) app ||= block if block_given? opts[:failure_app] ||= failure_app opts[:default_strategies] ||= [:password] opts[:default_serializers] ||= [:session] blk = opts[:configurator] || proc{} Rack::Builder.new do use opts[:session] || Warden::Spec::Helpers::Session unless opts[:nil_session] use Warden::Manager, opts, &blk run app end end def valid_response Rack::Response.new("OK").finish end def failure_app Warden::Spec::Helpers::FAILURE_APP end def success_app lambda{|e| [200, {"Content-Type" => "text/plain"}, ["You Win"]]} end class Session attr_accessor :app def initialize(app,configs = {}) @app = app end def call(e) e['rack.session'] ||= {} @app.call(e) end end # session end end warden-1.2.8/spec/helpers/strategies/000077500000000000000000000000001337340105400175505ustar00rootroot00000000000000warden-1.2.8/spec/helpers/strategies/fail_with_user.rb000066400000000000000000000004171337340105400231030ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true Warden::Strategies.add(:fail_with_user) do def authenticate! request.env['warden.spec.strategies'] ||= [] request.env['warden.spec.strategies'] << :fail_with_user self.user = 'Valid User' fail! end end warden-1.2.8/spec/helpers/strategies/failz.rb000066400000000000000000000004041337340105400212000ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true Warden::Strategies.add(:failz) do def authenticate! request.env['warden.spec.strategies'] ||= [] request.env['warden.spec.strategies'] << :failz fail!("The Fails Strategy Has Failed You") end end warden-1.2.8/spec/helpers/strategies/invalid.rb000066400000000000000000000002171337340105400215230ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true Warden::Strategies.add(:invalid) do def valid? false end def authenticate!; end end warden-1.2.8/spec/helpers/strategies/pass.rb000066400000000000000000000004051337340105400210420ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true Warden::Strategies.add(:pass) do def authenticate! request.env['warden.spec.strategies'] ||= [] request.env['warden.spec.strategies'] << :pass success!("Valid User") unless scope == :failz end end warden-1.2.8/spec/helpers/strategies/pass_with_message.rb000066400000000000000000000005101337340105400235760ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true Warden::Strategies.add(:pass_with_message) do def authenticate! request.env['warden.spec.strategies'] ||= [] request.env['warden.spec.strategies'] << :pass_with_message success!("Valid User", "The Success Strategy Has Accepted You") unless scope == :failz end end warden-1.2.8/spec/helpers/strategies/password.rb000066400000000000000000000007021337340105400217360ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true Warden::Strategies.add(:password) do def authenticate! request.env['warden.spec.strategies'] ||= [] request.env['warden.spec.strategies'] << :password if params["password"] || params["username"] params["password"] == "sekrit" && params["username"] == "fred" ? success!("Authenticated User") : fail!("Username or password is incorrect") else pass end end end warden-1.2.8/spec/helpers/strategies/single.rb000066400000000000000000000004201337340105400213520ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true Warden::Strategies.add(:single) do def authenticate! request.env['warden.spec.strategies'] ||= [] request.env['warden.spec.strategies'] << :single success!("Valid User") end def store? false end end warden-1.2.8/spec/spec_helper.rb000066400000000000000000000011511337340105400165500ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true $TESTING=true $:.unshift File.join(File.dirname(__FILE__), '..', 'lib') $:.unshift File.expand_path(File.join(File.dirname(__FILE__))) require 'warden' require 'rubygems' require 'rack' Dir[File.join(File.dirname(__FILE__), "helpers", "**/*.rb")].each do |f| require f end RSpec.configure do |config| config.include(Warden::Spec::Helpers) config.include(Warden::Test::Helpers) config.include(Warden::Test::Mock) def load_strategies Dir[File.join(File.dirname(__FILE__), "helpers", "strategies", "**/*.rb")].each do |f| load f end end end warden-1.2.8/spec/warden/000077500000000000000000000000001337340105400152145ustar00rootroot00000000000000warden-1.2.8/spec/warden/authenticated_data_store_spec.rb000066400000000000000000000073271337340105400236130ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true RSpec.describe "authenticated data store" do before(:each) do @env = env_with_params @env['rack.session'] = { "warden.user.foo.key" => "foo user", "warden.user.default.key" => "default user", :foo => "bar" } end it "should store data for the default scope" do app = lambda do |e| e['warden'].authenticate(:pass) e['warden'].authenticate(:pass, :scope => :foo) expect(e['warden']).to be_authenticated expect(e['warden']).to be_authenticated(:foo) # Store the data for :default e['warden'].session[:key] = "value" valid_response end setup_rack(app).call(@env) expect(@env['rack.session']['warden.user.default.session']).to eq(key: "value") expect(@env['rack.session']['warden.user.foo.session']).to be_nil end it "should store data for the foo user" do app = lambda do |e| e['warden'].session(:foo)[:key] = "value" valid_response end setup_rack(app).call(@env) expect(@env['rack.session']['warden.user.foo.session']).to eq(key: "value") end it "should store the data separately" do app = lambda do |e| e['warden'].session[:key] = "value" e['warden'].session(:foo)[:key] = "another value" valid_response end setup_rack(app).call(@env) expect(@env['rack.session']['warden.user.default.session']).to eq(key: "value") expect(@env['rack.session']['warden.user.foo.session' ]).to eq(key: "another value") end it "should clear the foo scoped data when foo logs out" do app = lambda do |e| e['warden'].session[:key] = "value" e['warden'].session(:foo)[:key] = "another value" e['warden'].logout(:foo) valid_response end setup_rack(app).call(@env) expect(@env['rack.session']['warden.user.default.session']).to eq(key: "value") expect(@env['rack.session']['warden.user.foo.session' ]).to be_nil end it "should clear out the default data when :default logs out" do app = lambda do |e| e['warden'].session[:key] = "value" e['warden'].session(:foo)[:key] = "another value" e['warden'].logout(:default) valid_response end setup_rack(app).call(@env) expect(@env['rack.session']['warden.user.default.session']).to be_nil expect(@env['rack.session']['warden.user.foo.session' ]).to eq(key: "another value") end it "should clear out all data when a general logout is performed" do app = lambda do |e| e['warden'].session[:key] = "value" e['warden'].session(:foo)[:key] = "another value" e['warden'].logout valid_response end setup_rack(app).call(@env) expect(@env['rack.session']['warden.user.default.session']).to be_nil expect(@env['rack.session']['warden.user.foo.session' ]).to be_nil end it "should logout multiple persons at once" do @env['rack.session']['warden.user.bar.key'] = "bar user" app = lambda do |e| e['warden'].session[:key] = "value" e['warden'].session(:foo)[:key] = "another value" e['warden'].session(:bar)[:key] = "yet another" e['warden'].logout(:bar, :default) valid_response end setup_rack(app).call(@env) expect(@env['rack.session']['warden.user.default.session']).to be_nil expect(@env['rack.session']['warden.user.foo.session' ]).to eq(key: "another value") expect(@env['rack.session']['warden.user.bar.session' ]).to be_nil end it "should not store data for a user who is not logged in" do @env['rack.session'] app = lambda do |e| e['warden'].session(:not_here)[:key] = "value" valid_response end expect { setup_rack(app).call(@env) }.to raise_error(Warden::NotAuthenticated) end end warden-1.2.8/spec/warden/config_spec.rb000066400000000000000000000025321337340105400200220ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true RSpec.describe Warden::Config do before(:each) do @config = Warden::Config.new end it "should behave like a hash" do @config[:foo] = :bar expect(@config[:foo]).to eq(:bar) end it "should provide hash accessors" do @config.failure_app = :foo expect(@config[:failure_app]).to eq(:foo) @config[:failure_app] = :bar expect(@config.failure_app).to eq(:bar) end it "should allow to read and set default strategies" do @config.default_strategies :foo, :bar expect(@config.default_strategies).to eq([:foo, :bar]) end it "should allow to silence missing strategies" do @config.silence_missing_strategies! expect(@config.silence_missing_strategies?).to eq(true) end it "should set the default_scope" do expect(@config.default_scope).to eq(:default) @config.default_scope = :foo expect(@config.default_scope).to eq(:foo) end it "should merge given options on initialization" do expect(Warden::Config.new(:foo => :bar)[:foo]).to eq(:bar) end it "should setup defaults with the scope_defaults method" do c = Warden::Config.new c.scope_defaults :foo, :strategies => [:foo, :bar], :store => false expect(c.default_strategies(:scope => :foo)).to eq([:foo, :bar]) expect(c.scope_defaults(:foo)).to eq(store: false) end end warden-1.2.8/spec/warden/errors_spec.rb000066400000000000000000000023761337340105400200770ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true RSpec.describe Warden::Proxy::Errors do before(:each) do @errors = Warden::Proxy::Errors.new end it "should report that it is empty on first creation" do expect(@errors).to be_empty end it "should continue to report that it is empty even after being checked" do @errors.on(:foo) expect(@errors).to be_empty end it "should add an error" do @errors.add(:login, "Login or password incorrect") expect(@errors[:login]).to eq(["Login or password incorrect"]) end it "should allow many errors to be added to the same field" do @errors.add(:login, "bad 1") @errors.add(:login, "bad 2") expect(@errors.on(:login)).to eq(["bad 1", "bad 2"]) end it "should give the full messages for an error" do @errors.add(:login, "login wrong") @errors.add(:password, "password wrong") ["password wrong", "login wrong"].each do |msg| expect(@errors.full_messages).to include(msg) end end it "should return the error for a specific field / label" do @errors.add(:login, "wrong") expect(@errors.on(:login)).to eq(["wrong"]) end it "should return nil for a specific field if it's not been set" do expect(@errors.on(:not_there)).to be_nil end end warden-1.2.8/spec/warden/hooks_spec.rb000066400000000000000000000314341337340105400177030ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true RSpec.describe "standard authentication hooks" do before(:all) do load_strategies end describe "after_set_user" do before(:each) do RAM = Warden::Manager unless defined?(RAM) RAM._after_set_user.clear end after(:each) do RAM._after_set_user.clear end it "should allow me to add an after_set_user hook" do RAM.after_set_user do |user, auth, opts| "boo" end expect(RAM._after_set_user.length).to eq(1) end it "should allow me to add multiple after_set_user hooks" do RAM.after_set_user{|user, auth, opts| "foo"} RAM.after_set_user{|u,a| "bar"} expect(RAM._after_set_user.length).to eq(2) end it "should run each after_set_user hook after the user is set" do RAM.after_set_user{|u,a,o| a.env['warden.spec.hook.foo'] = "run foo"} RAM.after_set_user{|u,a,o| a.env['warden.spec.hook.bar'] = "run bar"} RAM.after_set_user{|u,a,o| a.logout} app = lambda do |e| e['warden'].set_user("foo") valid_response end env = env_with_params setup_rack(app).call(env) expect(env['warden'].user).to be_nil expect(env['warden.spec.hook.foo']).to eq("run foo") expect(env['warden.spec.hook.bar']).to eq("run bar") end it "should not run the event specified with except" do RAM.after_set_user(:except => :set_user){|u,a,o| fail} app = lambda do |e| e['warden'].set_user("foo") valid_response end env = env_with_params setup_rack(app).call(env) end it "should only run the event specified with only" do RAM.after_set_user(:only => :set_user){|u,a,o| fail} app = lambda do |e| e['warden'].authenticate(:pass) valid_response end env = env_with_params setup_rack(app).call(env) end it "should run filters in the given order" do RAM.after_set_user{|u,a,o| a.env['warden.spec.order'] << 2} RAM.after_set_user{|u,a,o| a.env['warden.spec.order'] << 3} RAM.prepend_after_set_user{|u,a,o| a.env['warden.spec.order'] << 1} app = lambda do |e| e['warden.spec.order'] = [] e['warden'].set_user("foo") valid_response end env = env_with_params setup_rack(app).call(env) expect(env['warden.spec.order']).to eq([1,2,3]) end context "after_authentication" do it "should be a wrapper to after_set_user behavior" do RAM.after_authentication{|u,a,o| a.env['warden.spec.hook.baz'] = "run baz"} RAM.after_authentication{|u,a,o| a.env['warden.spec.hook.paz'] = "run paz"} RAM.after_authentication{|u,a,o| expect(o[:event]).to eq(:authentication) } app = lambda do |e| e['warden'].authenticate(:pass) valid_response end env = env_with_params setup_rack(app).call(env) expect(env['warden.spec.hook.baz']).to eq('run baz') expect(env['warden.spec.hook.paz']).to eq('run paz') end it "should not be invoked on default after_set_user scenario" do RAM.after_authentication{|u,a,o| fail} app = lambda do |e| e['warden'].set_user("foo") valid_response end env = env_with_params setup_rack(app).call(env) end it "should run filters in the given order" do RAM.after_authentication{|u,a,o| a.env['warden.spec.order'] << 2} RAM.after_authentication{|u,a,o| a.env['warden.spec.order'] << 3} RAM.prepend_after_authentication{|u,a,o| a.env['warden.spec.order'] << 1} app = lambda do |e| e['warden.spec.order'] = [] e['warden'].authenticate(:pass) valid_response end env = env_with_params setup_rack(app).call(env) expect(env['warden.spec.order']).to eq([1,2,3]) end it "should allow me to log out a user in an after_set_user block" do RAM.after_set_user{|u,a,o| a.logout} app = lambda do |e| e['warden'].authenticate(:pass) valid_response end env = env_with_params setup_rack(app).call(env) expect(env['warden']).not_to be_authenticated end end context "after_fetch" do it "should be a wrapper to after_set_user behavior" do RAM.after_fetch{|u,a,o| a.env['warden.spec.hook.baz'] = "run baz"} RAM.after_fetch{|u,a,o| a.env['warden.spec.hook.paz'] = "run paz"} RAM.after_fetch{|u,a,o| expect(o[:event]).to eq(:fetch) } env = env_with_params setup_rack(lambda { |e| valid_response }).call(env) env['rack.session']['warden.user.default.key'] = "Foo" expect(env['warden'].user).to eq("Foo") expect(env['warden.spec.hook.baz']).to eq('run baz') expect(env['warden.spec.hook.paz']).to eq('run paz') end it "should not be invoked on default after_set_user scenario" do RAM.after_fetch{|u,a,o| fail} app = lambda do |e| e['warden'].set_user("foo") valid_response end env = env_with_params setup_rack(app).call(env) end it "should not be invoked if fetched user is nil" do RAM.after_fetch{|u,a,o| fail} env = env_with_params setup_rack(lambda { |e| valid_response }).call(env) env['rack.session']['warden.user.default.key'] = nil expect(env['warden'].user).to be_nil end it "should run filters in the given order" do RAM.after_fetch{|u,a,o| a.env['warden.spec.order'] << 2} RAM.after_fetch{|u,a,o| a.env['warden.spec.order'] << 3} RAM.prepend_after_fetch{|u,a,o| a.env['warden.spec.order'] << 1} app = lambda do |e| e['warden.spec.order'] = [] e['rack.session']['warden.user.default.key'] = "Foo" e['warden'].user valid_response end env = env_with_params setup_rack(app).call(env) expect(env['warden.spec.order']).to eq([1,2,3]) end end end describe "after_failed_fetch" do before(:each) do RAM = Warden::Manager unless defined?(RAM) RAM._after_failed_fetch.clear end after(:each) do RAM._after_failed_fetch.clear end it "should not be called when user is fetched" do RAM.after_failed_fetch{|u,a,o| fail } env = env_with_params setup_rack(lambda { |e| valid_response }).call(env) env['rack.session']['warden.user.default.key'] = "Foo" expect(env['warden'].user).to eq("Foo") end it "should be called if fetched user is nil" do calls = 0 RAM.after_failed_fetch{|u,a,o| calls += 1 } env = env_with_params setup_rack(lambda { |e| valid_response }).call(env) expect(env['warden'].user).to be_nil expect(calls).to eq(1) end end describe "before_failure" do before(:each) do RAM = Warden::Manager unless defined?(RAM) RAM._before_failure.clear end after(:each) do RAM._before_failure.clear end it "should allow me to add a before_failure hook" do RAM.before_failure{|env, opts| "foo"} expect(RAM._before_failure.length).to eq(1) end it "should allow me to add multiple before_failure hooks" do RAM.before_failure{|env, opts| "foo"} RAM.before_failure{|env, opts| "bar"} expect(RAM._before_failure.length).to eq(2) end it "should run each before_failure hooks before failing" do RAM.before_failure{|e,o| e['warden.spec.before_failure.foo'] = "foo"} RAM.before_failure{|e,o| e['warden.spec.before_failure.bar'] = "bar"} app = lambda{|e| e['warden'].authenticate!(:failz); valid_response} env = env_with_params setup_rack(app).call(env) expect(env['warden.spec.before_failure.foo']).to eq("foo") expect(env['warden.spec.before_failure.bar']).to eq("bar") end it "should run filters in the given order" do RAM.before_failure{|e,o| e['warden.spec.order'] << 2} RAM.before_failure{|e,o| e['warden.spec.order'] << 3} RAM.prepend_before_failure{|e,o| e['warden.spec.order'] << 1} app = lambda do |e| e['warden.spec.order'] = [] e['warden'].authenticate!(:failz) valid_response end env = env_with_params setup_rack(app).call(env) expect(env['warden.spec.order']).to eq([1,2,3]) end end describe "before_logout" do before(:each) do RAM = Warden::Manager unless defined?(RAM) RAM._before_logout.clear end after(:each) do RAM._before_logout.clear end it "should allow me to add an before_logout hook" do RAM.before_logout{|user, auth, scopes| "foo"} expect(RAM._before_logout.length).to eq(1) end it "should allow me to add multiple after_authentication hooks" do RAM.before_logout{|u,a,o| "bar"} RAM.before_logout{|u,a,o| "baz"} expect(RAM._before_logout.length).to eq(2) end it "should run each before_logout hook before logout is run" do RAM.before_logout{|u,a,o| a.env['warden.spec.hook.lorem'] = "run lorem"} RAM.before_logout{|u,a,o| a.env['warden.spec.hook.ipsum'] = "run ipsum"} app = lambda{|e| e['warden'].authenticate(:pass); valid_response} env = env_with_params setup_rack(app).call(env) env['warden'].logout expect(env['warden.spec.hook.lorem']).to eq('run lorem') expect(env['warden.spec.hook.ipsum']).to eq('run ipsum') end it "should run before_logout hook for a specified scope" do RAM.before_logout(:scope => :scope1){|u,a,o| a.env["warden.spec.hook.a"] << :scope1 } RAM.before_logout(:scope => [:scope2]){|u,a,o| a.env["warden.spec.hook.b"] << :scope2 } app = lambda do |e| e['warden'].authenticate(:pass, :scope => :scope1) e['warden'].authenticate(:pass, :scope => :scope2) valid_response end env = env_with_params env["warden.spec.hook.a"] ||= [] env["warden.spec.hook.b"] ||= [] setup_rack(app).call(env) env['warden'].logout(:scope1) expect(env['warden.spec.hook.a']).to eq([:scope1]) expect(env['warden.spec.hook.b']).to eq([]) env['warden'].logout(:scope2) expect(env['warden.spec.hook.a']).to eq([:scope1]) expect(env['warden.spec.hook.b']).to eq([:scope2]) end it "should run filters in the given order" do RAM.before_logout{|u,a,o| a.env['warden.spec.order'] << 2} RAM.before_logout{|u,a,o| a.env['warden.spec.order'] << 3} RAM.prepend_before_logout{|u,a,o| a.env['warden.spec.order'] << 1} app = lambda do |e| e['warden.spec.order'] = [] e['warden'].authenticate(:pass) e['warden'].logout valid_response end env = env_with_params setup_rack(app).call(env) expect(env['warden.spec.order']).to eq([1,2,3]) end end describe "on_request" do before(:each) do RAM = Warden::Manager unless defined?(RAM) @old_on_request = RAM._on_request.dup RAM._on_request.clear end after(:each) do RAM._on_request.clear RAM._on_request.replace(@old_on_request) end it "should allow me to add an on_request hook" do RAM.on_request{|proxy| "foo"} expect(RAM._on_request.length).to eq(1) end it "should allow me to add multiple on_request hooks" do RAM.on_request{|proxy| "foo"} RAM.on_request{|proxy| "bar"} expect(RAM._on_request.length).to eq(2) end it "should run each on_request hooks when initializing" do RAM.on_request{|proxy| proxy.env['warden.spec.on_request.foo'] = "foo"} RAM.on_request{|proxy| proxy.env['warden.spec.on_request.bar'] = "bar"} app = lambda{|e| valid_response} env = env_with_params setup_rack(app).call(env) expect(env['warden.spec.on_request.foo']).to eq("foo") expect(env['warden.spec.on_request.bar']).to eq("bar") end it "should run filters in the given order" do RAM.on_request{|proxy| proxy.env['warden.spec.order'] << 2} RAM.on_request{|proxy| proxy.env['warden.spec.order'] << 3} RAM.prepend_on_request{|proxy| proxy.env['warden.spec.order'] << 1} app = lambda do |e| valid_response end env = Rack::MockRequest.env_for("/", "warden.spec.order" => []) setup_rack(app).call(env) expect(env['warden.spec.order']).to eq([1,2,3]) end it "should have the proxy on env in on_request" do warden = nil RAM.on_request{|proxy| warden = proxy.env['warden']} app = lambda{|e| valid_response} env = env_with_params setup_rack(app).call(env) expect(warden).to eq(env['warden']) end it "should be able to throw in on_request" do RAM.on_request{|proxy| throw :warden} app = lambda{|e| valid_response} env = env_with_params result = setup_rack(app).call(env) expect(result.first).to eq(401) end end end warden-1.2.8/spec/warden/manager_spec.rb000066400000000000000000000264441337340105400201770ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true RSpec.describe Warden::Manager do before(:all) do load_strategies end it "should insert a Proxy object into the rack env" do env = env_with_params setup_rack(success_app).call(env) expect(env["warden"]).to be_an_instance_of(Warden::Proxy) end describe "thrown auth" do before(:each) do @basic_app = lambda{|env| [200,{'Content-Type' => 'text/plain'},'OK']} @authd_app = lambda do |e| if e['warden'].authenticated? [200,{'Content-Type' => 'text/plain'},"OK"] else [401,{'Content-Type' => 'text/plain'},"Fail From The App"] end end @env = Rack::MockRequest. env_for('/', 'HTTP_VERSION' => '1.1', 'REQUEST_METHOD' => 'GET') end # before(:each) describe "Failure" do it "should respond with a 401 response if the strategy fails authentication" do env = env_with_params("/", :foo => "bar") app = lambda do |_env| _env['warden'].authenticate(:failz) throw(:warden, :action => :unauthenticated) end result = setup_rack(app, :failure_app => @fail_app).call(env) # TODO: What is @fail_app? expect(result.first).to eq(401) end it "should use the failure message given to the failure method" do env = env_with_params("/", {}) app = lambda do |_env| _env['warden'].authenticate(:failz) throw(:warden) end result = setup_rack(app, :failure_app => @fail_app).call(env) # TODO: What is @fail_app? expect(result.last).to eq(["You Fail!"]) end it "should set the message from the winning strategy in warden.options hash" do env = env_with_params("/", {}) app = lambda do |_env| _env['warden'].authenticate(:failz) throw(:warden) end setup_rack(app, :failure_app => @fail_app).call(env) # TODO: What is @fail_app? expect(env["warden.options"][:message]).to eq("The Fails Strategy Has Failed You") end it "should render the failure app when there's a failure" do app = lambda do |e| throw(:warden, :action => :unauthenticated) unless e['warden'].authenticated?(:failz) end fail_app = lambda do |e| [401, {"Content-Type" => "text/plain"}, ["Failure App"]] end result = setup_rack(app, :failure_app => fail_app).call(env_with_params) expect(result.last).to eq(["Failure App"]) end it "should call failure app if warden is thrown even after successful authentication" do env = env_with_params("/", {}) app = lambda do |_env| _env['warden'].authenticate(:pass) throw(:warden) end result = setup_rack(app, :failure_app => @fail_app).call(env) expect(result.first).to eq(401) expect(result.last).to eq(["You Fail!"]) end it "should set the attempted url in warden.options hash" do env = env_with_params("/access/path", {}) app = lambda do |_env| _env['warden'].authenticate(:pass) throw(:warden) end result = setup_rack(app, :failure_app => @fail_app).call(env) # TODO: What is @fail_app? expect(result.first).to eq(401) expect(env["warden.options"][:attempted_path]).to eq("/access/path") end it "should set action in warden.options if overridden" do env = env_with_params("/access/path", {}) app = lambda do |_env| _env['warden'].authenticate(:pass) throw(:warden, action: :different_action) end result = setup_rack(app, :failure_app => @fail_app).call(env) expect(result.first).to eq(401) expect(env["warden.options"][:action]).to eq(:different_action) end it "should catch a resubmitted request" do # this is a bit convoluted. but it's occurred in the field with Rack::OpenID $count = 0 $throw_count = 0 env = env_with_params("/foo") class ::ResubmittingMiddleware @@app = nil def initialize(app) @@app = app end def self.call(env) if $count > 1 Rack::Response.new("Bad", 401) else $count += 1 @@app.call(env) end end def call(env) $count += 1 @@app.call(env) end end app = lambda do |e| $throw_count += 1 throw(:warden) end builder = Rack::Builder.new do use ResubmittingMiddleware use Warden::Manager do |config| config.failure_app = ResubmittingMiddleware end run app end result = builder.to_app.call(env) expect(result[0]).to eq(401) expect(result[2].body).to eq(["Bad"]) expect($throw_count).to eq(2) end it "should use the default scopes action when a bare throw is used" do env = env_with_params("/", :foo => "bar") action = nil failure = lambda do |_env| action = _env['PATH_INFO'] [401, {}, ['fail']] end app = lambda do |_env| throw(:warden) end result = setup_rack(app, :failure_app => failure, :configurator => lambda{ |c| c.scope_defaults(:default, :action => 'my_action', :strategies => [:password]) } ).call(env) expect(action).to eq("/my_action") expect(result.first).to eq(401) end end # failure end describe "integrated strategies" do before(:each) do RAS = Warden::Strategies unless defined?(RAS) Warden::Strategies.clear! @app = setup_rack do |env| env['warden'].authenticate!(:foobar) [200, {"Content-Type" => "text/plain"}, ["Foo Is A Winna"]] end end describe "redirecting" do it "should redirect with a message" do RAS.add(:foobar) do def authenticate! redirect!("/foo/bar", {:foo => "bar"}, :message => "custom redirection message") end end result = @app.call(env_with_params) expect(result[0]).to be(302) expect(result[1]["Location"]).to eq("/foo/bar?foo=bar") expect(result[2]).to eq(["custom redirection message"]) end it "should redirect with a default message" do RAS.add(:foobar) do def authenticate! redirect!("/foo/bar", {:foo => "bar"}) end end result = @app.call(env_with_params) expect(result[0]).to eq(302) expect(result[1]['Location']).to eq("/foo/bar?foo=bar") expect(result[2]).to eq(["You are being redirected to /foo/bar?foo=bar"]) end it "should redirect with a permanent redirect" do RAS.add(:foobar) do def authenticate! redirect!("/foo/bar", {}, :permanent => true) end end result = @app.call(env_with_params) expect(result[0]).to eq(301) end it "should redirect with a content type" do RAS.add(:foobar) do def authenticate! redirect!("/foo/bar", {:foo => "bar"}, :content_type => "text/xml") end end result = @app.call(env_with_params) expect(result[0]).to eq(302) expect(result[1]["Location"]).to eq("/foo/bar?foo=bar") expect(result[1]["Content-Type"]).to eq("text/xml") end it "should redirect with a default content type" do RAS.add(:foobar) do def authenticate! redirect!("/foo/bar", {:foo => "bar"}) end end result = @app.call(env_with_params) expect(result[0]).to eq(302) expect(result[1]["Location"]).to eq("/foo/bar?foo=bar") expect(result[1]["Content-Type"]).to eq("text/plain") end end describe "failing" do it "should fail according to the failure app" do RAS.add(:foobar) do def authenticate! fail! end end env = env_with_params result = @app.call(env) expect(result[0]).to eq(401) expect(result[2]).to eq(["You Fail!"]) expect(env['PATH_INFO']).to eq("/unauthenticated") end it "should allow you to customize the response" do app = lambda do |e| e['warden'].custom_failure! [401,{'Content-Type' => 'text/plain'},["Fail From The App"]] end env = env_with_params result = setup_rack(app).call(env) expect(result[0]).to eq(401) expect(result[2]).to eq(["Fail From The App"]) end it "should allow you to customize the response without the explicit call to custom_failure! if not intercepting 401" do app = lambda do |e| [401,{'Content-Type' => 'text/plain'},["Fail From The App"]] end env = env_with_params result = setup_rack(app, :intercept_401 => false).call(env) expect(result[0]).to eq(401) expect(result[2]).to eq(["Fail From The App"]) end it "should render the failure application for a 401 if no custom_failure flag is set" do app = lambda do |e| [401,{'Content-Type' => 'text/plain'},["Fail From The App"]] end result = setup_rack(app).call(env_with_params) expect(result[0]).to eq(401) expect(result[2]).to eq(["You Fail!"]) end end # failing describe "custom rack response" do it "should return a custom rack response" do RAS.add(:foobar) do def authenticate! custom!([523, {"Content-Type" => "text/plain", "Custom-Header" => "foo"}, ["Custom Stuff"]]) end end result = @app.call(env_with_params) expect(result[0]).to be(523) expect(result[1]["Custom-Header"]).to eq("foo") expect(result[2]).to eq(["Custom Stuff"]) end end describe "app returns Rack::Response" do it "should return it" do RAS.add(:foobar) do def authenticate! custom!(Rack::Response.new(['body'], 201, {"Content-Type" => "text/plain"})) end end result = @app.call(env_with_params) expect(result.status).to eq(201) expect(result.body).to eq(['body']) expect(result.header['Content-Type']).to eq('text/plain') end end describe "success" do it "should pass through to the application when there is success" do RAS.add(:foobar) do def authenticate! success!("A User") end end env = env_with_params result = @app.call(env) expect(result[0]).to eq(200) expect(result[2]).to eq(["Foo Is A Winna"]) end end end # integrated strategies it "should allow me to set a different default scope for warden" do Rack::Builder.new do use Warden::Manager, :default_scope => :default do |manager| expect(manager.default_scope).to eq(:default) manager.default_scope = :other expect(manager.default_scope).to eq(:other) end end end it "should allow me to access strategies through manager" do Rack::Builder.new do use Warden::Manager do |manager| expect(manager.strategies).to eq(Warden::Strategies) end end end end warden-1.2.8/spec/warden/proxy_spec.rb000066400000000000000000001050021337340105400177320ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true RSpec.describe Warden::Proxy do before(:all) do load_strategies end before(:each) do @basic_app = lambda{|_env| [200,{'Content-Type' => 'text/plain'},'OK']} @authd_app = lambda do |e| e['warden'].authenticate if e['warden'].authenticated? [200,{'Content-Type' => 'text/plain'},"OK"] else [401,{'Content-Type' => 'text/plain'},"You Fail"] end end @env = env_with_params("/") end # before(:each) describe "authentication" do it "should not check the authentication if it is not checked" do app = setup_rack(@basic_app) expect(app.call(@env).first).to eq(200) end it "should check the authentication if it is explicitly checked" do app = setup_rack(@authd_app) expect(app.call(@env).first).to eq(401) end it "should not allow the request if incorrect conditions are supplied" do env = env_with_params("/", :foo => "bar") app = setup_rack(@authd_app) response = app.call(env) expect(response.first).to eq(401) end it "should allow the request if the correct conditions are supplied" do env = env_with_params("/", :username => "fred", :password => "sekrit") app = setup_rack(@authd_app) resp = app.call(env) expect(resp.first).to eq(200) end it "should allow authentication in my application" do env = env_with_params('/', :username => "fred", :password => "sekrit") app = lambda do |env| env['warden'].authenticate expect(env['warden']).to be_authenticated expect(env['warden.spec.strategies']).to eq([:password]) valid_response end setup_rack(app).call(env) end it "should allow me to select which strategies I use in my application" do env = env_with_params("/", :foo => "bar") app = lambda do |env| env['warden'].authenticate(:failz) expect(env['warden']).not_to be_authenticated expect(env['warden.spec.strategies']).to eq([:failz]) valid_response end setup_rack(app).call(env) end it "should raise error on missing strategies" do app = lambda do |env| env['warden'].authenticate(:unknown) end expect { setup_rack(app).call(@env) }.to raise_error(RuntimeError, "Invalid strategy unknown") end it "should raise error if the strategy failed" do app = lambda do |env| env['warden'].authenticate(:fail_with_user) expect(env['warden'].user).to be_nil valid_response end setup_rack(app).call(@env) end it "should not raise error on missing strategies if silencing" do app = lambda do |env| env['warden'].authenticate valid_response end expect { setup_rack(app, :silence_missing_strategies => true, :default_strategies => [:unknown]).call(@env) }.not_to raise_error end it "should allow me to get access to the user at warden.user." do app = lambda do |env| env['warden'].authenticate(:pass) expect(env['warden']).to be_authenticated expect(env['warden.spec.strategies']).to eq([:pass]) valid_response end setup_rack(app).call(@env) end it "should run strategies when authenticate? is asked" do app = lambda do |env| expect(env['warden']).not_to be_authenticated env['warden'].authenticate?(:pass) expect(env['warden']).to be_authenticated expect(env['warden.spec.strategies']).to eq([:pass]) valid_response end setup_rack(app).call(@env) end it "should properly send the scope to the strategy" do app = lambda do |env| env['warden'].authenticate(:pass, :scope => :failz) expect(env['warden']).not_to be_authenticated expect(env['warden.spec.strategies']).to eq([:pass]) valid_response end setup_rack(app).call(@env) end it "should try multiple authentication strategies" do app = lambda do |env| env['warden'].authenticate(:password,:pass) expect(env['warden']).to be_authenticated expect(env['warden.spec.strategies']).to eq([:password, :pass]) valid_response end setup_rack(app).call(@env) end it "should look for an active user in the session with authenticate" do app = lambda do |env| env['rack.session']["warden.user.default.key"] = "foo as a user" env['warden'].authenticate(:pass) valid_response end setup_rack(app).call(@env) expect(@env['warden'].user).to eq("foo as a user") end it "should look for an active user in the session with authenticate?" do app = lambda do |env| env['rack.session']['warden.user.foo_scope.key'] = "a foo user" env['warden'].authenticate?(:pass, :scope => :foo_scope) valid_response end setup_rack(app).call(@env) expect(@env['warden'].user(:foo_scope)).to eq("a foo user") end it "should look for an active user in the session with authenticate!" do app = lambda do |env| env['rack.session']['warden.user.foo_scope.key'] = "a foo user" env['warden'].authenticate!(:pass, :scope => :foo_scope) valid_response end setup_rack(app).call(@env) expect(@env['warden'].user(:foo_scope)).to eq("a foo user") end it "should throw an error when authenticate!" do app = lambda do |env| env['warden'].authenticate!(:pass, :scope => :failz) raise "OMG" end setup_rack(app).call(@env) end it "should login 2 different users from the session" do app = lambda do |env| env['rack.session']['warden.user.foo.key'] = 'foo user' env['rack.session']['warden.user.bar.key'] = 'bar user' expect(env['warden']).to be_authenticated(:foo) expect(env['warden']).to be_authenticated(:bar) expect(env['warden']).not_to be_authenticated # default scope valid_response end setup_rack(app).call(@env) expect(@env['warden'].user(:foo)).to eq('foo user') expect(@env['warden'].user(:bar)).to eq('bar user') expect(@env['warden'].user).to be_nil end it "should not authenticate other scopes just because the first is authenticated" do app = lambda do |env| env['warden'].authenticate(:pass, :scope => :foo) env['warden'].authenticate(:invalid, :scope => :bar) expect(env['warden']).to be_authenticated(:foo) expect(env['warden']).not_to be_authenticated(:bar) valid_response end setup_rack(app).call(@env) end SID_REGEXP = /rack\.session=([^;]*);/ it "should renew session when user is set" do app = lambda do |env| env["rack.session"]["counter"] ||= 0 env["rack.session"]["counter"] += 1 if env["warden.on"] env["warden"].authenticate!(:pass) expect(env["warden"]).to be_authenticated end valid_response end # Setup a rack app with Pool session. app = setup_rack(app, :session => Rack::Session::Pool).to_app response = app.call(@env) expect(@env["rack.session"]["counter"]).to eq(1) # Ensure a cookie was given back cookie = response[1]["Set-Cookie"] expect(cookie).not_to be_nil # Ensure a session id was given sid = cookie.match(SID_REGEXP)[1] expect(sid).not_to be_nil # Do another request, giving a cookie but turning on warden authentication env = env_with_params("/", {}, 'rack.session' => @env['rack.session'], "HTTP_COOKIE" => cookie, "warden.on" => true) response = app.call(env) expect(env["rack.session"]["counter"]).to be(2) # Regardless of rack version, a cookie should be sent back new_cookie = response[1]["Set-Cookie"] expect(new_cookie).not_to be_nil # And the session id in this cookie should not be the same as the previous one new_sid = new_cookie.match(SID_REGEXP)[1] expect(new_sid).not_to be_nil expect(new_sid).not_to eq(sid) end it "should not renew session when user is fetch" do app = lambda do |env| env["rack.session"]["counter"] ||= 0 env["rack.session"]["counter"] += 1 env["warden"].authenticate!(:pass) expect(env["warden"]).to be_authenticated valid_response end # Setup a rack app with Pool session. app = setup_rack(app, :session => Rack::Session::Pool).to_app response = app.call(@env) expect(@env["rack.session"]["counter"]).to eq(1) # Ensure a cookie was given back cookie = response[1]["Set-Cookie"] expect(cookie).not_to be_nil # Ensure a session id was given sid = cookie.match(SID_REGEXP)[1] expect(sid).not_to be_nil # Do another request, passing the cookie. The user should be fetched from cookie. env = env_with_params("/", {}, "HTTP_COOKIE" => cookie) response = app.call(env) expect(env["rack.session"]["counter"]).to eq(2) # Depending on rack version, a cookie will be returned with the # same session id or no cookie is given back (becase it did not change). # If we don't get any of these two behaviors, raise an error. # Regardless of rack version, a cookie should be sent back new_cookie = response[1]["Set-Cookie"] if new_cookie && new_cookie.match(SID_REGEXP)[1] != sid raise "Expected a cookie to not be sent or session id to match" end end end describe "authentication cache" do it "should run strategies just once for a given scope" do app = lambda do |env| env['warden'].authenticate(:password, :pass, :scope => :failz) expect(env['warden']).not_to be_authenticated(:failz) env['warden'].authenticate(:password, :pass, :scope => :failz) expect(env['warden']).not_to be_authenticated(:failz) expect(env['warden.spec.strategies']).to eq([:password, :pass]) valid_response end setup_rack(app).call(@env) end it "should run strategies for a given scope several times if cache is cleaned" do app = lambda do |env| env['warden'].authenticate(:password, :pass, :scope => :failz) env['warden'].clear_strategies_cache!(:scope => :failz) env['warden'].authenticate(:password, :pass, :scope => :failz) expect(env['warden.spec.strategies']).to eq([:password, :pass, :password, :pass]) valid_response end setup_rack(app).call(@env) end it "should clear the cache for a specified strategy" do app = lambda do |env| env['warden'].authenticate(:password, :pass, :scope => :failz) env['warden'].clear_strategies_cache!(:password, :scope => :failz) env['warden'].authenticate(:password, :pass, :scope => :failz) expect(env['warden.spec.strategies']).to eq([:password, :pass, :password]) valid_response end setup_rack(app).call(@env) end it "should run the strategies several times for different scopes" do app = lambda do |env| env['warden'].authenticate(:password, :pass, :scope => :failz) expect(env['warden']).not_to be_authenticated(:failz) env['warden'].authenticate(:password, :pass) expect(env['warden']).to be_authenticated expect(env['warden.spec.strategies']).to eq([:password, :pass, :password, :pass]) valid_response end setup_rack(app).call(@env) end it "should not run strategies until cache is cleaned if latest winning strategy halted" do app = lambda do |env| env['warden'].authenticate(:failz) expect(env['warden']).not_to be_authenticated env['warden'].authenticate(:pass) expect(env['warden'].winning_strategy.message).to eq("The Fails Strategy Has Failed You") valid_response end setup_rack(app).call(@env) end it "should not store user if strategy isn't meant for permanent login" do session = Warden::SessionSerializer.new(@env) app = lambda do |env| env['warden'].authenticate(:single) expect(env['warden']).to be_authenticated expect(env['warden'].user).to eq("Valid User") expect(session).not_to be_stored(:default) valid_response end setup_rack(app).call(@env) end end describe "set user" do it "should store the user into the session" do app = lambda do |env| env['warden'].authenticate(:pass) expect(env['warden']).to be_authenticated expect(env['warden'].user).to eq("Valid User") expect(env['rack.session']["warden.user.default.key"]).to eq("Valid User") valid_response end setup_rack(app).call(@env) end it "should not store the user if the :store option is set to false" do app = lambda do |env| env['warden'].authenticate(:pass, :store => false) expect(env['warden']).to be_authenticated expect(env['warden'].user).to eq("Valid User") expect(env['rack.session']['warden.user.default.key']).to be_nil valid_response end setup_rack(app).call(@env) end it "should not throw error when no session is configured and store is false" do app = lambda do |env| env['rack.session'] = nil env['warden'].authenticate(:pass, :store => false) expect(env['warden']).to be_authenticated expect(env['warden'].user).to eq("Valid User") valid_response end setup_rack(app).call(@env) end it "should not run the callbacks when :run_callbacks is false" do app = lambda do |env| expect(env['warden'].manager).not_to receive(:_run_callbacks) env['warden'].authenticate(:run_callbacks => false, :scope => :pass) valid_response end setup_rack(app).call(@env) end it "should run the callbacks when :run_callbacks is true" do app = lambda do |env| expect(env['warden'].manager).to receive(:_run_callbacks).at_least(:once) env['warden'].authenticate(:pass) valid_response end setup_rack(app).call(@env) end it "should run the callbacks by default" do app = lambda do |env| expect(env['warden'].manager).to receive(:_run_callbacks).at_least(:once) env['warden'].authenticate(:pass) valid_response end setup_rack(app).call(@env) end it "should set renew on rack.session.options" do app = lambda do |env| env['warden'].authenticate(:pass) valid_response end @env[Warden::Proxy::ENV_SESSION_OPTIONS] = {} setup_rack(app).call(@env) expect(@env[Warden::Proxy::ENV_SESSION_OPTIONS]).to include(renew: true) expect(@env[Warden::Proxy::ENV_SESSION_OPTIONS]).to_not be_frozen end it "should not modify attempt to modify a frozen rack.session.options" do app = lambda do |env| env['warden'].authenticate(:pass) valid_response end original_options = {}.freeze @env[Warden::Proxy::ENV_SESSION_OPTIONS] = original_options setup_rack(app).call(@env) expect(original_options).to be_empty expect(@env[Warden::Proxy::ENV_SESSION_OPTIONS]).to include(renew: true) expect(@env[Warden::Proxy::ENV_SESSION_OPTIONS]).to be_frozen end end describe "lock" do it "should not run any strategy" do app = lambda do |env| env['warden'].lock! env['warden'].authenticate(:pass) expect(env['warden'].user).to be_nil valid_response end setup_rack(app).call(@env) end it "should keep already authenticated users" do app = lambda do |env| env['warden'].authenticate(:pass) env['warden'].lock! expect(env['warden'].user).not_to be_nil valid_response end setup_rack(app).call(@env) end end describe "get user" do before(:each) do @env['rack.session'] ||= {} @env['rack.session'].delete("warden.user.default.key") end it "should return nil when not logged in" do app = lambda do |env| expect(env['warden'].user).to be_nil valid_response end setup_rack(app).call(@env) end it "should not run strategies when not logged in" do app = lambda do |env| expect(env['warden'].user).to be_nil expect(env['warden.spec.strategies']).to be_nil valid_response end setup_rack(app).call(@env) end it "should cache unfound user" do expect_any_instance_of(Warden::SessionSerializer).to receive(:fetch).once app = lambda do |env| expect(env['warden'].user).to be_nil expect(env['warden'].user).to be_nil valid_response end setup_rack(app).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'] = [] end it "should take the user from the session when logged in" do app = lambda do |env| expect(env['warden'].user).to eq("A Previous User") valid_response end setup_rack(app).call(@env) end it "should cache found user" do expect_any_instance_of(Warden::SessionSerializer).to receive(:fetch).once.and_return "A Previous User" app = lambda do |env| expect(env['warden'].user).to eq("A Previous User") expect(env['warden'].user).to eq("A Previous User") valid_response end setup_rack(app).call(@env) end it "should not run strategies when the user exists in the session" do app = lambda do |env| env['warden'].authenticate!(:pass) valid_response end setup_rack(app).call(@env) expect(@env['warden.spec.strategies']).not_to include(:pass) end describe "run callback option" do it "should not call run_callbacks when we pass a :run_callback => false" do app = lambda do |env| expect(env['warden'].manager).not_to receive(:_run_callbacks) env['warden'].user(:run_callbacks => false) valid_response end setup_rack(app).call(@env) end it "should call run_callbacks when we pass a :run_callback => true" do app = lambda do |env| expect(env['warden'].manager).to receive(:_run_callbacks).at_least(:once) env['warden'].user(:run_callbacks => true) valid_response end setup_rack(app).call(@env) end it "should call run_callbacks by default" do app = lambda do |env| expect(env['warden'].manager).to receive(:_run_callbacks).at_least(:once) env['warden'].user valid_response end setup_rack(app).call(@env) end end end end describe "logout" do before(:each) do @env['rack.session'] = {"warden.user.default.key" => "default key", "warden.user.foo.key" => "foo key", :foo => "bar"} @app = lambda do |e| e['warden'].logout(e['warden.spec.which_logout']) valid_response end end it "should logout only the scoped foo user" do @app = setup_rack(@app) @env['warden.spec.which_logout'] = :foo @app.call(@env) expect(@env['rack.session']['warden.user.default.key']).to eq("default key") expect(@env['rack.session']['warden.user.foo.key']).to be_nil expect(@env['rack.session'][:foo]).to eq("bar") end it "should logout only the scoped default user" do @app = setup_rack(@app) @env['warden.spec.which_logout'] = :default @app.call(@env) expect(@env['rack.session']['warden.user.default.key']).to be_nil expect(@env['rack.session']['warden.user.foo.key']).to eq("foo key") expect(@env['rack.session'][:foo]).to eq("bar") end it "should clear the session when no argument is given to logout" do expect(@env['rack.session']).not_to be_nil app = lambda do |e| e['warden'].logout valid_response end setup_rack(app).call(@env) expect(@env['rack.session']).to be_empty end it "should not raise exception if raw_session is nil" do @app = setup_rack(@app, { nil_session: true }) @env['rack.session'] = nil @env['warden.spec.which_logout'] = :foo expect { @app.call(@env) }.to_not raise_error end it "should clear the user when logging out" do expect(@env['rack.session']).not_to be_nil app = lambda do |e| expect(e['warden'].user).not_to be_nil e['warden'].logout expect(e['warden']).not_to be_authenticated expect(e['warden'].user).to be_nil valid_response end setup_rack(app).call(@env) expect(@env['warden'].user).to be_nil end it "should clear the session data when logging out" do expect(@env['rack.session']).not_to be_nil app = lambda do |e| expect(e['warden'].user).not_to be_nil e['warden'].session[:foo] = :bar e['warden'].logout valid_response end setup_rack(app).call(@env) end it "should clear out the session by calling reset_session! so that plugins can setup their own session clearing" do expect(@env['rack.session']).not_to be_nil app = lambda do |e| expect(e['warden'].user).not_to be_nil expect(e['warden']).to receive(:reset_session!) e['warden'].logout valid_response end setup_rack(app).call(@env) end end describe "messages" do it "should allow access to the failure message" do failure = lambda do |e| [401, {"Content-Type" => "text/plain"}, [e['warden'].message]] end app = lambda do |e| e['warden'].authenticate! :failz end result = setup_rack(app, :failure_app => failure).call(@env) expect(result.last).to eq(["The Fails Strategy Has Failed You"]) end it "should allow access to the success message" do success = lambda do |e| [200, {"Content-Type" => "text/plain"}, [e['warden'].message]] end app = lambda do |e| e['warden'].authenticate! :pass_with_message success.call(e) end result = setup_rack(app).call(@env) expect(result.last).to eq(["The Success Strategy Has Accepted You"]) end it "should not die when accessing a message from a source where no authentication has occurred" do app = lambda do |e| [200, {"Content-Type" => "text/plain"}, [e['warden'].message]] end result = setup_rack(app).call(@env) expect(result[2]).to eq([nil]) end end describe "when all strategies are not valid?" do it "should return false for authenticated? when there are no valid? strategies" do @env['rack.session'] = {} app = lambda do |e| expect(e['warden'].authenticate(:invalid)).to be_nil expect(e['warden']).not_to be_authenticated end setup_rack(app).call(@env) end it "should return nil for authenticate when there are no valid strategies" do @env['rack.session'] = {} app = lambda do |e| expect(e['warden'].authenticate(:invalid)).to be_nil end setup_rack(app).call(@env) end it "should return false for authenticate? when there are no valid strategies" do @env['rack.session'] = {} app = lambda do |e| expect(e['warden'].authenticate?(:invalid)).to eq(false) end setup_rack(app).call(@env) end it "should respond with a 401 when authenticate! cannot find any valid strategies" do @env['rack.session'] = {} app = lambda do |e| e['warden'].authenticate!(:invalid) end result = setup_rack(app).call(@env) expect(result.first).to eq(401) end end describe "authenticated?" do describe "positive authentication" do before do @env['rack.session'] = {'warden.user.default.key' => 'defult_key'} $captures = [] end it "should return true when authenticated in the session" do app = lambda do |e| expect(e['warden']).to be_authenticated end setup_rack(app).call(@env) end it "should yield to a block when the block is passed and authenticated" do app = lambda do |e| e['warden'].authenticated? do $captures << :in_the_block end end setup_rack(app).call(@env) expect($captures).to eq([:in_the_block]) end it "should authenticate for a user in a different scope" do @env['rack.session'] = {'warden.user.foo.key' => 'foo_key'} app = lambda do |e| e['warden'].authenticated?(:foo) do $captures << :in_the_foo_block end end setup_rack(app).call(@env) expect($captures).to eq([:in_the_foo_block]) end end describe "negative authentication" do before do @env['rack.session'] = {'warden.foo.default.key' => 'foo_key'} $captures = [] end it "should return false when authenticated in the session" do app = lambda do |e| expect(e['warden']).not_to be_authenticated end setup_rack(app).call(@env) end it "should return false if scope cannot be retrieved from session" do begin Warden::Manager.serialize_from_session { |_k| nil } app = lambda do |env| env['rack.session']['warden.user.foo_scope.key'] = "a foo user" env['warden'].authenticated?(:foo_scope) valid_response end setup_rack(app).call(@env) expect(@env['warden'].user(:foo_scope)).to be_nil ensure Warden::Manager.serialize_from_session { |k| k } end end it "should not yield to a block when the block is passed and authenticated" do app = lambda do |e| e['warden'].authenticated? do $captures << :in_the_block end end setup_rack(app).call(@env) expect($captures).to eq([]) end it "should not yield for a user in a different scope" do app = lambda do |e| e['warden'].authenticated?(:bar) do $captures << :in_the_bar_block end end setup_rack(app).call(@env) expect($captures).to eq([]) end end end describe "unauthenticated?" do describe "negative unauthentication" do before do @env['rack.session'] = {'warden.user.default.key' => 'defult_key'} $captures = [] end it "should return false when authenticated in the session" do app = lambda do |e| expect(e['warden']).not_to be_unauthenticated end _result = setup_rack(app).call(@env) end it "should not yield to a block when the block is passed and authenticated" do app = lambda do |e| e['warden'].unauthenticated? do $captures << :in_the_block end end setup_rack(app).call(@env) expect($captures).to eq([]) end it "should not yield to the block for a user in a different scope" do @env['rack.session'] = {'warden.user.foo.key' => 'foo_key'} app = lambda do |e| e['warden'].unauthenticated?(:foo) do $captures << :in_the_foo_block end end setup_rack(app).call(@env) expect($captures).to eq([]) end end describe "positive unauthentication" do before do @env['rack.session'] = {'warden.foo.default.key' => 'foo_key'} $captures = [] end it "should return false when unauthenticated in the session" do app = lambda do |e| expect(e['warden']).to be_unauthenticated end setup_rack(app).call(@env) end it "should yield to a block when the block is passed and authenticated" do app = lambda do |e| e['warden'].unauthenticated? do $captures << :in_the_block end end setup_rack(app).call(@env) expect($captures).to eq([:in_the_block]) end it "should yield for a user in a different scope" do app = lambda do |e| e['warden'].unauthenticated?(:bar) do $captures << :in_the_bar_block end end setup_rack(app).call(@env) expect($captures).to eq([:in_the_bar_block]) end end end describe "attributes" do def def_app(&blk) @app = setup_rack(blk) end it "should have a config attribute" do app = def_app do |e| expect(e['warden'].config).to be_a_kind_of(Hash) valid_response end app.call(@env) end end end describe "dynamic default_strategies" do before(:all) do load_strategies class ::DynamicDefaultStrategies def initialize(app, &blk) @app, @blk = app, blk end def call(env) @blk.call(env) @app.call(env) end end Warden::Strategies.add(:one) do def authenticate!; $captures << :one; success!("User") end end Warden::Strategies.add(:two) do def authenticate!; $captures << :two; fail("User not found") end end end before(:each) do @app = lambda{|e| e['warden'].authenticate! } @env = env_with_params("/") $captures = [] end def wrap_app(app, &blk) builder = Rack::Builder.new do use DynamicDefaultStrategies, &blk run app end builder.to_app end it "should allow me to change the default strategies on the fly" do app = wrap_app(@app) do |e| expect(e['warden'].default_strategies).to eq([:password]) expect(e['warden'].config.default_strategies).to eq([:password]) e['warden'].default_strategies :one e['warden'].authenticate! Rack::Response.new("OK").finish end setup_rack(app).call(@env) expect($captures).to eq([:one]) end it "should allow me to append to the default strategies on the fly" do app = wrap_app(@app) do |e| e['warden'].default_strategies << :one expect(e['warden'].default_strategies).to eq([:password, :one]) e['warden'].authenticate! Rack::Response.new("OK").finish end setup_rack(app).call(@env) expect($captures).to eq([:one]) end it "should allow me to set the default strategies on a per scope basis" do app = wrap_app(@app) do |e| w = e['warden'] w.default_strategies(:two, :one, :scope => :foo) w.default_strategies(:two, :scope => :default) expect(w.default_strategies(:scope => :foo)).to eq([:two, :one]) w.authenticate(:scope => :foo) expect($captures).to eq([:two, :one]) $captures.clear w.authenticate expect($captures).to eq([:two]) end setup_rack(app).call(@env) expect($captures).to eq([:two]) end it "should allow me to setup default strategies for each scope on the manager" do builder = Rack::Builder.new do use Warden::Spec::Helpers::Session use Warden::Manager do |config| config.default_strategies :one config.default_strategies :two, :one, :scope => :foo config.failure_app = Warden::Spec::Helpers::FAILURE_APP end run(lambda do |e| w = e['warden'] w.authenticate w.authenticate(:scope => :foo) $captures << :complete end) end builder.to_app.call(@env) expect($captures).to eq([:one, :two, :one, :complete]) end it "should not change the master configurations strategies when I change them" do app = wrap_app(@app) do |e| e['warden'].default_strategies << :one expect(e['warden'].default_strategies).to eq([:password, :one]) expect(e['warden'].manager.config.default_strategies).to eq([:password]) e['warden'].authenticate! Rack::Response.new("OK").finish end setup_rack(app).call(@env) expect($captures).to eq([:one]) end describe "default scope options" do it "should allow me to set a default action for a given scope" do $captures = [] builder = Rack::Builder.new do use Warden::Manager do |config| config.scope_defaults :foo, :strategies => [:two], :action => "some_bad_action" config.failure_app = Warden::Spec::Helpers::FAILURE_APP end run(lambda do |e| e['warden'].authenticate!(:scope => :foo) end) end env = env_with_params("/foo") env["rack.session"] = {} builder.to_app.call(env) request = Rack::Request.new(env) expect(request.path).to eq("/some_bad_action") end it "should allow me to set store, false on a given scope" do $captures = [] warden = [] builder = Rack::Builder.new do use Warden::Manager do |config| config.default_strategies :one config.default_strategies :two, :one, :scope => :foo config.default_strategies :two, :one, :scope => :bar config.scope_defaults :bar, :store => false config.scope_defaults :baz, :store => false config.failure_app = Warden::Spec::Helpers::FAILURE_APP end run(lambda do |e| w = e['warden'] w.authenticate w.authenticate(:scope => :foo) w.authenticate(:one, :scope => :bar) w.authenticate(:one, :scope => :baz, :store => true) warden << w $captures << :complete Rack::Response.new("OK").finish end) end session = @env["rack.session"] = {} builder.to_app.call(@env) expect($captures).to include(:complete) w = warden.first expect(w.user).to eq("User") expect(w.user(:foo)).to eq("User") expect(w.user(:bar)).to eq("User") expect(w.user(:baz)).to eq("User") expect(session['warden.user.default.key']).to eq("User") expect(session['warden.user.foo.key']).to eq("User") expect(session.key?('warden.user.bar.key')).to eq(false) expect(session['warden.user.bar.key']).to be_nil expect(session['warden.user.baz.key']).to eq("User") end end describe "#asset_request?" do before(:each) do @asset_regex = /^\/assets\// ::Warden.asset_paths = @asset_regex end it "should return true if PATH_INFO is in asset list" do env = env_with_params('/assets/fun.gif') setup_rack(success_app).call(env) proxy = env["warden"] expect(proxy.env['PATH_INFO']).to match(@asset_regex) expect(proxy).to be_asset_request end it "should return false if PATH_INFO is not in asset list" do env = env_with_params('/home') setup_rack(success_app).call(env) proxy = env["warden"] expect(proxy.env['PATH_INFO']).not_to match(@asset_regex) expect(proxy).not_to be_asset_request end end end warden-1.2.8/spec/warden/scoped_session_serializer.rb000066400000000000000000000065461337340105400230250ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true RSpec.describe Warden::Manager do before(:each) do @env = env_with_params @env['rack.session'] ||= {} Warden::Manager.serialize_from_session { |k| k } Warden::Manager.serialize_into_session { |u| u } begin Warden::SessionSerializer.send :remove_method, :admin_serialize rescue end begin Warden::SessionSerializer.send :remove_method, :admin_deserialize rescue end end after(:each) do Warden::Manager.serialize_from_session { |k| k } Warden::Manager.serialize_into_session { |u| u } begin Warden::SessionSerializer.send :remove_method, :admin_deserialize Warden::SessionSerializer.send :remove_method, :admin_serialize rescue end end def serializer_respond_to?(name) Warden::SessionSerializer.new(@env).respond_to? name end it "should respond to :serialize" do serializer_respond_to?(:serialize).should be_true end it "should respond to :deserialize" do serializer_respond_to?(:deserialize).should be_true end it "should respond to {scope}_deserialize if Manager.serialize_from_session is called with scope" do Rack::Builder.new do Warden::Manager.serialize_from_session(:admin) { |n| n } end serializer_respond_to?(:admin_deserialize).should be_true end it "should respond to {scope}_serialize if Manager.serialize_into_session is called with scope" do Rack::Builder.new do Warden::Manager.serialize_into_session(:admin) { |n| n } end serializer_respond_to?(:admin_serialize).should be_true end def initialize_with_scope(scope, &block) Rack::Builder.new do Warden::Manager.serialize_into_session(scope, &block) end end it "should execute serialize if no {scope}_serialize is present" do serialized_object = nil initialize_with_scope(nil) do |user| serialized_object = user user end serializer = Warden::SessionSerializer.new(@env) serializer.store("user", :admin) serialized_object.should eq("user") end it "should not have a {scope}_serialize by default" do serializer_respond_to?(:admin_serialize).should be_false end it "should execute {scope}_serialize when calling store with a scope" do serialized_object = nil initialize_with_scope(:admin) do |user| serialized_object = user user end serializer = Warden::SessionSerializer.new(@env) serializer.store("user", :admin) serialized_object.should eq("user") end it "should execute {scope}_deserialize when calling store with a scope" do serialized_object = nil Rack::Builder.new do Warden::Manager.serialize_from_session(:admin) do |key| serialized_object = key key end end serializer = Warden::SessionSerializer.new(@env) @env['rack.session'][serializer.key_for(:admin)] = "test" serializer.fetch(:admin) serialized_object.should eq("test") end it "should execute deserialize if {scope}_deserialize is not present" do serialized_object = nil Rack::Builder.new do Warden::Manager.serialize_from_session do |key| serialized_object = key key end end serializer = Warden::SessionSerializer.new(@env) @env['rack.session'][serializer.key_for(:admin)] = "test" serializer.fetch(:admin) serialized_object.should eq("test") end end warden-1.2.8/spec/warden/session_serializer_spec.rb000066400000000000000000000031741337340105400224740ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true RSpec.describe Warden::SessionSerializer do before(:each) do @env = env_with_params @env['rack.session'] ||= {} @session = Warden::SessionSerializer.new(@env) end it "should store data for the default scope" do @session.store("user", :default) expect(@env['rack.session']).to eq({ "warden.user.default.key"=>"user" }) end it "should check if a data is stored or not" do expect(@session).not_to be_stored(:default) @session.store("user", :default) expect(@session).to be_stored(:default) end it "should load an user from store" do expect(@session.fetch(:default)).to be_nil @session.store("user", :default) expect(@session.fetch(:default)).to eq("user") end it "should store data based on the scope" do @session.store("user", :default) expect(@session.fetch(:default)).to eq("user") expect(@session.fetch(:another)).to be_nil end it "should delete data from store" do @session.store("user", :default) expect(@session.fetch(:default)).to eq("user") @session.delete(:default) expect(@session.fetch(:default)).to be_nil end it "should delete information from store if user cannot be retrieved" do @session.store("user", :default) expect(@env['rack.session']).to have_key("warden.user.default.key") allow(@session).to receive(:deserialize).and_return(nil) @session.fetch(:default) expect(@env['rack.session']).not_to have_key("warden.user.default.key") end it "should support a nil session store" do @env['rack.session'] = nil expect(@session.fetch(:default)).to be_nil end end warden-1.2.8/spec/warden/strategies/000077500000000000000000000000001337340105400173665ustar00rootroot00000000000000warden-1.2.8/spec/warden/strategies/base_spec.rb000066400000000000000000000167621337340105400216530ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true require 'spec_helper' describe Warden::Strategies::Base do before(:each) do RAS = Warden::Strategies unless defined?(RAS) Warden::Strategies.clear! end describe "headers" do it "should have headers" do Warden::Strategies.add(:foo) do def authenticate! headers("foo" => "bar") end end strategy = Warden::Strategies[:foo].new(env_with_params) strategy._run! expect(strategy.headers["foo"]).to eq("bar") end it "should allow us to clear the headers" do Warden::Strategies.add(:foo) do def authenticate! headers("foo" => "bar") end end strategy = Warden::Strategies[:foo].new(env_with_params) strategy._run! expect(strategy.headers["foo"]).to eq("bar") strategy.headers.clear expect(strategy.headers).to be_empty end end it "should have a user object" do RAS.add(:foobar) do def authenticate! success!("foo") end end strategy = RAS[:foobar].new(env_with_params) strategy._run! expect(strategy.user).to eq("foo") end it "should be performed after run" do RAS.add(:foobar) do def authenticate!; end end strategy = RAS[:foobar].new(env_with_params) expect(strategy).not_to be_performed strategy._run! expect(strategy).to be_performed strategy.clear! expect(strategy).not_to be_performed end it "should set the scope" do RAS.add(:foobar) do def authenticate! expect(self.scope).to eq(:user) # TODO: Not being called at all. What's this? end end _strategy = RAS[:foobar].new(env_with_params, :user) end it "should allow you to set a message" do RAS.add(:foobar) do def authenticate! self.message = "foo message" end end strategy = RAS[:foobar].new(env_with_params) strategy._run! expect(strategy.message).to eq("foo message") end it "should provide access to the errors" do RAS.add(:foobar) do def authenticate! errors.add(:foo, "foo has an error") end end env = env_with_params env['warden'] = Warden::Proxy.new(env, Warden::Manager.new({})) strategy = RAS[:foobar].new(env) strategy._run! expect(strategy.errors.on(:foo)).to eq(["foo has an error"]) end describe "halting" do it "should allow you to halt a strategy" do RAS.add(:foobar) do def authenticate! halt! end end str = RAS[:foobar].new(env_with_params) str._run! expect(str).to be_halted end it "should not be halted if halt was not called" do RAS.add(:foobar) do def authenticate! "foo" end end str = RAS[:foobar].new(env_with_params) str._run! expect(str).not_to be_halted end end describe "pass" do it "should allow you to pass" do RAS.add(:foobar) do def authenticate! pass end end str = RAS[:foobar].new(env_with_params) str._run! expect(str).not_to be_halted expect(str.user).to be_nil end end describe "redirect" do it "should allow you to set a redirection" do RAS.add(:foobar) do def authenticate! redirect!("/foo/bar") end end str = RAS[:foobar].new(env_with_params) str._run! expect(str.user).to be_nil end it "should mark the strategy as halted when redirecting" do RAS.add(:foobar) do def authenticate! redirect!("/foo/bar") end end str = RAS[:foobar].new(env_with_params) str._run! expect(str).to be_halted end it "should escape redirected url parameters" do RAS.add(:foobar) do def authenticate! redirect!("/foo/bar", :foo => "bar") end end str = RAS[:foobar].new(env_with_params) str._run! expect(str.headers["Location"]).to eq("/foo/bar?foo=bar") end it "should allow you to set a message" do RAS.add(:foobar) do def authenticate! redirect!("/foo/bar", {:foo => "bar"}, :message => "You are being redirected foo") end end str = RAS[:foobar].new(env_with_params) str._run! expect(str.headers["Location"]).to eq("/foo/bar?foo=bar") expect(str.message).to eq("You are being redirected foo") end it "should set the action as :redirect" do RAS.add(:foobar) do def authenticate! redirect!("/foo/bar", {:foo => "bar"}, :message => "foo") end end str = RAS[:foobar].new(env_with_params) str._run! expect(str.result).to be(:redirect) end end describe "failure" do before(:each) do RAS.add(:hard_fail) do def authenticate! fail!("You are not cool enough") end end RAS.add(:soft_fail) do def authenticate! fail("You are too soft") end end @hard = RAS[:hard_fail].new(env_with_params) @soft = RAS[:soft_fail].new(env_with_params) end it "should allow you to fail hard" do @hard._run! expect(@hard.user).to be_nil end it "should halt the strategies when failing hard" do @hard._run! expect(@hard).to be_halted end it "should allow you to set a message when failing hard" do @hard._run! expect(@hard.message).to eq("You are not cool enough") end it "should set the action as :failure when failing hard" do @hard._run! expect(@hard.result).to be(:failure) end it "should allow you to fail soft" do @soft._run! expect(@soft.user).to be_nil end it "should not halt the strategies when failing soft" do @soft._run! expect(@soft).not_to be_halted end it "should allow you to set a message when failing soft" do @soft._run! expect(@soft.message).to eq("You are too soft") end it "should set the action as :failure when failing soft" do @soft._run! expect(@soft.result).to be(:failure) end end describe "success" do before(:each) do RAS.add(:foobar) do def authenticate! success!("Foo User", "Welcome to the club!") end end @str = RAS[:foobar].new(env_with_params) end it "should allow you to succeed" do @str._run! end it "should be authenticated after success" do @str._run! expect(@str.user).not_to be_nil end it "should allow you to set a message when succeeding" do @str._run! expect(@str.message).to eq("Welcome to the club!") end it "should store the user" do @str._run! expect(@str.user).to eq("Foo User") end it "should set the action as :success" do @str._run! expect(@str.result).to be(:success) end end describe "custom response" do before(:each) do RAS.add(:foobar) do def authenticate! custom!([521, {"foo" => "bar"}, ["BAD"]]) end end @str = RAS[:foobar].new(env_with_params) @str._run! end it "should allow me to set a custom rack response" do expect(@str.user).to be_nil end it "should halt the strategy" do expect(@str).to be_halted end it "should provide access to the custom rack response" do expect(@str.custom_response).to eq([521, {"foo" => "bar"}, ["BAD"]]) end it "should set the action as :custom" do @str._run! expect(@str.result).to eq(:custom) end end end warden-1.2.8/spec/warden/strategies_spec.rb000066400000000000000000000051021337340105400207230ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true RSpec.describe Warden::Strategies do it "should let me add a strategy via a block" do Warden::Strategies.add(:strategy1) do def authenticate! success("foo") end end expect(Warden::Strategies[:strategy1].ancestors).to include(Warden::Strategies::Base) end it "should raise an error if I add a strategy via a block, that does not have an authenticate! method" do expect { Warden::Strategies.add(:strategy2) do end }.to raise_error(NoMethodError) end it "should raise an error if I add a strategy that does not extend Warden::Strategies::Base" do non_base = Class.new do def authenticate! end end expect do Warden::Strategies.add(:strategy_non_base, non_base) end.to raise_error(/is not a Warden::Strategies::Base/) end it "should allow me to get access to a particular strategy" do Warden::Strategies.add(:strategy3) do def authenticate!; end end strategy = Warden::Strategies[:strategy3] expect(strategy).not_to be_nil expect(strategy.ancestors).to include(Warden::Strategies::Base) end it "should allow me to add a strategy with the required methods" do class MyStrategy < Warden::Strategies::Base def authenticate!; end end expect { Warden::Strategies.add(:strategy4, MyStrategy) }.not_to raise_error end it "should not allow a strategy that does not have an authenticate! method" do class MyOtherStrategy end expect { Warden::Strategies.add(:strategy5, MyOtherStrategy) }.to raise_error(NoMethodError) end it "should allow me to change a class when providing a block and class" do class MyStrategy < Warden::Strategies::Base end Warden::Strategies.add(:foo, MyStrategy) do def authenticate!; end end expect(Warden::Strategies[:foo].ancestors).to include(MyStrategy) end it "should allow me to update a previously given strategy" do class MyStrategy < Warden::Strategies::Base def authenticate!; end end Warden::Strategies.add(:strategy6, MyStrategy) new_module = Module.new Warden::Strategies.update(:strategy6) do include new_module end expect(Warden::Strategies[:strategy6].ancestors).to include(new_module) end it "should allow me to clear the strategies" do Warden::Strategies.add(:foobar) do def authenticate! :foo end end expect(Warden::Strategies[:foobar]).not_to be_nil Warden::Strategies.clear! expect(Warden::Strategies[:foobar]).to be_nil end end warden-1.2.8/spec/warden/test/000077500000000000000000000000001337340105400161735ustar00rootroot00000000000000warden-1.2.8/spec/warden/test/helpers_spec.rb000066400000000000000000000046511337340105400212020ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true RSpec.describe Warden::Test::Helpers do before{ $captures = [] } after{ Warden.test_reset! } it "should log me in as a user" do user = "A User" login_as user app = lambda{|e| $captures << :run expect(e['warden']).to be_authenticated expect(e['warden'].user).to eq("A User") valid_response } setup_rack(app).call(env_with_params) expect($captures).to eq([:run]) end it "should log me in as a user of a given scope" do user = {:some => "user"} login_as user, :scope => :foo_scope app = lambda{|e| $captures << :run w = e['warden'] expect(w).to be_authenticated(:foo_scope) expect(w.user(:foo_scope)).to eq(some: "user") } setup_rack(app).call(env_with_params) expect($captures).to eq([:run]) end it "should login multiple users with different scopes" do user = "A user" foo_user = "A foo user" login_as user login_as foo_user, :scope => :foo app = lambda{|e| $captures << :run w = e['warden'] expect(w.user).to eq("A user") expect(w.user(:foo)).to eq("A foo user") expect(w).to be_authenticated expect(w).to be_authenticated(:foo) } setup_rack(app).call(env_with_params) expect($captures).to eq([:run]) end it "should log out all users" do user = "A user" foo = "Foo" login_as user login_as foo, :scope => :foo app = lambda{|e| $captures << :run w = e['warden'] expect(w.user).to eq("A user") expect(w.user(:foo)).to eq("Foo") w.logout expect(w.user).to be_nil expect(w.user(:foo)).to be_nil expect(w).not_to be_authenticated expect(w).not_to be_authenticated(:foo) } setup_rack(app).call(env_with_params) expect($captures).to eq([:run]) end it "should logout a specific user" do user = "A User" foo = "Foo" login_as user login_as foo, :scope => :foo app = lambda{|e| $captures << :run w = e['warden'] w.logout :foo expect(w.user).to eq("A User") expect(w.user(:foo)).to be_nil expect(w).not_to be_authenticated(:foo) } setup_rack(app).call(env_with_params) expect($captures).to eq([:run]) end describe "#asset_paths" do it "should default asset_paths to anything asset path regex" do expect(Warden.asset_paths).to eq([/^\/assets\//] ) end end end warden-1.2.8/spec/warden/test/mock_spec.rb000066400000000000000000000005001337340105400204560ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true RSpec.describe Warden::Test::Mock do before{ $captures = [] } after{ Warden.test_reset! } it "should return a valid mocked warden" do user = "A User" login_as user expect(warden.class).to eq(Warden::Proxy) expect(warden.user).to eq(user) end end warden-1.2.8/spec/warden/test/test_mode_spec.rb000066400000000000000000000042601337340105400215170ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true RSpec.describe Warden::Test::WardenHelpers do before :all do Warden.test_mode! end before do $captures = [] @app = lambda{|_e| valid_response } end after do Warden.test_reset! end it{ expect(Warden).to respond_to(:test_mode!) } it{ expect(Warden).to respond_to(:on_next_request) } it{ expect(Warden).to respond_to(:test_reset!) } it "should execute the on_next_request block on the next request" do Warden.on_next_request do |warden| $captures << warden end setup_rack(@app).call(env_with_params) expect($captures.length).to eq(1) expect($captures.first).to be_an_instance_of(Warden::Proxy) end it "should execute many on_next_request blocks on the next request" do Warden.on_next_request{|_w| $captures << :first } Warden.on_next_request{|_w| $captures << :second } setup_rack(@app).call(env_with_params) expect($captures).to eq([:first, :second]) end it "should not execute on_next_request blocks on subsequent requests" do app = setup_rack(@app) Warden.on_next_request{|_w| $captures << :first } app.call(env_with_params) expect($captures).to eq([:first]) $captures.clear app.call(env_with_params) expect($captures).to be_empty end it "should allow me to set new_on_next_request items to execute in the same test" do app = setup_rack(@app) Warden.on_next_request{|_w| $captures << :first } app.call(env_with_params) expect($captures).to eq([:first]) Warden.on_next_request{|_w| $captures << :second } app.call(env_with_params) expect($captures).to eq([:first, :second]) end it "should remove the on_next_request items when test is reset" do app = setup_rack(@app) Warden.on_next_request{|_w| $captures << :first } Warden.test_reset! app.call(env_with_params) expect($captures).to eq([]) end context "asset requests" do it "should not execute on_next_request blocks if this is an asset request" do app = setup_rack(@app) Warden.on_next_request{|_w| $captures << :first } app.call(env_with_params("/assets/fun.gif")) expect($captures).to eq([]) end end end warden-1.2.8/warden.gemspec000066400000000000000000000016531337340105400156340ustar00rootroot00000000000000# -*- encoding: utf-8 -*- # frozen_string_literal: true lib = File.expand_path("../lib", __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'warden/version' Gem::Specification.new do |spec| spec.name = "warden" spec.version = Warden::VERSION.dup spec.authors = ["Daniel Neighman", "Justin Smestad", "Whitney Smestad", "José Valim"] spec.email = %q{hasox.sox@gmail.com justin.smestad@gmail.com whitcolorado@gmail.com} spec.homepage = "https://github.com/hassox/warden" spec.summary = "An authentication library compatible with all Rack-based frameworks" spec.license = "MIT" spec.extra_rdoc_files = [ "LICENSE", "README.md" ] spec.files = `git ls-files -z`.split("\x0").reject do |f| f.match(%r{^(test|spec|features)/}) end spec.rdoc_options = ["--charset=UTF-8"] spec.require_paths = ["lib"] spec.rubyforge_project = %q{warden} spec.add_dependency "rack", ">= 2.0.6" end