Skip to content

Commit 4c0bc03

Browse files
blink1073addaleaxdurran
authored
DRIVERS-2415 Implement OIDC SASL mechanism (#1365)
Co-authored-by: Anna Henningsen <[email protected]> Co-authored-by: Durran Jordan <[email protected]>
1 parent c06650d commit 4c0bc03

9 files changed

+1620
-396
lines changed

source/auth/auth.rst

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,22 @@ or "SCRAM-SHA-256").
254254
The cache entry value MUST be either the ``saltedPassword`` parameter or the
255255
combination of the ``clientKey`` and ``serverKey`` parameters.
256256

257+
Reauthentication
258+
~~~~~~~~~~~~~~~~
259+
260+
On any operation that requires authentication, the server may raise the
261+
error ``ReauthenticationRequired`` (391), typically if the user's credential
262+
has expired. Drivers MUST immediately attempt to force a reauthenication on
263+
the connection when this error is raised, and then re-attempt the operation.
264+
This attempt MUST be irrespective of whether the operation is considered
265+
retryable. Any errors encountered during reauthentication or the
266+
subsequent re-attempt of the operation MUST be raised to the user. Currently
267+
the only auth mechanism on the server that supports reauthentication is OIDC.
268+
See the OIDC documentation on reauthentication for more details.
269+
Note that in order to implement the unified spec tests for reauthentication,
270+
it may be necessary to add reauthentication support for whichever auth
271+
mechanism is used when running the auth spec tests.
272+
257273
--------------------------------
258274
Supported Authentication Methods
259275
--------------------------------
@@ -1159,6 +1175,269 @@ If AWS authentication fails for any reason, the cache MUST be cleared.
11591175
.. note::
11601176
Five minutes was chosen based on the AWS documentation for `IAM roles for EC2 <https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html>`_ : "We make new credentials available at least five minutes before the expiration of the old credentials". The intent is to have some buffer between when the driver fetches the credentials and when the server verifies them.
11611177

1178+
MONGODB-OIDC
1179+
~~~~~~~~~~~~
1180+
1181+
:since: 7.0 Enterprise
1182+
1183+
MONGODB-OIDC authenticates using an `OIDC <https://openid.net/specs/openid-connect-core-1_0.html>`_ access tokens. Drivers MUST support
1184+
both callback-driven OIDC and automatic OIDC authentication for AWS.
1185+
1186+
1187+
Conversation
1188+
````````````
1189+
1190+
Authenticating using the MONGODB-OIDC mechanism will require 1 or 2 round trips between the client and MongoDB. The requests from the client and the replies from the server are described by the following IDL structs which are encoded in the payload as octet sequences defining BSON objects:
1191+
1192+
.. code:: idl
1193+
1194+
OIDCMechanismClientStep1:
1195+
description: Client's opening request in saslStart
1196+
strict: false
1197+
fields:
1198+
n:
1199+
description: "Principal name of client"
1200+
cpp_name: principalName
1201+
type: string
1202+
optional: true
1203+
1204+
Note that the principal name is optional as it may be provided by the IDP in environments where only one IDP is used. It is given by the user as the
1205+
username.
1206+
1207+
.. code:: idl
1208+
1209+
OIDCMechanismServerStep1:
1210+
description: "Server's reply to clientStep1"
1211+
strict: false
1212+
fields:
1213+
authorizationEndpoint:
1214+
description: >-
1215+
URL where the IDP may be contacted for end user
1216+
authentication and authorization code generation.
1217+
type: string
1218+
optional: true # Req if deviceAuthorizeEndpoint not present
1219+
tokenEndpoint:
1220+
description: >-
1221+
URL where the IDP may be contacted for authorization
1222+
code <=> ID/access token exchange.
1223+
type: string
1224+
optional: true # Req if deviceAuthorizeEndpoint not present
1225+
deviceAuthorizationEndpoint:
1226+
description: >-
1227+
URL where the IDP may be contacted for device
1228+
authentication and authorization code generation.
1229+
type: string
1230+
optional: true # Req if authorizeEndpoint not present
1231+
clientId:
1232+
description: "Unique client ID for this OIDC client"
1233+
type: string
1234+
clientSecret:
1235+
description: "Secret used when communicating with IDP"
1236+
type: string
1237+
optional: true
1238+
requestScopes:
1239+
description: "Additional scopes to request from IDP"
1240+
type: array<string>
1241+
optional: true
1242+
1243+
Server will use principalName (n) if provided in clientStep1 to select an appropriate IDP. This IDP's configuration will be returned in serverStep1 to instruct the client on how to acquire an Access Token. This Access Token will be used in clientStep2 to complete authentication. The principalName identified within the Access Token MUST match any provided during clientStep1, or the authentication operation will fail.
1244+
1245+
.. code:: idl
1246+
1247+
OIDCMechanismClientStep2:
1248+
description: "Client's request with signed token"
1249+
strict: false
1250+
fields:
1251+
jwt:
1252+
description: "Compact serialized JWT with signature"
1253+
cpp_name: JWT
1254+
type: string
1255+
1256+
`MongoCredential`_ Properties
1257+
`````````````````````````````
1258+
1259+
username
1260+
MUST specified if more than one OIDC provider is configured and
1261+
DEVICE_NAME mechanism property is not specified.
1262+
1263+
source
1264+
MUST be "$external". Defaults to ``$external``.
1265+
1266+
password
1267+
MUST NOT be specified.
1268+
1269+
mechanism
1270+
MUST be "MONGODB-OIDC"
1271+
1272+
mechanism_properties
1273+
DEVICE_NAME
1274+
Drivers MUST allow the user to specify a name for the device
1275+
workflow that is one of "aws", "azure", or "gcp".
1276+
REQUEST_TOKEN_CALLBACK
1277+
Drivers MUST allow the user to specify a callback of the form
1278+
"onOIDCRequestToken" (defined below), if the driver supports
1279+
providing objects as mechanism property values.
1280+
REFRESH_TOKEN_CALLBACK
1281+
Drivers MUST allow the user to specify a callback of the form
1282+
"onOIDCRefreshToken" (defined below), if the driver supports
1283+
providing objects as mechanism property values.
1284+
1285+
Drivers MUST skip client step 1 for device workflows
1286+
or when the server step 1 response value is cached. When skipping step 1,
1287+
drivers will use ``saslStart`` and a payload with the ``jwt`` value.
1288+
1289+
User Provided Callbacks
1290+
```````````````````````
1291+
1292+
Drivers MUST allow the user to provide callbacks for token request and
1293+
token refresh. The token request callback MUST accept the OIDCMechanismServerStep1 structure and return an OIDCRequestTokenResult of
1294+
the form:
1295+
1296+
.. code:: idl
1297+
1298+
OIDCRequestTokenResult:
1299+
description: "The result of a token request"
1300+
strict: false
1301+
fields:
1302+
accessToken:
1303+
description: "The OIDC access token"
1304+
type: string
1305+
expiresInSeconds:
1306+
description: "The expiration time in seconds from the current time"
1307+
type: int
1308+
optional: true
1309+
refreshToken:
1310+
description: "The OIDC refresh token"
1311+
type: str
1312+
optional: true
1313+
1314+
.. code:: typescript
1315+
1316+
function onOIDCRequestToken(principalName: str, serverInfo: OIDCMechanismServerStep1, timeoutSeconds: int): OIDCRequestTokenResult
1317+
1318+
Callbacks can be synchronous and/or asynchronous, depending on the driver
1319+
and/or language. Asynchronous callbacks should be preferred when other
1320+
operations in the driver use asynchronous functions.
1321+
1322+
Before calling a callback, the driver MUST acquire a lock, and verify that
1323+
there are no valid cache credentials before calling the callback.
1324+
This is because request callbacks may involve human interaction, and refresh
1325+
callbacks could use refresh tokens that can only be used once.
1326+
1327+
The driver MUST provide a way for the callback to be either automatically
1328+
cancelled, or to cancel itself. This can be as a timeout argument to the
1329+
callback, a cancellation context passed to the callback, or some other
1330+
language-appropriate mechanism. The timeout duration MUST be 5 minutes,
1331+
to account for the fact that there may be human interaction involved.
1332+
1333+
If the callback does not return an object in the correct form of ``OIDCRequestTokenResult``, the driver MUST raise an error. The driver will
1334+
inspect that the correct properties are given, but MUST NOT attempt to validate
1335+
the token(s) directly.
1336+
1337+
The optional token refresh callback will accept the IDP information as
1338+
well as the cached OIDCRequestTokenResult and return a new OIDCRequestTokenResult.
1339+
1340+
1341+
.. code:: typescript
1342+
1343+
function onOIDCRefreshToken(principalName: str, serverInfo: OIDCMechanismServerStep1, tokenResult: OIDCRequestTokenResult, timeoutSeconds: int): OIDCRequestTokenResult
1344+
1345+
If the callback does not return an object in the correct form of ``OIDCRequestTokenResult``, the driver MUST raise an error.
1346+
1347+
If the refresh callback is given and the request callback is not given,
1348+
the driver MUST raise an error. If DEVICE_NAME is given and one or more
1349+
callbacks are given, the driver MUST raise an error.
1350+
1351+
If no callbacks are given, the driver MUST enforce that a DEVICE_NAME
1352+
mechanism_properties is set and one of ("aws",).
1353+
The callback mechanism can be used to support both Authentication
1354+
Code Workflows or Device workflows that are not explicitly implemented
1355+
by drivers. If there is no callback and no DEVICE_NAME, or the
1356+
DEVICE_NAME is set but credentials cannot be automatically obtained,
1357+
the driver MUST raise an error.
1358+
1359+
1360+
Supported Device Workflows
1361+
``````````````````````````
1362+
1363+
Drivers MUST support device workflows for "aws", given
1364+
by the DEVICE_NAME mechanism property. In all cases the acquired token
1365+
will be given as the ``jwt`` argument and the second client step of the
1366+
OIDC SASL exchange MUST be made directly, skipping the clientStep1.
1367+
Drivers MUST raise an error if both a DEVICE_NAME and username are
1368+
given, since the device workflow will not use the username.
1369+
1370+
AWS
1371+
___
1372+
1373+
When the DEVICE_NAME mechanism property is set to "aws", the driver MUST
1374+
attempt to read the value given by the ``AWS_WEB_IDENTITY_TOKEN_FILE`` and
1375+
interpret it as a file path. The contents of the file are read as the
1376+
access token.
1377+
1378+
1379+
Caching Credentials
1380+
```````````````````
1381+
1382+
Drivers MUST enable caching when callback(s) are provided to the mongo client.
1383+
When an authorization request is made and there is a valid cached response,
1384+
the driver MUST use the cached authorization token if it has not expired.
1385+
1386+
A cache value is considered valid if it has been accessed in the past 5 hours.
1387+
The cache is kept alive to preserve the serverStep1 response, as well as
1388+
account for refresh tokens, which typically have an (unknown) lifetime that
1389+
is longer than the access token lifetime. The refresh token may either be
1390+
stored by the user application, or as part of the request/refresh token
1391+
response in the driver cache. To prevent a memory leak, the driver MUST clear
1392+
invalid cache values at a regular interval, or during every authentication
1393+
attempt.
1394+
1395+
The cache keys MUST include the username (or empty string) and the
1396+
actually used socket address and port for the current server. The cache key
1397+
MUST also include a hashes of the callback function(s), if relevant and
1398+
possible in the driver language.
1399+
1400+
Using the socket address and port accounts for the case when two different
1401+
servers use the same username but could be configurated differently.
1402+
There is an edge case where if the same username is used and two aliases
1403+
to the same local host address are given, there will be duplicate user/device
1404+
interactions, unless the driver can resolve the local host address as well.
1405+
Note that because we use the server socket address, there will different cache
1406+
keys for each member of a replica set.
1407+
1408+
The driver MUST cache the serverStep1 response as part of the cache value,
1409+
to enable skipping serverStep1 on subsequent authentications of the same
1410+
cache key.
1411+
1412+
A global cache should be preferred, to prevent multiple browser interactions
1413+
in the case of an authentication code workflow. However, drivers or dev tools
1414+
can choose to use their own caching scheme if appropriate for their language/
1415+
environment.
1416+
1417+
A cached ``accessToken`` will expire 5 minutes before the ``expiresInSeconds``
1418+
time, if given. If there is no ``expiresInSeconds``, the token must be consider expired after first usage. If a cached value is found but its
1419+
``accessToken`` has expired, the refresh callback will be called (if given)
1420+
with the OIDCMechanismServerStep1 and original OIDCRequestTokenResult
1421+
arguments, and it will return a new OIDCRequestTokenResult response.
1422+
1423+
In order to prevent a memory leak, the driver MUST loop over the existing cache
1424+
at some interval, or per-authorization, to remove expired credentials from
1425+
the cache.
1426+
1427+
If there is no refresh callback and no current valid cached value, the request callback will be called. Multithreaded drivers MUST ensure that there is at most one concurrent call to any callback for a given cache key.
1428+
1429+
If a cached value is used and authentication fails, the driver MUST clear the
1430+
cached value.
1431+
1432+
1433+
Reauthentication
1434+
````````````````
1435+
When reauthentication is requested and MONGODB-OIDC is in use, the driver MUST
1436+
ensure that a cached ``accessToken`` is not used for direct authentication,
1437+
since it is has been identified as expired by the server. If a refresh
1438+
callback is given, it will be called as usual. Otherwise the request callback
1439+
will be called.
1440+
11621441
-------------------------
11631442
Connection String Options
11641443
-------------------------

0 commit comments

Comments
 (0)