fix: add SAML challenge to reauth (#819)

* fix: add SAML challenge to reauth

* add enable_reauth_refresh flag

* address comments

* fix unit test

* address comments

* update

* update

* update

* update

* 🦉 Updates from OwlBot

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
Co-authored-by: Tres Seaver <tseaver@palladion.com>
diff --git a/tests/oauth2/test_challenges.py b/tests/oauth2/test_challenges.py
index 019b908..412895a 100644
--- a/tests/oauth2/test_challenges.py
+++ b/tests/oauth2/test_challenges.py
@@ -130,3 +130,11 @@
         assert challenges.PasswordChallenge().obtain_challenge_input({}) == {
             "credential": " "
         }
+
+
+def test_saml_challenge():
+    challenge = challenges.SamlChallenge()
+    assert challenge.is_locally_eligible
+    assert challenge.name == "SAML"
+    with pytest.raises(exceptions.ReauthSamlChallengeFailError):
+        challenge.obtain_challenge_input(None)
diff --git a/tests/oauth2/test_credentials.py b/tests/oauth2/test_credentials.py
index 4a7f66e..b6a80e3 100644
--- a/tests/oauth2/test_credentials.py
+++ b/tests/oauth2/test_credentials.py
@@ -51,6 +51,7 @@
             client_id=cls.CLIENT_ID,
             client_secret=cls.CLIENT_SECRET,
             rapt_token=cls.RAPT_TOKEN,
+            enable_reauth_refresh=True,
         )
 
     def test_default_state(self):
@@ -149,6 +150,7 @@
             self.CLIENT_SECRET,
             None,
             self.RAPT_TOKEN,
+            True,
         )
 
         # Check that the credentials have the token and expiry
@@ -219,6 +221,7 @@
             self.CLIENT_SECRET,
             None,
             self.RAPT_TOKEN,
+            False,
         )
 
         # Check that the credentials have the token and expiry
@@ -422,6 +425,7 @@
             scopes=scopes,
             default_scopes=default_scopes,
             rapt_token=self.RAPT_TOKEN,
+            enable_reauth_refresh=True,
         )
 
         # Refresh credentials
@@ -436,6 +440,7 @@
             self.CLIENT_SECRET,
             scopes,
             self.RAPT_TOKEN,
+            True,
         )
 
         # Check that the credentials have the token and expiry
@@ -484,6 +489,7 @@
             client_secret=self.CLIENT_SECRET,
             default_scopes=default_scopes,
             rapt_token=self.RAPT_TOKEN,
+            enable_reauth_refresh=True,
         )
 
         # Refresh credentials
@@ -498,6 +504,7 @@
             self.CLIENT_SECRET,
             default_scopes,
             self.RAPT_TOKEN,
+            True,
         )
 
         # Check that the credentials have the token and expiry
@@ -549,6 +556,7 @@
             client_secret=self.CLIENT_SECRET,
             scopes=scopes,
             rapt_token=self.RAPT_TOKEN,
+            enable_reauth_refresh=True,
         )
 
         # Refresh credentials
@@ -563,6 +571,7 @@
             self.CLIENT_SECRET,
             scopes,
             self.RAPT_TOKEN,
+            True,
         )
 
         # Check that the credentials have the token and expiry
@@ -615,6 +624,7 @@
             client_secret=self.CLIENT_SECRET,
             scopes=scopes,
             rapt_token=self.RAPT_TOKEN,
+            enable_reauth_refresh=True,
         )
 
         # Refresh credentials
@@ -632,6 +642,7 @@
             self.CLIENT_SECRET,
             scopes,
             self.RAPT_TOKEN,
+            True,
         )
 
         # Check that the credentials have the token and expiry
@@ -731,6 +742,7 @@
         assert creds.refresh_token == info["refresh_token"]
         assert creds.token_uri == credentials._GOOGLE_OAUTH2_TOKEN_ENDPOINT
         assert creds.scopes is None
+        assert creds.rapt_token is None
 
         scopes = ["email", "profile"]
         creds = credentials.Credentials.from_authorized_user_file(
@@ -742,6 +754,18 @@
         assert creds.token_uri == credentials._GOOGLE_OAUTH2_TOKEN_ENDPOINT
         assert creds.scopes == scopes
 
+    def test_from_authorized_user_file_with_rapt_token(self):
+        info = AUTH_USER_INFO.copy()
+        file_path = os.path.join(DATA_DIR, "authorized_user_with_rapt_token.json")
+
+        creds = credentials.Credentials.from_authorized_user_file(file_path)
+        assert creds.client_secret == info["client_secret"]
+        assert creds.client_id == info["client_id"]
+        assert creds.refresh_token == info["refresh_token"]
+        assert creds.token_uri == credentials._GOOGLE_OAUTH2_TOKEN_ENDPOINT
+        assert creds.scopes is None
+        assert creds.rapt_token == "rapt"
+
     def test_to_json(self):
         info = AUTH_USER_INFO.copy()
         expiry = datetime.datetime(2020, 8, 14, 15, 54, 1)
diff --git a/tests/oauth2/test_reauth.py b/tests/oauth2/test_reauth.py
index e9ffa8a..58d649d 100644
--- a/tests/oauth2/test_reauth.py
+++ b/tests/oauth2/test_reauth.py
@@ -270,6 +270,7 @@
                 "client_secret",
                 scopes=["foo", "bar"],
                 rapt_token="rapt_token",
+                enable_reauth_refresh=True,
             )
         assert excinfo.match(r"Bad request")
         mock_token_request.assert_called_with(
@@ -298,7 +299,12 @@
             "google.oauth2.reauth.get_rapt_token", return_value="new_rapt_token"
         ):
             assert reauth.refresh_grant(
-                MOCK_REQUEST, "token_uri", "refresh_token", "client_id", "client_secret"
+                MOCK_REQUEST,
+                "token_uri",
+                "refresh_token",
+                "client_id",
+                "client_secret",
+                enable_reauth_refresh=True,
             ) == (
                 "access_token",
                 "refresh_token",
@@ -306,3 +312,18 @@
                 {"access_token": "access_token"},
                 "new_rapt_token",
             )
+
+
+def test_refresh_grant_reauth_refresh_disabled():
+    with mock.patch(
+        "google.oauth2._client._token_endpoint_request_no_throw"
+    ) as mock_token_request:
+        mock_token_request.side_effect = [
+            (False, {"error": "invalid_grant", "error_subtype": "rapt_required"}),
+            (True, {"access_token": "access_token"}),
+        ]
+        with pytest.raises(exceptions.RefreshError) as excinfo:
+            reauth.refresh_grant(
+                MOCK_REQUEST, "token_uri", "refresh_token", "client_id", "client_secret"
+            )
+        assert excinfo.match(r"Reauthentication is needed")