summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/auth/curop_auth_info.js77
-rw-r--r--src/mongo/db/audit.cpp3
-rw-r--r--src/mongo/db/audit.h8
-rw-r--r--src/mongo/db/auth/SConscript31
-rw-r--r--src/mongo/db/auth/auth_types.idl38
-rw-r--r--src/mongo/db/auth/impersonation_session.cpp20
-rw-r--r--src/mongo/db/auth/impersonation_session.h2
-rw-r--r--src/mongo/db/auth/role_name.cpp38
-rw-r--r--src/mongo/db/auth/role_name.h18
-rw-r--r--src/mongo/db/auth/user_name.cpp44
-rw-r--r--src/mongo/db/auth/user_name.h11
-rw-r--r--src/mongo/db/curop.cpp28
-rw-r--r--src/mongo/embedded/embedded_auth_session.cpp4
-rw-r--r--src/mongo/rpc/SConscript19
-rw-r--r--src/mongo/rpc/metadata.cpp10
-rw-r--r--src/mongo/rpc/metadata/audit_metadata.cpp71
-rw-r--r--src/mongo/rpc/metadata/audit_metadata.h83
-rw-r--r--src/mongo/rpc/metadata/impersonated_user_metadata.cpp93
-rw-r--r--src/mongo/rpc/metadata/impersonated_user_metadata.h73
-rw-r--r--src/mongo/rpc/metadata/impersonated_user_metadata.idl35
-rw-r--r--src/mongo/s/SConscript1
-rw-r--r--src/mongo/s/sharding_egress_metadata_hook.cpp4
-rw-r--r--src/mongo/util/net/SConscript2
23 files changed, 491 insertions, 222 deletions
diff --git a/jstests/auth/curop_auth_info.js b/jstests/auth/curop_auth_info.js
new file mode 100644
index 00000000000..f59a4388916
--- /dev/null
+++ b/jstests/auth/curop_auth_info.js
@@ -0,0 +1,77 @@
+(function() {
+ 'use strict';
+
+ const runTest = function(conn, failPointConn) {
+ jsTestLog("Setting up users");
+ const db = conn.getDB("admin");
+ assert.commandWorked(
+ db.runCommand({createUser: "admin", pwd: "pwd", roles: jsTest.adminUserRoles}));
+ assert.eq(db.auth("admin", "pwd"), 1);
+ assert.commandWorked(db.runCommand({createUser: "testuser", pwd: "pwd", roles: []}));
+ db.grantRolesToUser("testuser", [{role: "readWrite", db: "test"}]);
+
+ const queryFn = function() {
+ assert.eq(db.getSiblingDB("admin").auth("testuser", "pwd"), 1);
+ let testDB = db.getSiblingDB("test");
+ testDB.test.insert({});
+ assert.eq(testDB.test.find({}).comment("curop_auth_info.js query").itcount(), 1);
+ };
+
+ jsTestLog("blocking finds and starting parallel shell to create op");
+ assert.commandWorked(failPointConn.getDB("admin").runCommand(
+ {configureFailPoint: "waitInFindBeforeMakingBatch", mode: "alwaysOn"}));
+ let finderWait = startParallelShell(queryFn, conn.port);
+ let myOp;
+
+ assert.soon(function() {
+ const curOpResults = db.runCommand({currentOp: 1});
+ assert.commandWorked(curOpResults);
+ print(tojson(curOpResults));
+ const myOps = curOpResults["inprog"].filter((op) => {
+ return (op["command"]["comment"] == "curop_auth_info.js query");
+ });
+
+ if (myOps.length == 0) {
+ return false;
+ }
+ myOp = myOps[0];
+ return true;
+ });
+
+ jsTestLog("found op");
+ assert.commandWorked(failPointConn.getDB("admin").runCommand(
+ {configureFailPoint: "waitInFindBeforeMakingBatch", mode: "off"}));
+ finderWait();
+
+ const authedUsers = myOp["effectiveUsers"];
+ const impersonators = myOp["userImpersonators"];
+ print(tojson(authedUsers), tojson(impersonators));
+ if (impersonators) {
+ assert.eq(authedUsers.length, 1);
+ assert.docEq(authedUsers[0], {user: "testuser", db: "admin"});
+ assert(impersonators);
+ assert.eq(impersonators.length, 1);
+ assert.docEq(impersonators[0], {user: "__system", db: "local"});
+ } else {
+ assert(authedUsers);
+ assert.eq(authedUsers.length, 1);
+ assert.docEq(authedUsers[0], {user: "testuser", db: "admin"});
+ }
+ };
+
+ const m = MongoRunner.runMongod();
+ runTest(m, m);
+ MongoRunner.stopMongod(m);
+
+ const st = new ShardingTest({
+ shards: 1,
+ mongos: 1,
+ config: 1,
+ keyFile: 'jstests/libs/key1',
+ other: {
+ shardAsReplicaSet: false,
+ }
+ });
+ runTest(st.s0, st.d0);
+ st.stop();
+})();
diff --git a/src/mongo/db/audit.cpp b/src/mongo/db/audit.cpp
index 0ae7a5bb946..c8d783d1546 100644
--- a/src/mongo/db/audit.cpp
+++ b/src/mongo/db/audit.cpp
@@ -171,7 +171,4 @@ void mongo::audit::logShardCollection(Client* client,
const BSONObj& keyPattern,
bool unique) {}
-void mongo::audit::writeImpersonatedUsersToMetadata(OperationContext* opCtx,
- BSONObjBuilder* metadata) {}
-
#endif
diff --git a/src/mongo/db/audit.h b/src/mongo/db/audit.h
index 60619a4b776..6e2c3fae986 100644
--- a/src/mongo/db/audit.h
+++ b/src/mongo/db/audit.h
@@ -311,13 +311,5 @@ void logRemoveShard(Client* client, StringData shardname);
*/
void logShardCollection(Client* client, StringData ns, const BSONObj& keyPattern, bool unique);
-
-/*
- * Appends an array of user/db pairs and an array of role/db pairs
- * to the provided metadata builder. The users and roles are extracted from the current client.
- * They are to be the impersonated users and roles for a Command run by an internal user.
- */
-void writeImpersonatedUsersToMetadata(OperationContext* opCtx, BSONObjBuilder* metadataBob);
-
} // namespace audit
} // namespace mongo
diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript
index 35c418f448d..a8f89e223b1 100644
--- a/src/mongo/db/auth/SConscript
+++ b/src/mongo/db/auth/SConscript
@@ -18,16 +18,6 @@ generateActionTypes = env.Command(
env.Alias('generated-sources', generateActionTypes)
env.Library(
- target='auth_rolename',
- source=[
- 'role_name.cpp'
- ],
- LIBDEPS=[
- '$BUILD_DIR/mongo/base',
- ],
-)
-
-env.Library(
target='authentication_restriction',
source=[
'restriction_environment.cpp',
@@ -58,24 +48,12 @@ env.Library(
'authorization_manager.cpp',
'authorization_session.cpp',
'auth_decorations.cpp',
- ],
- LIBDEPS=[
- 'auth_rolename',
- 'user_name',
- '$BUILD_DIR/mongo/base',
- '$BUILD_DIR/mongo/db/service_context',
- '$BUILD_DIR/mongo/rpc/audit_metadata',
- ],
-)
-
-
-env.Library(
- target='user_name',
- source=[
'user_name.cpp',
+ 'role_name.cpp'
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/db/service_context',
],
)
@@ -154,7 +132,6 @@ env.Library(
LIBDEPS=[
'address_restriction',
'auth',
- 'auth_rolename',
'authentication_restriction',
'authorization_manager_global',
'authprivilege',
@@ -196,6 +173,9 @@ env.Library(
'$BUILD_DIR/mongo/bson/mutable/mutable_bson',
'$BUILD_DIR/mongo/db/common',
],
+ LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/rpc/metadata_impersonated_user',
+ ]
)
env.Library(
@@ -299,7 +279,6 @@ env.Library(
'authprivilege',
'sasl_options',
'user',
- 'user_name',
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/base/secure_allocator',
'$BUILD_DIR/mongo/crypto/sha_block_${MONGO_CRYPTO}',
diff --git a/src/mongo/db/auth/auth_types.idl b/src/mongo/db/auth/auth_types.idl
new file mode 100644
index 00000000000..f035dc7f488
--- /dev/null
+++ b/src/mongo/db/auth/auth_types.idl
@@ -0,0 +1,38 @@
+# Copyright (C) 2018 MongoDB Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License, version 3,
+# as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+global:
+ cpp_namespace: "mongo"
+ cpp_includes:
+ - "mongo/db/auth/user_name.h"
+ - "mongo/db/auth/role_name.h"
+
+imports:
+ - "mongo/idl/basic_types.idl"
+
+types:
+ UserName:
+ bson_serialization_type: any
+ description: "A struct representing a UserName"
+ cpp_type: "UserName"
+ deserializer: "mongo::UserName::parseFromBSON"
+ serializer: "mongo::UserName::serializeToBSON"
+
+ RoleName:
+ bson_serialization_type: any
+ description: "A struct representing a Role"
+ cpp_type: "RoleName"
+ deserializer: "mongo::RoleName::parseFromBSON"
+ serializer: "mongo::RoleName::serializeToBSON"
diff --git a/src/mongo/db/auth/impersonation_session.cpp b/src/mongo/db/auth/impersonation_session.cpp
index 8b9a5f09fc7..666522cd043 100644
--- a/src/mongo/db/auth/impersonation_session.cpp
+++ b/src/mongo/db/auth/impersonation_session.cpp
@@ -39,7 +39,7 @@
#include "mongo/db/auth/resource_pattern.h"
#include "mongo/db/client.h"
#include "mongo/db/operation_context.h"
-#include "mongo/rpc/metadata/audit_metadata.h"
+#include "mongo/rpc/metadata/impersonated_user_metadata.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/destructor_guard.h"
@@ -47,28 +47,24 @@ namespace mongo {
ImpersonationSessionGuard::ImpersonationSessionGuard(OperationContext* opCtx) : _opCtx(opCtx) {
auto authSession = AuthorizationSession::get(_opCtx->getClient());
-
- const auto& impersonatedUsersAndRoles =
- rpc::AuditMetadata::get(opCtx).getImpersonatedUsersAndRoles();
-
- if (impersonatedUsersAndRoles != boost::none) {
+ const auto impersonatedUsersAndRoles = rpc::getImpersonatedUserMetadata(opCtx);
+ if (impersonatedUsersAndRoles) {
uassert(ErrorCodes::Unauthorized,
"Unauthorized use of impersonation metadata.",
authSession->isAuthorizedForPrivilege(
Privilege(ResourcePattern::forClusterResource(), ActionType::impersonate)));
-
fassert(ErrorCodes::InternalError, !authSession->isImpersonating());
-
- authSession->setImpersonatedUserData(std::get<0>(*impersonatedUsersAndRoles),
- std::get<1>(*impersonatedUsersAndRoles));
+ authSession->setImpersonatedUserData(impersonatedUsersAndRoles->getUsers(),
+ impersonatedUsersAndRoles->getRoles());
_active = true;
+ return;
}
}
ImpersonationSessionGuard::~ImpersonationSessionGuard() {
- DESTRUCTOR_GUARD(if (_active) {
+ if (_active) {
AuthorizationSession::get(_opCtx->getClient())->clearImpersonatedUserData();
- })
+ }
}
} // namespace mongo
diff --git a/src/mongo/db/auth/impersonation_session.h b/src/mongo/db/auth/impersonation_session.h
index a2986cb0e86..e32363be4e9 100644
--- a/src/mongo/db/auth/impersonation_session.h
+++ b/src/mongo/db/auth/impersonation_session.h
@@ -27,6 +27,7 @@
*/
#include "mongo/base/disallow_copying.h"
+#include "mongo/rpc/metadata/impersonated_user_metadata.h"
namespace mongo {
class OperationContext;
@@ -43,6 +44,7 @@ public:
~ImpersonationSessionGuard();
private:
+ rpc::MaybeImpersonatedUserMetadata _oldImpersonationData;
OperationContext* _opCtx;
bool _active{false};
};
diff --git a/src/mongo/db/auth/role_name.cpp b/src/mongo/db/auth/role_name.cpp
index 6c22d03a7c5..a49b80e1fba 100644
--- a/src/mongo/db/auth/role_name.cpp
+++ b/src/mongo/db/auth/role_name.cpp
@@ -33,6 +33,7 @@
#include <string>
#include "mongo/base/string_data.h"
+#include "mongo/db/auth/authorization_manager.h"
#include "mongo/util/assert_util.h"
namespace mongo {
@@ -52,4 +53,41 @@ std::ostream& operator<<(std::ostream& os, const RoleName& name) {
return os << name.getFullName();
}
+RoleName RoleName::parseFromBSON(const BSONElement& elem) {
+ auto obj = elem.embeddedObjectUserCheck();
+ std::array<BSONElement, 2> fields;
+ obj.getFields(
+ {AuthorizationManager::ROLE_NAME_FIELD_NAME, AuthorizationManager::ROLE_DB_FIELD_NAME},
+ &fields);
+ const auto& nameField = fields[0];
+ uassert(ErrorCodes::BadValue,
+ str::stream() << "user name must contain a string field named: "
+ << AuthorizationManager::ROLE_NAME_FIELD_NAME,
+ nameField.type() == String);
+
+ const auto& dbField = fields[1];
+ uassert(ErrorCodes::BadValue,
+ str::stream() << "role name must contain a string field named: "
+ << AuthorizationManager::ROLE_DB_FIELD_NAME,
+ nameField.type() == String);
+
+ return RoleName(nameField.valueStringData(), dbField.valueStringData());
+}
+
+void RoleName::serializeToBSON(StringData fieldName, BSONObjBuilder* bob) const {
+ BSONObjBuilder sub(bob->subobjStart(fieldName));
+ _serializeToSubObj(&sub);
+}
+
+void RoleName::serializeToBSON(BSONArrayBuilder* bob) const {
+ BSONObjBuilder sub(bob->subobjStart());
+ _serializeToSubObj(&sub);
+}
+
+void RoleName::_serializeToSubObj(BSONObjBuilder* sub) const {
+ sub->append(AuthorizationManager::ROLE_NAME_FIELD_NAME, getRole());
+ sub->append(AuthorizationManager::ROLE_DB_FIELD_NAME, getDB());
+}
+
+
} // namespace mongo
diff --git a/src/mongo/db/auth/role_name.h b/src/mongo/db/auth/role_name.h
index 5d9981cf9dc..809aa2c4d69 100644
--- a/src/mongo/db/auth/role_name.h
+++ b/src/mongo/db/auth/role_name.h
@@ -36,6 +36,8 @@
#include "mongo/base/disallow_copying.h"
#include "mongo/base/string_data.h"
+#include "mongo/bson/bsonelement.h"
+#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/platform/hash_namespace.h"
#include "mongo/util/assert_util.h"
@@ -51,6 +53,11 @@ public:
RoleName() : _splitPoint(0) {}
RoleName(StringData role, StringData dbname);
+ // Added for IDL support
+ static RoleName parseFromBSON(const BSONElement& elem);
+ void serializeToBSON(StringData fieldName, BSONObjBuilder* bob) const;
+ void serializeToBSON(BSONArrayBuilder* bob) const;
+
/**
* Gets the name of the role excluding the "@dbname" component.
*/
@@ -88,6 +95,8 @@ public:
private:
std::string _fullName; // The full name, stored as a string. "role@db".
size_t _splitPoint; // The index of the "@" separating the role and db name parts.
+
+ void _serializeToSubObj(BSONObjBuilder* sub) const;
};
static inline bool operator==(const RoleName& lhs, const RoleName& rhs) {
@@ -213,4 +222,13 @@ RoleNameIterator makeRoleNameIteratorForContainer(const Container& container) {
return makeRoleNameIterator(container.begin(), container.end());
}
+template <typename Container>
+Container roleNameIteratorToContainer(RoleNameIterator it) {
+ Container container;
+ while (it.more()) {
+ container.emplace_back(it.next());
+ }
+ return container;
+}
+
} // namespace mongo
diff --git a/src/mongo/db/auth/user_name.cpp b/src/mongo/db/auth/user_name.cpp
index 3bcdf3ad813..dd16bc993b3 100644
--- a/src/mongo/db/auth/user_name.cpp
+++ b/src/mongo/db/auth/user_name.cpp
@@ -32,6 +32,7 @@
#include <string>
#include "mongo/base/string_data.h"
+#include "mongo/db/auth/authorization_manager.h"
#include "mongo/util/assert_util.h"
namespace mongo {
@@ -62,6 +63,49 @@ StatusWith<UserName> UserName::parse(StringData userNameStr) {
return UserName(userNamePortion, userDBPortion);
}
+UserName UserName::parseFromBSON(const BSONElement& elem) {
+ if (elem.type() == String) {
+ return uassertStatusOK(UserName::parse(elem.valueStringData()));
+ } else if (elem.type() == Object) {
+ const auto obj = elem.embeddedObject();
+ std::array<BSONElement, 2> fields;
+ obj.getFields(
+ {AuthorizationManager::USER_NAME_FIELD_NAME, AuthorizationManager::USER_DB_FIELD_NAME},
+ &fields);
+
+ const auto& nameField = fields[0];
+ uassert(ErrorCodes::BadValue,
+ str::stream() << "username must contain a string field named: "
+ << AuthorizationManager::USER_NAME_FIELD_NAME,
+ nameField.type() == String);
+
+ const auto& dbField = fields[1];
+ uassert(ErrorCodes::BadValue,
+ str::stream() << "username must contain a string field named: "
+ << AuthorizationManager::USER_DB_FIELD_NAME,
+ dbField.type() == String);
+
+ return UserName(nameField.valueStringData(), dbField.valueStringData());
+ } else {
+ uasserted(ErrorCodes::BadValue, "username must be either a string or an object");
+ }
+}
+
+void UserName::serializeToBSON(StringData fieldName, BSONObjBuilder* bob) const {
+ BSONObjBuilder sub(bob->subobjStart(fieldName));
+ _serializeToSubObj(&sub);
+}
+
+void UserName::serializeToBSON(BSONArrayBuilder* bab) const {
+ BSONObjBuilder sub(bab->subobjStart());
+ _serializeToSubObj(&sub);
+}
+
+void UserName::_serializeToSubObj(BSONObjBuilder* sub) const {
+ *sub << AuthorizationManager::USER_NAME_FIELD_NAME << getUser()
+ << AuthorizationManager::USER_DB_FIELD_NAME << getDB();
+}
+
std::ostream& operator<<(std::ostream& os, const UserName& name) {
return os << name.getFullName();
}
diff --git a/src/mongo/db/auth/user_name.h b/src/mongo/db/auth/user_name.h
index a1b04f010d4..22c62db2d82 100644
--- a/src/mongo/db/auth/user_name.h
+++ b/src/mongo/db/auth/user_name.h
@@ -36,6 +36,8 @@
#include "mongo/base/disallow_copying.h"
#include "mongo/base/status_with.h"
#include "mongo/base/string_data.h"
+#include "mongo/bson/bsonelement.h"
+#include "mongo/bson/bsonobjbuilder.h"
namespace mongo {
@@ -54,6 +56,13 @@ public:
*/
static StatusWith<UserName> parse(StringData userNameStr);
+ /*
+ * These methods support parsing usernames from IDL
+ */
+ static UserName parseFromBSON(const BSONElement& elem);
+ void serializeToBSON(StringData fieldName, BSONObjBuilder* bob) const;
+ void serializeToBSON(BSONArrayBuilder* bob) const;
+
/**
* Gets the user part of a UserName.
*/
@@ -95,6 +104,8 @@ public:
}
private:
+ void _serializeToSubObj(BSONObjBuilder* sub) const;
+
std::string _fullName; // The full name, stored as a string. "user@db".
size_t _splitPoint; // The index of the "@" separating the user and db name parts.
};
diff --git a/src/mongo/db/curop.cpp b/src/mongo/db/curop.cpp
index dbe90b901f4..a8576d29120 100644
--- a/src/mongo/db/curop.cpp
+++ b/src/mongo/db/curop.cpp
@@ -38,6 +38,7 @@
#include "mongo/base/disallow_copying.h"
#include "mongo/bson/mutable/document.h"
+#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/client.h"
#include "mongo/db/commands.h"
#include "mongo/db/commands/server_status_metric.h"
@@ -47,6 +48,7 @@
#include "mongo/db/query/plan_summary_stats.h"
#include "mongo/rpc/metadata/client_metadata.h"
#include "mongo/rpc/metadata/client_metadata_ismaster.h"
+#include "mongo/rpc/metadata/impersonated_user_metadata.h"
#include "mongo/util/hex.h"
#include "mongo/util/log.h"
#include "mongo/util/net/socket_utils.h"
@@ -249,6 +251,32 @@ void CurOp::reportCurrentOpForClient(OperationContext* opCtx,
infoBuilder->append("currentOpTime",
opCtx->getServiceContext()->getPreciseClockSource()->now().toString());
+ auto authSession = AuthorizationSession::get(client);
+ // Depending on whether we're impersonating or not, this might be "effectiveUsers" or
+ // "userImpersonators".
+ const auto serializeAuthenticatedUsers = [&](StringData name) {
+ if (authSession->isAuthenticated()) {
+ BSONArrayBuilder users(infoBuilder->subarrayStart(name));
+ for (auto userIt = authSession->getAuthenticatedUserNames(); userIt.more();
+ userIt.next()) {
+ userIt->serializeToBSON(&users);
+ }
+ }
+ };
+
+ auto maybeImpersonationData = rpc::getImpersonatedUserMetadata(clientOpCtx);
+ if (maybeImpersonationData) {
+ BSONArrayBuilder users(infoBuilder->subarrayStart("effectiveUsers"));
+ for (const auto& user : maybeImpersonationData->getUsers()) {
+ user.serializeToBSON(&users);
+ }
+
+ users.doneFast();
+ serializeAuthenticatedUsers("userImpersonators"_sd);
+ } else {
+ serializeAuthenticatedUsers("effectiveUsers"_sd);
+ }
+
if (clientOpCtx) {
infoBuilder->append("opid", clientOpCtx->getOpID());
if (clientOpCtx->isKillPending()) {
diff --git a/src/mongo/embedded/embedded_auth_session.cpp b/src/mongo/embedded/embedded_auth_session.cpp
index fecb4e6d561..e01e0210e0b 100644
--- a/src/mongo/embedded/embedded_auth_session.cpp
+++ b/src/mongo/embedded/embedded_auth_session.cpp
@@ -80,7 +80,9 @@ public:
}
bool isAuthenticated() override {
- UASSERT_NOT_IMPLEMENTED;
+ // It should always be okay to check whether you're authenticated, but on embedded
+ // it should always return false
+ return false;
}
UserNameIterator getAuthenticatedUserNames() override {
diff --git a/src/mongo/rpc/SConscript b/src/mongo/rpc/SConscript
index 53757b9fcb7..f7883dbc9e2 100644
--- a/src/mongo/rpc/SConscript
+++ b/src/mongo/rpc/SConscript
@@ -80,7 +80,7 @@ env.Library(
],
LIBDEPS=[
'client_metadata',
- 'audit_metadata',
+ 'metadata_impersonated_user',
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/bson/util/bson_extract',
'$BUILD_DIR/mongo/client/read_preference',
@@ -90,20 +90,21 @@ env.Library(
],
)
-env.Clone().InjectModule("enterprise").Library(
+env.Library(
target=[
- 'audit_metadata',
+ 'metadata_impersonated_user'
],
source=[
- 'metadata/audit_metadata.cpp',
- ],
- LIBDEPS_PRIVATE=[
- '$BUILD_DIR/mongo/bson/util/bson_extract',
- '$BUILD_DIR/mongo/db/auth/auth_rolename',
- '$BUILD_DIR/mongo/db/auth/user_name',
+ 'metadata/impersonated_user_metadata.cpp',
+ env.Idlc('metadata/impersonated_user_metadata.idl')[0],
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/db/service_context',
+ ],
+ LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/db/auth/auth',
+ '$BUILD_DIR/mongo/db/server_options',
],
)
diff --git a/src/mongo/rpc/metadata.cpp b/src/mongo/rpc/metadata.cpp
index 74360ead237..6359c9e1952 100644
--- a/src/mongo/rpc/metadata.cpp
+++ b/src/mongo/rpc/metadata.cpp
@@ -36,9 +36,9 @@
#include "mongo/db/jsobj.h"
#include "mongo/db/logical_clock.h"
#include "mongo/db/logical_time_validator.h"
-#include "mongo/rpc/metadata/audit_metadata.h"
#include "mongo/rpc/metadata/client_metadata_ismaster.h"
#include "mongo/rpc/metadata/config_server_metadata.h"
+#include "mongo/rpc/metadata/impersonated_user_metadata.h"
#include "mongo/rpc/metadata/logical_time_metadata.h"
#include "mongo/rpc/metadata/sharding_metadata.h"
#include "mongo/rpc/metadata/tracking_metadata.h"
@@ -53,18 +53,16 @@ BSONObj makeEmptyMetadata() {
void readRequestMetadata(OperationContext* opCtx, const BSONObj& metadataObj, bool requiresAuth) {
BSONElement readPreferenceElem;
- BSONElement auditElem;
BSONElement configSvrElem;
BSONElement trackingElem;
BSONElement clientElem;
BSONElement logicalTimeElem;
+ BSONElement impersonationElem;
for (const auto& metadataElem : metadataObj) {
auto fieldName = metadataElem.fieldNameStringData();
if (fieldName == "$readPreference") {
readPreferenceElem = metadataElem;
- } else if (fieldName == AuditMetadata::fieldName()) {
- auditElem = metadataElem;
} else if (fieldName == ConfigServerMetadata::fieldName()) {
configSvrElem = metadataElem;
} else if (fieldName == ClientMetadata::fieldName()) {
@@ -73,6 +71,8 @@ void readRequestMetadata(OperationContext* opCtx, const BSONObj& metadataObj, bo
trackingElem = metadataElem;
} else if (fieldName == LogicalTimeMetadata::fieldName()) {
logicalTimeElem = metadataElem;
+ } else if (fieldName == kImpersonationMetadataSectionName) {
+ impersonationElem = metadataElem;
}
}
@@ -81,7 +81,7 @@ void readRequestMetadata(OperationContext* opCtx, const BSONObj& metadataObj, bo
uassertStatusOK(ReadPreferenceSetting::fromInnerBSON(readPreferenceElem));
}
- AuditMetadata::get(opCtx) = uassertStatusOK(AuditMetadata::readFromMetadata(auditElem));
+ readImpersonatedUserMetadata(impersonationElem, opCtx);
uassertStatusOK(ClientMetadataIsMasterState::readFromMetadata(opCtx, clientElem));
diff --git a/src/mongo/rpc/metadata/audit_metadata.cpp b/src/mongo/rpc/metadata/audit_metadata.cpp
deleted file mode 100644
index 1dacabd7dc4..00000000000
--- a/src/mongo/rpc/metadata/audit_metadata.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2015 MongoDB Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the GNU Affero General Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#include "mongo/platform/basic.h"
-
-#include "mongo/rpc/metadata/audit_metadata.h"
-
-#include <utility>
-
-#include "mongo/base/status_with.h"
-#include "mongo/bson/util/bson_extract.h"
-#include "mongo/db/auth/role_name.h"
-#include "mongo/db/auth/user_name.h"
-
-namespace mongo {
-namespace rpc {
-
-const OperationContext::Decoration<AuditMetadata> AuditMetadata::get =
- OperationContext::declareDecoration<AuditMetadata>();
-
-AuditMetadata::AuditMetadata(boost::optional<UsersAndRoles> impersonatedUsersAndRoles)
- : _impersonatedUsersAndRoles(std::move(impersonatedUsersAndRoles)) {}
-
-#if !defined(MONGO_ENTERPRISE_VERSION)
-
-StatusWith<AuditMetadata> AuditMetadata::readFromMetadata(const BSONObj&) {
- return AuditMetadata{};
-}
-
-StatusWith<AuditMetadata> AuditMetadata::readFromMetadata(const BSONElement&) {
- return AuditMetadata{};
-}
-
-Status AuditMetadata::writeToMetadata(BSONObjBuilder*) const {
- return Status::OK();
-}
-
-#endif
-
-const boost::optional<AuditMetadata::UsersAndRoles>& AuditMetadata::getImpersonatedUsersAndRoles()
- const {
- return _impersonatedUsersAndRoles;
-}
-
-} // namespace rpc
-} // namespace mongo
diff --git a/src/mongo/rpc/metadata/audit_metadata.h b/src/mongo/rpc/metadata/audit_metadata.h
deleted file mode 100644
index 0724001d97c..00000000000
--- a/src/mongo/rpc/metadata/audit_metadata.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2015 MongoDB Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the GNU Affero General Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include <boost/optional.hpp>
-#include <vector>
-
-#include "mongo/base/disallow_copying.h"
-#include "mongo/db/auth/role_name.h"
-#include "mongo/db/auth/user_name.h"
-#include "mongo/db/operation_context.h"
-
-namespace mongo {
-class BSONObj;
-class BSONObjBuilder;
-class Status;
-template <typename T>
-class StatusWith;
-
-namespace rpc {
-
-/**
- * This class comprises the request metadata fields involving auditing.
- */
-class AuditMetadata {
-public:
- static const OperationContext::Decoration<AuditMetadata> get;
-
- // Decorable requires a default constructor.
- AuditMetadata() = default;
-
- static StatusWith<AuditMetadata> readFromMetadata(const BSONObj& metadataObj);
-
- /**
- * Parses AuditMetadata from a pre-extracted BSONElement. When reading a metadata object, this
- * form is more efficient as it permits parsing the metadata in one pass.
- */
- static StatusWith<AuditMetadata> readFromMetadata(const BSONElement& metadataElem);
-
- Status writeToMetadata(BSONObjBuilder* metadataBob) const;
-
- using UsersAndRoles = std::tuple<std::vector<UserName>, std::vector<RoleName>>;
-
- const boost::optional<UsersAndRoles>& getImpersonatedUsersAndRoles() const;
-
- AuditMetadata(boost::optional<UsersAndRoles> impersonatedUsersAndRoles);
-
- static StringData fieldName() {
- return "$audit";
- }
-
-private:
- boost::optional<UsersAndRoles> _impersonatedUsersAndRoles;
-};
-
-} // namespace rpc
-} // namespace mongo
diff --git a/src/mongo/rpc/metadata/impersonated_user_metadata.cpp b/src/mongo/rpc/metadata/impersonated_user_metadata.cpp
new file mode 100644
index 00000000000..b8e9e77c595
--- /dev/null
+++ b/src/mongo/rpc/metadata/impersonated_user_metadata.cpp
@@ -0,0 +1,93 @@
+/**
+ * Copyright (C) 2018 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/rpc/metadata/impersonated_user_metadata.h"
+
+#include "mongo/db/auth/authorization_session.h"
+#include "mongo/db/server_options.h"
+
+namespace mongo {
+namespace rpc {
+namespace {
+
+static const OperationContext::Decoration<MaybeImpersonatedUserMetadata> getForOpCtx =
+ OperationContext::declareDecoration<MaybeImpersonatedUserMetadata>();
+} // namespace
+
+MaybeImpersonatedUserMetadata getImpersonatedUserMetadata(OperationContext* opCtx) {
+ return opCtx ? getForOpCtx(opCtx) : boost::none;
+}
+
+void readImpersonatedUserMetadata(const BSONElement& elem, OperationContext* opCtx) {
+ // If we have no opCtx, which does appear to happen, don't do anything.
+ if (!opCtx) {
+ return;
+ }
+
+ // Always reset the current impersonation data to boost::none.
+ getForOpCtx(opCtx) = boost::none;
+ if (elem.type() == Object) {
+ IDLParserErrorContext errCtx(kImpersonationMetadataSectionName);
+ auto data = ImpersonatedUserMetadata::parse(errCtx, elem.embeddedObject());
+
+ // Set the impersonation data only if there are actually impersonated
+ // users/roles.
+ if ((!data.getUsers().empty()) || (!data.getRoles().empty())) {
+ getForOpCtx(opCtx) = std::move(data);
+ }
+ }
+}
+
+void writeAuthDataToImpersonatedUserMetadata(OperationContext* opCtx, BSONObjBuilder* out) {
+ // If we have no opCtx, which does appear to happen, don't do anything.
+ if (!opCtx) {
+ return;
+ }
+
+ // Otherwise construct a metadata section from the list of authenticated users/roles
+ auto authSession = AuthorizationSession::get(opCtx->getClient());
+ ImpersonatedUserMetadata metadata;
+ metadata.setUsers(userNameIteratorToContainer<std::vector<UserName>>(
+ authSession->getAuthenticatedUserNames()));
+
+ metadata.setRoles(roleNameIteratorToContainer<std::vector<RoleName>>(
+ authSession->getAuthenticatedRoleNames()));
+
+ // If there are no users/roles being impersonated just exit
+ if (metadata.getUsers().empty() && metadata.getRoles().empty()) {
+ return;
+ }
+
+ BSONObjBuilder section(out->subobjStart(kImpersonationMetadataSectionName));
+ metadata.serialize(&section);
+}
+
+} // namespace rpc
+} // namespace mongo
diff --git a/src/mongo/rpc/metadata/impersonated_user_metadata.h b/src/mongo/rpc/metadata/impersonated_user_metadata.h
new file mode 100644
index 00000000000..f379b509d4c
--- /dev/null
+++ b/src/mongo/rpc/metadata/impersonated_user_metadata.h
@@ -0,0 +1,73 @@
+/**
+ * Copyright (C) 2018 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include "boost/optional.hpp"
+
+#include "mongo/db/operation_context.h"
+#include "mongo/rpc/metadata/impersonated_user_metadata_gen.h"
+
+namespace mongo {
+namespace rpc {
+
+/*
+ * The name of the BSON element in message metadata that contains the impersonated user data
+ *
+ * This is called "$audit" because in pre-4.2 the enterprise audit subsystem already passed
+ * the impersonated users info around in metadata for auditing purposes. This has been lifted
+ * into the community edition and appears in network messages as "$audit" for backwards
+ * compatibility.
+ *
+ * This metadata should only appear in requests from mongos to mongod.
+ */
+static constexpr auto kImpersonationMetadataSectionName = "$audit"_sd;
+
+/*
+ * A type that maybe contains parsed ImpersonationUserMetadata
+ */
+using MaybeImpersonatedUserMetadata = boost::optional<ImpersonatedUserMetadata>;
+
+/*
+ * Gets the current impersonation data from the OpCtx (assumes readImpersonatedUserMetadata
+ * has already been called)
+ */
+MaybeImpersonatedUserMetadata getImpersonatedUserMetadata(OperationContext* opCtx);
+
+/*
+ * Parses any impersonation data out of a metdata bson obj and into the opCtx
+ */
+void readImpersonatedUserMetadata(const BSONElement& elem, OperationContext* opCtx);
+
+/*
+ * Writes the current impersonation metadata off the opCtx and into a BSONObjBuilder
+ */
+void writeAuthDataToImpersonatedUserMetadata(OperationContext* opCtx, BSONObjBuilder* out);
+
+} // namespace rpc
+} // namespace mongo
diff --git a/src/mongo/rpc/metadata/impersonated_user_metadata.idl b/src/mongo/rpc/metadata/impersonated_user_metadata.idl
new file mode 100644
index 00000000000..c2b15e325fc
--- /dev/null
+++ b/src/mongo/rpc/metadata/impersonated_user_metadata.idl
@@ -0,0 +1,35 @@
+# Copyright (C) 2018 MongoDB Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License, version 3,
+# as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+global:
+ cpp_namespace: "mongo::rpc"
+
+imports:
+ - "mongo/idl/basic_types.idl"
+ - "mongo/db/auth/auth_types.idl"
+
+structs:
+ # This is the IDL version of the old enterprise-only Audit metadata struct
+ ImpersonatedUserMetadata:
+ description: "A struct representing the impersonated users from a mongos"
+ strict: true
+ fields:
+ "$impersonatedUsers":
+ type: array<UserName>
+ cpp_name: "users"
+ "$impersonatedRoles":
+ type: array<RoleName>
+ cpp_name: "roles"
+
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript
index 522419420c8..1dbc4f3d9a0 100644
--- a/src/mongo/s/SConscript
+++ b/src/mongo/s/SConscript
@@ -333,7 +333,6 @@ env.Library(
'sharding_egress_metadata_hook.cpp',
],
LIBDEPS=[
- '$BUILD_DIR/mongo/db/audit',
'$BUILD_DIR/mongo/util/concurrency/thread_pool',
'grid',
],
diff --git a/src/mongo/s/sharding_egress_metadata_hook.cpp b/src/mongo/s/sharding_egress_metadata_hook.cpp
index d0f9a2f39e2..0c42bd93cc7 100644
--- a/src/mongo/s/sharding_egress_metadata_hook.cpp
+++ b/src/mongo/s/sharding_egress_metadata_hook.cpp
@@ -33,10 +33,10 @@
#include <string>
#include "mongo/base/status.h"
-#include "mongo/db/audit.h"
#include "mongo/db/service_context.h"
#include "mongo/rpc/metadata/client_metadata_ismaster.h"
#include "mongo/rpc/metadata/config_server_metadata.h"
+#include "mongo/rpc/metadata/impersonated_user_metadata.h"
#include "mongo/rpc/metadata/metadata_hook.h"
#include "mongo/rpc/metadata/repl_set_metadata.h"
#include "mongo/s/client/shard_registry.h"
@@ -55,7 +55,7 @@ ShardingEgressMetadataHook::ShardingEgressMetadataHook(ServiceContext* serviceCo
Status ShardingEgressMetadataHook::writeRequestMetadata(OperationContext* opCtx,
BSONObjBuilder* metadataBob) {
try {
- audit::writeImpersonatedUsersToMetadata(opCtx, metadataBob);
+ writeAuthDataToImpersonatedUserMetadata(opCtx, metadataBob);
ClientMetadataIsMasterState::writeToMetadata(opCtx, metadataBob);
rpc::ConfigServerMetadata(_getConfigServerOpTime()).writeToMetadata(metadataBob);
return Status::OK();
diff --git a/src/mongo/util/net/SConscript b/src/mongo/util/net/SConscript
index 95a167f88c3..cbdad7a5273 100644
--- a/src/mongo/util/net/SConscript
+++ b/src/mongo/util/net/SConscript
@@ -111,7 +111,7 @@ env.Library(
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
- '$BUILD_DIR/mongo/db/auth/auth_rolename',
+ '$BUILD_DIR/mongo/db/auth/auth',
'$BUILD_DIR/third_party/shim_asio',
'network',
'socket',