diff --git a/mongo/client.go b/mongo/client.go index cda768cf0d..1560ace918 100644 --- a/mongo/client.go +++ b/mongo/client.go @@ -224,6 +224,9 @@ func NewClient(opts ...*options.ClientOptions) (*Client, error) { PasswordSet: clientOpt.Auth.PasswordSet, Props: clientOpt.Auth.AuthMechanismProperties, }) + if err != nil { + return nil, err + } } cfg, err := topology.NewConfigWithAuthenticator(clientOpt, client.clock, client.authenticator) diff --git a/x/mongo/driver/auth/auth.go b/x/mongo/driver/auth/auth.go index c5bcd90f75..bbfdcfe935 100644 --- a/x/mongo/driver/auth/auth.go +++ b/x/mongo/driver/auth/auth.go @@ -19,6 +19,7 @@ import ( "go.mongodb.org/mongo-driver/x/mongo/driver/session" ) +// Config contains the configuration for an Authenticator. type Config = driver.AuthConfig // AuthenticatorFactory constructs an authenticator. diff --git a/x/mongo/driver/auth/cred.go b/x/mongo/driver/auth/cred.go index 5f89f29018..a9685f6ed8 100644 --- a/x/mongo/driver/auth/cred.go +++ b/x/mongo/driver/auth/cred.go @@ -3,10 +3,12 @@ // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + package auth import ( "go.mongodb.org/mongo-driver/x/mongo/driver" ) +// Cred is the type of user credential type Cred = driver.Cred diff --git a/x/mongo/driver/auth/default.go b/x/mongo/driver/auth/default.go index 5e8c5b98ec..a07fba1faa 100644 --- a/x/mongo/driver/auth/default.go +++ b/x/mongo/driver/auth/default.go @@ -67,7 +67,7 @@ func (a *DefaultAuthenticator) Auth(ctx context.Context, cfg *Config) error { } // Reauth reauthenticates the connection. -func (a *DefaultAuthenticator) Reauth(ctx context.Context) error { +func (a *DefaultAuthenticator) Reauth(_ context.Context) error { return newAuthError("DefaultAuthenticator does not support reauthentication", nil) } diff --git a/x/mongo/driver/auth/mongodbcr.go b/x/mongo/driver/auth/mongodbcr.go index 7301469921..41e21d2dea 100644 --- a/x/mongo/driver/auth/mongodbcr.go +++ b/x/mongo/driver/auth/mongodbcr.go @@ -98,7 +98,7 @@ func (a *MongoDBCRAuthenticator) Auth(ctx context.Context, cfg *Config) error { } // Reauth reauthenticates the connection. -func (a *MongoDBCRAuthenticator) Reauth(ctx context.Context) error { +func (a *MongoDBCRAuthenticator) Reauth(_ context.Context) error { return newAuthError("MONGODB-CR does not support reauthentication", nil) } diff --git a/x/mongo/driver/auth/oidc.go b/x/mongo/driver/auth/oidc.go index 0217ca1a96..cce6c68fc7 100644 --- a/x/mongo/driver/auth/oidc.go +++ b/x/mongo/driver/auth/oidc.go @@ -16,9 +16,14 @@ import ( "go.mongodb.org/mongo-driver/x/mongo/driver" ) +// MongoDBOIDC is the string constant for the MONGODB-OIDC authentication mechanism. const MongoDBOIDC = "MONGODB-OIDC" -const tokenResourceProp = "TOKEN_RESOURCE" + +// TODO GODRIVER-2728: Automatic token acquisition for Azure Identity Provider +// const tokenResourceProp = "TOKEN_RESOURCE" const environmentProp = "ENVIRONMENT" + +// GODRIVER-3249 OIDC: Handle all possible OIDC configuration errors const allowedHostsProp = "ALLOWED_HOSTS" const azureEnvironmentValue = "azure" @@ -28,19 +33,27 @@ const apiVersion = 1 const invalidateSleepTimeout = 100 * time.Millisecond const machineCallbackTimeout = 60 * time.Second -var defaultAllowedHosts = []string{ - "*.mongodb.net", - "*.mongodb-qa.net", - "*.mongodb-dev.net", - "*.mongodbgov.net", - "localhost", - "127.0.0.1", - "::1", -} - +//GODRIVER-3246 OIDC: Implement Human Callback Mechanism +//var defaultAllowedHosts = []string{ +// "*.mongodb.net", +// "*.mongodb-qa.net", +// "*.mongodb-dev.net", +// "*.mongodbgov.net", +// "localhost", +// "127.0.0.1", +// "::1", +//} + +// OIDCCallback is a function that takes a context and OIDCArgs and returns an OIDCCredential. type OIDCCallback = driver.OIDCCallback + +// OIDCArgs contains the arguments for the OIDC callback. type OIDCArgs = driver.OIDCArgs + +// OIDCCredential contains the access token and refresh token. type OIDCCredential = driver.OIDCCredential + +// IDPInfo contains the information needed to perform OIDC authentication with an Identity Provider. type IDPInfo = driver.IDPInfo var _ driver.Authenticator = (*OIDCAuthenticator)(nil) @@ -79,13 +92,14 @@ func jwtStepRequest(accessToken string) []byte { Build() } -func principalStepRequest(principal string) []byte { - doc := bsoncore.NewDocumentBuilder() - if principal != "" { - doc.AppendString("n", principal) - } - return doc.Build() -} +// TODO GODRIVER-3246: Implement OIDC human flow +//func principalStepRequest(principal string) []byte { +// doc := bsoncore.NewDocumentBuilder() +// if principal != "" { +// doc.AppendString("n", principal) +// } +// return doc.Build() +//} func (oos *oidcOneStep) Start() (string, []byte, error) { return MongoDBOIDC, jwtStepRequest(oos.accessToken), nil @@ -108,6 +122,11 @@ func (oa *OIDCAuthenticator) providerCallback() (OIDCCallback, error) { switch env { // TODO GODRIVER-2728: Automatic token acquisition for Azure Identity Provider // TODO GODRIVER-2806: Automatic token acquisition for GCP Identity Provider + // This is here just to pass the linter, it will be fixed in one of the above tickets. + case azureEnvironmentValue, gcpEnvironmentValue: + return func(ctx context.Context, args *OIDCArgs) (*OIDCCredential, error) { + return nil, fmt.Errorf("automatic token acquisition for %q not implemented yet", env) + }, fmt.Errorf("automatic token acquisition for %q not implemented yet", env) } return nil, fmt.Errorf("%q %q not supported for MONGODB-OIDC", environmentProp, env) @@ -137,27 +156,28 @@ func (oa *OIDCAuthenticator) getAccessToken( return cred.AccessToken, nil } +// TODO GODRIVER-3246: Implement OIDC human flow // This should only be called with the Mutex held. -func (oa *OIDCAuthenticator) getAccessTokenWithRefresh( - ctx context.Context, - callback OIDCCallback, - refreshToken string, -) (string, error) { - - cred, err := callback(ctx, &OIDCArgs{ - Version: 1, - IDPInfo: oa.idpInfo, - RefreshToken: &refreshToken, - }) - if err != nil { - return "", err - } - - oa.accessToken = cred.AccessToken - oa.tokenGenID++ - oa.cfg.Connection.SetOIDCTokenGenID(oa.tokenGenID) - return cred.AccessToken, nil -} +//func (oa *OIDCAuthenticator) getAccessTokenWithRefresh( +// ctx context.Context, +// callback OIDCCallback, +// refreshToken string, +//) (string, error) { +// +// cred, err := callback(ctx, &OIDCArgs{ +// Version: apiVersion, +// IDPInfo: oa.idpInfo, +// RefreshToken: &refreshToken, +// }) +// if err != nil { +// return "", err +// } +// +// oa.accessToken = cred.AccessToken +// oa.tokenGenID++ +// oa.cfg.Connection.SetOIDCTokenGenID(oa.tokenGenID) +// return cred.AccessToken, nil +//} // invalidateAccessToken invalidates the access token, if the force flag is set to true (which is // only on a Reauth call) or if the tokenGenID of the connection is greater than or equal to the @@ -174,6 +194,8 @@ func (oa *OIDCAuthenticator) invalidateAccessToken(force bool) { } } +// Reauth reauthenticates the connection when the server returns a 391 code. Reauth is part of the +// driver.Authenticator interface. func (oa *OIDCAuthenticator) Reauth(ctx context.Context) error { oa.invalidateAccessToken(true) // it should be impossible to get a Reauth when an Auth has never occurred, @@ -230,12 +252,14 @@ func (oa *OIDCAuthenticator) Auth(ctx context.Context, cfg *Config) error { func (oa *OIDCAuthenticator) doAuthHuman(ctx context.Context, cfg *Config, humanCallback OIDCCallback) error { // TODO GODRIVER-3246: Implement OIDC human flow + // Println is for linter + fmt.Println("OIDC human flow not implemented yet", oa.idpInfo) return newAuthError("OIDC human flow not implemented yet", nil) } func (oa *OIDCAuthenticator) doAuthMachine(ctx context.Context, cfg *Config, machineCallback OIDCCallback) error { accessToken, err := oa.getAccessToken(ctx, - &OIDCArgs{Version: 1, + &OIDCArgs{Version: apiVersion, Timeout: time.Now().Add(machineCallbackTimeout), // idpInfo is nil for machine callbacks in the current spec. IDPInfo: nil, diff --git a/x/mongo/driver/auth/plain.go b/x/mongo/driver/auth/plain.go index 21ffe0465e..a11f0d6e06 100644 --- a/x/mongo/driver/auth/plain.go +++ b/x/mongo/driver/auth/plain.go @@ -35,7 +35,7 @@ func (a *PlainAuthenticator) Auth(ctx context.Context, cfg *Config) error { } // Reauth reauthenticates the connection. -func (a *PlainAuthenticator) Reauth(ctx context.Context) error { +func (a *PlainAuthenticator) Reauth(_ context.Context) error { return newAuthError("Plain authentication does not support reauthentication", nil) } diff --git a/x/mongo/driver/driver.go b/x/mongo/driver/driver.go index 626a307b61..cb5bf57b21 100644 --- a/x/mongo/driver/driver.go +++ b/x/mongo/driver/driver.go @@ -43,6 +43,7 @@ type AuthConfig struct { // nil in the OIDCArgs for the Machine flow. type OIDCCallback func(context.Context, *OIDCArgs) (*OIDCCredential, error) +// OIDCArgs contains the arguments for the OIDC callback. type OIDCArgs struct { Version int Timeout time.Time @@ -50,12 +51,14 @@ type OIDCArgs struct { RefreshToken *string } +// OIDCCredential contains the access token and refresh token. type OIDCCredential struct { AccessToken string ExpiresAt *time.Time RefreshToken *string } +// IDPInfo contains the information needed to perform OIDC authentication with an Identity Provider. type IDPInfo struct { Issuer string `bson:"issuer"` ClientID string `bson:"clientId"` diff --git a/x/mongo/driver/drivertest/channel_conn.go b/x/mongo/driver/drivertest/channel_conn.go index 874f100ef1..e2ca9642e7 100644 --- a/x/mongo/driver/drivertest/channel_conn.go +++ b/x/mongo/driver/drivertest/channel_conn.go @@ -26,12 +26,15 @@ type ChannelConn struct { Desc description.Server } +// OIDCTokenGenID implements the driver.Connection interface by returning the OIDCToken generation +// (which is always 0) func (c *ChannelConn) OIDCTokenGenID() uint64 { return 0 } -func (c *ChannelConn) SetOIDCTokenGenID(uint64) { -} +// OIDCTokenGenID implements the driver.Connection interface by setting the OIDCToken generation +// (which is always 0) +func (c *ChannelConn) SetOIDCTokenGenID(uint64) {} // WriteWireMessage implements the driver.Connection interface. func (c *ChannelConn) WriteWireMessage(ctx context.Context, wm []byte) error { diff --git a/x/mongo/driver/topology/connection.go b/x/mongo/driver/topology/connection.go index acdd7973ea..49a613aef8 100644 --- a/x/mongo/driver/topology/connection.go +++ b/x/mongo/driver/topology/connection.go @@ -866,12 +866,14 @@ func configureTLS(ctx context.Context, return client, nil } +// OIDCTokenGenID returns the OIDC token generation ID. func (c *Connection) OIDCTokenGenID() uint64 { return c.oidcTokenGenID } -func (c *Connection) SetOIDCTokenGenID(genId uint64) { - c.oidcTokenGenID = genId +// SetOIDCTokenGenID sets the OIDC token generation ID. +func (c *Connection) SetOIDCTokenGenID(genID uint64) { + c.oidcTokenGenID = genID } // TODO: Naming? @@ -922,6 +924,6 @@ func (c *connection) OIDCTokenGenID() uint64 { return c.oidcTokenGenID } -func (c *connection) SetOIDCTokenGenID(genId uint64) { - c.oidcTokenGenID = genId +func (c *connection) SetOIDCTokenGenID(genID uint64) { + c.oidcTokenGenID = genID } diff --git a/x/mongo/driver/topology/topology_options.go b/x/mongo/driver/topology/topology_options.go index 820b62a7ff..7d8dd62dc0 100644 --- a/x/mongo/driver/topology/topology_options.go +++ b/x/mongo/driver/topology/topology_options.go @@ -202,11 +202,6 @@ func NewConfigWithAuthenticator(co *options.ClientOptions, clock *session.Cluste } } - authenticator, err := auth.CreateAuthenticator(mechanism, cred) - if err != nil { - return nil, err - } - handshakeOpts := &auth.HandshakeOptions{ AppName: appName, Authenticator: authenticator,