1 require 'abstract_unit'
3 class HttpDigestAuthenticationTest
< ActionController
::TestCase
4 class DummyDigestController
< ActionController
::Base
5 before_filter
:authenticate, :only => :index
6 before_filter
:authenticate_with_request, :only => :display
8 USERS
= { 'lifo' => 'world', 'pretty' => 'please',
9 'dhh' => ::Digest::MD5::hexdigest(["dhh","SuperSecret","secret"].join(":"))}
12 render
:text => "Hello Secret"
16 render
:text => 'Definitely Maybe'
22 authenticate_or_request_with_http_digest("SuperSecret") do |username
|
28 def authenticate_with_request
29 if authenticate_with_http_digest("SuperSecret") { |username
| USERS
[username
] }
32 request_http_digest_authentication("SuperSecret", "Authentication Failed")
37 AUTH_HEADERS
= ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION', 'REDIRECT_X_HTTP_AUTHORIZATION']
39 tests DummyDigestController
41 AUTH_HEADERS
.each
do |header
|
42 test
"successful authentication with #{header.downcase}" do
43 @request.env[header
] = encode_credentials(:username => 'lifo', :password => 'world')
46 assert_response
:success
47 assert_equal
'Hello Secret', @response.body
, "Authentication failed for request header #{header}"
51 AUTH_HEADERS
.each
do |header
|
52 test
"unsuccessful authentication with #{header.downcase}" do
53 @request.env[header
] = encode_credentials(:username => 'h4x0r', :password => 'world')
56 assert_response
:unauthorized
57 assert_equal
"HTTP Digest: Access denied.\n", @response.body
, "Authentication didn't fail for request header #{header}"
61 test
"authentication request without credential" do
64 assert_response
:unauthorized
65 assert_equal
"Authentication Failed", @response.body
66 credentials
= decode_credentials(@response.headers
['WWW-Authenticate'])
67 assert_equal
'SuperSecret', credentials
[:realm]
70 test
"authentication request with invalid password" do
71 @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'foo')
74 assert_response
:unauthorized
75 assert_equal
"Authentication Failed", @response.body
78 test
"authentication request with invalid nonce" do
79 @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please', :nonce => "xxyyzz")
82 assert_response
:unauthorized
83 assert_equal
"Authentication Failed", @response.body
86 test
"authentication request with invalid opaque" do
87 @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'foo', :opaque => "xxyyzz")
90 assert_response
:unauthorized
91 assert_equal
"Authentication Failed", @response.body
94 test
"authentication request with invalid realm" do
95 @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'foo', :realm => "NotSecret")
98 assert_response
:unauthorized
99 assert_equal
"Authentication Failed", @response.body
102 test
"authentication request with valid credential" do
103 @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please')
106 assert_response
:success
107 assert
assigns(:logged_in)
108 assert_equal
'Definitely Maybe', @response.body
111 test
"authentication request with valid credential and nil session" do
112 @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please')
114 # session_id = "" in functional test, but is +nil+ in real life
115 @request.session
.session_id
= nil
118 assert_response
:success
119 assert
assigns(:logged_in)
120 assert_equal
'Definitely Maybe', @response.body
123 test
"authentication request with request-uri that doesn't match credentials digest-uri" do
124 @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please')
125 @request.env['REQUEST_URI'] = "/http_digest_authentication_test/dummy_digest/altered/uri"
128 assert_response
:unauthorized
129 assert_equal
"Authentication Failed", @response.body
132 test
"authentication request with absolute uri" do
133 @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:uri => "http://test.host/http_digest_authentication_test/dummy_digest/display",
134 :username => 'pretty', :password => 'please')
135 @request.env['REQUEST_URI'] = "http://test.host/http_digest_authentication_test/dummy_digest/display"
138 assert_response
:success
139 assert
assigns(:logged_in)
140 assert_equal
'Definitely Maybe', @response.body
143 test
"authentication request with password stored as ha1 digest hash" do
144 @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'dhh',
145 :password => ::Digest::MD5::hexdigest(["dhh","SuperSecret","secret"].join(":")),
146 :password_is_ha1 => true)
149 assert_response
:success
150 assert
assigns(:logged_in)
151 assert_equal
'Definitely Maybe', @response.body
156 def encode_credentials(options
)
157 options
.reverse_merge
!(:nc => "00000001", :cnonce => "0a4f113b", :password_is_ha1 => false)
158 password
= options
.delete(:password)
160 # Set in /initializers/session_store.rb. Used as secret in generating nonce
161 # to prevent tampering of timestamp
162 ActionController
::Base.session_options
[:secret] = "session_options_secret"
164 # Perform unauthenticated GET to retrieve digest parameters to use on subsequent request
167 assert_response
:unauthorized
169 credentials
= decode_credentials(@response.headers
['WWW-Authenticate'])
170 credentials
.merge
!(options
)
171 credentials
.reverse_merge
!(:uri => "#{@request.env['REQUEST_URI']}")
172 ActionController
::HttpAuthentication::Digest.encode_credentials("GET", credentials
, password
, options
[:password_is_ha1])
175 def decode_credentials(header
)
176 ActionController
::HttpAuthentication::Digest.decode_credentials(@response.headers
['WWW-Authenticate'])