PageRenderTime 90ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/activeresource/test/cases/authorization_test.rb

https://github.com/ghar/rails
Ruby | 248 lines | 197 code | 49 blank | 2 comment | 0 complexity | 91621bd4ace980cd429eaa36d22b6168 MD5 | raw file
  1. require 'abstract_unit'
  2. class AuthorizationTest < Test::Unit::TestCase
  3. Response = Struct.new(:code)
  4. def setup
  5. @conn = ActiveResource::Connection.new('http://localhost')
  6. @matz = { :person => { :id => 1, :name => 'Matz' } }.to_json
  7. @david = { :person => { :id => 2, :name => 'David' } }.to_json
  8. @authenticated_conn = ActiveResource::Connection.new("http://david:test123@localhost")
  9. @basic_authorization_request_header = { 'Authorization' => 'Basic ZGF2aWQ6dGVzdDEyMw==' }
  10. @nonce = "MTI0OTUxMzc4NzpjYWI3NDM3NDNmY2JmODU4ZjQ2ZjcwNGZkMTJiMjE0NA=="
  11. ActiveResource::HttpMock.respond_to do |mock|
  12. mock.get "/people/2.json", @basic_authorization_request_header, @david
  13. mock.get "/people/1.json", @basic_authorization_request_header, nil, 401, { 'WWW-Authenticate' => 'i_should_be_ignored' }
  14. mock.put "/people/2.json", @basic_authorization_request_header, nil, 204
  15. mock.delete "/people/2.json", @basic_authorization_request_header, nil, 200
  16. mock.post "/people/2/addresses.json", @basic_authorization_request_header, nil, 201, 'Location' => '/people/1/addresses/5'
  17. mock.head "/people/2.json", @basic_authorization_request_header, nil, 200
  18. mock.get "/people/2.json", { 'Authorization' => blank_digest_auth_header("/people/2.json", "fad396f6a34aeba28e28b9b96ddbb671") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header }
  19. mock.get "/people/2.json", { 'Authorization' => request_digest_auth_header("/people/2.json", "c064d5ba8891a25290c76c8c7d31fb7b") }, @david, 200
  20. mock.get "/people/1.json", { 'Authorization' => request_digest_auth_header("/people/1.json", "f9c0b594257bb8422af4abd429c5bb70") }, @matz, 200
  21. mock.put "/people/2.json", { 'Authorization' => blank_digest_auth_header("/people/2.json", "50a685d814f94665b9d160fbbaa3958a") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header }
  22. mock.put "/people/2.json", { 'Authorization' => request_digest_auth_header("/people/2.json", "5a75cde841122d8e0f20f8fd1f98a743") }, nil, 204
  23. mock.delete "/people/2.json", { 'Authorization' => blank_digest_auth_header("/people/2.json", "846f799107eab5ca4285b909ee299a33") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header }
  24. mock.delete "/people/2.json", { 'Authorization' => request_digest_auth_header("/people/2.json", "9f5b155224edbbb69fd99d8ce094681e") }, nil, 200
  25. mock.post "/people/2/addresses.json", { 'Authorization' => blank_digest_auth_header("/people/2/addresses.json", "6984d405ff3d9ed07bbf747dcf16afb0") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header }
  26. mock.post "/people/2/addresses.json", { 'Authorization' => request_digest_auth_header("/people/2/addresses.json", "4bda6a28dbf930b5af9244073623bd04") }, nil, 201, 'Location' => '/people/1/addresses/5'
  27. mock.head "/people/2.json", { 'Authorization' => blank_digest_auth_header("/people/2.json", "15e5ed84ba5c4cfcd5c98a36c2e4f421") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header }
  28. mock.head "/people/2.json", { 'Authorization' => request_digest_auth_header("/people/2.json", "d4c6d2bcc8717abb2e2ccb8c49ee6a91") }, nil, 200
  29. end
  30. # Make client nonce deterministic
  31. class << @authenticated_conn
  32. private
  33. def client_nonce
  34. 'i-am-a-client-nonce'
  35. end
  36. end
  37. end
  38. def test_authorization_header
  39. authorization_header = @authenticated_conn.__send__(:authorization_header, :get, URI.parse('/people/2.json'))
  40. assert_equal @basic_authorization_request_header['Authorization'], authorization_header['Authorization']
  41. authorization = authorization_header["Authorization"].to_s.split
  42. assert_equal "Basic", authorization[0]
  43. assert_equal ["david", "test123"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1]
  44. end
  45. def test_authorization_header_with_username_but_no_password
  46. @conn = ActiveResource::Connection.new("http://david:@localhost")
  47. authorization_header = @conn.__send__(:authorization_header, :get, URI.parse('/people/2.json'))
  48. authorization = authorization_header["Authorization"].to_s.split
  49. assert_equal "Basic", authorization[0]
  50. assert_equal ["david"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1]
  51. end
  52. def test_authorization_header_with_password_but_no_username
  53. @conn = ActiveResource::Connection.new("http://:test123@localhost")
  54. authorization_header = @conn.__send__(:authorization_header, :get, URI.parse('/people/2.json'))
  55. authorization = authorization_header["Authorization"].to_s.split
  56. assert_equal "Basic", authorization[0]
  57. assert_equal ["", "test123"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1]
  58. end
  59. def test_authorization_header_with_decoded_credentials_from_url
  60. @conn = ActiveResource::Connection.new("http://my%40email.com:%31%32%33@localhost")
  61. authorization_header = @conn.__send__(:authorization_header, :get, URI.parse('/people/2.json'))
  62. authorization = authorization_header["Authorization"].to_s.split
  63. assert_equal "Basic", authorization[0]
  64. assert_equal ["my@email.com", "123"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1]
  65. end
  66. def test_authorization_header_explicitly_setting_username_and_password
  67. @authenticated_conn = ActiveResource::Connection.new("http://@localhost")
  68. @authenticated_conn.user = 'david'
  69. @authenticated_conn.password = 'test123'
  70. authorization_header = @authenticated_conn.__send__(:authorization_header, :get, URI.parse('/people/2.json'))
  71. assert_equal @basic_authorization_request_header['Authorization'], authorization_header['Authorization']
  72. authorization = authorization_header["Authorization"].to_s.split
  73. assert_equal "Basic", authorization[0]
  74. assert_equal ["david", "test123"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1]
  75. end
  76. def test_authorization_header_explicitly_setting_username_but_no_password
  77. @conn = ActiveResource::Connection.new("http://@localhost")
  78. @conn.user = "david"
  79. authorization_header = @conn.__send__(:authorization_header, :get, URI.parse('/people/2.json'))
  80. authorization = authorization_header["Authorization"].to_s.split
  81. assert_equal "Basic", authorization[0]
  82. assert_equal ["david"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1]
  83. end
  84. def test_authorization_header_explicitly_setting_password_but_no_username
  85. @conn = ActiveResource::Connection.new("http://@localhost")
  86. @conn.password = "test123"
  87. authorization_header = @conn.__send__(:authorization_header, :get, URI.parse('/people/2.json'))
  88. authorization = authorization_header["Authorization"].to_s.split
  89. assert_equal "Basic", authorization[0]
  90. assert_equal ["", "test123"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1]
  91. end
  92. def test_authorization_header_if_credentials_supplied_and_auth_type_is_basic
  93. @authenticated_conn.auth_type = :basic
  94. authorization_header = @authenticated_conn.__send__(:authorization_header, :get, URI.parse('/people/2.json'))
  95. assert_equal @basic_authorization_request_header['Authorization'], authorization_header['Authorization']
  96. authorization = authorization_header["Authorization"].to_s.split
  97. assert_equal "Basic", authorization[0]
  98. assert_equal ["david", "test123"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1]
  99. end
  100. def test_authorization_header_if_credentials_supplied_and_auth_type_is_digest
  101. @authenticated_conn.auth_type = :digest
  102. authorization_header = @authenticated_conn.__send__(:authorization_header, :get, URI.parse('/people/2.json'))
  103. assert_equal blank_digest_auth_header("/people/2.json", "fad396f6a34aeba28e28b9b96ddbb671"), authorization_header['Authorization']
  104. end
  105. def test_get
  106. david = decode(@authenticated_conn.get("/people/2.json"))
  107. assert_equal "David", david["name"]
  108. end
  109. def test_post
  110. response = @authenticated_conn.post("/people/2/addresses.json")
  111. assert_equal "/people/1/addresses/5", response["Location"]
  112. end
  113. def test_put
  114. response = @authenticated_conn.put("/people/2.json")
  115. assert_equal 204, response.code
  116. end
  117. def test_delete
  118. response = @authenticated_conn.delete("/people/2.json")
  119. assert_equal 200, response.code
  120. end
  121. def test_head
  122. response = @authenticated_conn.head("/people/2.json")
  123. assert_equal 200, response.code
  124. end
  125. def test_get_with_digest_auth_handles_initial_401_response_and_retries
  126. @authenticated_conn.auth_type = :digest
  127. response = @authenticated_conn.get("/people/2.json")
  128. assert_equal "David", decode(response)["name"]
  129. end
  130. def test_post_with_digest_auth_handles_initial_401_response_and_retries
  131. @authenticated_conn.auth_type = :digest
  132. response = @authenticated_conn.post("/people/2/addresses.json")
  133. assert_equal "/people/1/addresses/5", response["Location"]
  134. assert_equal 201, response.code
  135. end
  136. def test_put_with_digest_auth_handles_initial_401_response_and_retries
  137. @authenticated_conn.auth_type = :digest
  138. response = @authenticated_conn.put("/people/2.json")
  139. assert_equal 204, response.code
  140. end
  141. def test_delete_with_digest_auth_handles_initial_401_response_and_retries
  142. @authenticated_conn.auth_type = :digest
  143. response = @authenticated_conn.delete("/people/2.json")
  144. assert_equal 200, response.code
  145. end
  146. def test_head_with_digest_auth_handles_initial_401_response_and_retries
  147. @authenticated_conn.auth_type = :digest
  148. response = @authenticated_conn.head("/people/2.json")
  149. assert_equal 200, response.code
  150. end
  151. def test_get_with_digest_auth_caches_nonce
  152. @authenticated_conn.auth_type = :digest
  153. response = @authenticated_conn.get("/people/2.json")
  154. assert_equal "David", decode(response)["name"]
  155. # There is no mock for this request with a non-cached nonce.
  156. response = @authenticated_conn.get("/people/1.json")
  157. assert_equal "Matz", decode(response)["name"]
  158. end
  159. def test_retry_on_401_only_happens_with_digest_auth
  160. assert_raise(ActiveResource::UnauthorizedAccess) { @authenticated_conn.get("/people/1.json") }
  161. assert_equal "", @authenticated_conn.send(:response_auth_header)
  162. end
  163. def test_raises_invalid_request_on_unauthorized_requests
  164. assert_raise(ActiveResource::InvalidRequestError) { @conn.get("/people/2.json") }
  165. assert_raise(ActiveResource::InvalidRequestError) { @conn.post("/people/2/addresses.json") }
  166. assert_raise(ActiveResource::InvalidRequestError) { @conn.put("/people/2.json") }
  167. assert_raise(ActiveResource::InvalidRequestError) { @conn.delete("/people/2.json") }
  168. assert_raise(ActiveResource::InvalidRequestError) { @conn.head("/people/2.json") }
  169. end
  170. def test_raises_invalid_request_on_unauthorized_requests_with_digest_auth
  171. @conn.auth_type = :digest
  172. assert_raise(ActiveResource::InvalidRequestError) { @conn.get("/people/2.json") }
  173. assert_raise(ActiveResource::InvalidRequestError) { @conn.post("/people/2/addresses.json") }
  174. assert_raise(ActiveResource::InvalidRequestError) { @conn.put("/people/2.json") }
  175. assert_raise(ActiveResource::InvalidRequestError) { @conn.delete("/people/2.json") }
  176. assert_raise(ActiveResource::InvalidRequestError) { @conn.head("/people/2.json") }
  177. end
  178. def test_client_nonce_is_not_nil
  179. assert_not_nil ActiveResource::Connection.new("http://david:test123@localhost").send(:client_nonce)
  180. end
  181. protected
  182. def assert_response_raises(klass, code)
  183. assert_raise(klass, "Expected response code #{code} to raise #{klass}") do
  184. @conn.__send__(:handle_response, Response.new(code))
  185. end
  186. end
  187. def blank_digest_auth_header(uri, response)
  188. %Q(Digest username="david", realm="", qop="", uri="#{uri}", nonce="", nc="0", cnonce="i-am-a-client-nonce", opaque="", response="#{response}")
  189. end
  190. def request_digest_auth_header(uri, response)
  191. %Q(Digest username="david", realm="RailsTestApp", qop="auth", uri="#{uri}", nonce="#{@nonce}", nc="0", cnonce="i-am-a-client-nonce", opaque="ef6dfb078ba22298d366f99567814ffb", response="#{response}")
  192. end
  193. def response_digest_auth_header
  194. %Q(Digest realm="RailsTestApp", qop="auth", algorithm=MD5, nonce="#{@nonce}", opaque="ef6dfb078ba22298d366f99567814ffb")
  195. end
  196. def decode(response)
  197. @authenticated_conn.format.decode(response.body)
  198. end
  199. end