test_utils.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. # Copyright 2020 Google LLC
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import json
  15. import pytest # type: ignore
  16. from google.auth import exceptions
  17. from google.oauth2 import utils
  18. CLIENT_ID = "username"
  19. CLIENT_SECRET = "password"
  20. # Base64 encoding of "username:password"
  21. BASIC_AUTH_ENCODING = "dXNlcm5hbWU6cGFzc3dvcmQ="
  22. # Base64 encoding of "username:"
  23. BASIC_AUTH_ENCODING_SECRETLESS = "dXNlcm5hbWU6"
  24. class AuthHandler(utils.OAuthClientAuthHandler):
  25. def __init__(self, client_auth=None):
  26. super(AuthHandler, self).__init__(client_auth)
  27. def apply_client_authentication_options(
  28. self, headers, request_body=None, bearer_token=None
  29. ):
  30. return super(AuthHandler, self).apply_client_authentication_options(
  31. headers, request_body, bearer_token
  32. )
  33. class TestClientAuthentication(object):
  34. @classmethod
  35. def make_client_auth(cls, client_secret=None):
  36. return utils.ClientAuthentication(
  37. utils.ClientAuthType.basic, CLIENT_ID, client_secret
  38. )
  39. def test_initialization_with_client_secret(self):
  40. client_auth = self.make_client_auth(CLIENT_SECRET)
  41. assert client_auth.client_auth_type == utils.ClientAuthType.basic
  42. assert client_auth.client_id == CLIENT_ID
  43. assert client_auth.client_secret == CLIENT_SECRET
  44. def test_initialization_no_client_secret(self):
  45. client_auth = self.make_client_auth()
  46. assert client_auth.client_auth_type == utils.ClientAuthType.basic
  47. assert client_auth.client_id == CLIENT_ID
  48. assert client_auth.client_secret is None
  49. class TestOAuthClientAuthHandler(object):
  50. CLIENT_AUTH_BASIC = utils.ClientAuthentication(
  51. utils.ClientAuthType.basic, CLIENT_ID, CLIENT_SECRET
  52. )
  53. CLIENT_AUTH_BASIC_SECRETLESS = utils.ClientAuthentication(
  54. utils.ClientAuthType.basic, CLIENT_ID
  55. )
  56. CLIENT_AUTH_REQUEST_BODY = utils.ClientAuthentication(
  57. utils.ClientAuthType.request_body, CLIENT_ID, CLIENT_SECRET
  58. )
  59. CLIENT_AUTH_REQUEST_BODY_SECRETLESS = utils.ClientAuthentication(
  60. utils.ClientAuthType.request_body, CLIENT_ID
  61. )
  62. @classmethod
  63. def make_oauth_client_auth_handler(cls, client_auth=None):
  64. return AuthHandler(client_auth)
  65. def test_apply_client_authentication_options_none(self):
  66. headers = {"Content-Type": "application/json"}
  67. request_body = {"foo": "bar"}
  68. auth_handler = self.make_oauth_client_auth_handler()
  69. auth_handler.apply_client_authentication_options(headers, request_body)
  70. assert headers == {"Content-Type": "application/json"}
  71. assert request_body == {"foo": "bar"}
  72. def test_apply_client_authentication_options_basic(self):
  73. headers = {"Content-Type": "application/json"}
  74. request_body = {"foo": "bar"}
  75. auth_handler = self.make_oauth_client_auth_handler(self.CLIENT_AUTH_BASIC)
  76. auth_handler.apply_client_authentication_options(headers, request_body)
  77. assert headers == {
  78. "Content-Type": "application/json",
  79. "Authorization": "Basic {}".format(BASIC_AUTH_ENCODING),
  80. }
  81. assert request_body == {"foo": "bar"}
  82. def test_apply_client_authentication_options_basic_nosecret(self):
  83. headers = {"Content-Type": "application/json"}
  84. request_body = {"foo": "bar"}
  85. auth_handler = self.make_oauth_client_auth_handler(
  86. self.CLIENT_AUTH_BASIC_SECRETLESS
  87. )
  88. auth_handler.apply_client_authentication_options(headers, request_body)
  89. assert headers == {
  90. "Content-Type": "application/json",
  91. "Authorization": "Basic {}".format(BASIC_AUTH_ENCODING_SECRETLESS),
  92. }
  93. assert request_body == {"foo": "bar"}
  94. def test_apply_client_authentication_options_request_body(self):
  95. headers = {"Content-Type": "application/json"}
  96. request_body = {"foo": "bar"}
  97. auth_handler = self.make_oauth_client_auth_handler(
  98. self.CLIENT_AUTH_REQUEST_BODY
  99. )
  100. auth_handler.apply_client_authentication_options(headers, request_body)
  101. assert headers == {"Content-Type": "application/json"}
  102. assert request_body == {
  103. "foo": "bar",
  104. "client_id": CLIENT_ID,
  105. "client_secret": CLIENT_SECRET,
  106. }
  107. def test_apply_client_authentication_options_request_body_nosecret(self):
  108. headers = {"Content-Type": "application/json"}
  109. request_body = {"foo": "bar"}
  110. auth_handler = self.make_oauth_client_auth_handler(
  111. self.CLIENT_AUTH_REQUEST_BODY_SECRETLESS
  112. )
  113. auth_handler.apply_client_authentication_options(headers, request_body)
  114. assert headers == {"Content-Type": "application/json"}
  115. assert request_body == {
  116. "foo": "bar",
  117. "client_id": CLIENT_ID,
  118. "client_secret": "",
  119. }
  120. def test_apply_client_authentication_options_request_body_no_body(self):
  121. headers = {"Content-Type": "application/json"}
  122. auth_handler = self.make_oauth_client_auth_handler(
  123. self.CLIENT_AUTH_REQUEST_BODY
  124. )
  125. with pytest.raises(exceptions.OAuthError) as excinfo:
  126. auth_handler.apply_client_authentication_options(headers)
  127. assert excinfo.match(r"HTTP request does not support request-body")
  128. def test_apply_client_authentication_options_bearer_token(self):
  129. bearer_token = "ACCESS_TOKEN"
  130. headers = {"Content-Type": "application/json"}
  131. request_body = {"foo": "bar"}
  132. auth_handler = self.make_oauth_client_auth_handler()
  133. auth_handler.apply_client_authentication_options(
  134. headers, request_body, bearer_token
  135. )
  136. assert headers == {
  137. "Content-Type": "application/json",
  138. "Authorization": "Bearer {}".format(bearer_token),
  139. }
  140. assert request_body == {"foo": "bar"}
  141. def test_apply_client_authentication_options_bearer_and_basic(self):
  142. bearer_token = "ACCESS_TOKEN"
  143. headers = {"Content-Type": "application/json"}
  144. request_body = {"foo": "bar"}
  145. auth_handler = self.make_oauth_client_auth_handler(self.CLIENT_AUTH_BASIC)
  146. auth_handler.apply_client_authentication_options(
  147. headers, request_body, bearer_token
  148. )
  149. # Bearer token should have higher priority.
  150. assert headers == {
  151. "Content-Type": "application/json",
  152. "Authorization": "Bearer {}".format(bearer_token),
  153. }
  154. assert request_body == {"foo": "bar"}
  155. def test_apply_client_authentication_options_bearer_and_request_body(self):
  156. bearer_token = "ACCESS_TOKEN"
  157. headers = {"Content-Type": "application/json"}
  158. request_body = {"foo": "bar"}
  159. auth_handler = self.make_oauth_client_auth_handler(
  160. self.CLIENT_AUTH_REQUEST_BODY
  161. )
  162. auth_handler.apply_client_authentication_options(
  163. headers, request_body, bearer_token
  164. )
  165. # Bearer token should have higher priority.
  166. assert headers == {
  167. "Content-Type": "application/json",
  168. "Authorization": "Bearer {}".format(bearer_token),
  169. }
  170. assert request_body == {"foo": "bar"}
  171. def test__handle_error_response_code_only():
  172. error_resp = {"error": "unsupported_grant_type"}
  173. response_data = json.dumps(error_resp)
  174. with pytest.raises(exceptions.OAuthError) as excinfo:
  175. utils.handle_error_response(response_data)
  176. assert excinfo.match(r"Error code unsupported_grant_type")
  177. def test__handle_error_response_code_description():
  178. error_resp = {
  179. "error": "unsupported_grant_type",
  180. "error_description": "The provided grant_type is unsupported",
  181. }
  182. response_data = json.dumps(error_resp)
  183. with pytest.raises(exceptions.OAuthError) as excinfo:
  184. utils.handle_error_response(response_data)
  185. assert excinfo.match(
  186. r"Error code unsupported_grant_type: The provided grant_type is unsupported"
  187. )
  188. def test__handle_error_response_code_description_uri():
  189. error_resp = {
  190. "error": "unsupported_grant_type",
  191. "error_description": "The provided grant_type is unsupported",
  192. "error_uri": "https://tools.ietf.org/html/rfc6749",
  193. }
  194. response_data = json.dumps(error_resp)
  195. with pytest.raises(exceptions.OAuthError) as excinfo:
  196. utils.handle_error_response(response_data)
  197. assert excinfo.match(
  198. r"Error code unsupported_grant_type: The provided grant_type is unsupported - https://tools.ietf.org/html/rfc6749"
  199. )
  200. def test__handle_error_response_non_json():
  201. response_data = "Oops, something wrong happened"
  202. with pytest.raises(exceptions.OAuthError) as excinfo:
  203. utils.handle_error_response(response_data)
  204. assert excinfo.match(r"Oops, something wrong happened")