Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enforce new authentication #4075

Merged
merged 52 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
fbaf68a
get authentication mechanism from db
chilagrow Feb 14, 2024
f5c6049
add test for conneting without plain username password
chilagrow Feb 14, 2024
88b6316
add authentication to sasl start
chilagrow Feb 15, 2024
bcfd350
add authentication to all handlers except command query
chilagrow Feb 15, 2024
3699034
move files
chilagrow Feb 15, 2024
8e65773
Merge branch 'main' into enforce-new-auth
chilagrow Feb 15, 2024
70f0183
until first user is created new authentication always succeeds
chilagrow Feb 15, 2024
470ca14
is master does not need authentication
chilagrow Feb 15, 2024
40be66d
handle database without any pool yet
chilagrow Feb 16, 2024
2e98e84
merge conflict
chilagrow Feb 16, 2024
fd048c6
do not authenticate on some handlers
chilagrow Feb 16, 2024
4a6b841
authentication for sha256 is done by conversation step, so handler ch…
chilagrow Feb 16, 2024
90de3fa
Plain credential hashes password
chilagrow Feb 16, 2024
b4b4c57
add test for scram sha256 user for empty database
chilagrow Feb 16, 2024
5dc7ae5
fix create update and drop user tests
chilagrow Feb 16, 2024
c3583d1
update error and panic
chilagrow Feb 16, 2024
8d72103
create pool upon registry creation
chilagrow Feb 19, 2024
f694f4e
do not authenticate on handler if bypass backend auth is not set
chilagrow Feb 19, 2024
b08beea
user tests use credentials for test runner
chilagrow Feb 19, 2024
4286628
lint
chilagrow Feb 19, 2024
287b728
Revert "user tests use credentials for test runner"
chilagrow Feb 19, 2024
950e567
authentication checks user instead of db.user
chilagrow Feb 19, 2024
a9be0e2
backend fallback
chilagrow Feb 19, 2024
a4b5699
cleanup
chilagrow Feb 19, 2024
daba28a
missing import
chilagrow Feb 19, 2024
5a8014e
revert
chilagrow Feb 19, 2024
eda4ed1
tidy up
chilagrow Feb 19, 2024
add453e
add test for plain mechanism backend user
chilagrow Feb 19, 2024
0d786cb
simplify test user
chilagrow Feb 19, 2024
5bdcfc4
update comments
chilagrow Feb 19, 2024
f74532c
remove unused var
chilagrow Feb 19, 2024
5c4b117
Merge branch 'main' into enforce-new-auth
chilagrow Feb 19, 2024
d407f5f
sqlite does not have backend auth
chilagrow Feb 19, 2024
0ab1f56
use opt out way
chilagrow Feb 20, 2024
306c10b
add todo links
chilagrow Feb 20, 2024
55a52b9
merge
chilagrow Feb 20, 2024
0128186
rename reorder
chilagrow Feb 20, 2024
a0df39f
add todo
chilagrow Feb 20, 2024
24c393c
address feedback
chilagrow Feb 21, 2024
e3edaae
Merge branch 'main' into enforce-new-auth
chilagrow Feb 21, 2024
73ec82a
create user during the setup
chilagrow Feb 21, 2024
ae2d02b
Merge branch 'main' into enforce-new-auth
chilagrow Feb 22, 2024
07c749a
fix test
chilagrow Feb 22, 2024
3f95100
update comment add explaination add more mechanisms
chilagrow Feb 22, 2024
c4c1224
PLAIN and SHA handles authenticated users the same way
chilagrow Feb 22, 2024
53d76ae
Merge branch 'main' into enforce-new-auth
chilagrow Feb 26, 2024
d5d2499
do not use pwd as abbrev
chilagrow Feb 26, 2024
7bcc892
update comment
chilagrow Feb 26, 2024
dbd27a8
do not allow SCRAM if new authentication is not enabled
chilagrow Feb 27, 2024
e45cc60
Merge branch 'main' into enforce-new-auth
AlekSi Feb 27, 2024
339b52d
Merge branch 'main' into enforce-new-auth
AlekSi Feb 28, 2024
fb4dd9e
Merge branch 'main' into enforce-new-auth
AlekSi Feb 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
backend fallback
  • Loading branch information
chilagrow committed Feb 19, 2024
commit a9be0e245fe3159d3b6b631717104cb63598e2e9
28 changes: 18 additions & 10 deletions integration/users/connection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,8 @@ func TestAuthentication(t *testing.T) {
}

// TestAuthenticationEnableNewAuthNoUser tests that the authentication succeeds
// with any PLAIN mechanism user until the first user is created. This is temporary
// until local exception is implemented.
// with PLAIN mechanism user when there are no users in the database.
// It uses backend to authenticate the user such case.
// For SCRAM-SHA-256 mechanism users, authentication fails if the user does not exist.
func TestAuthenticationEnableNewAuthNoUserExists(t *testing.T) {
t.Parallel()
Expand All @@ -237,23 +237,25 @@ func TestAuthenticationEnableNewAuthNoUserExists(t *testing.T) {
password string
mechanism string

err string
pingErr string
insertErr string
}{
"PLAIN": {
"PLAINNonExistingUser": {
username: "plain-user",
password: "whatever",
mechanism: "PLAIN",
insertErr: `role "plain-user" does not exist`,
},
"PLAINEmpty": {
username: "",
password: "",
"PLAINBackendUser": {
username: "username",
password: "password",
mechanism: "PLAIN",
},
"SHA256": {
username: "sha256-user",
password: "whatever",
mechanism: "SCRAM-SHA-256",
err: "Authentication failed",
pingErr: "Authentication failed",
},
}

Expand All @@ -280,15 +282,21 @@ func TestAuthenticationEnableNewAuthNoUserExists(t *testing.T) {

err = client.Ping(ctx, nil)

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

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

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

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

require.NoError(t, err, "cannot insert document")
})
}
Expand Down
4 changes: 2 additions & 2 deletions integration/users/create_user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ func createUserTestRunnerUser(tb *testing.T, s *setup.SetupResult) (*mongo.Datab

username, pwd, mechanism := "user-test-runner", "password", "PLAIN"

err := s.Collection.Database().RunCommand(s.Ctx, bson.D{
err := s.Collection.Database().Client().Database("admin").RunCommand(s.Ctx, bson.D{
{"createUser", username},
{"roles", bson.A{}},
{"pwd", pwd},
Expand All @@ -341,7 +341,7 @@ func createUserTestRunnerUser(tb *testing.T, s *setup.SetupResult) (*mongo.Datab
collection := db.Collection(s.Collection.Name())

tb.Cleanup(func() {
require.NoError(tb, db.RunCommand(s.Ctx, bson.D{{"dropAllUsersFromDatabase", 1}}).Err())
_ = db.RunCommand(s.Ctx, bson.D{{"dropAllUsersFromDatabase", 1}})
})

return db, collection
Expand Down
7 changes: 1 addition & 6 deletions integration/users/drop_all_users_from_database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,11 @@ func TestDropAllUsersFromDatabase(t *testing.T) {
// So this call should remove zero users as the database doesn't exist. The next one, "quantity" users.
assertDropAllUsersFromDatabase(t, ctx, client.Database(t.Name()+"_another_database"), 0)

if !setup.IsMongoDB(t) {
// For non MongoDB, a user created to run the tests is also dropped.
quantity++
}

assertDropAllUsersFromDatabase(t, ctx, db, quantity)

// Run for the second time to check if it still succeeds when there aren't any users remaining,
// instead of returning an error.
assertDropAllUsersFromDatabase(t, ctx, db, 0)
assertDropAllUsersFromDatabase(t, ctx, s.Collection.Database(), 0)
}

func assertDropAllUsersFromDatabase(t *testing.T, ctx context.Context, db *mongo.Database, quantity int) {
Expand Down
8 changes: 8 additions & 0 deletions internal/clientconn/conninfo/conn_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,14 @@ func (connInfo *ConnInfo) SetBypassBackendAuth() {
connInfo.bypassBackendAuth = true
}

// UnsetBypassBackendAuth marks the connection as requiring backend authentication.
func (connInfo *ConnInfo) UnsetBypassBackendAuth() {
connInfo.rw.Lock()
defer connInfo.rw.Unlock()

connInfo.bypassBackendAuth = false
}

henvic marked this conversation as resolved.
Show resolved Hide resolved
// BypassBackendAuth returns whether the connection requires backend authentication.
func (connInfo *ConnInfo) BypassBackendAuth() bool {
connInfo.rw.RLock()
Expand Down
7 changes: 5 additions & 2 deletions internal/handler/authenticate.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
// the first user is created.
func (h *Handler) authenticate(ctx context.Context, msg *wire.OpMsg) error {
if !h.EnableNewAuth {
return nil

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

View check run for this annotation

Codecov / codecov/patch

internal/handler/authenticate.go#L40

Added line #L40 was not covered by tests
}

if !conninfo.Get(ctx).BypassBackendAuth() {
Expand All @@ -46,12 +46,12 @@

adminDB, err := h.b.Database("admin")
if err != nil {
return lazyerrors.Error(err)

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

View check run for this annotation

Codecov / codecov/patch

internal/handler/authenticate.go#L49

Added line #L49 was not covered by tests
}

usersCol, err := adminDB.Collection("system.users")
if err != nil {
return lazyerrors.Error(err)

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

View check run for this annotation

Codecov / codecov/patch

internal/handler/authenticate.go#L54

Added line #L54 was not covered by tests
}

username, pwd := conninfo.Get(ctx).Auth()
Expand All @@ -60,7 +60,7 @@

qr, err := usersCol.Query(ctx, nil)
if err != nil {
return lazyerrors.Error(err)

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

View check run for this annotation

Codecov / codecov/patch

internal/handler/authenticate.go#L63

Added line #L63 was not covered by tests
}

defer qr.Iter.Close()
Expand All @@ -78,7 +78,7 @@
}

if err != nil {
return lazyerrors.Error(err)

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

View check run for this annotation

Codecov / codecov/patch

internal/handler/authenticate.go#L81

Added line #L81 was not covered by tests
}

hasUser = true
rumyantseva marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -86,7 +86,7 @@
var matches bool

if matches, err = common.FilterDocument(v, filter); err != nil {
return lazyerrors.Error(err)

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

View check run for this annotation

Codecov / codecov/patch

internal/handler/authenticate.go#L89

Added line #L89 was not covered by tests
}

if matches {
Expand All @@ -96,17 +96,20 @@
}

if !hasUser {
// If a user connects with any credentials or no credentials at all,
// the authentication succeeds until the first user is created.
// There is no user in the database, let backend check the authentication.
// Do not want unauthenticated users accessing the database, while there need
// to be a way to access the database until local exception is implemented.
conninfo.Get(ctx).UnsetBypassBackendAuth()
AlekSi marked this conversation as resolved.
Show resolved Hide resolved

return nil
}

if storedUser == nil {
return handlererrors.NewCommandErrorMsgWithArgument(
handlererrors.ErrAuthenticationFailed,
"Authentication failed",
"authenticate",
)

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

View check run for this annotation

Codecov / codecov/patch

internal/handler/authenticate.go#L108-L112

Added lines #L108 - L112 were not covered by tests
}

credentials := must.NotFail(storedUser.Get("credentials")).(*types.Document)
Expand All @@ -118,24 +121,24 @@
return nil
case credentials.Has("PLAIN"):
break
default:
panic("credentials does not contain a known mechanism")

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

View check run for this annotation

Codecov / codecov/patch

internal/handler/authenticate.go#L124-L125

Added lines #L124 - L125 were not covered by tests
}

v := must.NotFail(credentials.Get("PLAIN"))

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#L132

Added line #L132 was not covered by tests
}

err = password.PlainVerify(pwd, doc)
if err != nil {
return handlererrors.NewCommandErrorMsgWithArgument(
handlererrors.ErrAuthenticationFailed,
"Authentication failed",
"authenticate",
)

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

View check run for this annotation

Codecov / codecov/patch

internal/handler/authenticate.go#L137-L141

Added lines #L137 - L141 were not covered by tests
}

return nil
Expand Down
Loading