summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/auth/usersInfo.js47
-rw-r--r--src/mongo/client/dbclientcursor.cpp15
-rw-r--r--src/mongo/client/dbclientcursor.h10
-rw-r--r--src/mongo/db/commands/user_management_commands.cpp22
4 files changed, 79 insertions, 15 deletions
diff --git a/jstests/auth/usersInfo.js b/jstests/auth/usersInfo.js
new file mode 100644
index 00000000000..fdd4a1b0a5f
--- /dev/null
+++ b/jstests/auth/usersInfo.js
@@ -0,0 +1,47 @@
+// Test behavior and edge cases in usersInfo
+(function() {
+ 'use strict';
+
+ function runTest(conn) {
+ let db = conn.getDB("test");
+ let emptyDB = conn.getDB("test2");
+ let otherDB = conn.getDB("other");
+
+ const userCount = 200;
+ for (let i = 0; i < userCount; ++i) {
+ assert.commandWorked(db.runCommand({createUser: "user" + i, pwd: "pwd", roles: []}));
+ }
+ assert.commandWorked(otherDB.runCommand({createUser: "otherUser", pwd: "pwd", roles: []}));
+
+ // Check info for all users on the "test" database.
+ const allTestInfo = assert.commandWorked(db.runCommand({usersInfo: 1}));
+ assert.eq(userCount, allTestInfo.users.length);
+
+ // Check we can find a particular user on the "test" database.
+ assert.eq(1, assert.commandWorked(db.runCommand({usersInfo: "user12"})).users.length);
+ assert.eq(1,
+ assert.commandWorked(db.runCommand({usersInfo: {user: "user12", db: "test"}}))
+ .users.length);
+ assert.eq(0,
+ assert.commandWorked(db.runCommand({usersInfo: {user: "user12", db: "test2"}}))
+ .users.length);
+ assert.eq(0, assert.commandWorked(emptyDB.runCommand({usersInfo: "user12"})).users.length);
+
+ // No users are found on a database without users.
+ assert.eq(0, assert.commandWorked(emptyDB.runCommand({usersInfo: 1})).users.length);
+
+ // Check that we can find records for all users on all databases.
+ const allInfo = assert.commandWorked(db.runCommand({usersInfo: {forAllDBs: true}}));
+ assert.eq(userCount + 1, allInfo.users.length);
+ }
+
+ const m = MongoRunner.runMongod();
+ runTest(m);
+ MongoRunner.stopMongod(m);
+
+ // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed.
+ const st =
+ new ShardingTest({shards: 1, mongos: 1, config: 1, other: {shardAsReplicaSet: false}});
+ runTest(st.s0);
+ st.stop();
+}());
diff --git a/src/mongo/client/dbclientcursor.cpp b/src/mongo/client/dbclientcursor.cpp
index 0efe1e2a32c..2736023861a 100644
--- a/src/mongo/client/dbclientcursor.cpp
+++ b/src/mongo/client/dbclientcursor.cpp
@@ -466,13 +466,15 @@ DBClientCursor::DBClientCursor(DBClientBase* client,
nToSkip,
fieldsToReturn,
queryOptions,
- batchSize) {}
+ batchSize,
+ {}) {}
DBClientCursor::DBClientCursor(DBClientBase* client,
const std::string& ns,
long long cursorId,
int nToReturn,
- int queryOptions)
+ int queryOptions,
+ std::vector<BSONObj> initialBatch)
: DBClientCursor(client,
ns,
BSONObj(), // query
@@ -481,7 +483,8 @@ DBClientCursor::DBClientCursor(DBClientBase* client,
0, // nToSkip
nullptr, // fieldsToReturn
queryOptions,
- 0) {} // batchSize
+ 0,
+ std::move(initialBatch)) {} // batchSize
DBClientCursor::DBClientCursor(DBClientBase* client,
const std::string& ns,
@@ -491,8 +494,10 @@ DBClientCursor::DBClientCursor(DBClientBase* client,
int nToSkip,
const BSONObj* fieldsToReturn,
int queryOptions,
- int batchSize)
- : _client(client),
+ int batchSize,
+ std::vector<BSONObj> initialBatch)
+ : batch{std::move(initialBatch)},
+ _client(client),
_originalHost(_client->getServerAddress()),
ns(ns),
_isCommand(nsIsFull(ns) ? nsToCollectionSubstring(ns) == "$cmd" : false),
diff --git a/src/mongo/client/dbclientcursor.h b/src/mongo/client/dbclientcursor.h
index 0601a3bf6ef..876d3f30db7 100644
--- a/src/mongo/client/dbclientcursor.h
+++ b/src/mongo/client/dbclientcursor.h
@@ -152,7 +152,8 @@ public:
const std::string& ns,
long long cursorId,
int nToReturn,
- int options);
+ int options,
+ std::vector<BSONObj> initialBatch = {});
virtual ~DBClientCursor();
@@ -224,11 +225,16 @@ private:
int nToSkip,
const BSONObj* fieldsToReturn,
int queryOptions,
- int bs);
+ int bs,
+ std::vector<BSONObj> initialBatch);
int nextBatchSize();
struct Batch {
+ // TODO remove constructors after c++17 toolchain upgrade
+ Batch() = default;
+ Batch(std::vector<BSONObj> initial, size_t initialPos = 0)
+ : objs(std::move(initial)), pos(initialPos) {}
std::vector<BSONObj> objs;
size_t pos = 0;
};
diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp
index e0f205b18fd..d1e53b2cb03 100644
--- a/src/mongo/db/commands/user_management_commands.cpp
+++ b/src/mongo/db/commands/user_management_commands.cpp
@@ -1379,21 +1379,27 @@ public:
pipeline.push_back(BSON("$match" << *args.filter));
}
+ DBDirectClient client(opCtx);
+
BSONObjBuilder responseBuilder;
AggregationRequest aggRequest(AuthorizationManager::usersCollectionNamespace,
std::move(pipeline));
- Status status = runAggregate(opCtx,
+ uassertStatusOK(runAggregate(opCtx,
AuthorizationManager::usersCollectionNamespace,
aggRequest,
aggRequest.serializeToCommandObj().toBson(),
- responseBuilder);
- uassertStatusOK(status);
-
+ responseBuilder));
CommandHelpers::appendSimpleCommandStatus(responseBuilder, true);
- auto swResponse = CursorResponse::parseFromBSON(responseBuilder.obj());
- uassertStatusOK(swResponse.getStatus());
- for (const BSONObj& obj : swResponse.getValue().getBatch()) {
- usersArrayBuilder.append(obj);
+ auto response = CursorResponse::parseFromBSONThrowing(responseBuilder.obj());
+ DBClientCursor cursor(&client,
+ response.getNSS().toString(),
+ response.getCursorId(),
+ 0,
+ 0,
+ response.releaseBatch());
+
+ while (cursor.more()) {
+ usersArrayBuilder.append(cursor.next());
}
}
result.append("users", usersArrayBuilder.arr());