Skip to content

Commit

Permalink
DOCSP-39405: kotlin v5.1 content (#161)
Browse files Browse the repository at this point in the history
* DOCSP-39405: kotlin v5.1 content

* NR small fixes

* RL tech review comments

(cherry picked from commit efd48c9)
  • Loading branch information
rustagir committed Jun 28, 2024
1 parent 0c5f540 commit 7f3b03e
Show file tree
Hide file tree
Showing 12 changed files with 292 additions and 7 deletions.
2 changes: 1 addition & 1 deletion examples/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
kotlin.code.style=official
kotlin_mongodb_version=4.11.0
kotlin_mongodb_version=5.1.0
85 changes: 85 additions & 0 deletions examples/src/test/kotlin/EnterpriseAuthTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ import com.mongodb.ConnectionString
import com.mongodb.KerberosSubjectProvider
import com.mongodb.MongoClientSettings
import com.mongodb.MongoCredential
import com.mongodb.MongoCredential.OidcCallbackResult
import com.mongodb.ServerAddress
import com.mongodb.kotlin.client.coroutine.MongoClient
import kotlinx.coroutines.runBlocking
import java.nio.file.Files
import java.nio.file.Paths
import javax.naming.Context
import javax.security.auth.Subject
import javax.security.auth.login.LoginContext
import kotlin.test.Ignore
Expand Down Expand Up @@ -113,6 +117,87 @@ internal class EnterpriseAuthTest {
val mongoClient = MongoClient.create(connectionString)
// :snippet-end:
}

fun oidcAzureConnectionString() = runBlocking {
// :snippet-start: oidc-azure-connection-string
val connectionString = ConnectionString(
"mongodb://<username>@<hostname>:<port>/?" +
"?authMechanism=MONGODB-OIDC" +
"&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:<percent-encoded audience>")
val mongoClient = MongoClient.create(connectionString)
// :snippet-end:
}

fun oidcAzureCredential() = runBlocking {
// :snippet-start: oidc-azure-credential
val credential = MongoCredential.createOidcCredential("<username>")
.withMechanismProperty("ENVIRONMENT", "azure")
.withMechanismProperty("TOKEN_RESOURCE", "<audience>")

val mongoClient = MongoClient.create(
MongoClientSettings.builder()
.applyToClusterSettings { builder ->
builder.hosts(listOf(ServerAddress("<hostname>", PORT)))
}
.credential(credential)
.build())
// :snippet-end:
}

fun oidcGCPConnectionString() = runBlocking {
// :snippet-start: oidc-gcp-connection-string
val connectionString = ConnectionString(
"mongodb://<hostname>:<port>/?" +
"authMechanism=MONGODB-OIDC" +
"&authMechanismProperties=ENVIRONMENT:gcp,TOKEN_RESOURCE:<percent-encoded audience>")
val mongoClient = MongoClient.create(connectionString)
// :snippet-end:
}

fun oidcGCPCredential() = runBlocking {
// :snippet-start: oidc-gcp-credential
val credential = MongoCredential.createOidcCredential("<username>")
.withMechanismProperty("ENVIRONMENT", "gcp")
.withMechanismProperty("TOKEN_RESOURCE", "<audience>")

val mongoClient = MongoClient.create(
MongoClientSettings.builder()
.applyToClusterSettings { builder ->
builder.hosts(listOf(ServerAddress("<hostname>", PORT)))
}
.credential(credential)
.build())
// :snippet-end:
}

fun oidcCallback() = runBlocking {
// :snippet-start: oidc-callback
val credential = MongoCredential.createOidcCredential(null)
.withMechanismProperty("OIDC_CALLBACK") { context: Context ->
val accessToken = "..."
OidcCallbackResult(accessToken)
}
// :snippet-end:
}

fun oidcCallbackFile() = runBlocking {
// :snippet-start: oidc-callback-file
val credential = MongoCredential.createOidcCredential(null)
.withMechanismProperty("OIDC_CALLBACK") { context: Context ->
val accessToken = String(Files.readAllBytes(Paths.get("access-token.dat")))
OidcCallbackResult(accessToken)
}

val mongoClient = MongoClient.create(
MongoClientSettings.builder()
.applyToClusterSettings { builder ->
builder.hosts(listOf(ServerAddress("<hostname>", PORT)))
}
.credential(credential)
.build()
)
// :snippet-end:
}
}
// :replace-end:

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
val connectionString = ConnectionString(
"mongodb://<username>@<hostname>:<port>/?" +
"?authMechanism=MONGODB-OIDC" +
"&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:<percent-encoded audience>")
val mongoClient = MongoClient.create(connectionString)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
val credential = MongoCredential.createOidcCredential("<username>")
.withMechanismProperty("ENVIRONMENT", "azure")
.withMechanismProperty("TOKEN_RESOURCE", "<audience>")

val mongoClient = MongoClient.create(
MongoClientSettings.builder()
.applyToClusterSettings { builder ->
builder.hosts(listOf(ServerAddress("<hostname>", <port>)))
}
.credential(credential)
.build())
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
val credential = MongoCredential.createOidcCredential(null)
.withMechanismProperty("OIDC_CALLBACK") { context: Context ->
val accessToken = String(Files.readAllBytes(Paths.get("access-token.dat")))
OidcCallbackResult(accessToken)
}

val mongoClient = MongoClient.create(
MongoClientSettings.builder()
.applyToClusterSettings { builder ->
builder.hosts(listOf(ServerAddress("<hostname>", <port>)))
}
.credential(credential)
.build()
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
val credential = MongoCredential.createOidcCredential(null)
.withMechanismProperty("OIDC_CALLBACK") { context: Context ->
val accessToken = "..."
OidcCallbackResult(accessToken)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
val connectionString = ConnectionString(
"mongodb://<hostname>:<port>/?" +
"authMechanism=MONGODB-OIDC" +
"&authMechanismProperties=ENVIRONMENT:gcp,TOKEN_RESOURCE:<percent-encoded audience>")
val mongoClient = MongoClient.create(connectionString)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
val credential = MongoCredential.createOidcCredential("<username>")
.withMechanismProperty("ENVIRONMENT", "gcp")
.withMechanismProperty("TOKEN_RESOURCE", "<audience>")

val mongoClient = MongoClient.create(
MongoClientSettings.builder()
.applyToClusterSettings { builder ->
builder.hosts(listOf(ServerAddress("<hostname>", <port>)))
}
.credential(credential)
.build())
9 changes: 9 additions & 0 deletions source/fundamentals/connection/connection-options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,15 @@ parameters of the connection URI to specify the behavior of the client.

| **Default**: ``true``

* - **serverMonitoringMode**
- string
- Specifies which server monitoring protocol the driver uses. When set to
``auto``, the monitoring mode is determined by the environment in which
the driver is running. The driver uses ``poll`` mode in function-as-a-service
(FaaS) environments and ``stream`` mode in other environments.

| **Default**: ``auto``

* - **uuidRepresentation**
- string
- Specifies the UUID representation to use for read and write
Expand Down
3 changes: 3 additions & 0 deletions source/fundamentals/connection/mongoclientsettings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,9 @@ settings to modify the driver's behavior:
* - ``minHeartbeatFrequency()``
- Sets the minimum interval for server monitoring checks.

* - ``serverMonitoringMode()``
- Specifies which server monitoring protocol the driver uses.

Example
~~~~~~~

Expand Down
140 changes: 139 additions & 1 deletion source/fundamentals/enterprise-auth.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
Enterprise Authentication Mechanisms
====================================

.. facet::
:name: genre
:values: reference

.. meta::
:keywords: ldap, encryption, principal, tls


.. contents:: On this page
:local:
:backlinks: none
Expand All @@ -22,6 +30,7 @@ Enterprise Edition:

- :ref:`Kerberos (GSSAPI) <gssapi-auth-mechanism>`
- :ref:`LDAP (PLAIN) <plain-auth-mechanism>`
- :ref:`MONGODB-OIDC <kotlin-oidc>`

:doc:`Authentication Mechanisms guide </fundamentals/auth>`.

Expand Down Expand Up @@ -278,4 +287,133 @@ mechanism:

.. literalinclude:: /examples/generated/EnterpriseAuthTest.snippet.ldap-mongo-credential.kt
:language: kotlin


.. _kotlin-oidc:

MONGODB-OIDC
~~~~~~~~~~~~

.. important::

The MONGODB-OIDC authentication mechanism requires {+mdb-server+} v7.0 or later running
on a Linux platform.

The following sections describe how to use the MONGODB-OIDC
authentication mechanism to authenticate to various platforms.

For more information about the MONGODB-OIDC authentication mechanism, see
:manual:`OpenID Connect Authentication </core/security-oidc/>` and
:manual:`MongoDB Server Parameters </reference/parameters/#mongodb-parameter-param.oidcIdentityProviders>`
in the MongoDB Server manual.

.. _kotlin-mongodb-oidc-azure-imds:

Azure IMDS
++++++++++

If your application runs on an Azure VM, or otherwise uses the
`Azure Instance Metadata Service <https://learn.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service>`__
(IMDS), you can authenticate to MongoDB by using the {+driver-short+}'s built-in Azure
support.

You can specify Azure IMDS OIDC authentication either by
using a ``MongoCredential`` instance or by specifying your credentials
in the connection string.

Select from the :guilabel:`Connection String` or :guilabel:`MongoCredential` tabs to
see the corresponding syntax.

.. tabs::

.. tab:: Connection String
:tabid: mongodb-azure-imds-connection-string

Replace the ``<percent-encoded audience>`` placeholder in the
following code with the percent-encoded value of the audience server
parameter configured on your MongoDB deployment.

The comma (``,``) character and its encoding (``%2C``) are
reserved, and using these characters in a value causes the
driver to interpret commas as delimiters of key-value pairs.
You must specify values that contain commas in a ``MongoCredential`` instance, as
demonstrated in the :guilabel:`MongoCredential` tab.

.. literalinclude:: /examples/generated/EnterpriseAuthTest.snippet.oidc-azure-connection-string.kt
:language: kotlin

.. tab:: MongoCredential
:tabid: mongodb-azure-mongo-credential

Replace the ``<username>`` placeholder with the client ID or application ID of the
Azure managed identity or enterprise application. Replace the ``<audience>``
placeholder with the value of the
``audience`` server parameter configured on your MongoDB deployment.

.. literalinclude:: /examples/generated/EnterpriseAuthTest.snippet.oidc-azure-credential.kt
:language: kotlin

.. _kotlin-mongodb-oidc-gcp-imds:

GCP IMDS
++++++++

If your application runs on a Google Compute Engine VM, or otherwise uses the
`GCP Instance Metadata Service <https://cloud.google.com/compute/docs/metadata/querying-metadata>`__,
you can authenticate to MongoDB by using the {+driver-short+}'s built-in GCP
support.

You can specify GCP IMDS OIDC authentication either by
using a ``MongoCredential`` instance or by specifying your credentials
in the connection string.

Select from the :guilabel:`Connection String` or :guilabel:`MongoCredential` tabs to
see the corresponding syntax.

.. tabs::

.. tab:: Connection String
:tabid: mongodb-gcp-imds-connection-string

Replace the ``<percent-encoded audience>`` placeholder in the
following code with the percent-encoded value of the audience server
parameter configured on your MongoDB deployment.

The comma (``,``) character and its encoding (``%2C``) are
reserved, and using these characters in a value causes the
driver to interpret commas as delimiters of key-value pairs.
You must specify values that contain commas in a ``MongoCredential`` instance, as
demonstrated in the :guilabel:`MongoCredential` tab.

.. literalinclude:: /examples/generated/EnterpriseAuthTest.snippet.oidc-gcp-connection-string.kt
:language: kotlin

.. tab:: MongoCredential
:tabid: mongodb-gcp-mongo-credential

Replace the ``<audience>`` placeholder with the value of the
``audience`` server parameter configured on your MongoDB deployment.

.. literalinclude:: /examples/generated/EnterpriseAuthTest.snippet.oidc-gcp-credential.kt
:language: kotlin

Custom Callback
+++++++++++++++

The {+driver-short+} doesn't offer built-in support for all platforms, including
Azure Functions and Azure Kubernetes Service (AKS). Instead, you
must define a custom callback to use OIDC to authenticate from these platforms.
To do so, use the ``"OIDC_CALLBACK"`` authentication property, as shown in the following
code example:

.. literalinclude:: /examples/generated/EnterpriseAuthTest.snippet.oidc-callback.kt
:language: kotlin

The value of the ``"OIDC_CALLBACK"`` property must be a lambda or other implementation
of the ``OidcCallback`` functional interface that accepts an ``OidcCallbackContext``
as a parameter and returns an ``OidcCallbackResult``.

The following example uses an example callback to retrieve an OIDC token from a file
named ``"access-token.dat"`` in the local file system:

.. literalinclude:: /examples/generated/EnterpriseAuthTest.snippet.oidc-callback-file.kt
:language: kotlin
9 changes: 4 additions & 5 deletions source/whats-new.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ Improvements in 5.1
native applications by using the GraalVM native-image tool.

- Enhanced support for the ``MONGODB-OIDC`` authentication mechanism.

.. TODO add OIDC content and link
To learn more about OIDC, see the :ref:`kotlin-oidc` section of the
Enterprise Authentication Mechanisms guide.

- Fixes an issue in which operations used the incorrect codec when using
a polymorphic ``MongoCollection`` instance. This ensures that
Expand All @@ -72,9 +72,8 @@ New Features in 5.1

.. TODO add polymorphic serialization content

- Introduces the ``serverMonitoringMode`` connection URI option.

.. TODO add serverMonitoringMode content and link
- Introduces the ``serverMonitoringMode`` connection URI option. To
learn more, see the :ref:`connection-options` guide.

.. _version-5.0:

Expand Down

0 comments on commit 7f3b03e

Please sign in to comment.