Skip to content

Commit 90fdeba

Browse files
author
Divjot Arora
authored
GODRIVER-1569 Add support for authorizedDatabases option (#371)
1 parent 5e7e89c commit 90fdeba

File tree

6 files changed

+144
-65
lines changed

6 files changed

+144
-65
lines changed

mongo/client.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,9 +718,14 @@ func (c *Client) ListDatabases(ctx context.Context, filter interface{}, opts ...
718718
op := operation.NewListDatabases(filterDoc).
719719
Session(sess).ReadPreference(c.readPreference).CommandMonitor(c.monitor).
720720
ServerSelector(selector).ClusterClock(c.clock).Database("admin").Deployment(c.deployment).Crypt(c.crypt)
721+
721722
if ldo.NameOnly != nil {
722723
op = op.NameOnly(*ldo.NameOnly)
723724
}
725+
if ldo.AuthorizedDatabases != nil {
726+
op = op.AuthorizedDatabases(*ldo.AuthorizedDatabases)
727+
}
728+
724729
retry := driver.RetryNone
725730
if c.retryReads {
726731
retry = driver.RetryOncePerCommand

mongo/integration/client_test.go

Lines changed: 91 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"go.mongodb.org/mongo-driver/mongo/integration/mtest"
2828
"go.mongodb.org/mongo-driver/mongo/options"
2929
"go.mongodb.org/mongo-driver/mongo/readpref"
30+
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
3031
"go.mongodb.org/mongo-driver/x/mongo/driver"
3132
"go.mongodb.org/mongo-driver/x/mongo/driver/drivertest"
3233
"go.mongodb.org/mongo-driver/x/mongo/driver/wiremessage"
@@ -147,68 +148,106 @@ func TestClient(t *testing.T) {
147148
mt.Fatal("unable to find authenticated user")
148149
})
149150
mt.RunOpts("list databases", noClientOpts, func(mt *mtest.T) {
150-
testCases := []struct {
151-
name string
152-
filter bson.D
153-
hasTestDb bool
154-
minServerVersion string
155-
}{
156-
{"no filter", bson.D{}, true, ""},
157-
{"filter", bson.D{{"name", "foobar"}}, false, "3.6"},
158-
}
159-
160-
for _, tc := range testCases {
161-
opts := mtest.NewOptions()
162-
if tc.minServerVersion != "" {
163-
opts.MinServerVersion(tc.minServerVersion)
151+
mt.RunOpts("filter", noClientOpts, func(mt *mtest.T) {
152+
testCases := []struct {
153+
name string
154+
filter bson.D
155+
hasTestDb bool
156+
minServerVersion string
157+
}{
158+
{"empty", bson.D{}, true, ""},
159+
{"non-empty", bson.D{{"name", "foobar"}}, false, "3.6"},
164160
}
165161

166-
mt.RunOpts(tc.name, opts, func(mt *mtest.T) {
167-
res, err := mt.Client.ListDatabases(mtest.Background, tc.filter)
168-
assert.Nil(mt, err, "ListDatabases error: %v", err)
162+
for _, tc := range testCases {
163+
opts := mtest.NewOptions()
164+
if tc.minServerVersion != "" {
165+
opts.MinServerVersion(tc.minServerVersion)
166+
}
167+
168+
mt.RunOpts(tc.name, opts, func(mt *mtest.T) {
169+
res, err := mt.Client.ListDatabases(mtest.Background, tc.filter)
170+
assert.Nil(mt, err, "ListDatabases error: %v", err)
169171

170-
var found bool
171-
for _, db := range res.Databases {
172-
if db.Name == mtest.TestDb {
173-
found = true
174-
break
172+
var found bool
173+
for _, db := range res.Databases {
174+
if db.Name == mtest.TestDb {
175+
found = true
176+
break
177+
}
175178
}
176-
}
177-
assert.Equal(mt, tc.hasTestDb, found, "expected to find test db: %v, found: %v", tc.hasTestDb, found)
178-
})
179-
}
179+
assert.Equal(mt, tc.hasTestDb, found, "expected to find test db: %v, found: %v", tc.hasTestDb, found)
180+
})
181+
}
182+
})
183+
mt.Run("options", func(mt *mtest.T) {
184+
allOpts := options.ListDatabases().SetNameOnly(true).SetAuthorizedDatabases(true)
185+
mt.ClearEvents()
186+
187+
_, err := mt.Client.ListDatabases(mtest.Background, bson.D{}, allOpts)
188+
assert.Nil(mt, err, "ListDatabases error: %v", err)
189+
190+
evt := mt.GetStartedEvent()
191+
assert.Equal(mt, "listDatabases", evt.CommandName, "expected ")
192+
193+
expectedDoc := bsoncore.BuildDocumentFromElements(nil,
194+
bsoncore.AppendBooleanElement(nil, "nameOnly", true),
195+
bsoncore.AppendBooleanElement(nil, "authorizedDatabases", true),
196+
)
197+
err = compareDocs(mt, expectedDoc, evt.Command)
198+
assert.Nil(mt, err, "compareDocs error: %v", err)
199+
})
180200
})
181201
mt.RunOpts("list database names", noClientOpts, func(mt *mtest.T) {
182-
testCases := []struct {
183-
name string
184-
filter bson.D
185-
hasTestDb bool
186-
minServerVersion string
187-
}{
188-
{"no filter", bson.D{}, true, ""},
189-
{"filter", bson.D{{"name", "foobar"}}, false, "3.6"},
190-
}
191-
192-
for _, tc := range testCases {
193-
opts := mtest.NewOptions()
194-
if tc.minServerVersion != "" {
195-
opts.MinServerVersion(tc.minServerVersion)
202+
mt.RunOpts("filter", noClientOpts, func(mt *mtest.T) {
203+
testCases := []struct {
204+
name string
205+
filter bson.D
206+
hasTestDb bool
207+
minServerVersion string
208+
}{
209+
{"no filter", bson.D{}, true, ""},
210+
{"filter", bson.D{{"name", "foobar"}}, false, "3.6"},
196211
}
197212

198-
mt.RunOpts(tc.name, opts, func(mt *mtest.T) {
199-
dbs, err := mt.Client.ListDatabaseNames(mtest.Background, tc.filter)
200-
assert.Nil(mt, err, "ListDatabaseNames error: %v", err)
213+
for _, tc := range testCases {
214+
opts := mtest.NewOptions()
215+
if tc.minServerVersion != "" {
216+
opts.MinServerVersion(tc.minServerVersion)
217+
}
218+
219+
mt.RunOpts(tc.name, opts, func(mt *mtest.T) {
220+
dbs, err := mt.Client.ListDatabaseNames(mtest.Background, tc.filter)
221+
assert.Nil(mt, err, "ListDatabaseNames error: %v", err)
201222

202-
var found bool
203-
for _, db := range dbs {
204-
if db == mtest.TestDb {
205-
found = true
206-
break
223+
var found bool
224+
for _, db := range dbs {
225+
if db == mtest.TestDb {
226+
found = true
227+
break
228+
}
207229
}
208-
}
209-
assert.Equal(mt, tc.hasTestDb, found, "expected to find test db: %v, found: %v", tc.hasTestDb, found)
210-
})
211-
}
230+
assert.Equal(mt, tc.hasTestDb, found, "expected to find test db: %v, found: %v", tc.hasTestDb, found)
231+
})
232+
}
233+
})
234+
mt.Run("options", func(mt *mtest.T) {
235+
allOpts := options.ListDatabases().SetNameOnly(true).SetAuthorizedDatabases(true)
236+
mt.ClearEvents()
237+
238+
_, err := mt.Client.ListDatabaseNames(mtest.Background, bson.D{}, allOpts)
239+
assert.Nil(mt, err, "ListDatabaseNames error: %v", err)
240+
241+
evt := mt.GetStartedEvent()
242+
assert.Equal(mt, "listDatabases", evt.CommandName, "expected ")
243+
244+
expectedDoc := bsoncore.BuildDocumentFromElements(nil,
245+
bsoncore.AppendBooleanElement(nil, "nameOnly", true),
246+
bsoncore.AppendBooleanElement(nil, "authorizedDatabases", true),
247+
)
248+
err = compareDocs(mt, expectedDoc, evt.Command)
249+
assert.Nil(mt, err, "compareDocs error: %v", err)
250+
})
212251
})
213252
mt.RunOpts("ping", noClientOpts, func(mt *mtest.T) {
214253
mt.Run("default read preference", func(mt *mtest.T) {

mongo/integration/cmd_monitoring_helpers_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,9 @@ func compareDocsHelper(mt *mtest.T, expected, actual bson.Raw, prefix string) er
171171
}
172172

173173
aVal, err := actual.LookupErr(eKey)
174-
assert.Nil(mt, err, "key %s not found in result", e.Key())
174+
if err != nil {
175+
return fmt.Errorf("key %s not found in result", fullKeyName)
176+
}
175177

176178
if err := compareValues(mt, fullKeyName, e.Value(), aVal); err != nil {
177179
return err

mongo/options/listdatabasesoptions.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ type ListDatabasesOptions struct {
1111
// If true, only the Name field of the returned DatabaseSpecification objects will be populated. The default value
1212
// is false.
1313
NameOnly *bool
14+
15+
// If true, only the databases which the user is authorized to see will be returned. For more information about
16+
// the behavior of this option, see https://docs.mongodb.com/manual/reference/privilege-actions/#find. The default
17+
// value is true.
18+
AuthorizedDatabases *bool
1419
}
1520

1621
// ListDatabases creates a new ListDatabasesOptions instance.
@@ -24,6 +29,12 @@ func (ld *ListDatabasesOptions) SetNameOnly(b bool) *ListDatabasesOptions {
2429
return ld
2530
}
2631

32+
// SetAuthorizedDatabases sets the value for the AuthorizedDatabases field.
33+
func (ld *ListDatabasesOptions) SetAuthorizedDatabases(b bool) *ListDatabasesOptions {
34+
ld.AuthorizedDatabases = &b
35+
return ld
36+
}
37+
2738
// MergeListDatabasesOptions combines the given ListDatabasesOptions instances into a single *ListDatabasesOptions in a
2839
// last-one-wins fashion.
2940
func MergeListDatabasesOptions(opts ...*ListDatabasesOptions) *ListDatabasesOptions {
@@ -35,6 +46,9 @@ func MergeListDatabasesOptions(opts ...*ListDatabasesOptions) *ListDatabasesOpti
3546
if opt.NameOnly != nil {
3647
ld.NameOnly = opt.NameOnly
3748
}
49+
if opt.AuthorizedDatabases != nil {
50+
ld.AuthorizedDatabases = opt.AuthorizedDatabases
51+
}
3852
}
3953

4054
return ld

x/mongo/driver/operation/listDatabases.go

Lines changed: 26 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x/mongo/driver/operation/listDatabases.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ documentation = "Filter determines what results are returned from listDatabases.
2121
type = "boolean"
2222
documentation = "NameOnly specifies whether to only return database names."
2323

24+
[request.authorizedDatabases]
25+
type = "boolean"
26+
documentation = "AuthorizedDatabases specifies whether to only return databases which the user is authorized to use."
27+
2428
[response]
2529
name = "ListDatabasesResult"
2630

@@ -30,4 +34,4 @@ documentation = "The sum of the size of all the database files on disk in bytes.
3034

3135
[response.field.databases]
3236
type = "value"
33-
documentation = "An array of documents, one document for each database"
37+
documentation = "An array of documents, one document for each database"

0 commit comments

Comments
 (0)