loyal_warden 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +11 -0
- data/History.rdoc +150 -0
- data/LICENSE +20 -0
- data/README.textile +9 -0
- data/Rakefile +12 -0
- data/lib/loyal_warden.rb +2 -0
- data/lib/warden.rb +45 -0
- data/lib/warden/config.rb +112 -0
- data/lib/warden/errors.rb +66 -0
- data/lib/warden/hooks.rb +211 -0
- data/lib/warden/manager.rb +136 -0
- data/lib/warden/mixins/common.rb +44 -0
- data/lib/warden/proxy.rb +371 -0
- data/lib/warden/session_serializer.rb +52 -0
- data/lib/warden/strategies.rb +47 -0
- data/lib/warden/strategies/base.rb +175 -0
- data/lib/warden/test/helpers.rb +36 -0
- data/lib/warden/test/warden_helpers.rb +43 -0
- data/lib/warden/version.rb +4 -0
- data/loyal_warden.gemspec +26 -0
- data/spec/helpers/request_helper.rb +51 -0
- data/spec/helpers/strategies/failz.rb +8 -0
- data/spec/helpers/strategies/invalid.rb +8 -0
- data/spec/helpers/strategies/pass.rb +8 -0
- data/spec/helpers/strategies/pass_with_message.rb +8 -0
- data/spec/helpers/strategies/password.rb +13 -0
- data/spec/helpers/strategies/single.rb +12 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/warden/authenticated_data_store_spec.rb +114 -0
- data/spec/warden/config_spec.rb +48 -0
- data/spec/warden/errors_spec.rb +47 -0
- data/spec/warden/hooks_spec.rb +373 -0
- data/spec/warden/manager_spec.rb +316 -0
- data/spec/warden/proxy_spec.rb +1041 -0
- data/spec/warden/scoped_session_serializer.rb +123 -0
- data/spec/warden/session_serializer_spec.rb +53 -0
- data/spec/warden/strategies/base_spec.rb +313 -0
- data/spec/warden/strategies_spec.rb +93 -0
- data/spec/warden/test/helpers_spec.rb +93 -0
- data/spec/warden/test/test_mode_spec.rb +76 -0
- data/warden.gemspec +24 -0
- metadata +105 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Warden
|
3
|
+
class SessionSerializer
|
4
|
+
attr_reader :env
|
5
|
+
|
6
|
+
def initialize(env)
|
7
|
+
@env = env
|
8
|
+
end
|
9
|
+
|
10
|
+
def key_for(scope)
|
11
|
+
"warden.user.#{scope}.key"
|
12
|
+
end
|
13
|
+
|
14
|
+
def serialize(user)
|
15
|
+
user
|
16
|
+
end
|
17
|
+
|
18
|
+
def deserialize(key)
|
19
|
+
key
|
20
|
+
end
|
21
|
+
|
22
|
+
def store(user, scope)
|
23
|
+
return unless user
|
24
|
+
method_name = "#{scope}_serialize"
|
25
|
+
specialized = respond_to?(method_name)
|
26
|
+
session[key_for(scope)] = specialized ? send(method_name, user) : serialize(user)
|
27
|
+
end
|
28
|
+
|
29
|
+
def fetch(scope)
|
30
|
+
key = session[key_for(scope)]
|
31
|
+
return nil unless key
|
32
|
+
|
33
|
+
method_name = "#{scope}_deserialize"
|
34
|
+
user = respond_to?(method_name) ? send(method_name, key) : deserialize(key)
|
35
|
+
delete(scope) unless user
|
36
|
+
user
|
37
|
+
end
|
38
|
+
|
39
|
+
def stored?(scope)
|
40
|
+
!!session[key_for(scope)]
|
41
|
+
end
|
42
|
+
|
43
|
+
def delete(scope, user=nil)
|
44
|
+
session.delete(key_for(scope))
|
45
|
+
end
|
46
|
+
|
47
|
+
# We can't cache this result because the session can be lazy loaded
|
48
|
+
def session
|
49
|
+
env["rack.session"] || {}
|
50
|
+
end
|
51
|
+
end # SessionSerializer
|
52
|
+
end # Warden
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Warden
|
3
|
+
module Strategies
|
4
|
+
class << self
|
5
|
+
# Add a strategy and store it in a hash.
|
6
|
+
def add(label, strategy = nil, &block)
|
7
|
+
strategy ||= Class.new(Warden::Strategies::Base)
|
8
|
+
strategy.class_eval(&block) if block_given?
|
9
|
+
|
10
|
+
unless strategy.method_defined?(:authenticate!)
|
11
|
+
raise NoMethodError, "authenticate! is not declared in the #{label.inspect} strategy"
|
12
|
+
end
|
13
|
+
|
14
|
+
base = Warden::Strategies::Base
|
15
|
+
unless strategy.ancestors.include?(base)
|
16
|
+
raise "#{label.inspect} is not a #{base}"
|
17
|
+
end
|
18
|
+
|
19
|
+
_strategies[label] = strategy
|
20
|
+
end
|
21
|
+
|
22
|
+
# Update a previously given strategy.
|
23
|
+
def update(label, &block)
|
24
|
+
strategy = _strategies[label]
|
25
|
+
raise "Unknown strategy #{label.inspect}" unless strategy
|
26
|
+
add(label, strategy, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Provides access to strategies by label
|
30
|
+
# :api: public
|
31
|
+
def [](label)
|
32
|
+
_strategies[label]
|
33
|
+
end
|
34
|
+
|
35
|
+
# Clears all declared.
|
36
|
+
# :api: public
|
37
|
+
def clear!
|
38
|
+
_strategies.clear
|
39
|
+
end
|
40
|
+
|
41
|
+
# :api: private
|
42
|
+
def _strategies
|
43
|
+
@strategies ||= {}
|
44
|
+
end
|
45
|
+
end # << self
|
46
|
+
end # Strategies
|
47
|
+
end # Warden
|
@@ -0,0 +1,175 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Warden
|
3
|
+
module Strategies
|
4
|
+
# A strategy is a place where you can put logic related to authentication. Any strategy inherits
|
5
|
+
# from Warden::Strategies::Base.
|
6
|
+
#
|
7
|
+
# The Warden::Strategies.add method is a simple way to provide custom strategies.
|
8
|
+
# You _must_ declare an @authenticate!@ method.
|
9
|
+
# You _may_ provide a @valid?@ method.
|
10
|
+
# The valid method should return true or false depending on if the strategy is a valid one for the request.
|
11
|
+
#
|
12
|
+
# The parameters for Warden::Strategies.add method is:
|
13
|
+
# <label: Symbol> The label is the name given to a strategy. Use the label to refer to the strategy when authenticating
|
14
|
+
# <strategy: Class|nil> The optional stragtegy argument if set _must_ be a class that inherits from Warden::Strategies::Base and _must_
|
15
|
+
# implement an @authenticate!@ method
|
16
|
+
# <block> The block acts as a convinient way to declare your strategy. Inside is the class definition of a strategy.
|
17
|
+
#
|
18
|
+
# Examples:
|
19
|
+
#
|
20
|
+
# Block Declared Strategy:
|
21
|
+
# Warden::Strategies.add(:foo) do
|
22
|
+
# def authenticate!
|
23
|
+
# # authentication logic
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# Class Declared Strategy:
|
28
|
+
# Warden::Strategies.add(:foo, MyStrategy)
|
29
|
+
#
|
30
|
+
class Base
|
31
|
+
# :api: public
|
32
|
+
attr_accessor :user, :message
|
33
|
+
|
34
|
+
# :api: private
|
35
|
+
attr_accessor :result, :custom_response
|
36
|
+
|
37
|
+
# :api: public
|
38
|
+
attr_reader :env, :scope, :status
|
39
|
+
|
40
|
+
include ::Warden::Mixins::Common
|
41
|
+
|
42
|
+
# :api: private
|
43
|
+
def initialize(env, scope=nil) # :nodoc:
|
44
|
+
@env, @scope = env, scope
|
45
|
+
@status, @headers = nil, {}
|
46
|
+
@halted, @performed = false, false
|
47
|
+
end
|
48
|
+
|
49
|
+
# The method that is called from above. This method calls the underlying authenticate! method
|
50
|
+
# :api: private
|
51
|
+
def _run! # :nodoc:
|
52
|
+
@performed = true
|
53
|
+
authenticate!
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns if this strategy was already performed.
|
58
|
+
# :api: private
|
59
|
+
def performed? #:nodoc:
|
60
|
+
@performed
|
61
|
+
end
|
62
|
+
|
63
|
+
# Marks this strategy as not performed.
|
64
|
+
# :api: private
|
65
|
+
def clear!
|
66
|
+
@performed = false
|
67
|
+
end
|
68
|
+
|
69
|
+
# Acts as a guarding method for the strategy.
|
70
|
+
# If #valid? responds false, the strategy will not be executed
|
71
|
+
# Overwrite with your own logic
|
72
|
+
# :api: overwritable
|
73
|
+
def valid?; true; end
|
74
|
+
|
75
|
+
# Provides access to the headers hash for setting custom headers
|
76
|
+
# :api: public
|
77
|
+
def headers(header = {})
|
78
|
+
@headers ||= {}
|
79
|
+
@headers.merge! header
|
80
|
+
@headers
|
81
|
+
end
|
82
|
+
|
83
|
+
# Access to the errors object.
|
84
|
+
# :api: public
|
85
|
+
def errors
|
86
|
+
@env['warden'].errors
|
87
|
+
end
|
88
|
+
|
89
|
+
# Cause the processing of the strategies to stop and cascade no further
|
90
|
+
# :api: public
|
91
|
+
def halt!
|
92
|
+
@halted = true
|
93
|
+
end
|
94
|
+
|
95
|
+
# Checks to see if a strategy was halted
|
96
|
+
# :api: public
|
97
|
+
def halted?
|
98
|
+
!!@halted
|
99
|
+
end
|
100
|
+
|
101
|
+
# Checks to see if a strategy should result in a permanent login
|
102
|
+
# :api: public
|
103
|
+
def store?
|
104
|
+
true
|
105
|
+
end
|
106
|
+
|
107
|
+
# A simple method to return from authenticate! if you want to ignore this strategy
|
108
|
+
# :api: public
|
109
|
+
def pass; end
|
110
|
+
|
111
|
+
# Whenever you want to provide a user object as "authenticated" use the +success!+ method.
|
112
|
+
# This will halt the strategy, and set the user in the approprieate scope.
|
113
|
+
# It is the "login" method
|
114
|
+
#
|
115
|
+
# Parameters:
|
116
|
+
# user - The user object to login. This object can be anything you have setup to serialize in and out of the session
|
117
|
+
#
|
118
|
+
# :api: public
|
119
|
+
def success!(user, message = nil)
|
120
|
+
halt!
|
121
|
+
@user = user
|
122
|
+
@message = message
|
123
|
+
@result = :success
|
124
|
+
end
|
125
|
+
|
126
|
+
# This causes the strategy to fail. It does not throw an :warden symbol to drop the request out to the failure application
|
127
|
+
# You must throw an :warden symbol somewhere in the application to enforce this
|
128
|
+
# Halts the strategies so that this is the last strategy checked
|
129
|
+
# :api: public
|
130
|
+
def fail!(message = "Failed to Login")
|
131
|
+
halt!
|
132
|
+
@message = message
|
133
|
+
@result = :failure
|
134
|
+
end
|
135
|
+
|
136
|
+
# Casuses 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.
|
137
|
+
# :api: public
|
138
|
+
def fail(message = "Failed to Login")
|
139
|
+
@message = message
|
140
|
+
@result = :failure
|
141
|
+
end
|
142
|
+
|
143
|
+
# Causes the authentication to redirect. An :warden symbol must be thrown to actually execute this redirect
|
144
|
+
#
|
145
|
+
# Parameters:
|
146
|
+
# url <String> - The string representing the URL to be redirected to
|
147
|
+
# pararms <Hash> - Any parameters to encode into the URL
|
148
|
+
# opts <Hash> - Any options to recirect with.
|
149
|
+
# available options: permanent => (true || false)
|
150
|
+
#
|
151
|
+
# :api: public
|
152
|
+
def redirect!(url, params = {}, opts = {})
|
153
|
+
halt!
|
154
|
+
@status = opts[:permanent] ? 301 : 302
|
155
|
+
headers["Location"] = url
|
156
|
+
headers["Location"] << "?" << Rack::Utils.build_query(params) unless params.empty?
|
157
|
+
headers["Content-Type"] = opts[:content_type] || 'text/plain'
|
158
|
+
|
159
|
+
@message = opts[:message] || "You are being redirected to #{headers["Location"]}"
|
160
|
+
@result = :redirect
|
161
|
+
|
162
|
+
headers["Location"]
|
163
|
+
end
|
164
|
+
|
165
|
+
# Return a custom rack array. You must throw an :warden symbol to activate this
|
166
|
+
# :api: public
|
167
|
+
def custom!(response)
|
168
|
+
halt!
|
169
|
+
@custom_response = response
|
170
|
+
@result = :custom
|
171
|
+
end
|
172
|
+
|
173
|
+
end # Base
|
174
|
+
end # Strategies
|
175
|
+
end # Warden
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Warden
|
4
|
+
module Test
|
5
|
+
# A collection of test helpers for testing full stack rack applications using Warden
|
6
|
+
# These provide the ability to login and logout on any given request
|
7
|
+
# Note: During the teardown phase of your specs you should include: Warden.test_reset!
|
8
|
+
module Helpers
|
9
|
+
def self.included(base)
|
10
|
+
::Warden.test_mode!
|
11
|
+
end
|
12
|
+
|
13
|
+
# A helper method that will peform a login of a user in warden for the next request
|
14
|
+
# Provide it the same options as you would to Warden::Proxy#set_user
|
15
|
+
# @see Warden::Proxy#set_user
|
16
|
+
# @api public
|
17
|
+
def login_as(user, opts = {})
|
18
|
+
Warden.on_next_request do |proxy|
|
19
|
+
opts[:event] ||= :authentication
|
20
|
+
proxy.set_user(user, opts)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Logs out a user from the session.
|
25
|
+
# Without arguments, all users will be logged out
|
26
|
+
# Provide a list of scopes to only log out users with that scope.
|
27
|
+
# @see Warden::Proxy#logout
|
28
|
+
# @api public
|
29
|
+
def logout(*scopes)
|
30
|
+
Warden.on_next_request do |proxy|
|
31
|
+
proxy.logout(*scopes)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Warden
|
4
|
+
|
5
|
+
module Test
|
6
|
+
module WardenHelpers
|
7
|
+
# Returns list of regex objects that match paths expected to be an asset
|
8
|
+
# @see Warden::Proxy#asset_request?
|
9
|
+
# @api public
|
10
|
+
def asset_paths
|
11
|
+
@asset_paths ||= [/^\/assets\//]
|
12
|
+
end
|
13
|
+
|
14
|
+
# Sets list of regex objects that match paths expected to be an asset
|
15
|
+
# @see Warden::Proxy#asset_request?
|
16
|
+
# @api public
|
17
|
+
def asset_paths=(*vals)
|
18
|
+
@asset_paths = vals
|
19
|
+
end
|
20
|
+
|
21
|
+
# Adds a block to be executed on the next request when the stack reaches warden.
|
22
|
+
# The warden proxy is yielded to the block
|
23
|
+
# @api public
|
24
|
+
def on_next_request(&blk)
|
25
|
+
_on_next_request << blk
|
26
|
+
end
|
27
|
+
|
28
|
+
# resets wardens tests
|
29
|
+
# any blocks queued to execute will be removed
|
30
|
+
# @api public
|
31
|
+
def test_reset!
|
32
|
+
_on_next_request.clear
|
33
|
+
end
|
34
|
+
|
35
|
+
# A containter for the on_next_request items.
|
36
|
+
# @api private
|
37
|
+
def _on_next_request
|
38
|
+
@_on_next_request ||= []
|
39
|
+
@_on_next_request
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require './lib/warden/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = %q{loyal_warden}
|
7
|
+
# s.version = Warden::VERSION.dup
|
8
|
+
s.version = '0.0.5'
|
9
|
+
s.authors = ["Daniel Neighman"]
|
10
|
+
s.email = %q{has.sox@gmail.com}
|
11
|
+
s.license = "MIT"
|
12
|
+
s.extra_rdoc_files = [
|
13
|
+
"LICENSE",
|
14
|
+
"README.textile"
|
15
|
+
]
|
16
|
+
s.files = Dir["**/*"] - Dir["*.gem"] - ["Gemfile.lock"]
|
17
|
+
s.homepage = %q{http://github.com/hassox/warden}
|
18
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
s.rubyforge_project = %q{warden}
|
21
|
+
s.rubygems_version = %q{1.3.7}
|
22
|
+
s.summary = %q{Rack middleware that provides authentication for rack applications}
|
23
|
+
|
24
|
+
s.add_dependency "rack", ">= 1.0"
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Warden::Spec
|
3
|
+
module Helpers
|
4
|
+
FAILURE_APP = lambda{|e|[401, {"Content-Type" => "text/plain"}, ["You Fail!"]] }
|
5
|
+
|
6
|
+
def env_with_params(path = "/", params = {}, env = {})
|
7
|
+
method = params.delete(:method) || "GET"
|
8
|
+
env = { 'HTTP_VERSION' => '1.1', 'REQUEST_METHOD' => "#{method}" }.merge(env)
|
9
|
+
Rack::MockRequest.env_for("#{path}?#{Rack::Utils.build_query(params)}", env)
|
10
|
+
end
|
11
|
+
|
12
|
+
def setup_rack(app = nil, opts = {}, &block)
|
13
|
+
app ||= block if block_given?
|
14
|
+
|
15
|
+
opts[:failure_app] ||= failure_app
|
16
|
+
opts[:default_strategies] ||= [:password]
|
17
|
+
opts[:default_serializers] ||= [:session]
|
18
|
+
blk = opts[:configurator] || proc{}
|
19
|
+
|
20
|
+
Rack::Builder.new do
|
21
|
+
use opts[:session] || Warden::Spec::Helpers::Session unless opts[:nil_session]
|
22
|
+
use Warden::Manager, opts, &blk
|
23
|
+
run app
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def valid_response
|
28
|
+
Rack::Response.new("OK").finish
|
29
|
+
end
|
30
|
+
|
31
|
+
def failure_app
|
32
|
+
Warden::Spec::Helpers::FAILURE_APP
|
33
|
+
end
|
34
|
+
|
35
|
+
def success_app
|
36
|
+
lambda{|e| [200, {"Content-Type" => "text/plain"}, ["You Win"]]}
|
37
|
+
end
|
38
|
+
|
39
|
+
class Session
|
40
|
+
attr_accessor :app
|
41
|
+
def initialize(app,configs = {})
|
42
|
+
@app = app
|
43
|
+
end
|
44
|
+
|
45
|
+
def call(e)
|
46
|
+
e['rack.session'] ||= {}
|
47
|
+
@app.call(e)
|
48
|
+
end
|
49
|
+
end # session
|
50
|
+
end
|
51
|
+
end
|