Skip to content

Commit

Permalink
until first user is created new authentication always succeeds
Browse files Browse the repository at this point in the history
  • Loading branch information
chilagrow committed Feb 15, 2024
1 parent 8e65773 commit 70f0183
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 17 deletions.
80 changes: 68 additions & 12 deletions integration/users/connection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,68 @@ func TestAuthentication(t *testing.T) {
}
}

// TestAuthenticationEnableNewAuthNoUser tests that the authentication succeeds
// with any user until the first user is created.
func TestAuthenticationEnableNewAuthNoUser(t *testing.T) {
t.Parallel()

s := setup.SetupWithOpts(t, nil)
ctx := s.Ctx
collection := s.Collection
db := collection.Database()

testCases := map[string]struct { //nolint:vet // for readability
username string
password string
mechanism string

err string
}{
"PLAIN": {
username: "plain-user",
password: "whatever",
mechanism: "PLAIN",
},
"PLAINEmpty": {
username: "",
password: "",
mechanism: "PLAIN",
},
}

for name, tc := range testCases {
name, tc := name, tc
t.Run(name, func(t *testing.T) {
t.Parallel()

credential := options.Credential{
AuthMechanism: tc.mechanism,
AuthSource: db.Name(),
Username: tc.username,
Password: tc.password,
}

opts := options.Client().ApplyURI(s.MongoDBURI).SetAuth(credential)

client, err := mongo.Connect(ctx, opts)
require.NoError(t, err, "cannot connect to MongoDB")

err = client.Ping(ctx, nil)

if tc.err != "" {
require.ErrorContains(t, err, tc.err)
return
}

require.NoError(t, err, "cannot ping MongoDB")

connCollection := client.Database(db.Name()).Collection(collection.Name())
_, err = connCollection.InsertOne(ctx, bson.D{{"ping", "pong"}})
require.NoError(t, err, "cannot insert document")
})
}
}

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

Expand All @@ -188,19 +250,13 @@ func TestAuthenticationEnableNewAuth(t *testing.T) {
collection := s.Collection
db := collection.Database()

var res bson.D
err := db.RunCommand(ctx, bson.D{
{"dropAllUsersFromDatabase", 1},
}).Decode(&res)
require.NoError(t, err)

//err = db.RunCommand(ctx, bson.D{
// {"createUser", "plain-user"},
// {"roles", bson.A{}},
// {"pwd", "correct"},
// {"mechanisms", bson.A{"PLAIN"}},
//}).Err()
//require.NoErrorf(t, err, "cannot create user")
{"createUser", "plain-user"},
{"roles", bson.A{}},
{"pwd", "correct"},
{"mechanisms", bson.A{"PLAIN"}},
}).Err()
require.NoErrorf(t, err, "cannot create user")

testCases := map[string]struct { //nolint:vet // for readability
username string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,20 +103,36 @@ func (h *Handler) authenticate(ctx context.Context, msg *wire.OpMsg) error {
}

if !hasUser {
// an exception where authentication is skipped until the first user is created.
// If a user connects with any credentials or no credentials at all,
// the authentication succeeds until the first user is created.
return nil
}

if storedUser == nil {
return handlererrors.NewCommandErrorMsgWithArgument(
handlererrors.ErrAuthenticationFailed,
"User not found",
"PLAIN",
)
}

credentials := must.NotFail(storedUser.Get("credentials")).(*types.Document)

Check warning on line 119 in internal/handler/authenticate.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/authenticate.go#L119

Added line #L119 was not covered by tests
if !credentials.Has("PLAIN") {

v, _ := credentials.Get("PLAIN")
if v == nil {
return handlererrors.NewCommandErrorMsgWithArgument(
handlererrors.ErrAuthenticationFailed,
"TODO: wrong authentication mechanism",
"PLAIN",
)

Check warning on line 127 in internal/handler/authenticate.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/authenticate.go#L121-L127

Added lines #L121 - L127 were not covered by tests
}

err = password.PlainVerify(pwd, credentials)
doc, ok := v.(*types.Document)
if !ok {
return lazyerrors.Errorf("field 'PLAIN' has type %T, expected Document", v)

Check warning on line 132 in internal/handler/authenticate.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/authenticate.go#L130-L132

Added lines #L130 - L132 were not covered by tests
}

err = password.PlainVerify(pwd, doc)
if err != nil {
return lazyerrors.Error(err)

Check warning on line 137 in internal/handler/authenticate.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/authenticate.go#L135-L137

Added lines #L135 - L137 were not covered by tests
}
Expand Down
7 changes: 5 additions & 2 deletions internal/handler/msg_saslstart.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,11 @@ func (h *Handler) MsgSASLStart(ctx context.Context, msg *wire.OpMsg) (*wire.OpMs
}

if h.EnableNewAuth {
// even if the database does not contain the first user yet
// backend authentication is bypassed
// If new auth is enabled and the database does not contain any user,
// backend authentication is bypassed.
//
// If a user connects with any credentials or no credentials at all,
// the authentication succeeds until the first user is created.
conninfo.Get(ctx).BypassBackendAuth = true
} else {
conninfo.Get(ctx).SetAuth(username, password)

Check warning on line 81 in internal/handler/msg_saslstart.go

View check run for this annotation

Codecov / codecov/patch

internal/handler/msg_saslstart.go#L81

Added line #L81 was not covered by tests
Expand Down

0 comments on commit 70f0183

Please sign in to comment.