mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 10:37:56 +00:00 
			
		
		
		
	DBPW - Update MongoDB to adhere to v5 Database interface (#10053)
This commit is contained in:
		| @@ -5,7 +5,6 @@ import ( | ||||
| 	"crypto/tls" | ||||
| 	"crypto/x509" | ||||
| 	"fmt" | ||||
| 	"net/url" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| @@ -13,230 +12,185 @@ import ( | ||||
|  | ||||
| 	"github.com/hashicorp/vault/helper/testhelpers/certhelpers" | ||||
| 	"github.com/hashicorp/vault/helper/testhelpers/mongodb" | ||||
| 	"github.com/hashicorp/vault/sdk/database/dbplugin" | ||||
| 	"github.com/hashicorp/vault/sdk/database/newdbplugin" | ||||
| 	dbtesting "github.com/hashicorp/vault/sdk/database/newdbplugin/testing" | ||||
| 	"go.mongodb.org/mongo-driver/mongo" | ||||
| 	"go.mongodb.org/mongo-driver/mongo/options" | ||||
| 	"go.mongodb.org/mongo-driver/mongo/readpref" | ||||
| ) | ||||
|  | ||||
| const testMongoDBRole = `{ "db": "admin", "roles": [ { "role": "readWrite" } ] }` | ||||
|  | ||||
| const testMongoDBWriteConcern = `{ "wmode": "majority", "wtimeout": 5000 }` | ||||
| const mongoAdminRole = `{ "db": "admin", "roles": [ { "role": "readWrite" } ] }` | ||||
|  | ||||
| func TestMongoDB_Initialize(t *testing.T) { | ||||
| 	cleanup, connURL := mongodb.PrepareTestContainer(t, "latest") | ||||
| 	defer cleanup() | ||||
|  | ||||
| 	connectionDetails := map[string]interface{}{ | ||||
| 	db := new() | ||||
| 	defer dbtesting.AssertClose(t, db) | ||||
|  | ||||
| 	config := map[string]interface{}{ | ||||
| 		"connection_url": connURL, | ||||
| 	} | ||||
|  | ||||
| 	db := new() | ||||
| 	_, err := db.Init(context.Background(), connectionDetails, true) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	// Make a copy since the original map could be modified by the Initialize call | ||||
| 	expectedConfig := copyConfig(config) | ||||
|  | ||||
| 	req := newdbplugin.InitializeRequest{ | ||||
| 		Config:           config, | ||||
| 		VerifyConnection: true, | ||||
| 	} | ||||
|  | ||||
| 	resp := dbtesting.AssertInitialize(t, db, req) | ||||
|  | ||||
| 	if !reflect.DeepEqual(resp.Config, expectedConfig) { | ||||
| 		t.Fatalf("Actual config: %#v\nExpected config: %#v", resp.Config, expectedConfig) | ||||
| 	} | ||||
|  | ||||
| 	if !db.Initialized { | ||||
| 		t.Fatal("Database should be initialized") | ||||
| 	} | ||||
|  | ||||
| 	err = db.Close() | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestMongoDB_CreateUser(t *testing.T) { | ||||
| 	cleanup, connURL := mongodb.PrepareTestContainer(t, "latest") | ||||
| 	defer cleanup() | ||||
|  | ||||
| 	connectionDetails := map[string]interface{}{ | ||||
| 		"connection_url": connURL, | ||||
| 	} | ||||
|  | ||||
| 	db := new() | ||||
| 	_, err := db.Init(context.Background(), connectionDetails, true) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
| 	defer dbtesting.AssertClose(t, db) | ||||
|  | ||||
| 	statements := dbplugin.Statements{ | ||||
| 		Creation: []string{testMongoDBRole}, | ||||
| 	initReq := newdbplugin.InitializeRequest{ | ||||
| 		Config: map[string]interface{}{ | ||||
| 			"connection_url": connURL, | ||||
| 		}, | ||||
| 		VerifyConnection: true, | ||||
| 	} | ||||
| 	dbtesting.AssertInitialize(t, db, initReq) | ||||
|  | ||||
| 	usernameConfig := dbplugin.UsernameConfig{ | ||||
| 		DisplayName: "test", | ||||
| 		RoleName:    "test", | ||||
| 	password := "myreallysecurepassword" | ||||
| 	createReq := newdbplugin.NewUserRequest{ | ||||
| 		UsernameConfig: newdbplugin.UsernameMetadata{ | ||||
| 			DisplayName: "test", | ||||
| 			RoleName:    "test", | ||||
| 		}, | ||||
| 		Statements: newdbplugin.Statements{ | ||||
| 			Commands: []string{mongoAdminRole}, | ||||
| 		}, | ||||
| 		Password:   password, | ||||
| 		Expiration: time.Now().Add(time.Minute), | ||||
| 	} | ||||
| 	createResp := dbtesting.AssertNewUser(t, db, createReq) | ||||
|  | ||||
| 	username, password, err := db.CreateUser(context.Background(), statements, usernameConfig, time.Now().Add(time.Minute)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	if err := testCredsExist(t, connURL, username, password); err != nil { | ||||
| 		t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 	} | ||||
| 	assertCredsExist(t, createResp.Username, password, connURL) | ||||
| } | ||||
|  | ||||
| func TestMongoDB_CreateUser_writeConcern(t *testing.T) { | ||||
| 	cleanup, connURL := mongodb.PrepareTestContainer(t, "latest") | ||||
| 	defer cleanup() | ||||
|  | ||||
| 	connectionDetails := map[string]interface{}{ | ||||
| 		"connection_url": connURL, | ||||
| 		"write_concern":  testMongoDBWriteConcern, | ||||
| 	initReq := newdbplugin.InitializeRequest{ | ||||
| 		Config: map[string]interface{}{ | ||||
| 			"connection_url": connURL, | ||||
| 			"write_concern":  `{ "wmode": "majority", "wtimeout": 5000 }`, | ||||
| 		}, | ||||
| 		VerifyConnection: true, | ||||
| 	} | ||||
|  | ||||
| 	db := new() | ||||
| 	_, err := db.Init(context.Background(), connectionDetails, true) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
| 	defer dbtesting.AssertClose(t, db) | ||||
|  | ||||
| 	statements := dbplugin.Statements{ | ||||
| 		Creation: []string{testMongoDBRole}, | ||||
| 	} | ||||
| 	dbtesting.AssertInitialize(t, db, initReq) | ||||
|  | ||||
| 	usernameConfig := dbplugin.UsernameConfig{ | ||||
| 		DisplayName: "test", | ||||
| 		RoleName:    "test", | ||||
| 	password := "myreallysecurepassword" | ||||
| 	createReq := newdbplugin.NewUserRequest{ | ||||
| 		UsernameConfig: newdbplugin.UsernameMetadata{ | ||||
| 			DisplayName: "test", | ||||
| 			RoleName:    "test", | ||||
| 		}, | ||||
| 		Statements: newdbplugin.Statements{ | ||||
| 			Commands: []string{mongoAdminRole}, | ||||
| 		}, | ||||
| 		Password:   password, | ||||
| 		Expiration: time.Now().Add(time.Minute), | ||||
| 	} | ||||
| 	createResp := dbtesting.AssertNewUser(t, db, createReq) | ||||
|  | ||||
| 	username, password, err := db.CreateUser(context.Background(), statements, usernameConfig, time.Now().Add(time.Minute)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	if err := testCredsExist(t, connURL, username, password); err != nil { | ||||
| 		t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 	} | ||||
| 	assertCredsExist(t, createResp.Username, password, connURL) | ||||
| } | ||||
|  | ||||
| func TestMongoDB_RevokeUser(t *testing.T) { | ||||
| func TestMongoDB_DeleteUser(t *testing.T) { | ||||
| 	cleanup, connURL := mongodb.PrepareTestContainer(t, "latest") | ||||
| 	defer cleanup() | ||||
|  | ||||
| 	connectionDetails := map[string]interface{}{ | ||||
| 		"connection_url": connURL, | ||||
| 	} | ||||
|  | ||||
| 	db := new() | ||||
| 	_, err := db.Init(context.Background(), connectionDetails, true) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
| 	defer dbtesting.AssertClose(t, db) | ||||
|  | ||||
| 	statements := dbplugin.Statements{ | ||||
| 		Creation: []string{testMongoDBRole}, | ||||
| 	initReq := newdbplugin.InitializeRequest{ | ||||
| 		Config: map[string]interface{}{ | ||||
| 			"connection_url": connURL, | ||||
| 		}, | ||||
| 		VerifyConnection: true, | ||||
| 	} | ||||
| 	dbtesting.AssertInitialize(t, db, initReq) | ||||
|  | ||||
| 	usernameConfig := dbplugin.UsernameConfig{ | ||||
| 		DisplayName: "test", | ||||
| 		RoleName:    "test", | ||||
| 	} | ||||
|  | ||||
| 	username, password, err := db.CreateUser(context.Background(), statements, usernameConfig, time.Now().Add(time.Minute)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	if err := testCredsExist(t, connURL, username, password); err != nil { | ||||
| 		t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 	password := "myreallysecurepassword" | ||||
| 	createReq := newdbplugin.NewUserRequest{ | ||||
| 		UsernameConfig: newdbplugin.UsernameMetadata{ | ||||
| 			DisplayName: "test", | ||||
| 			RoleName:    "test", | ||||
| 		}, | ||||
| 		Statements: newdbplugin.Statements{ | ||||
| 			Commands: []string{mongoAdminRole}, | ||||
| 		}, | ||||
| 		Password:   password, | ||||
| 		Expiration: time.Now().Add(time.Minute), | ||||
| 	} | ||||
| 	createResp := dbtesting.AssertNewUser(t, db, createReq) | ||||
| 	assertCredsExist(t, createResp.Username, password, connURL) | ||||
|  | ||||
| 	// Test default revocation statement | ||||
| 	err = db.RevokeUser(context.Background(), statements, username) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	delReq := newdbplugin.DeleteUserRequest{ | ||||
| 		Username: createResp.Username, | ||||
| 	} | ||||
|  | ||||
| 	if err = testCredsExist(t, connURL, username, password); err == nil { | ||||
| 		t.Fatal("Credentials were not revoked") | ||||
| 	} | ||||
| 	dbtesting.AssertDeleteUser(t, db, delReq) | ||||
|  | ||||
| 	assertCredsDoNotExist(t, createResp.Username, password, connURL) | ||||
| } | ||||
|  | ||||
| func testCredsExist(t testing.TB, connURL, username, password string) error { | ||||
| 	connURL = strings.Replace(connURL, "mongodb://", fmt.Sprintf("mongodb://%s:%s@", username, password), 1) | ||||
|  | ||||
| 	ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) | ||||
| 	client, err := mongo.Connect(ctx, options.Client().ApplyURI(connURL)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return client.Ping(ctx, readpref.Primary()) | ||||
| } | ||||
|  | ||||
| func TestMongoDB_SetCredentials(t *testing.T) { | ||||
| func TestMongoDB_UpdateUser_Password(t *testing.T) { | ||||
| 	cleanup, connURL := mongodb.PrepareTestContainer(t, "latest") | ||||
| 	defer cleanup() | ||||
|  | ||||
| 	// The docker test method PrepareTestContainer defaults to a database "test" | ||||
| 	// if none is provided | ||||
| 	connURL = connURL + "/test" | ||||
| 	connectionDetails := map[string]interface{}{ | ||||
| 		"connection_url": connURL, | ||||
| 	} | ||||
|  | ||||
| 	db := new() | ||||
| 	_, err := db.Init(context.Background(), connectionDetails, true) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	defer dbtesting.AssertClose(t, db) | ||||
|  | ||||
| 	initReq := newdbplugin.InitializeRequest{ | ||||
| 		Config: map[string]interface{}{ | ||||
| 			"connection_url": connURL, | ||||
| 		}, | ||||
| 		VerifyConnection: true, | ||||
| 	} | ||||
| 	dbtesting.AssertInitialize(t, db, initReq) | ||||
|  | ||||
| 	// create the database user in advance, and test the connection | ||||
| 	dbUser := "testmongouser" | ||||
| 	startingPassword := "password" | ||||
| 	testCreateDBUser(t, connURL, "test", dbUser, startingPassword) | ||||
| 	if err := testCredsExist(t, connURL, dbUser, startingPassword); err != nil { | ||||
| 		t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 	} | ||||
| 	createDBUser(t, connURL, "test", dbUser, startingPassword) | ||||
|  | ||||
| 	newPassword, err := db.GenerateCredentials(context.Background()) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	newPassword := "myreallysecurecredentials" | ||||
|  | ||||
| 	usernameConfig := dbplugin.StaticUserConfig{ | ||||
| 	updateReq := newdbplugin.UpdateUserRequest{ | ||||
| 		Username: dbUser, | ||||
| 		Password: newPassword, | ||||
| 		Password: &newdbplugin.ChangePassword{ | ||||
| 			NewPassword: newPassword, | ||||
| 		}, | ||||
| 	} | ||||
| 	dbtesting.AssertUpdateUser(t, db, updateReq) | ||||
|  | ||||
| 	username, password, err := db.SetCredentials(context.Background(), dbplugin.Statements{}, usernameConfig) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	if err := testCredsExist(t, connURL, username, password); err != nil { | ||||
| 		t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 	} | ||||
| 	// confirm the original creds used to set still work (should be the same) | ||||
| 	if err := testCredsExist(t, connURL, dbUser, newPassword); err != nil { | ||||
| 		t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	if (dbUser != username) || (newPassword != password) { | ||||
| 		t.Fatalf("username/password mismatch: (%s)/(%s) vs (%s)/(%s)", dbUser, username, newPassword, password) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func testCreateDBUser(t testing.TB, connURL, db, username, password string) { | ||||
| 	ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) | ||||
| 	client, err := mongo.Connect(ctx, options.Client().ApplyURI(connURL)) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	createUserCmd := &createUserCommand{ | ||||
| 		Username: username, | ||||
| 		Password: password, | ||||
| 		Roles:    []interface{}{}, | ||||
| 	} | ||||
| 	result := client.Database(db).RunCommand(ctx, createUserCmd, nil) | ||||
| 	if result.Err() != nil { | ||||
| 		t.Fatal(result.Err()) | ||||
| 	} | ||||
| 	assertCredsExist(t, dbUser, newPassword, connURL) | ||||
| } | ||||
|  | ||||
| func TestGetTLSAuth(t *testing.T) { | ||||
| @@ -336,129 +290,67 @@ func appendToCertPool(t *testing.T, pool *x509.CertPool, caPem []byte) *x509.Cer | ||||
| 	return pool | ||||
| } | ||||
|  | ||||
| func TestMongoDB_RotateRootCredentials(t *testing.T) { | ||||
| 	cleanup, connURL := mongodb.PrepareTestContainer(t, "latest") | ||||
| 	defer cleanup() | ||||
|  | ||||
| 	// Test to ensure that we can't rotate the root creds if no username has been specified | ||||
| 	testCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second) | ||||
| 	defer cancel() | ||||
|  | ||||
| 	db := new() | ||||
| 	connDetailsWithoutUsername := map[string]interface{}{ | ||||
| 		"connection_url": connURL, | ||||
| 	} | ||||
| 	_, err := db.Init(testCtx, connDetailsWithoutUsername, true) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	// Rotate credentials should fail because no username is specified | ||||
| 	cfg, err := db.RotateRootCredentials(testCtx, nil) | ||||
| 	if err == nil { | ||||
| 		t.Fatalf("successfully rotated root credentials when no username was present") | ||||
| 	} | ||||
| 	if !reflect.DeepEqual(cfg, connDetailsWithoutUsername) { | ||||
| 		t.Fatalf("expected connection details: %#v but were %#v", connDetailsWithoutUsername, cfg) | ||||
| 	} | ||||
|  | ||||
| 	db.Close() | ||||
|  | ||||
| 	// Reset the database object with new connection details | ||||
| 	username := "vault-test-admin" | ||||
| 	initialPassword := "myreallysecurepassword" | ||||
|  | ||||
| 	db = new() | ||||
| 	connDetailsWithUsername := map[string]interface{}{ | ||||
| 		"connection_url": connURL, | ||||
| 		"username":       username, | ||||
| 		"password":       initialPassword, | ||||
| 	} | ||||
| 	_, err = db.Init(testCtx, connDetailsWithUsername, true) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	// Create root user | ||||
| 	createUser(t, connURL, username, initialPassword) | ||||
| 	initialURL := setUserPassOnURL(t, connURL, username, initialPassword) | ||||
|  | ||||
| 	// Ensure the initial root user can connect | ||||
| 	err = assertConnection(testCtx, initialURL) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("%s", err) | ||||
| 	} | ||||
|  | ||||
| 	// Rotate credentials | ||||
| 	newCfg, err := db.RotateRootCredentials(testCtx, nil) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("unexpected err rotating root credentials: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	// Ensure the initial root user can no longer connect | ||||
| 	err = assertConnection(testCtx, initialURL) | ||||
| 	if err == nil { | ||||
| 		t.Fatalf("connection with initial credentials succeeded when it shouldn't have") | ||||
| 	} | ||||
|  | ||||
| 	// Ensure the new password can connect | ||||
| 	newURL := setUserPassOnURL(t, connURL, username, newCfg["password"].(string)) | ||||
| 	err = assertConnection(testCtx, newURL) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("unexpected error pinging client with new credentials: %s", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func createUser(t *testing.T, connURL, username, password string) { | ||||
| func createDBUser(t testing.TB, connURL, db, username, password string) { | ||||
| 	t.Helper() | ||||
|  | ||||
| 	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) | ||||
| 	defer cancel() | ||||
|  | ||||
| 	client, err := createClient(ctx, connURL, nil) | ||||
| 	ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) | ||||
| 	client, err := mongo.Connect(ctx, options.Client().ApplyURI(connURL)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Unable to make initial connection: %s", err) | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	createUserCmd := createUserCommand{ | ||||
| 	createUserCmd := &createUserCommand{ | ||||
| 		Username: username, | ||||
| 		Password: password, | ||||
| 		Roles: []interface{}{ | ||||
| 			"userAdminAnyDatabase", | ||||
| 			"dbAdminAnyDatabase", | ||||
| 			"readWriteAnyDatabase", | ||||
| 		}, | ||||
| 		Roles:    []interface{}{}, | ||||
| 	} | ||||
| 	result := client.Database(db).RunCommand(ctx, createUserCmd, nil) | ||||
| 	if result.Err() != nil { | ||||
| 		t.Fatalf("failed to create user in mongodb: %s", result.Err()) | ||||
| 	} | ||||
|  | ||||
| 	result := client.Database("admin").RunCommand(ctx, createUserCmd, nil) | ||||
| 	err = result.Err() | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Unable to create admin user: %s", err) | ||||
| 	} | ||||
| 	assertCredsExist(t, username, password, connURL) | ||||
| } | ||||
|  | ||||
| func assertConnection(testCtx context.Context, connURL string) error { | ||||
| 	// Connect as initial root user and ensure the connection is successful | ||||
| 	client, err := createClient(testCtx, connURL, nil) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("unable to create client connection with initial root user: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	err = client.Ping(testCtx, nil) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("failed to ping server with initial root user: %w", err) | ||||
| 	} | ||||
| 	client.Disconnect(testCtx) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func setUserPassOnURL(t *testing.T, connURL, username, password string) string { | ||||
| func assertCredsExist(t testing.TB, username, password, connURL string) { | ||||
| 	t.Helper() | ||||
| 	uri, err := url.Parse(connURL) | ||||
|  | ||||
| 	connURL = strings.Replace(connURL, "mongodb://", fmt.Sprintf("mongodb://%s:%s@", username, password), 1) | ||||
|  | ||||
| 	ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) | ||||
| 	client, err := mongo.Connect(ctx, options.Client().ApplyURI(connURL)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("unable to parse connection URL: %s", err) | ||||
| 		t.Fatalf("Failed to connect to mongo: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	uri.User = url.UserPassword(username, password) | ||||
| 	return uri.String() | ||||
| 	err = client.Ping(ctx, readpref.Primary()) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Failed to ping mongo with user %q: %s", username, err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func assertCredsDoNotExist(t testing.TB, username, password, connURL string) { | ||||
| 	t.Helper() | ||||
|  | ||||
| 	connURL = strings.Replace(connURL, "mongodb://", fmt.Sprintf("mongodb://%s:%s@", username, password), 1) | ||||
|  | ||||
| 	ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) | ||||
| 	client, err := mongo.Connect(ctx, options.Client().ApplyURI(connURL)) | ||||
| 	if err != nil { | ||||
| 		return // Creds don't exist as expected | ||||
| 	} | ||||
|  | ||||
| 	err = client.Ping(ctx, readpref.Primary()) | ||||
| 	if err != nil { | ||||
| 		return // Creds don't exist as expected | ||||
| 	} | ||||
| 	t.Fatalf("User %q exists and was able to authenticate", username) | ||||
| } | ||||
|  | ||||
| func copyConfig(config map[string]interface{}) map[string]interface{} { | ||||
| 	newConfig := map[string]interface{}{} | ||||
| 	for k, v := range config { | ||||
| 		newConfig[k] = v | ||||
| 	} | ||||
| 	return newConfig | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Michael Golowka
					Michael Golowka