|
28 | 28 | from pymongo._csot import remaining
|
29 | 29 | from pymongo._gcp_helpers import _get_gcp_response
|
30 | 30 | from pymongo.errors import ConfigurationError, OperationFailure
|
| 31 | +from pymongo.helpers import _AUTHENTICATION_FAILURE_CODE |
31 | 32 |
|
32 | 33 | if TYPE_CHECKING:
|
33 | 34 | from pymongo.auth import MongoCredential
|
|
37 | 38 | @dataclass
|
38 | 39 | class OIDCIdPInfo:
|
39 | 40 | issuer: str
|
40 |
| - clientId: str |
| 41 | + clientId: Optional[str] = field(default=None) |
41 | 42 | requestScopes: Optional[list[str]] = field(default=None)
|
42 | 43 |
|
43 | 44 |
|
@@ -189,30 +190,43 @@ def get_spec_auth_cmd(self) -> Optional[MutableMapping[str, Any]]:
|
189 | 190 |
|
190 | 191 | def _authenticate_machine(self, conn: Connection) -> Mapping[str, Any]:
|
191 | 192 | # If there is a cached access token, try to authenticate with it. If
|
192 |
| - # authentication fails, it's possible the cached access token is expired. In |
193 |
| - # that case, invalidate the access token, fetch a new access token, and try |
194 |
| - # to authenticate again. |
| 193 | + # authentication fails with error code 18, invalidate the access token, |
| 194 | + # fetch a new access token, and try to authenticate again. If authentication |
| 195 | + # fails for any other reason, raise the error to the user. |
195 | 196 | if self.access_token:
|
196 | 197 | try:
|
197 | 198 | return self._sasl_start_jwt(conn)
|
198 |
| - except Exception: # noqa: S110 |
199 |
| - pass |
| 199 | + except OperationFailure as e: |
| 200 | + if self._is_auth_error(e): |
| 201 | + return self._authenticate_machine(conn) |
| 202 | + raise |
200 | 203 | return self._sasl_start_jwt(conn)
|
201 | 204 |
|
202 | 205 | def _authenticate_human(self, conn: Connection) -> Optional[Mapping[str, Any]]:
|
203 | 206 | # If we have a cached access token, try a JwtStepRequest.
|
| 207 | + # authentication fails with error code 18, invalidate the access token, |
| 208 | + # and try to authenticate again. If authentication fails for any other |
| 209 | + # reason, raise the error to the user. |
204 | 210 | if self.access_token:
|
205 | 211 | try:
|
206 | 212 | return self._sasl_start_jwt(conn)
|
207 |
| - except Exception: # noqa: S110 |
208 |
| - pass |
| 213 | + except OperationFailure as e: |
| 214 | + if self._is_auth_error(e): |
| 215 | + return self._authenticate_human(conn) |
| 216 | + raise |
209 | 217 |
|
210 | 218 | # If we have a cached refresh token, try a JwtStepRequest with that.
|
| 219 | + # If authentication fails with error code 18, invalidate the access and |
| 220 | + # refresh tokens, and try to authenticate again. If authentication fails for |
| 221 | + # any other reason, raise the error to the user. |
211 | 222 | if self.refresh_token:
|
212 | 223 | try:
|
213 | 224 | return self._sasl_start_jwt(conn)
|
214 |
| - except Exception: # noqa: S110 |
215 |
| - pass |
| 225 | + except OperationFailure as e: |
| 226 | + if self._is_auth_error(e): |
| 227 | + self.refresh_token = None |
| 228 | + return self._authenticate_human(conn) |
| 229 | + raise |
216 | 230 |
|
217 | 231 | # Start a new Two-Step SASL conversation.
|
218 | 232 | # Run a PrincipalStepRequest to get the IdpInfo.
|
@@ -280,10 +294,16 @@ def _get_access_token(self) -> Optional[str]:
|
280 | 294 | def _run_command(self, conn: Connection, cmd: MutableMapping[str, Any]) -> Mapping[str, Any]:
|
281 | 295 | try:
|
282 | 296 | return conn.command("$external", cmd, no_reauth=True) # type: ignore[call-arg]
|
283 |
| - except OperationFailure: |
284 |
| - self._invalidate(conn) |
| 297 | + except OperationFailure as e: |
| 298 | + if self._is_auth_error(e): |
| 299 | + self._invalidate(conn) |
285 | 300 | raise
|
286 | 301 |
|
| 302 | + def _is_auth_error(self, err: Exception) -> bool: |
| 303 | + if not isinstance(err, OperationFailure): |
| 304 | + return False |
| 305 | + return err.code == _AUTHENTICATION_FAILURE_CODE |
| 306 | + |
287 | 307 | def _invalidate(self, conn: Connection) -> None:
|
288 | 308 | # Ignore the invalidation if a token gen id is given and is less than our
|
289 | 309 | # current token gen id.
|
|
0 commit comments