qoobaa-rack 1.0.0.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/COPYING +18 -0
- data/KNOWN-ISSUES +18 -0
- data/RDOX +0 -0
- data/README +353 -0
- data/Rakefile +164 -0
- data/SPEC +164 -0
- data/bin/rackup +176 -0
- data/contrib/rack_logo.svg +111 -0
- data/example/lobster.ru +4 -0
- data/example/protectedlobster.rb +14 -0
- data/example/protectedlobster.ru +8 -0
- data/lib/rack/adapter/camping.rb +22 -0
- data/lib/rack/auth/abstract/handler.rb +37 -0
- data/lib/rack/auth/abstract/request.rb +37 -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 +51 -0
- data/lib/rack/auth/digest/params.rb +55 -0
- data/lib/rack/auth/digest/request.rb +40 -0
- data/lib/rack/auth/openid.rb +487 -0
- data/lib/rack/builder.rb +63 -0
- data/lib/rack/cascade.rb +41 -0
- data/lib/rack/chunked.rb +49 -0
- data/lib/rack/commonlogger.rb +52 -0
- data/lib/rack/conditionalget.rb +47 -0
- data/lib/rack/content_length.rb +29 -0
- data/lib/rack/content_type.rb +23 -0
- data/lib/rack/deflater.rb +96 -0
- data/lib/rack/directory.rb +153 -0
- data/lib/rack/file.rb +88 -0
- data/lib/rack/handler/cgi.rb +61 -0
- data/lib/rack/handler/evented_mongrel.rb +8 -0
- data/lib/rack/handler/fastcgi.rb +88 -0
- data/lib/rack/handler/lsws.rb +60 -0
- data/lib/rack/handler/mongrel.rb +87 -0
- data/lib/rack/handler/scgi.rb +62 -0
- data/lib/rack/handler/swiftiplied_mongrel.rb +8 -0
- data/lib/rack/handler/thin.rb +18 -0
- data/lib/rack/handler/webrick.rb +71 -0
- data/lib/rack/handler.rb +69 -0
- data/lib/rack/head.rb +19 -0
- data/lib/rack/lint.rb +546 -0
- data/lib/rack/lobster.rb +65 -0
- data/lib/rack/lock.rb +16 -0
- data/lib/rack/methodoverride.rb +27 -0
- data/lib/rack/mime.rb +204 -0
- data/lib/rack/mock.rb +187 -0
- data/lib/rack/recursive.rb +57 -0
- data/lib/rack/reloader.rb +107 -0
- data/lib/rack/request.rb +248 -0
- data/lib/rack/response.rb +183 -0
- data/lib/rack/rewindable_input.rb +100 -0
- data/lib/rack/session/abstract/id.rb +142 -0
- data/lib/rack/session/cookie.rb +91 -0
- data/lib/rack/session/memcache.rb +109 -0
- data/lib/rack/session/pool.rb +100 -0
- data/lib/rack/showexceptions.rb +349 -0
- data/lib/rack/showstatus.rb +106 -0
- data/lib/rack/static.rb +38 -0
- data/lib/rack/urlmap.rb +55 -0
- data/lib/rack/utils.rb +528 -0
- data/lib/rack.rb +90 -0
- data/rack.gemspec +60 -0
- data/test/cgi/lighttpd.conf +20 -0
- data/test/cgi/test +9 -0
- data/test/cgi/test.fcgi +8 -0
- data/test/cgi/test.ru +7 -0
- data/test/multipart/binary +0 -0
- data/test/multipart/empty +10 -0
- data/test/multipart/file1.txt +1 -0
- data/test/multipart/ie +6 -0
- data/test/multipart/nested +10 -0
- data/test/multipart/none +9 -0
- data/test/multipart/text +10 -0
- data/test/spec_rack_auth_basic.rb +73 -0
- data/test/spec_rack_auth_digest.rb +226 -0
- data/test/spec_rack_auth_openid.rb +84 -0
- data/test/spec_rack_builder.rb +84 -0
- data/test/spec_rack_camping.rb +51 -0
- data/test/spec_rack_cascade.rb +48 -0
- data/test/spec_rack_cgi.rb +89 -0
- data/test/spec_rack_chunked.rb +62 -0
- data/test/spec_rack_commonlogger.rb +61 -0
- data/test/spec_rack_conditionalget.rb +41 -0
- data/test/spec_rack_content_length.rb +43 -0
- data/test/spec_rack_content_type.rb +30 -0
- data/test/spec_rack_deflater.rb +127 -0
- data/test/spec_rack_directory.rb +61 -0
- data/test/spec_rack_fastcgi.rb +89 -0
- data/test/spec_rack_file.rb +75 -0
- data/test/spec_rack_handler.rb +43 -0
- data/test/spec_rack_head.rb +30 -0
- data/test/spec_rack_lint.rb +521 -0
- data/test/spec_rack_lobster.rb +45 -0
- data/test/spec_rack_lock.rb +38 -0
- data/test/spec_rack_methodoverride.rb +60 -0
- data/test/spec_rack_mock.rb +243 -0
- data/test/spec_rack_mongrel.rb +189 -0
- data/test/spec_rack_recursive.rb +77 -0
- data/test/spec_rack_request.rb +504 -0
- data/test/spec_rack_response.rb +218 -0
- data/test/spec_rack_rewindable_input.rb +118 -0
- data/test/spec_rack_session_cookie.rb +82 -0
- data/test/spec_rack_session_memcache.rb +250 -0
- data/test/spec_rack_session_pool.rb +172 -0
- data/test/spec_rack_showexceptions.rb +21 -0
- data/test/spec_rack_showstatus.rb +72 -0
- data/test/spec_rack_static.rb +37 -0
- data/test/spec_rack_thin.rb +91 -0
- data/test/spec_rack_urlmap.rb +185 -0
- data/test/spec_rack_utils.rb +467 -0
- data/test/spec_rack_webrick.rb +130 -0
- data/test/testrequest.rb +57 -0
- data/test/unregistered_handler/rack/handler/unregistered.rb +7 -0
- data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +7 -0
- metadata +276 -0
|
@@ -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 ||= params.unpack("m*").first.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(*args)
|
|
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
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'digest/md5'
|
|
2
|
+
|
|
3
|
+
module Rack
|
|
4
|
+
module Auth
|
|
5
|
+
module Digest
|
|
6
|
+
# Rack::Auth::Digest::Nonce is the default nonce generator for the
|
|
7
|
+
# Rack::Auth::Digest::MD5 authentication handler.
|
|
8
|
+
#
|
|
9
|
+
# +private_key+ needs to set to a constant string.
|
|
10
|
+
#
|
|
11
|
+
# +time_limit+ can be optionally set to an integer (number of seconds),
|
|
12
|
+
# to limit the validity of the generated nonces.
|
|
13
|
+
|
|
14
|
+
class Nonce
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
attr_accessor :private_key, :time_limit
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.parse(string)
|
|
21
|
+
new(*string.unpack("m*").first.split(' ', 2))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def initialize(timestamp = Time.now, given_digest = nil)
|
|
25
|
+
@timestamp, @given_digest = timestamp.to_i, given_digest
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def to_s
|
|
29
|
+
[([ @timestamp, digest ] * ' ')].pack("m*").strip
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def digest
|
|
33
|
+
::Digest::MD5.hexdigest([ @timestamp, self.class.private_key ] * ':')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def valid?
|
|
37
|
+
digest == @given_digest
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def stale?
|
|
41
|
+
!self.class.time_limit.nil? && (@timestamp - Time.now.to_i) < self.class.time_limit
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def fresh?
|
|
45
|
+
!stale?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Rack
|
|
2
|
+
module Auth
|
|
3
|
+
module Digest
|
|
4
|
+
class Params < Hash
|
|
5
|
+
|
|
6
|
+
def self.parse(str)
|
|
7
|
+
split_header_value(str).inject(new) do |header, param|
|
|
8
|
+
k, v = param.split('=', 2)
|
|
9
|
+
header[k] = dequote(v)
|
|
10
|
+
header
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.dequote(str) # From WEBrick::HTTPUtils
|
|
15
|
+
ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup
|
|
16
|
+
ret.gsub!(/\\(.)/, "\\1")
|
|
17
|
+
ret
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.split_header_value(str)
|
|
21
|
+
str.scan( /(\w+\=(?:"[^\"]+"|[^,]+))/n ).collect{ |v| v[0] }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def initialize
|
|
25
|
+
super
|
|
26
|
+
|
|
27
|
+
yield self if block_given?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def [](k)
|
|
31
|
+
super k.to_s
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def []=(k, v)
|
|
35
|
+
super k.to_s, v.to_s
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
UNQUOTED = ['qop', 'nc', 'stale']
|
|
39
|
+
|
|
40
|
+
def to_s
|
|
41
|
+
inject([]) do |parts, (k, v)|
|
|
42
|
+
parts << "#{k}=" + (UNQUOTED.include?(k) ? v.to_s : quote(v))
|
|
43
|
+
parts
|
|
44
|
+
end.join(', ')
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def quote(str) # From WEBrick::HTTPUtils
|
|
48
|
+
'"' << str.gsub(/[\\\"]/o, "\\\1") << '"'
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'rack/auth/abstract/request'
|
|
2
|
+
require 'rack/auth/digest/params'
|
|
3
|
+
require 'rack/auth/digest/nonce'
|
|
4
|
+
|
|
5
|
+
module Rack
|
|
6
|
+
module Auth
|
|
7
|
+
module Digest
|
|
8
|
+
class Request < Auth::AbstractRequest
|
|
9
|
+
|
|
10
|
+
def method
|
|
11
|
+
@env['rack.methodoverride.original_method'] || @env['REQUEST_METHOD']
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def digest?
|
|
15
|
+
:digest == scheme
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def correct_uri?
|
|
19
|
+
(@env['SCRIPT_NAME'].to_s + @env['PATH_INFO'].to_s) == uri
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def nonce
|
|
23
|
+
@nonce ||= Nonce.parse(params['nonce'])
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def params
|
|
27
|
+
@params ||= Params.parse(parts.last)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def method_missing(sym)
|
|
31
|
+
if params.has_key? key = sym.to_s
|
|
32
|
+
return params[key]
|
|
33
|
+
end
|
|
34
|
+
super
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|