rack 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rack might be problematic. Click here for more details.
- data/AUTHORS +2 -0
- data/RDOX +46 -1
- data/README +19 -4
- data/Rakefile +9 -8
- data/bin/rackup +2 -0
- data/example/protectedlobster.rb +14 -0
- data/lib/rack.rb +19 -0
- data/lib/rack/adapter/camping.rb +6 -0
- data/lib/rack/auth/abstract/handler.rb +28 -0
- data/lib/rack/auth/abstract/request.rb +39 -0
- data/lib/rack/auth/basic.rb +58 -0
- data/lib/rack/auth/digest/md5.rb +124 -0
- data/lib/rack/auth/digest/nonce.rb +52 -0
- data/lib/rack/auth/digest/params.rb +55 -0
- data/lib/rack/auth/digest/request.rb +40 -0
- data/lib/rack/commonlogger.rb +1 -1
- data/lib/rack/file.rb +1 -1
- data/lib/rack/handler/cgi.rb +7 -7
- data/lib/rack/handler/fastcgi.rb +1 -1
- data/lib/rack/handler/mongrel.rb +8 -7
- data/lib/rack/handler/webrick.rb +7 -6
- data/lib/rack/lint.rb +3 -3
- data/lib/rack/lobster.rb +4 -4
- data/lib/rack/mock.rb +9 -33
- data/lib/rack/recursive.rb +1 -1
- data/lib/rack/reloader.rb +1 -1
- data/lib/rack/request.rb +32 -9
- data/lib/rack/response.rb +54 -8
- data/lib/rack/session/cookie.rb +73 -0
- data/lib/rack/showexceptions.rb +2 -2
- data/lib/rack/showstatus.rb +103 -0
- data/lib/rack/static.rb +38 -0
- data/lib/rack/urlmap.rb +1 -1
- data/lib/rack/utils.rb +45 -3
- data/test/spec_rack_auth_basic.rb +68 -0
- data/test/spec_rack_auth_digest.rb +167 -0
- data/test/spec_rack_camping.rb +3 -0
- data/test/spec_rack_mock.rb +2 -0
- data/test/spec_rack_mongrel.rb +12 -0
- data/test/spec_rack_request.rb +60 -0
- data/test/spec_rack_response.rb +50 -1
- data/test/spec_rack_session_cookie.rb +49 -0
- data/test/spec_rack_showstatus.rb +71 -0
- data/test/spec_rack_static.rb +37 -0
- data/test/spec_rack_urlmap.rb +1 -7
- data/test/spec_rack_webrick.rb +17 -0
- metadata +23 -3
- data/lib/rack/adapter/rails.rb +0 -65
data/AUTHORS
CHANGED
@@ -1,3 +1,5 @@
|
|
1
1
|
* Christian Neukirchen <chneukirchen@gmail.com>
|
2
2
|
* Rails adapter: Christoffer Sawicki <christoffer.sawicki@gmail.com>
|
3
|
+
* HTTP authentication: Tim Fletcher <twoggle@gmail.com>
|
4
|
+
* Cookie sessions, Static handler: Luc Heinrich <luc@honk-honk.com>
|
3
5
|
* Official Logo: Armin Ronacher
|
data/RDOX
CHANGED
@@ -1,4 +1,21 @@
|
|
1
1
|
|
2
|
+
== Rack::Auth::Basic
|
3
|
+
* should challenge correctly when no credentials are specified
|
4
|
+
* should rechallenge if incorrect credentials are specified
|
5
|
+
* should return application output if correct credentials are specified
|
6
|
+
* should return 400 Bad Request if different auth scheme used
|
7
|
+
|
8
|
+
== Rack::Auth::Digest::MD5
|
9
|
+
* should challenge when no credentials are specified
|
10
|
+
* should return application output if correct credentials given
|
11
|
+
* should return application output if correct credentials given (hashed passwords)
|
12
|
+
* should rechallenge if incorrect username given
|
13
|
+
* should rechallenge if incorrect password given
|
14
|
+
* should rechallenge with stale parameter if nonce is stale
|
15
|
+
* should return 400 Bad Request if incorrect qop given
|
16
|
+
* should return 400 Bad Request if incorrect uri given
|
17
|
+
* should return 400 Bad Request if different auth scheme used
|
18
|
+
|
2
19
|
== Rack::Adapter::Camping
|
3
20
|
* works with GET
|
4
21
|
* works with POST
|
@@ -82,6 +99,7 @@
|
|
82
99
|
* should have CGI headers on POST
|
83
100
|
* should support HTTP auth
|
84
101
|
* should set status
|
102
|
+
* should provide a .run
|
85
103
|
|
86
104
|
== Rack::Recursive
|
87
105
|
* should allow for subrequests
|
@@ -93,12 +111,17 @@
|
|
93
111
|
* can figure out the correct host
|
94
112
|
* can parse the query string
|
95
113
|
* can parse POST data
|
114
|
+
* can get value by key from params with #[]
|
115
|
+
* can set value to key on params with #[]=
|
116
|
+
* values_at answers values by keys in order given
|
117
|
+
* referrer should be extracted correct
|
96
118
|
* can cache, but invalidates the cache
|
97
119
|
* can figure out if called via XHR
|
98
120
|
* can parse cookies
|
99
121
|
* provides setters
|
100
122
|
* provides the original env
|
101
123
|
* can restore the URL
|
124
|
+
* can restore the full path
|
102
125
|
* can parse multipart form data
|
103
126
|
* can parse big multipart form data
|
104
127
|
* can detect invalid multipart form data
|
@@ -112,10 +135,31 @@
|
|
112
135
|
* has a useful constructor
|
113
136
|
* has a constructor that can take a block
|
114
137
|
* doesn't return invalid responses
|
138
|
+
* knows if it's empty
|
139
|
+
* should provide access to the HTTP status
|
140
|
+
* should provide access to the HTTP headers
|
141
|
+
|
142
|
+
== Rack::Session::Cookie
|
143
|
+
* creates a new cookie
|
144
|
+
* loads from a cookie
|
145
|
+
* survives broken cookies
|
146
|
+
* barks on too big cookies
|
115
147
|
|
116
148
|
== Rack::ShowExceptions
|
117
149
|
* catches exceptions
|
118
150
|
|
151
|
+
== Rack::ShowStatus
|
152
|
+
* should provide a default status message
|
153
|
+
* should let the app provide additional information
|
154
|
+
* should not replace existing messages
|
155
|
+
* should pass on original headers
|
156
|
+
* should replace existing messages if there is detail
|
157
|
+
|
158
|
+
== Rack::Static
|
159
|
+
* serves files
|
160
|
+
* 404s if url root is known but it can't find the file
|
161
|
+
* calls down the chain if url root is not known
|
162
|
+
|
119
163
|
== Rack::URLMap
|
120
164
|
* dispatches paths correctly
|
121
165
|
* dispatches hosts correctly
|
@@ -140,5 +184,6 @@
|
|
140
184
|
* should have CGI headers on POST
|
141
185
|
* should support HTTP auth
|
142
186
|
* should set status
|
187
|
+
* should provide a .run
|
143
188
|
|
144
|
-
|
189
|
+
137 specifications (546 requirements), 0 failures
|
data/README
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= Rack, a modular Ruby webserver interface
|
2
2
|
|
3
|
-
Rack provides minimal, modular and adaptable interface for developing
|
3
|
+
Rack provides a minimal, modular and adaptable interface for developing
|
4
4
|
web applications in Ruby. By wrapping HTTP requests and responses in
|
5
5
|
the simplest way possible, it unifies and distills the API for web
|
6
6
|
servers, web frameworks, and software in between (the so-called
|
@@ -13,6 +13,7 @@ which all Rack applications should conform to.
|
|
13
13
|
|
14
14
|
The included *handlers* connect all kinds of web servers to Rack:
|
15
15
|
* Mongrel
|
16
|
+
* Mongrel/Swiftcore (require it before Rack.)
|
16
17
|
* WEBrick
|
17
18
|
* FCGI
|
18
19
|
* CGI
|
@@ -76,11 +77,11 @@ Try the lobster!
|
|
76
77
|
|
77
78
|
Either with the embedded WEBrick starter:
|
78
79
|
|
79
|
-
|
80
|
+
ruby -Ilib lib/rack/lobster.rb
|
80
81
|
|
81
82
|
Or with rackup:
|
82
83
|
|
83
|
-
|
84
|
+
bin/rackup -Ilib example/lobster.ru
|
84
85
|
|
85
86
|
By default, the lobster is found at http://localhost:9292.
|
86
87
|
|
@@ -99,6 +100,16 @@ at my site:
|
|
99
100
|
|
100
101
|
* March 3rd, 2007: First public release 0.1.
|
101
102
|
|
103
|
+
* May 16th, 2007: Second public release 0.2.
|
104
|
+
* HTTP Basic authentication.
|
105
|
+
* Cookie Sessions.
|
106
|
+
* Static file handler.
|
107
|
+
* Improved Rack::Request.
|
108
|
+
* Improved Rack::Response.
|
109
|
+
* Added Rack::ShowStatus, for better default error messages.
|
110
|
+
* Bug fixes in the Camping adapter.
|
111
|
+
* Removed Rails adapter, was too alpha.
|
112
|
+
|
102
113
|
== Contact
|
103
114
|
|
104
115
|
Please mail bugs, suggestions and patches to
|
@@ -111,9 +122,13 @@ You are also welcome to join the #rack channel on irc.freenode.net.
|
|
111
122
|
|
112
123
|
== Thanks to
|
113
124
|
|
114
|
-
* Michael Fellinger, for the helpful discussion
|
125
|
+
* Michael Fellinger, for the helpful discussion, bugfixes and a better
|
126
|
+
Rack::Request interface.
|
115
127
|
* Christoffer Sawicki, for the Rails adapter.
|
128
|
+
* Tim Fletcher, for the HTTP authentication code.
|
116
129
|
* Armin Ronacher, for the logo and racktools.
|
130
|
+
* Aredridel, for bug fixing.
|
131
|
+
* Gary Wright, for proposing a better Rack::Response interface.
|
117
132
|
* Alexander Kellett for testing the Gem and reviewing the announce.
|
118
133
|
* Marcus Rückert, for help with configuring and debugging lighttpd.
|
119
134
|
* The WSGI team for the well-done and documented work they've done and
|
data/Rakefile
CHANGED
@@ -12,13 +12,14 @@ task :predist => [:chmod, :changelog, :rdoc]
|
|
12
12
|
|
13
13
|
desc "Make an archive as .tar.gz"
|
14
14
|
task :dist => :fulltest do
|
15
|
-
|
16
|
-
|
15
|
+
sh "export DARCS_REPO=#{File.expand_path "."}; " +
|
16
|
+
"darcs dist -d rack-#{get_darcs_tree_version}"
|
17
17
|
end
|
18
18
|
|
19
19
|
# Helper to retrieve the "revision number" of the darcs tree.
|
20
20
|
def get_darcs_tree_version
|
21
21
|
unless File.directory? "_darcs"
|
22
|
+
$: << "lib"
|
22
23
|
require 'rack'
|
23
24
|
return Rack.version
|
24
25
|
end
|
@@ -58,13 +59,13 @@ end
|
|
58
59
|
|
59
60
|
desc "Generate a ChangeLog"
|
60
61
|
task :changelog do
|
61
|
-
|
62
|
+
sh "darcs changes --repo=#{ENV["DARCS_REPO"] || "."} >ChangeLog"
|
62
63
|
end
|
63
64
|
|
64
65
|
|
65
66
|
desc "Generate RDox"
|
66
67
|
task "RDOX" do
|
67
|
-
|
68
|
+
sh "specrb -Ilib:test -a --rdox >RDOX"
|
68
69
|
end
|
69
70
|
|
70
71
|
desc "Generate Rack Specification"
|
@@ -80,12 +81,12 @@ end
|
|
80
81
|
|
81
82
|
desc "Run all the fast tests"
|
82
83
|
task :test do
|
83
|
-
|
84
|
+
sh "specrb -Ilib:test -w #{ENV['TEST'] || '-a'} #{ENV['TESTOPTS'] || '-t "^(?!Rack::Handler|Rack::Adapter)"'}"
|
84
85
|
end
|
85
86
|
|
86
87
|
desc "Run all the tests"
|
87
88
|
task :fulltest do
|
88
|
-
|
89
|
+
sh "specrb -Ilib:test -w #{ENV['TEST'] || '-a'} #{ENV['TESTOPTS']}"
|
89
90
|
end
|
90
91
|
|
91
92
|
begin
|
@@ -155,8 +156,8 @@ end
|
|
155
156
|
task :rdoc => ["SPEC", "RDOX"]
|
156
157
|
|
157
158
|
task :pushsite => [:rdoc] do
|
158
|
-
|
159
|
-
|
159
|
+
sh "rsync -avz doc/ chneukirchen@rack.rubyforge.org:/var/www/gforge-projects/rack/doc/"
|
160
|
+
sh "rsync -avz site/ chneukirchen@rack.rubyforge.org:/var/www/gforge-projects/rack/"
|
160
161
|
end
|
161
162
|
|
162
163
|
begin
|
data/bin/rackup
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'rack/lobster'
|
3
|
+
|
4
|
+
lobster = Rack::Lobster.new
|
5
|
+
|
6
|
+
protected_lobster = Rack::Auth::Basic.new(lobster) do |username, password|
|
7
|
+
'secret' == password
|
8
|
+
end
|
9
|
+
|
10
|
+
protected_lobster.realm = 'Lobster 2.0'
|
11
|
+
|
12
|
+
pretty_protected_lobster = Rack::ShowStatus.new(Rack::ShowExceptions.new(protected_lobster))
|
13
|
+
|
14
|
+
Rack::Handler::WEBrick.run pretty_protected_lobster, :Port => 9292
|
data/lib/rack.rb
CHANGED
@@ -22,6 +22,7 @@ module Rack
|
|
22
22
|
end
|
23
23
|
|
24
24
|
autoload :Builder, "rack/builder"
|
25
|
+
autoload :Cascade, "rack/cascade"
|
25
26
|
autoload :CommonLogger, "rack/commonlogger"
|
26
27
|
autoload :File, "rack/file"
|
27
28
|
autoload :ForwardRequest, "rack/recursive"
|
@@ -29,6 +30,8 @@ module Rack
|
|
29
30
|
autoload :Recursive, "rack/recursive"
|
30
31
|
autoload :Reloader, "rack/reloader"
|
31
32
|
autoload :ShowExceptions, "rack/showexceptions"
|
33
|
+
autoload :ShowStatus, "rack/showstatus"
|
34
|
+
autoload :Static, "rack/static"
|
32
35
|
autoload :URLMap, "rack/urlmap"
|
33
36
|
autoload :Utils, "rack/utils"
|
34
37
|
|
@@ -38,6 +41,22 @@ module Rack
|
|
38
41
|
autoload :Request, "rack/request"
|
39
42
|
autoload :Response, "rack/response"
|
40
43
|
|
44
|
+
module Auth
|
45
|
+
autoload :Basic, "rack/auth/basic"
|
46
|
+
autoload :AbstractRequest, "rack/auth/abstract/request"
|
47
|
+
autoload :AbstractHandler, "rack/auth/abstract/handler"
|
48
|
+
module Digest
|
49
|
+
autoload :MD5, "rack/auth/digest/md5"
|
50
|
+
autoload :Nonce, "rack/auth/digest/nonce"
|
51
|
+
autoload :Params, "rack/auth/digest/params"
|
52
|
+
autoload :Request, "rack/auth/digest/request"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module Session
|
57
|
+
autoload :Cookie, "rack/session/cookie"
|
58
|
+
end
|
59
|
+
|
41
60
|
# *Adapters* connect Rack with third party web frameworks.
|
42
61
|
#
|
43
62
|
# Rack includes adapters for Camping and Rails.
|
data/lib/rack/adapter/camping.rb
CHANGED
@@ -9,6 +9,12 @@ module Rack
|
|
9
9
|
env["PATH_INFO"] ||= ""
|
10
10
|
env["SCRIPT_NAME"] ||= ""
|
11
11
|
controller = @app.run(env['rack.input'], env)
|
12
|
+
h = controller.headers
|
13
|
+
h.each_pair do |k,v|
|
14
|
+
if v.kind_of? URI
|
15
|
+
h[k] = v.to_s
|
16
|
+
end
|
17
|
+
end
|
12
18
|
[controller.status, controller.headers, controller.body]
|
13
19
|
end
|
14
20
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Rack
|
2
|
+
module Auth
|
3
|
+
# Rack::Auth::AbstractHandler implements common authentication functionality.
|
4
|
+
#
|
5
|
+
# +realm+ should be set for all handlers.
|
6
|
+
|
7
|
+
class AbstractHandler
|
8
|
+
|
9
|
+
attr_accessor :realm
|
10
|
+
|
11
|
+
def initialize(app, &authenticator)
|
12
|
+
@app, @authenticator = app, authenticator
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def unauthorized(www_authenticate = challenge)
|
19
|
+
return [ 401, { 'WWW-Authenticate' => www_authenticate.to_s }, [] ]
|
20
|
+
end
|
21
|
+
|
22
|
+
def bad_request
|
23
|
+
[ 400, {}, [] ]
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
module Auth
|
5
|
+
class AbstractRequest
|
6
|
+
|
7
|
+
def initialize(env)
|
8
|
+
@env = env
|
9
|
+
end
|
10
|
+
|
11
|
+
def provided?
|
12
|
+
!authorization_key.nil?
|
13
|
+
end
|
14
|
+
|
15
|
+
def parts
|
16
|
+
@parts ||= @env[authorization_key].split(' ', 2)
|
17
|
+
end
|
18
|
+
|
19
|
+
def scheme
|
20
|
+
@scheme ||= parts.first.downcase.to_sym
|
21
|
+
end
|
22
|
+
|
23
|
+
def params
|
24
|
+
@params ||= parts.last
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
AUTHORIZATION_KEYS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION']
|
31
|
+
|
32
|
+
def authorization_key
|
33
|
+
@authorization_key ||= AUTHORIZATION_KEYS.detect { |key| @env.has_key?(key) }
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rack/auth/abstract/handler'
|
2
|
+
require 'rack/auth/abstract/request'
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
module Auth
|
6
|
+
# Rack::Auth::Basic implements HTTP Basic Authentication, as per RFC 2617.
|
7
|
+
#
|
8
|
+
# Initialize with the Rack application that you want protecting,
|
9
|
+
# and a block that checks if a username and password pair are valid.
|
10
|
+
#
|
11
|
+
# See also: <tt>example/protectedlobster.rb</tt>
|
12
|
+
|
13
|
+
class Basic < AbstractHandler
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
auth = Basic::Request.new(env)
|
17
|
+
|
18
|
+
return unauthorized unless auth.provided?
|
19
|
+
|
20
|
+
return bad_request unless auth.basic?
|
21
|
+
|
22
|
+
if valid?(auth)
|
23
|
+
env['REMOTE_USER'] = auth.username
|
24
|
+
|
25
|
+
return @app.call(env)
|
26
|
+
end
|
27
|
+
|
28
|
+
unauthorized
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def challenge
|
35
|
+
'Basic realm="%s"' % realm
|
36
|
+
end
|
37
|
+
|
38
|
+
def valid?(auth)
|
39
|
+
@authenticator.call(*auth.credentials)
|
40
|
+
end
|
41
|
+
|
42
|
+
class Request < Auth::AbstractRequest
|
43
|
+
def basic?
|
44
|
+
:basic == scheme
|
45
|
+
end
|
46
|
+
|
47
|
+
def credentials
|
48
|
+
@credentials ||= Base64.decode64(params).split(/:/, 2)
|
49
|
+
end
|
50
|
+
|
51
|
+
def username
|
52
|
+
credentials.first
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'rack/auth/abstract/handler'
|
2
|
+
require 'rack/auth/digest/request'
|
3
|
+
require 'rack/auth/digest/params'
|
4
|
+
require 'rack/auth/digest/nonce'
|
5
|
+
require 'digest/md5'
|
6
|
+
|
7
|
+
module Rack
|
8
|
+
module Auth
|
9
|
+
module Digest
|
10
|
+
# Rack::Auth::Digest::MD5 implements the MD5 algorithm version of
|
11
|
+
# HTTP Digest Authentication, as per RFC 2617.
|
12
|
+
#
|
13
|
+
# Initialize with the [Rack] application that you want protecting,
|
14
|
+
# and a block that looks up a plaintext password for a given username.
|
15
|
+
#
|
16
|
+
# +opaque+ needs to be set to a constant base64/hexadecimal string.
|
17
|
+
#
|
18
|
+
class MD5 < AbstractHandler
|
19
|
+
|
20
|
+
attr_accessor :opaque
|
21
|
+
|
22
|
+
attr_writer :passwords_hashed
|
23
|
+
|
24
|
+
def initialize(app)
|
25
|
+
super
|
26
|
+
@passwords_hashed = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def passwords_hashed?
|
30
|
+
!!@passwords_hashed
|
31
|
+
end
|
32
|
+
|
33
|
+
def call(env)
|
34
|
+
auth = Request.new(env)
|
35
|
+
|
36
|
+
unless auth.provided?
|
37
|
+
return unauthorized
|
38
|
+
end
|
39
|
+
|
40
|
+
if !auth.digest? || !auth.correct_uri? || !valid_qop?(auth)
|
41
|
+
return bad_request
|
42
|
+
end
|
43
|
+
|
44
|
+
if valid?(auth)
|
45
|
+
if auth.nonce.stale?
|
46
|
+
return unauthorized(challenge(:stale => true))
|
47
|
+
else
|
48
|
+
env['REMOTE_USER'] = auth.username
|
49
|
+
|
50
|
+
return @app.call(env)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
unauthorized
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
QOP = 'auth'.freeze
|
61
|
+
|
62
|
+
def params(hash = {})
|
63
|
+
Params.new do |params|
|
64
|
+
params['realm'] = realm
|
65
|
+
params['nonce'] = Nonce.new.to_s
|
66
|
+
params['opaque'] = H(opaque)
|
67
|
+
params['qop'] = QOP
|
68
|
+
|
69
|
+
hash.each { |k, v| params[k] = v }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def challenge(hash = {})
|
74
|
+
"Digest #{params(hash)}"
|
75
|
+
end
|
76
|
+
|
77
|
+
def valid?(auth)
|
78
|
+
valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth)
|
79
|
+
end
|
80
|
+
|
81
|
+
def valid_qop?(auth)
|
82
|
+
QOP == auth.qop
|
83
|
+
end
|
84
|
+
|
85
|
+
def valid_opaque?(auth)
|
86
|
+
H(opaque) == auth.opaque
|
87
|
+
end
|
88
|
+
|
89
|
+
def valid_nonce?(auth)
|
90
|
+
auth.nonce.valid?
|
91
|
+
end
|
92
|
+
|
93
|
+
def valid_digest?(auth)
|
94
|
+
digest(auth, @authenticator.call(auth.username)) == auth.response
|
95
|
+
end
|
96
|
+
|
97
|
+
def md5(data)
|
98
|
+
::Digest::MD5.hexdigest(data)
|
99
|
+
end
|
100
|
+
|
101
|
+
alias :H :md5
|
102
|
+
|
103
|
+
def KD(secret, data)
|
104
|
+
H([secret, data] * ':')
|
105
|
+
end
|
106
|
+
|
107
|
+
def A1(auth, password)
|
108
|
+
[ auth.username, auth.realm, password ] * ':'
|
109
|
+
end
|
110
|
+
|
111
|
+
def A2(auth)
|
112
|
+
[ auth.method, auth.uri ] * ':'
|
113
|
+
end
|
114
|
+
|
115
|
+
def digest(auth, password)
|
116
|
+
password_hash = passwords_hashed? ? password : H(A1(auth, password))
|
117
|
+
|
118
|
+
KD(password_hash, [ auth.nonce, auth.nc, auth.cnonce, QOP, H(A2(auth)) ] * ':')
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|