test_challenges.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. # Copyright 2021 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. """Tests for the reauth module."""
  15. import base64
  16. import sys
  17. import mock
  18. import pytest
  19. import pyu2f
  20. from google.auth import exceptions
  21. from google.oauth2 import challenges
  22. def test_get_user_password():
  23. with mock.patch("getpass.getpass", return_value="foo"):
  24. assert challenges.get_user_password("") == "foo"
  25. def test_security_key():
  26. metadata = {
  27. "status": "READY",
  28. "challengeId": 2,
  29. "challengeType": "SECURITY_KEY",
  30. "securityKey": {
  31. "applicationId": "security_key_application_id",
  32. "challenges": [
  33. {
  34. "keyHandle": "some_key",
  35. "challenge": base64.urlsafe_b64encode(
  36. "some_challenge".encode("ascii")
  37. ).decode("ascii"),
  38. }
  39. ],
  40. },
  41. }
  42. mock_key = mock.Mock()
  43. challenge = challenges.SecurityKeyChallenge()
  44. # Test the case that security key challenge is passed.
  45. with mock.patch("pyu2f.model.RegisteredKey", return_value=mock_key):
  46. with mock.patch(
  47. "pyu2f.convenience.authenticator.CompositeAuthenticator.Authenticate"
  48. ) as mock_authenticate:
  49. mock_authenticate.return_value = "security key response"
  50. assert challenge.name == "SECURITY_KEY"
  51. assert challenge.is_locally_eligible
  52. assert challenge.obtain_challenge_input(metadata) == {
  53. "securityKey": "security key response"
  54. }
  55. mock_authenticate.assert_called_with(
  56. "security_key_application_id",
  57. [{"key": mock_key, "challenge": b"some_challenge"}],
  58. print_callback=sys.stderr.write,
  59. )
  60. # Test various types of exceptions.
  61. with mock.patch("pyu2f.model.RegisteredKey", return_value=mock_key):
  62. with mock.patch(
  63. "pyu2f.convenience.authenticator.CompositeAuthenticator.Authenticate"
  64. ) as mock_authenticate:
  65. mock_authenticate.side_effect = pyu2f.errors.U2FError(
  66. pyu2f.errors.U2FError.DEVICE_INELIGIBLE
  67. )
  68. assert challenge.obtain_challenge_input(metadata) is None
  69. with mock.patch(
  70. "pyu2f.convenience.authenticator.CompositeAuthenticator.Authenticate"
  71. ) as mock_authenticate:
  72. mock_authenticate.side_effect = pyu2f.errors.U2FError(
  73. pyu2f.errors.U2FError.TIMEOUT
  74. )
  75. assert challenge.obtain_challenge_input(metadata) is None
  76. with mock.patch(
  77. "pyu2f.convenience.authenticator.CompositeAuthenticator.Authenticate"
  78. ) as mock_authenticate:
  79. mock_authenticate.side_effect = pyu2f.errors.U2FError(
  80. pyu2f.errors.U2FError.BAD_REQUEST
  81. )
  82. with pytest.raises(pyu2f.errors.U2FError):
  83. challenge.obtain_challenge_input(metadata)
  84. with mock.patch(
  85. "pyu2f.convenience.authenticator.CompositeAuthenticator.Authenticate"
  86. ) as mock_authenticate:
  87. mock_authenticate.side_effect = pyu2f.errors.NoDeviceFoundError()
  88. assert challenge.obtain_challenge_input(metadata) is None
  89. with mock.patch(
  90. "pyu2f.convenience.authenticator.CompositeAuthenticator.Authenticate"
  91. ) as mock_authenticate:
  92. mock_authenticate.side_effect = pyu2f.errors.UnsupportedVersionException()
  93. with pytest.raises(pyu2f.errors.UnsupportedVersionException):
  94. challenge.obtain_challenge_input(metadata)
  95. with mock.patch.dict("sys.modules"):
  96. sys.modules["pyu2f"] = None
  97. with pytest.raises(exceptions.ReauthFailError) as excinfo:
  98. challenge.obtain_challenge_input(metadata)
  99. assert excinfo.match(r"pyu2f dependency is required")
  100. @mock.patch("getpass.getpass", return_value="foo")
  101. def test_password_challenge(getpass_mock):
  102. challenge = challenges.PasswordChallenge()
  103. with mock.patch("getpass.getpass", return_value="foo"):
  104. assert challenge.is_locally_eligible
  105. assert challenge.name == "PASSWORD"
  106. assert challenges.PasswordChallenge().obtain_challenge_input({}) == {
  107. "credential": "foo"
  108. }
  109. with mock.patch("getpass.getpass", return_value=None):
  110. assert challenges.PasswordChallenge().obtain_challenge_input({}) == {
  111. "credential": " "
  112. }