warden 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Daniel Neighman
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1 @@
1
+ Please see the "Warden Wiki":http://wiki.github.com/hassox/warden for overview documentation.
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'date'
5
+ require 'spec/rake/spectask'
6
+
7
+ GEM = "warden"
8
+ GEM_VERSION = "0.2.1"
9
+ AUTHOR = "Daniel Neighman"
10
+ EMAIL = "has.sox@gmail.com"
11
+ HOMEPAGE = "http://github.com/hassox/warden"
12
+ SUMMARY = "Rack middleware that provides authentication for rack applications"
13
+
14
+ spec = Gem::Specification.new do |s|
15
+ s.name = GEM
16
+ s.version = GEM_VERSION
17
+ s.platform = Gem::Platform::RUBY
18
+ s.has_rdoc = true
19
+ s.extra_rdoc_files = ["README.textile", "LICENSE", 'TODO.textile']
20
+ s.summary = SUMMARY
21
+ s.description = s.summary
22
+ s.author = AUTHOR
23
+ s.email = EMAIL
24
+ s.homepage = HOMEPAGE
25
+
26
+ # Uncomment this to add a dependency
27
+ # s.add_dependency "foo"
28
+
29
+ s.require_path = 'lib'
30
+ s.autorequire = GEM
31
+ s.files = %w(LICENSE README.textile Rakefile TODO.textile) + Dir.glob("{lib,spec}/**/*")
32
+ end
33
+
34
+ task :default => :spec
35
+
36
+ desc "Run specs"
37
+ Spec::Rake::SpecTask.new do |t|
38
+ t.spec_files = FileList['spec/**/*_spec.rb']
39
+ t.spec_opts = %w(-fs --color)
40
+ end
41
+
42
+
43
+ Rake::GemPackageTask.new(spec) do |pkg|
44
+ pkg.gem_spec = spec
45
+ end
46
+
47
+ desc "install the gem locally"
48
+ task :install => [:package] do
49
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
50
+ end
51
+
52
+ desc "create a gemspec file"
53
+ task :make_spec do
54
+ File.open("#{GEM}.gemspec", "w") do |file|
55
+ file.puts spec.to_ruby
56
+ end
57
+ end
@@ -0,0 +1,2 @@
1
+ * Allow a spec / test mode where a _spec_authenticate! method is called on a strategy instead if present
2
+ * Implement back urls
@@ -0,0 +1,14 @@
1
+ require 'forwardable'
2
+ $:.unshift File.join(File.dirname(__FILE__))
3
+ require 'warden/mixins/common'
4
+ require 'warden/proxy'
5
+ require 'warden/manager'
6
+ require 'warden/errors'
7
+ require 'warden/authentication/hooks'
8
+ require 'warden/authentication/strategy_base'
9
+ require 'warden/authentication/strategies'
10
+
11
+
12
+ module Warden
13
+ class NotAuthenticated < StandardError; end
14
+ end
@@ -0,0 +1,125 @@
1
+ module Warden
2
+ class Manager
3
+
4
+ class << self
5
+ # A callback hook set to run every time after a user is set.
6
+ # This will happen the first time the user is either authenticated, accessed or manually set
7
+ # during a request. You can supply as many hooks as you like, and they will be run in order of decleration
8
+ #
9
+ # Parameters:
10
+ # <block> A block where you can set arbitrary logic to run every time a user is set
11
+ # Block Parameters: |user, auth, opts|
12
+ # user - The user object that is being set
13
+ # auth - The raw authentication proxy object.
14
+ # opts - any options passed into the set_user call includeing :scope
15
+ #
16
+ # Example:
17
+ # Warden::Manager.after_set_user do |user,auth,opts|
18
+ # scope = opts[:scope]
19
+ # if auth.session["#{scope}.last_access"].to_i > (Time.now - 5.minutes)
20
+ # auth.logout(scope)
21
+ # throw(:warden, :scope => scope, :reason => "Times Up")
22
+ # end
23
+ # auth.session["#{scope}.last_access"] = Time.now
24
+ # end
25
+ #
26
+ # :api: public
27
+ def after_set_user(&block)
28
+ raise BlockNotGiven unless block_given?
29
+ _after_set_user << block
30
+ end
31
+
32
+ # Provides access to the array of after_set_user blocks to run
33
+ # :api: private
34
+ def _after_set_user # :nodoc:
35
+ @_after_set_user ||= []
36
+ end
37
+
38
+ # A callback hook set to run after the first authentiation of a session.
39
+ # This will only happenwhen the session is first authenticated
40
+ #
41
+ # Parameters:
42
+ # <block> A block to contain logic for the callback
43
+ # Block Parameters: |user, auth, opts|
44
+ # user - The user object that is being set
45
+ # auth - The raw authentication proxy object.
46
+ # opts - any options passed into the authenticate call includeing :scope
47
+ #
48
+ # Example:
49
+ #
50
+ # Warden::Manager.after_authentication do |user, auth, opts|
51
+ # throw(:warden, opts) unless user.active?
52
+ # end
53
+ #
54
+ # :api: public
55
+ def after_authentication(&block)
56
+ raise BlockNotGiven unless block_given?
57
+ _after_authentication << block
58
+ end
59
+
60
+ # Provides access to the array of after_authentication blocks
61
+ # :api: private
62
+ def _after_authentication
63
+ @_after_authentication ||= []
64
+ end
65
+
66
+ # A callback that runs just prior to the failur application being called.
67
+ # This callback occurs after PATH_INFO has been modified for the failure (default /unauthenticated)
68
+ # In this callback you can mutate the environment as required by the failure application
69
+ # If a Rails controller were used for the failure_app for example, you would need to set request[:params][:action] = :unauthenticated
70
+ #
71
+ # Parameters:
72
+ # <block> A block to contain logic for the callback
73
+ # Block Parameters: |user, auth, opts|
74
+ # env - The rack env hash
75
+ # opts - any options passed into the authenticate call includeing :scope
76
+ #
77
+ # Example:
78
+ # Warden::Manager.before_failure do |env, opts|
79
+ # params = Rack::Request.new(env).params
80
+ # params[:action] = :unauthenticated
81
+ # params[:warden_failure] = opts
82
+ # end
83
+ #
84
+ # :api: public
85
+ def before_failure(&block)
86
+ _before_failure << block
87
+ end
88
+
89
+ # Provides access to the callback array for before_failure
90
+ # :api: private
91
+ def _before_failure
92
+ @_before_failure ||= []
93
+ end
94
+
95
+ # A callback that runs just after to the failur application being called.
96
+ # This callback is primarily included for Rails 2.3 since Rails 2.3 controllers are not pure Rack Applications
97
+ # Return whatever you want to be returned for the actual rack response array
98
+ #
99
+ # Parameters:
100
+ # <block> A block to contain logic for the callback
101
+ # Block Parameters: |user, auth, opts|
102
+ # result - The result of the rack application
103
+ # opts - any options passed into the authenticate call includeing :scope
104
+ #
105
+ # Example:
106
+ # # Rails 2.3 after_failure
107
+ # Warden::Manager.after_failure do |result|
108
+ # result.to_a
109
+ # end
110
+ #
111
+ # :api: public
112
+ def after_failure(&block)
113
+ _after_failure << block
114
+ end
115
+
116
+ # Provides access to the callback array for after_failure
117
+ # :api: private
118
+ def _after_failure
119
+ @_after_failure ||= []
120
+ end
121
+
122
+ end
123
+
124
+ end # Manager
125
+ end # Warden
@@ -0,0 +1,58 @@
1
+ module Warden
2
+ module Strategies
3
+ class << self
4
+
5
+ # Adds a strategy to the grab-bag of strategies available to use.
6
+ # A strategy is a place where you can put logic related to authentication.
7
+ # A strategy inherits from Warden::Strategies::Base. The _add_ method provides a clean way
8
+ # to declare your strategies.
9
+ # You _must_ declare an @authenticate!@ method.
10
+ # You _may_ provide a @valid?@ method.
11
+ # The valid method should return true or false depending on if the strategy is a valid one for the request.
12
+ #
13
+ # Parameters:
14
+ # <label: Symbol> The label is the name given to a strategy. Use the label to refer to the strategy when authenticating
15
+ # <strategy: Class|nil> The optional stragtegy argument if set _must_ be a class that inherits from Warden::Strategies::Base and _must_
16
+ # implement an @authenticate!@ method
17
+ # <block> The block acts as a convinient way to declare your strategy. Inside is the class definition of a strategy.
18
+ #
19
+ # Examples:
20
+ #
21
+ # Block Declared Strategy:
22
+ # Warden::Strategies.add(:foo) do
23
+ # def authenticate!
24
+ # # authentication logic
25
+ # end
26
+ # end
27
+ #
28
+ # Class Declared Strategy:
29
+ # Warden::Strategies.add(:foo, MyStrategy)
30
+ #
31
+ # :api: public
32
+ def add(label, strategy = nil, &blk)
33
+ strategy = strategy.nil? ? Class.new(Warden::Strategies::Base, &blk) : strategy
34
+ raise NoMethodError, "authenticate! is not declared in the #{label} strategy" if !strategy.method_defined?(:authenticate!)
35
+ raise "#{label.inspect} is Not a Warden::Strategy::Base" if !strategy.ancestors.include?(Warden::Strategies::Base)
36
+ _strategies[label] = strategy
37
+ end
38
+
39
+ # Provides access to declared strategies by label
40
+ # :api: public
41
+ def [](label)
42
+ _strategies[label]
43
+ end
44
+
45
+ # Clears all declared middleware.
46
+ # :api: public
47
+ def clear!
48
+ @strategies = {}
49
+ end
50
+
51
+ # :api: private
52
+ def _strategies
53
+ @strategies ||= {}
54
+ end
55
+ end # << self
56
+
57
+ end # Strategies
58
+ end # Warden
@@ -0,0 +1,124 @@
1
+ module Warden
2
+ module Strategies
3
+ class Base
4
+ # :api: public
5
+ attr_accessor :user, :message
6
+
7
+ #:api: private
8
+ attr_accessor :result, :custom_response
9
+
10
+ # Setup for redirection
11
+ # :api: private
12
+ attr_reader :_status
13
+
14
+ # Accessor for the rack env
15
+ # :api: public
16
+ attr_reader :env
17
+ include ::Warden::Mixins::Common
18
+
19
+ # :api: private
20
+ def initialize(env, config = {}) # :nodoc:
21
+ @config = config
22
+ @env, @_status, @headers = env, nil, {}
23
+ @halted = false
24
+ end
25
+
26
+ # The method that is called from above. This method calls the underlying authetniate! method
27
+ # :api: private
28
+ def _run! # :nodoc:
29
+ result = authenticate!
30
+ self
31
+ end
32
+
33
+ # Acts as a guarding method for the strategy.
34
+ # If #valid? responds false, the strategy will not be executed
35
+ # Overwrite with your own logic
36
+ # :api: overwritable
37
+ def valid?; true; end
38
+
39
+ # Provides access to the headers hash for setting custom headers
40
+ # :api: public
41
+ def headers(header = {})
42
+ @headers ||= {}
43
+ @headers.merge! header
44
+ @headers
45
+ end
46
+
47
+ # Access to the errors object.
48
+ # :api: public
49
+ def errors
50
+ @env['warden.errors']
51
+ end
52
+
53
+ # Cause the processing of the strategies to stop and cascade no further
54
+ # :api: public
55
+ def halt!
56
+ @halted = true
57
+ end
58
+
59
+ # Checks to see if a strategy was halted
60
+ # :api: public
61
+ def halted?
62
+ !!@halted
63
+ end
64
+
65
+ # A simple method to return from authenticate! if you want to ignore this strategy
66
+ # :api: public
67
+ def pass; end
68
+
69
+ # Whenever you want to provide a user object as "authenticated" use the +success!+ method.
70
+ # This will halt the strategy, and set the user in the approprieate scope.
71
+ # It is the "login" method
72
+ #
73
+ # Parameters:
74
+ # user - The user object to login. This object can be anything you have setup to serialize in and out of the session
75
+ #
76
+ # :api: public
77
+ def success!(user)
78
+ halt!
79
+ @user = user
80
+ @result = :success
81
+ end
82
+
83
+ # This causes the strategy to fail. It does not throw an :warden symbol to drop the request out to the failure application
84
+ # You must throw an :warden symbol somewhere in the application to enforce this
85
+ # :api: public
86
+ def fail!(message = "Failed to Login")
87
+ halt!
88
+ @message = message
89
+ @result = :failure
90
+ end
91
+
92
+ # Causes the authentication to redirect. An :warden symbol must be thrown to actually execute this redirect
93
+ #
94
+ # Parameters:
95
+ # url <String> - The string representing the URL to be redirected to
96
+ # pararms <Hash> - Any parameters to encode into the URL
97
+ # opts <Hash> - Any options to recirect with.
98
+ # available options: permanent => (true || false)
99
+ #
100
+ # :api: public
101
+ def redirect!(url, params = {}, opts = {})
102
+ halt!
103
+ @_status = opts[:permanent] ? 301 : 302
104
+ headers["Location"] = url
105
+ headers["Location"] << "?" << Rack::Utils.build_query(params) unless params.empty?
106
+
107
+ @message = opts[:message].nil? ? "You are being redirected to #{headers["Location"]}" : opts[:message]
108
+
109
+ @result = :redirect
110
+
111
+ headers["Location"]
112
+ end
113
+
114
+ # Return a custom rack array. You must throw an :warden symbol to activate this
115
+ # :api: public
116
+ def custom!(response)
117
+ halt!
118
+ @custom_response = response
119
+ @result = :custom
120
+ end
121
+
122
+ end # Base
123
+ end # Strategies
124
+ end # Warden
@@ -0,0 +1,70 @@
1
+ module Warden
2
+ class Proxy
3
+ # :api: public
4
+ def errors
5
+ @env['warden.errors'] ||= Errors.new
6
+ end
7
+
8
+ # Lifted from DataMapper's dm-validations plugin :)
9
+ # @author Guy van den Berg
10
+ # @since DM 0.9
11
+ class Errors
12
+
13
+ include Enumerable
14
+
15
+ # Clear existing authentication errors.
16
+ def clear!
17
+ errors.clear
18
+ end
19
+
20
+ # Add a authentication error. Use the field_name :general if the errors does
21
+ # not apply to a specific field of the Resource.
22
+ #
23
+ # @param <Symbol> field_name the name of the field that caused the error
24
+ # @param <String> message the message to add
25
+ def add(field_name, message)
26
+ (errors[field_name] ||= []) << message
27
+ end
28
+
29
+ # Collect all errors into a single list.
30
+ def full_messages
31
+ errors.inject([]) do |list,pair|
32
+ list += pair.last
33
+ end
34
+ end
35
+
36
+ # Return authentication errors for a particular field_name.
37
+ #
38
+ # @param <Symbol> field_name the name of the field you want an error for
39
+ def on(field_name)
40
+ errors_for_field = errors[field_name]
41
+ blank?(errors_for_field) ? nil : errors_for_field
42
+ end
43
+
44
+ def each
45
+ errors.map.each do |k,v|
46
+ next if blank?(v)
47
+ yield(v)
48
+ end
49
+ end
50
+
51
+ def empty?
52
+ entries.empty?
53
+ end
54
+
55
+ def method_missing(meth, *args, &block)
56
+ errors.send(meth, *args, &block)
57
+ end
58
+
59
+ private
60
+ def errors
61
+ @errors ||= {}
62
+ end
63
+
64
+ def blank?(thing)
65
+ thing.nil? || thing == "" || (thing.respond_to?(:empty?) && thing.empty?)
66
+ end
67
+
68
+ end # class Errors
69
+ end # Proxy
70
+ end # Warden