warden 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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