4e14ccc74d
Instiki now runs on the Rails 2.3.0 Candidate Release. Among other improvements, this means that it now automagically selects between WEBrick and Mongrel. Just run ./instiki --daemon
169 lines
4.7 KiB
Ruby
169 lines
4.7 KiB
Ruby
require 'test/spec'
|
|
|
|
require 'rack/auth/digest/md5'
|
|
require 'rack/mock'
|
|
|
|
context 'Rack::Auth::Digest::MD5' do
|
|
|
|
def realm
|
|
'WallysWorld'
|
|
end
|
|
|
|
def unprotected_app
|
|
lambda do |env|
|
|
[ 200, {'Content-Type' => 'text/plain'}, ["Hi #{env['REMOTE_USER']}"] ]
|
|
end
|
|
end
|
|
|
|
def protected_app
|
|
app = Rack::Auth::Digest::MD5.new(unprotected_app) do |username|
|
|
{ 'Alice' => 'correct-password' }[username]
|
|
end
|
|
app.realm = realm
|
|
app.opaque = 'this-should-be-secret'
|
|
app
|
|
end
|
|
|
|
def protected_app_with_hashed_passwords
|
|
app = Rack::Auth::Digest::MD5.new(unprotected_app) do |username|
|
|
username == 'Alice' ? Digest::MD5.hexdigest("Alice:#{realm}:correct-password") : nil
|
|
end
|
|
app.realm = realm
|
|
app.opaque = 'this-should-be-secret'
|
|
app.passwords_hashed = true
|
|
app
|
|
end
|
|
|
|
setup do
|
|
@request = Rack::MockRequest.new(protected_app)
|
|
end
|
|
|
|
def request(path, headers = {}, &block)
|
|
response = @request.get(path, headers)
|
|
block.call(response) if block
|
|
return response
|
|
end
|
|
|
|
class MockDigestRequest
|
|
def initialize(params)
|
|
@params = params
|
|
end
|
|
def method_missing(sym)
|
|
if @params.has_key? k = sym.to_s
|
|
return @params[k]
|
|
end
|
|
super
|
|
end
|
|
def method
|
|
'GET'
|
|
end
|
|
def response(password)
|
|
Rack::Auth::Digest::MD5.new(nil).send :digest, self, password
|
|
end
|
|
end
|
|
|
|
def request_with_digest_auth(path, username, password, options = {}, &block)
|
|
response = request('/')
|
|
|
|
return response unless response.status == 401
|
|
|
|
if wait = options.delete(:wait)
|
|
sleep wait
|
|
end
|
|
|
|
challenge = response['WWW-Authenticate'].split(' ', 2).last
|
|
|
|
params = Rack::Auth::Digest::Params.parse(challenge)
|
|
|
|
params['username'] = username
|
|
params['nc'] = '00000001'
|
|
params['cnonce'] = 'nonsensenonce'
|
|
params['uri'] = path
|
|
|
|
params.update options
|
|
|
|
params['response'] = MockDigestRequest.new(params).response(password)
|
|
|
|
request(path, { 'HTTP_AUTHORIZATION' => "Digest #{params}" }, &block)
|
|
end
|
|
|
|
def assert_digest_auth_challenge(response)
|
|
response.should.be.a.client_error
|
|
response.status.should.equal 401
|
|
response.should.include 'WWW-Authenticate'
|
|
response.headers['WWW-Authenticate'].should =~ /^Digest /
|
|
response.body.should.be.empty
|
|
end
|
|
|
|
def assert_bad_request(response)
|
|
response.should.be.a.client_error
|
|
response.status.should.equal 400
|
|
response.should.not.include 'WWW-Authenticate'
|
|
end
|
|
|
|
specify 'should challenge when no credentials are specified' do
|
|
request '/' do |response|
|
|
assert_digest_auth_challenge response
|
|
end
|
|
end
|
|
|
|
specify 'should return application output if correct credentials given' do
|
|
request_with_digest_auth '/', 'Alice', 'correct-password' do |response|
|
|
response.status.should.equal 200
|
|
response.body.to_s.should.equal 'Hi Alice'
|
|
end
|
|
end
|
|
|
|
specify 'should return application output if correct credentials given (hashed passwords)' do
|
|
@request = Rack::MockRequest.new(protected_app_with_hashed_passwords)
|
|
|
|
request_with_digest_auth '/', 'Alice', 'correct-password' do |response|
|
|
response.status.should.equal 200
|
|
response.body.to_s.should.equal 'Hi Alice'
|
|
end
|
|
end
|
|
|
|
specify 'should rechallenge if incorrect username given' do
|
|
request_with_digest_auth '/', 'Bob', 'correct-password' do |response|
|
|
assert_digest_auth_challenge response
|
|
end
|
|
end
|
|
|
|
specify 'should rechallenge if incorrect password given' do
|
|
request_with_digest_auth '/', 'Alice', 'wrong-password' do |response|
|
|
assert_digest_auth_challenge response
|
|
end
|
|
end
|
|
|
|
specify 'should rechallenge with stale parameter if nonce is stale' do
|
|
begin
|
|
Rack::Auth::Digest::Nonce.time_limit = 1
|
|
|
|
request_with_digest_auth '/', 'Alice', 'correct-password', :wait => 2 do |response|
|
|
assert_digest_auth_challenge response
|
|
response.headers['WWW-Authenticate'].should =~ /\bstale=true\b/
|
|
end
|
|
ensure
|
|
Rack::Auth::Digest::Nonce.time_limit = nil
|
|
end
|
|
end
|
|
|
|
specify 'should return 400 Bad Request if incorrect qop given' do
|
|
request_with_digest_auth '/', 'Alice', 'correct-password', 'qop' => 'auth-int' do |response|
|
|
assert_bad_request response
|
|
end
|
|
end
|
|
|
|
specify 'should return 400 Bad Request if incorrect uri given' do
|
|
request_with_digest_auth '/', 'Alice', 'correct-password', 'uri' => '/foo' do |response|
|
|
assert_bad_request response
|
|
end
|
|
end
|
|
|
|
specify 'should return 400 Bad Request if different auth scheme used' do
|
|
request '/', 'HTTP_AUTHORIZATION' => 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==' do |response|
|
|
assert_bad_request response
|
|
end
|
|
end
|
|
|
|
end
|