Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// 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 options
package optionsutil

// Options stores internal options.
type Options struct {
Expand Down
4 changes: 2 additions & 2 deletions mongo/options/clientoptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
"go.mongodb.org/mongo-driver/v2/bson"
"go.mongodb.org/mongo-driver/v2/event"
"go.mongodb.org/mongo-driver/v2/internal/httputil"
"go.mongodb.org/mongo-driver/v2/internal/options"
"go.mongodb.org/mongo-driver/v2/internal/optionsutil"
"go.mongodb.org/mongo-driver/v2/mongo/readconcern"
"go.mongodb.org/mongo-driver/v2/mongo/readpref"
"go.mongodb.org/mongo-driver/v2/mongo/writeconcern"
Expand Down Expand Up @@ -302,7 +302,7 @@ type ClientOptions struct {
//
// Deprecated: This option is for internal use only and should not be set. It may be changed or removed in any
// release.
Custom options.Options
Custom optionsutil.Options

connString *connstring.ConnString
err error
Expand Down
6 changes: 3 additions & 3 deletions mongo/options/clientoptions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (
"go.mongodb.org/mongo-driver/v2/event"
"go.mongodb.org/mongo-driver/v2/internal/assert"
"go.mongodb.org/mongo-driver/v2/internal/httputil"
"go.mongodb.org/mongo-driver/v2/internal/options"
"go.mongodb.org/mongo-driver/v2/internal/optionsutil"
"go.mongodb.org/mongo-driver/v2/internal/ptrutil"
"go.mongodb.org/mongo-driver/v2/mongo/readconcern"
"go.mongodb.org/mongo-driver/v2/mongo/readpref"
Expand Down Expand Up @@ -157,7 +157,7 @@ func TestClientOptions(t *testing.T) {
cmp.Comparer(func(r1, r2 *bson.Registry) bool { return r1 == r2 }),
cmp.Comparer(func(cfg1, cfg2 *tls.Config) bool { return cfg1 == cfg2 }),
cmp.Comparer(func(fp1, fp2 *event.PoolMonitor) bool { return fp1 == fp2 }),
cmp.Comparer(options.Equal),
cmp.Comparer(optionsutil.Equal),
cmp.AllowUnexported(ClientOptions{}),
cmpopts.IgnoreFields(http.Client{}, "Transport"),
); diff != "" {
Expand Down Expand Up @@ -1255,7 +1255,7 @@ func TestApplyURI(t *testing.T) {
cmp.Comparer(func(r1, r2 *bson.Registry) bool { return r1 == r2 }),
cmp.Comparer(compareTLSConfig),
cmp.Comparer(compareErrors),
cmp.Comparer(options.Equal),
cmp.Comparer(optionsutil.Equal),
cmpopts.SortSlices(stringLess),
cmpopts.IgnoreFields(connstring.ConnString{}, "SSLClientCertificateKeyPassword"),
cmpopts.IgnoreFields(http.Client{}, "Transport"),
Expand Down
59 changes: 59 additions & 0 deletions x/mongo/driver/auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,19 @@
package auth_test

import (
"context"
"fmt"
"net/http"
"testing"

"github.com/google/go-cmp/cmp"
"go.mongodb.org/mongo-driver/v2/internal/require"
"go.mongodb.org/mongo-driver/v2/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/auth"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/description"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/drivertest"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/mnet"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/wiremessage"
)

Expand Down Expand Up @@ -101,3 +107,56 @@ func compareResponses(t *testing.T, wm []byte, expectedPayload bsoncore.Document
t.Errorf("Payloads don't match. got %v; want %v", actualPayload, expectedPayload)
}
}

type testAuthenticator struct{}

func (a *testAuthenticator) Auth(context.Context, *driver.AuthConfig) error {
return fmt.Errorf("test error")
}

func (a *testAuthenticator) Reauth(context.Context, *driver.AuthConfig) error {
return nil
}

func TestPerformAuthentication(t *testing.T) {
t.Parallel()

cases := []struct {
name string
needToPerform bool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[optional] Suggest calling this bool authenticateToAnything.

assert func(*testing.T, error)
}{
{
name: "positive",
needToPerform: true,
assert: func(t *testing.T, err error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[optional] Suggest renaming this to require.

require.EqualError(t, err, "auth error: test error")
},
},
{
name: "negative",
needToPerform: false,
assert: func(t *testing.T, err error) {
require.NoError(t, err)
},
},
}
mnetconn := mnet.NewConnection(&drivertest.ChannelConn{})
for _, tc := range cases {
tc := tc

t.Run(tc.name, func(t *testing.T) {
t.Parallel()

handshaker := auth.Handshaker(nil, &auth.HandshakeOptions{
Authenticator: &testAuthenticator{},
PerformAuthentication: func(description.Server) bool {
return tc.needToPerform
},
})

err := handshaker.FinishHandshake(context.Background(), mnetconn)
tc.assert(t, err)
})
}
}
10 changes: 10 additions & 0 deletions x/mongo/driver/topology/topology_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ import (

"go.mongodb.org/mongo-driver/v2/event"
"go.mongodb.org/mongo-driver/v2/internal/logger"
"go.mongodb.org/mongo-driver/v2/internal/optionsutil"
"go.mongodb.org/mongo-driver/v2/mongo/options"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/auth"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/description"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/ocsp"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/operation"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/session"
Expand Down Expand Up @@ -270,6 +272,14 @@ func NewConfigFromOptionsWithAuthenticator(opts *options.ClientOptions, clock *s
// Required for SASL mechanism negotiation during handshake
handshakeOpts.DBUser = opts.Auth.AuthSource + "." + opts.Auth.Username
}
if a := optionsutil.Value(opts.Custom, "authenticateToAnything"); a != nil {
if v, ok := a.(bool); ok && v {
// Authenticate arbiters
handshakeOpts.PerformAuthentication = func(_ description.Server) bool {
return true
}
}
}

handshaker = func(driver.Handshaker) driver.Handshaker {
return auth.Handshaker(nil, handshakeOpts)
Expand Down
75 changes: 75 additions & 0 deletions x/mongo/driver/topology/topology_options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package topology

import (
"context"
"fmt"
"net/url"
"reflect"
Expand All @@ -17,6 +18,10 @@ import (
"go.mongodb.org/mongo-driver/v2/internal/require"
"go.mongodb.org/mongo-driver/v2/mongo/options"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/description"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/drivertest"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/mnet"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/xoptions"
)

func TestDirectConnectionFromConnString(t *testing.T) {
Expand Down Expand Up @@ -85,6 +90,76 @@ func TestLoadBalancedFromConnString(t *testing.T) {
}
}

type testAuthenticator struct{}

var _ driver.Authenticator = &testAuthenticator{}

func (a *testAuthenticator) Auth(context.Context, *driver.AuthConfig) error {
return fmt.Errorf("test error")
}

func (a *testAuthenticator) Reauth(context.Context, *driver.AuthConfig) error {
return nil
}

func TestAuthenticateToAnything(t *testing.T) {
t.Parallel()

cases := []struct {
name string
set func(*options.ClientOptions) error
assert func(*testing.T, error)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Optional] Suggest renaming this to require.

}{
{
name: "default",
set: func(*options.ClientOptions) error { return nil },
assert: func(t *testing.T, err error) {
require.NoError(t, err)
},
},
{
name: "positive",
set: func(opt *options.ClientOptions) error {
return xoptions.SetInternalClientOptions(opt, "authenticateToAnything", true)
},
assert: func(t *testing.T, err error) {
require.EqualError(t, err, "auth error: test error")
},
},
{
name: "negative",
set: func(opt *options.ClientOptions) error {
return xoptions.SetInternalClientOptions(opt, "authenticateToAnything", false)
},
assert: func(t *testing.T, err error) {
require.NoError(t, err)
},
},
}

describer := &drivertest.ChannelConn{
Desc: description.Server{Kind: description.ServerKindRSArbiter},
}
for _, tc := range cases {
tc := tc

t.Run(tc.name, func(t *testing.T) {
t.Parallel()

opt := options.Client().SetAuth(options.Credential{Username: "foo", Password: "bar"})
err := tc.set(opt)
require.NoError(t, err, "error setting authenticateToAnything: %v", err)
cfg, err := NewConfigFromOptionsWithAuthenticator(opt, nil, &testAuthenticator{})
require.NoError(t, err, "error constructing topology config: %v", err)

srvrCfg := newServerConfig(defaultConnectionTimeout, cfg.ServerOpts...)
connCfg := newConnectionConfig(srvrCfg.connectionOpts...)
err = connCfg.handshaker.FinishHandshake(context.TODO(), &mnet.Connection{Describer: describer})
tc.assert(t, err)
})
}
}

func TestTopologyNewConfig(t *testing.T) {
t.Run("default ServerSelectionTimeout", func(t *testing.T) {
cfg, err := NewConfig(options.Client(), nil)
Expand Down
15 changes: 12 additions & 3 deletions x/mongo/driver/xoptions/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package xoptions
import (
"fmt"

"go.mongodb.org/mongo-driver/v2/internal/optionsutil"
"go.mongodb.org/mongo-driver/v2/mongo/options"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver"
)
Expand All @@ -17,20 +18,28 @@ import (
//
// Deprecated: This function is for internal use only. It may be changed or removed in any release.
func SetInternalClientOptions(opts *options.ClientOptions, key string, option any) error {
const typeErr = "unexpected type for %s"
typeErrFunc := func(t string) error {
return fmt.Errorf("unexpected type for %s: %T is not %s", key, option, t)
}
switch key {
case "crypt":
c, ok := option.(driver.Crypt)
if !ok {
return fmt.Errorf(typeErr, key)
return typeErrFunc("driver.Crypt")
}
opts.Crypt = c
case "deployment":
d, ok := option.(driver.Deployment)
if !ok {
return fmt.Errorf(typeErr, key)
return typeErrFunc("driver.Deployment")
}
opts.Deployment = d
case "authenticateToAnything":
b, ok := option.(bool)
if !ok {
return typeErrFunc("bool")
}
opts.Custom = optionsutil.WithValue(opts.Custom, key, b)
default:
return fmt.Errorf("unsupported option: %s", key)
}
Expand Down
29 changes: 27 additions & 2 deletions x/mongo/driver/xoptions/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
package xoptions

import (
"fmt"
"testing"

"go.mongodb.org/mongo-driver/v2/internal/optionsutil"
"go.mongodb.org/mongo-driver/v2/internal/require"
"go.mongodb.org/mongo-driver/v2/mongo/options"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver"
Expand All @@ -18,6 +20,29 @@ import (
func TestSetInternalClientOptions(t *testing.T) {
t.Parallel()

cases := []struct {
key string
value any
}{
{
key: "authenticateToAnything",
value: true,
},
}
for _, tc := range cases {
tc := tc

t.Run(fmt.Sprintf("set %s", tc.key), func(t *testing.T) {
t.Parallel()

opts := options.Client()
err := SetInternalClientOptions(opts, tc.key, tc.value)
require.NoError(t, err, "error setting %s: %v", tc.key, err)
v := optionsutil.Value(opts.Custom, tc.key)
require.Equal(t, tc.value, v, "expected %v, got %v", tc.value, v)
})
}

t.Run("set crypt", func(t *testing.T) {
t.Parallel()

Expand All @@ -33,7 +58,7 @@ func TestSetInternalClientOptions(t *testing.T) {

opts := options.Client()
err := SetInternalClientOptions(opts, "crypt", &drivertest.MockDeployment{})
require.EqualError(t, err, "unexpected type for crypt")
require.EqualError(t, err, "unexpected type for crypt: *drivertest.MockDeployment is not driver.Crypt")
})

t.Run("set deployment", func(t *testing.T) {
Expand All @@ -51,7 +76,7 @@ func TestSetInternalClientOptions(t *testing.T) {

opts := options.Client()
err := SetInternalClientOptions(opts, "deployment", driver.NewCrypt(&driver.CryptOptions{}))
require.EqualError(t, err, "unexpected type for deployment")
require.EqualError(t, err, "unexpected type for deployment: *driver.crypt is not driver.Deployment")
})

t.Run("set unsupported option", func(t *testing.T) {
Expand Down
Loading