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

Advertise SCRAM / SASL support in addition to PLAIN #4113

Merged
merged 34 commits into from Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
f7b34b5
Unmark showCredentials as ignored property of usersInfo
henvic Feb 22, 2024
477ab17
wip
henvic Feb 22, 2024
2208a62
failure example
henvic Feb 23, 2024
3dfe891
Merge branch 'main' into feat/sasl-adv
henvic Feb 26, 2024
b35ac42
wip
henvic Feb 26, 2024
136ecf9
wip
henvic Feb 26, 2024
1963561
wip
henvic Feb 26, 2024
5e3e377
wip
henvic Feb 26, 2024
46bcdad
wip
henvic Feb 26, 2024
ad289de
Merge branch 'main' into feat/sasl-adv
henvic Feb 26, 2024
a0e504f
wip
henvic Feb 26, 2024
01282a9
wip
henvic Feb 26, 2024
2c834b4
wip
henvic Feb 26, 2024
78b41d7
wip
henvic Feb 27, 2024
5a77a3d
wip
henvic Feb 27, 2024
76efeee
wip
henvic Feb 27, 2024
3cc579a
Merge branch 'main' into feat/sasl-adv
henvic Feb 27, 2024
830386d
wip
henvic Feb 28, 2024
2736c4a
wip
henvic Feb 28, 2024
e769c90
wip
henvic Feb 28, 2024
87bcf66
wip
henvic Feb 28, 2024
cb336a1
Merge branch 'main' into feat/sasl-adv
henvic Mar 1, 2024
92ebe16
wip
henvic Mar 3, 2024
530e14e
Merge branch 'main' into feat/sasl-adv
henvic Mar 4, 2024
0173295
Fix `saslContinue` crashing due to not found authentication conversat…
henvic Mar 5, 2024
efd071b
code review remarks
henvic Mar 5, 2024
fae330e
wip
henvic Mar 5, 2024
22a2be4
wip
henvic Mar 5, 2024
b930a1b
update test
chilagrow Mar 6, 2024
444a39d
flatten if statements
chilagrow Mar 6, 2024
d44e886
update test
chilagrow Mar 6, 2024
76990ef
update test to not panic for failForMongoDB
chilagrow Mar 6, 2024
586cb05
Merge branch 'main' into feat/sasl-adv
chilagrow Mar 6, 2024
ceadf72
Merge branch 'main' into feat/sasl-adv
AlekSi Mar 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 1 addition & 2 deletions integration/commands_administration_test.go
Expand Up @@ -252,7 +252,6 @@ func TestCommandsAdministrationListDatabases(t *testing.T) {
}

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

Expand Down Expand Up @@ -858,7 +857,7 @@ func TestGetParameterCommandAuthenticationMechanisms(t *testing.T) {
require.NoError(t, err)

expected := bson.D{
{"authenticationMechanisms", bson.A{"PLAIN"}},
{"authenticationMechanisms", bson.A{"SCRAM-SHA-1", "SCRAM-SHA-256", "PLAIN"}},
{"ok", float64(1)},
}
require.Equal(t, expected, res)
Expand Down
1 change: 0 additions & 1 deletion integration/create_test.go
Expand Up @@ -333,7 +333,6 @@ func TestCreateCappedCommandInvalidSpec(t *testing.T) {
},
},
} {
tc, name := tc, name
t.Run(name, func(t *testing.T) {
t.Parallel()

Expand Down
181 changes: 181 additions & 0 deletions integration/hello_command_test.go
@@ -0,0 +1,181 @@
// Copyright 2021 FerretDB Inc.
//
// 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
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package integration

import (
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"

"github.com/FerretDB/FerretDB/integration/setup"
"github.com/FerretDB/FerretDB/integration/shareddata"
"github.com/FerretDB/FerretDB/internal/types"
"github.com/FerretDB/FerretDB/internal/util/must"
"github.com/FerretDB/FerretDB/internal/util/testutil/testtb"
)

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

ctx, collection := setup.Setup(t, shareddata.Scalars, shareddata.Composites)
db := collection.Database()

var res bson.D

require.NoError(t, db.RunCommand(ctx, bson.D{
{"hello", "1"},
}).Decode(&res))

actual := ConvertDocument(t, res)

assert.Equal(t, must.NotFail(actual.Get("isWritablePrimary")), true)
assert.Equal(t, must.NotFail(actual.Get("maxBsonObjectSize")), int32(16777216))
assert.Equal(t, must.NotFail(actual.Get("maxMessageSizeBytes")), int32(48000000))
assert.Equal(t, must.NotFail(actual.Get("maxMessageSizeBytes")), int32(48000000))
assert.Equal(t, must.NotFail(actual.Get("maxWriteBatchSize")), int32(100000))
assert.IsType(t, must.NotFail(actual.Get("localTime")), time.Time{})
assert.IsType(t, must.NotFail(actual.Get("connectionId")), int32(1))
assert.Equal(t, must.NotFail(actual.Get("minWireVersion")), int32(0))
assert.Equal(t, must.NotFail(actual.Get("maxWireVersion")), int32(21))
assert.Equal(t, must.NotFail(actual.Get("readOnly")), false)
assert.Equal(t, must.NotFail(actual.Get("ok")), float64(1))
}

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

ctx, collection := setup.Setup(t, shareddata.Scalars, shareddata.Composites)
db := collection.Database()

usersPayload := []bson.D{
{
{"createUser", "hello_user"},
{"roles", bson.A{}},
{"pwd", "hello_password"},
},
{
{"createUser", "hello_user_scram1"},
{"roles", bson.A{}},
{"pwd", "hello_password"},
{"mechanisms", bson.A{"SCRAM-SHA-1"}},
},
{
{"createUser", "hello_user_scram256"},
{"roles", bson.A{}},
{"pwd", "hello_password"},
{"mechanisms", bson.A{"SCRAM-SHA-256"}},
},
}

if !setup.IsMongoDB(t) {
usersPayload = append(usersPayload, primitive.D{
{"createUser", "hello_user_plain"},
{"roles", bson.A{}},
{"pwd", "hello_password"},
{"mechanisms", bson.A{"PLAIN"}},
})
}

for _, u := range usersPayload {
require.NoError(t, db.RunCommand(ctx, u).Err())
}

testCases := map[string]struct { //nolint:vet // used for test only
user string
mechs *types.Array
err string
}{
"NotFound": {
user: db.Name() + ".not_found",
},
"AnotherDB": {
user: db.Name() + "_not_found.another_db",
},
"HelloUser": {
user: db.Name() + ".hello_user",
mechs: must.NotFail(types.NewArray("SCRAM-SHA-1", "SCRAM-SHA-256")),
},
"HelloUserPlain": {
user: db.Name() + ".hello_user_plain",
mechs: must.NotFail(types.NewArray("PLAIN")),
},
"HelloUserSCRAM1": {
user: db.Name() + ".hello_user_scram1",
mechs: must.NotFail(types.NewArray("SCRAM-SHA-1")),
},
"HelloUserSCRAM256": {
user: db.Name() + ".hello_user_scram256",
mechs: must.NotFail(types.NewArray("SCRAM-SHA-256")),
},
"EmptyUsername": {
user: db.Name() + ".",
mechs: nil,
},
"MissingSeparator": {
user: db.Name(),
err: "UserName must contain a '.' separated database.user pair",
},
}

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

var t testtb.TB = tt

if tc.mechs != nil && tc.mechs.Contains("PLAIN") {
t = setup.FailsForMongoDB(t, "PLAIN authentication mechanism is not support by MongoDB")
}

var res bson.D

err := db.RunCommand(ctx, bson.D{
{"hello", "1"},
{"saslSupportedMechs", tc.user},
}).Decode(&res)

if tc.err != "" {
require.ErrorContains(t, err, tc.err)
chilagrow marked this conversation as resolved.
Show resolved Hide resolved
return
}

actual := ConvertDocument(t, res)

assert.Equal(t, must.NotFail(actual.Get("isWritablePrimary")), true)
assert.Equal(t, must.NotFail(actual.Get("maxBsonObjectSize")), int32(16777216))
assert.Equal(t, must.NotFail(actual.Get("maxMessageSizeBytes")), int32(48000000))
assert.Equal(t, must.NotFail(actual.Get("maxMessageSizeBytes")), int32(48000000))
assert.Equal(t, must.NotFail(actual.Get("maxWriteBatchSize")), int32(100000))
assert.IsType(t, must.NotFail(actual.Get("localTime")), time.Time{})
assert.IsType(t, must.NotFail(actual.Get("connectionId")), int32(1))
assert.Equal(t, must.NotFail(actual.Get("minWireVersion")), int32(0))
assert.Equal(t, must.NotFail(actual.Get("maxWireVersion")), int32(21))
assert.Equal(t, must.NotFail(actual.Get("readOnly")), false)
assert.Equal(t, must.NotFail(actual.Get("ok")), float64(1))

if tc.mechs == nil {
assert.False(t, actual.Has("saslSupportedMechs"))
return
}

mechanisms := must.NotFail(actual.Get("saslSupportedMechs"))
assert.True(t, mechanisms.(*types.Array).ContainsAll(tc.mechs))
})
}
}
1 change: 0 additions & 1 deletion integration/query_test.go
Expand Up @@ -728,7 +728,6 @@ func TestQueryCommandLimitPushDown(t *testing.T) {
limitPushdown: noPushdown,
},
} {
tc, name := tc, name
t.Run(name, func(t *testing.T) {
t.Parallel()

Expand Down
2 changes: 1 addition & 1 deletion integration/setup/helpers.go
Expand Up @@ -89,7 +89,7 @@ func FailsForMongoDB(tb testtb.TB, reason string) testtb.TB {

// SkipForMongoDB skips the current test for MongoDB.
//
// Use [FailsForMongoDB] in new code.
// Deprecated: Use [FailsForMongoDB] in new code.
func SkipForMongoDB(tb testtb.TB, reason string) {
tb.Helper()

Expand Down
4 changes: 2 additions & 2 deletions integration/users/connection_test.go
Expand Up @@ -101,7 +101,7 @@ func TestAuthentication(t *testing.T) {
mechanisms: []string{"SCRAM-SHA-256"},
connectionMechanism: "SCRAM-SHA-256",
userNotFound: true,
errorMessage: "Authentication failed",
errorMessage: "Authentication failed.",
topologyError: true,
},
"BadPassword": {
Expand All @@ -111,7 +111,7 @@ func TestAuthentication(t *testing.T) {
connectionMechanism: "SCRAM-SHA-256",
wrongPassword: true,
topologyError: true,
errorMessage: "Authentication failed",
errorMessage: "Authentication failed.",
},
"MechanismNotSet": {
username: "user_mechanism_not_set",
Expand Down