Skip to content

Commit

Permalink
DRIVERS-2836 Only invalidate cached OIDC access tokens if the server …
Browse files Browse the repository at this point in the history
…returns error 18
  • Loading branch information
blink1073 committed Mar 19, 2024
1 parent 510a1e7 commit 6e09e49
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 25 deletions.
26 changes: 15 additions & 11 deletions source/auth/auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -1575,8 +1575,8 @@ Use the following algorithm to authenticate a new connection:

- Check if the the *Client Cache* has an access token.
- If it does, cache the access token in the *Connection Cache* and perform a `One-Step` SASL conversation using the
access token in the *Client Cache*. If the server returns an error, invalidate that access token, sleep 100ms then
continue.
access token in the *Client Cache*. If the server returns a Authentication error (18), invalidate that access token,
sleep 100ms then continue.
- Call the configured built-in provider integration or the OIDC callback to retrieve a new access token.
- Cache the new access token in the *Client Cache* and *Connection Cache*.
- Perform a `One-Step` SASL conversation using the new access token. Raise any errors to the user.
Expand All @@ -1588,18 +1588,21 @@ def auth(connection):
access_token, is_cache = get_access_token()

# If there is a cached access token, try to authenticate with it. If
# authentication fails, it's possible the cached access token is expired. In
# authentication fails with an Authentication error (18),
# it's possible the cached access token is expired. In
# that case, invalidate the access token, fetch a new access token, and try
# to authenticate again.
# If the server fails for any other reason, do not clear the cache.
if is_cache:
try:
connection.oidc_cache.access_token = access_token
sasl_start(connection, payload={"jwt": access_token})
return
except ServerError:
invalidate(access_token)
sleep(0.1)
access_token, _ = get_access_token()
except ServerError as e:
if e.code == 18:
invalidate(access_token)
sleep(0.1)
access_token, _ = get_access_token()

connection.oidc_cache.access_token = access_token
sasl_start(connection, payload={"jwt": access_token})
Expand All @@ -1610,14 +1613,15 @@ authenticate a new connection when a [OIDC Human Callback](#oidc-human-callback)

- Check if the *Client Cache* has an access token.
- If it does, cache the access token in the *Connection Cache* and perform a [One-Step](#one-step) SASL conversation
using the access token. If the server returns an error, invalidate the access token token from the *Client Cache*,
clear the *Connection Cache*, and continue.
using the access token. If the server returns an Authentication error (18), invalidate the access token token from
the *Client Cache*, clear the *Connection Cache*, and continue. If the server returns another error, continue.
- Check if the *Client Cache* has a refresh token.
- If it does, call the [OIDC Human Callback](#oidc-human-callback) with the cached refresh token and `IdpInfo` to get
a new access token. Cache the new access token in the *Client Cache* and *Connection Cache*. Perform a
[One-Step](#one-step) SASL conversation using the new access token. If the
[OIDC Human Callback](#oidc-human-callback) or the server return an error, invalidate the access token from the
*Client Cache*, clear the *Connection Cache*, and continue.
[OIDC Human Callback](#oidc-human-callback) or the server returns an Authentication error (18), invalidate the
access token from the *Client Cache*, clear the *Connection Cache*, and continue. If the server returns another
error, continue.
- Start a new [Two-Step](#two-step) SASL conversation.
- Run a `PrincipalStepRequest` to get the `IdpInfo`.
- Call the [OIDC Human Callback](#oidc-human-callback) with the new `IdpInfo` to get a new access token and optional
Expand Down
38 changes: 34 additions & 4 deletions source/auth/tests/mongodb-oidc.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,12 +240,14 @@ Drivers MUST be able to authenticate using OIDC callback(s) when there is one pr
```javascript
{
configureFailPoint: "failCommand",
mode: "alwaysOn",
mode: {
times: 1
},
data: {
failCommands: [
"saslStart"
],
errorCode: 20
errorCode: 18
}
}
```
Expand All @@ -261,17 +263,45 @@ Drivers MUST be able to authenticate using OIDC callback(s) when there is one pr
```javascript
{
configureFailPoint: "failCommand",
mode: "alwaysOn",
mode: {
times: 1
},
data: {
failCommands: [
"saslStart"
],
errorCode: 18
}
}
```

- Perform a `find` operation that fails.
- Close the client.

**3.3 Unexpected error code does not clear the cache**

- Create a `MongoClient` with a human callback that returns a valid token.
- Set a fail point for `saslStart` commands of the form:

```javascript
{
configureFailPoint: "failCommand",
mode: {
times: 1
},
data: {
failCommands: [
"saslStart"
],
errorCode: 20 // IllegalOperation
errorCode: 20
}
}
```

- Perform a `find` operation that fails.
- Assert that the human callback has been called once.
- Perform a `find` operation that succeeds.
- Assert that the human callback has been called once.
- Close the client.

### (4) Reauthentication
Expand Down
10 changes: 5 additions & 5 deletions source/auth/tests/unified/mongodb-oidc-no-retry.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 7 additions & 5 deletions source/auth/tests/unified/mongodb-oidc-no-retry.yml
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,12 @@ tests:
client: failPointClient
failPoint:
configureFailPoint: failCommand
mode: "alwaysOn"
mode:
times: 1
data:
failCommands:
- saslStart
errorCode: 20 # IllegalOperation
errorCode: 18
- name: insertOne
object: collection0
arguments:
Expand Down Expand Up @@ -211,19 +212,20 @@ tests:
client: failPointClient
failPoint:
configureFailPoint: failCommand
mode: "alwaysOn"
mode:
times: 1
data:
failCommands:
- saslStart
errorCode: 20 # IllegalOperation
errorCode: 18
- name: insertOne
object: collection0
arguments:
document:
_id: 1
x: 1
expectError:
errorCode: 20 # IllegalOperation
errorCode: 18
- description: Read commands should fail if reauthentication fails
operations:
- name: find
Expand Down

0 comments on commit 6e09e49

Please sign in to comment.