summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorADAM David Alan Martin <adam.martin@10gen.com>2018-05-11 12:59:17 -0400
committerADAM David Alan Martin <adam.martin@10gen.com>2018-05-11 12:59:17 -0400
commitecf8ad987548705e773d23d5ddc3973cbc1ea7e5 (patch)
tree62164575b6303aebecbe41670c74b713cfa314c7 /src
parent56cbcf28c6bd4d9f9e739fb834d83b61c99516f1 (diff)
downloadmongo-ecf8ad987548705e773d23d5ddc3973cbc1ea7e5.tar.gz
SERVER-33008 Slice Authorization framework
The Authorization framework was intertwined with many subsystems and needed to be properly abstracted in order to facilitate cutting down on certain unnecessary dependencies in some libraries. This also facilitates creating a reduced authorization framework for use in embedded builds.
Diffstat (limited to 'src')
-rw-r--r--src/mongo/SConscript5
-rw-r--r--src/mongo/base/counter.h4
-rw-r--r--src/mongo/base/shim.h4
-rw-r--r--src/mongo/client/SConscript4
-rw-r--r--src/mongo/client/embedded/SConscript3
-rw-r--r--src/mongo/db/SConscript46
-rw-r--r--src/mongo/db/auth/SConscript169
-rw-r--r--src/mongo/db/auth/auth_decorations.cpp3
-rw-r--r--src/mongo/db/auth/authorization_manager.cpp734
-rw-r--r--src/mongo/db/auth/authorization_manager.h257
-rw-r--r--src/mongo/db/auth/authorization_manager_global.cpp10
-rw-r--r--src/mongo/db/auth/authorization_manager_impl.cpp765
-rw-r--r--src/mongo/db/auth/authorization_manager_impl.h246
-rw-r--r--src/mongo/db/auth/authorization_manager_mock_init.cpp55
-rw-r--r--src/mongo/db/auth/authorization_manager_test.cpp9
-rw-r--r--src/mongo/db/auth/authorization_session.cpp1015
-rw-r--r--src/mongo/db/auth/authorization_session.h198
-rw-r--r--src/mongo/db/auth/authorization_session_for_test.h5
-rw-r--r--src/mongo/db/auth/authorization_session_impl.cpp1063
-rw-r--r--src/mongo/db/auth/authorization_session_impl.h232
-rw-r--r--src/mongo/db/auth/authorization_session_test.cpp12
-rw-r--r--src/mongo/db/auth/authz_manager_external_state.cpp2
-rw-r--r--src/mongo/db/auth/authz_manager_external_state.h6
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_d.cpp5
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_mock.cpp6
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_s.cpp6
-rw-r--r--src/mongo/db/auth/authz_session_external_state.cpp2
-rw-r--r--src/mongo/db/auth/authz_session_external_state.h6
-rw-r--r--src/mongo/db/auth/authz_session_external_state_d.cpp5
-rw-r--r--src/mongo/db/auth/authz_session_external_state_mock.cpp (renamed from src/mongo/db/authz_manager_external_state_factory_d.cpp)26
-rw-r--r--src/mongo/db/auth/authz_session_external_state_mock.h3
-rw-r--r--src/mongo/db/auth/authz_session_external_state_s.cpp5
-rw-r--r--src/mongo/db/auth/sasl_authentication_session_test.cpp6
-rw-r--r--src/mongo/db/auth/sasl_mechanism_registry_test.cpp6
-rw-r--r--src/mongo/db/auth/sasl_scram_test.cpp21
-rw-r--r--src/mongo/db/auth/user.cpp9
-rw-r--r--src/mongo/db/auth/user.h9
-rw-r--r--src/mongo/db/catalog/SConscript9
-rw-r--r--src/mongo/db/commands/SConscript23
-rw-r--r--src/mongo/db/exec/SConscript3
-rw-r--r--src/mongo/db/free_mon/SConscript3
-rw-r--r--src/mongo/db/ftdc/SConscript3
-rw-r--r--src/mongo/db/logical_session_cache_test.cpp12
-rw-r--r--src/mongo/db/logical_session_id_test.cpp21
-rw-r--r--src/mongo/db/ops/SConscript1
-rw-r--r--src/mongo/db/pipeline/SConscript10
-rw-r--r--src/mongo/db/query/SConscript2
-rw-r--r--src/mongo/db/repl/SConscript66
-rw-r--r--src/mongo/db/repl/topology_coordinator_v1_test.cpp10
-rw-r--r--src/mongo/db/s/SConscript9
-rw-r--r--src/mongo/db/storage/ephemeral_for_test/SConscript2
-rw-r--r--src/mongo/db/storage/kv/SConscript5
-rw-r--r--src/mongo/db/storage/mmap_v1/SConscript1
-rw-r--r--src/mongo/db/storage/mobile/SConscript2
-rw-r--r--src/mongo/db/storage/wiredtiger/SConscript5
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit_test.cpp3
-rw-r--r--src/mongo/db/views/SConscript2
-rw-r--r--src/mongo/dbtests/SConscript2
-rw-r--r--src/mongo/executor/SConscript3
-rw-r--r--src/mongo/rpc/SConscript21
-rw-r--r--src/mongo/s/SConscript1
-rw-r--r--src/mongo/s/catalog/SConscript1
-rw-r--r--src/mongo/s/client/SConscript1
-rw-r--r--src/mongo/s/commands/SConscript10
-rw-r--r--src/mongo/s/query/SConscript15
-rw-r--r--src/mongo/s/server.cpp8
-rw-r--r--src/mongo/s/write_ops/SConscript2
-rw-r--r--src/mongo/shell/shell_utils.cpp3
68 files changed, 2922 insertions, 2299 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript
index ab5d89cb24c..3cb34a42bcf 100644
--- a/src/mongo/SConscript
+++ b/src/mongo/SConscript
@@ -292,6 +292,8 @@ env.Library(
"db/db.cpp",
],
LIBDEPS_PRIVATE=[
+ 'base',
+ 'db/auth/authmongod',
'db/catalog/health_log',
'db/commands/mongod',
'db/commands/mongod_fcv',
@@ -462,8 +464,9 @@ if not has_option('noshell') and usemozjs:
"shell/shell_utils_launcher.cpp",
],
LIBDEPS=[
- 'db/logical_session_id_helpers',
'db/catalog/index_key_validate',
+ 'db/logical_session_id_helpers',
+ 'db/mongohasher',
'db/query/command_request_response',
'db/query/query_request',
'db/server_options_core',
diff --git a/src/mongo/base/counter.h b/src/mongo/base/counter.h
index fad095fc385..02e2318a03a 100644
--- a/src/mongo/base/counter.h
+++ b/src/mongo/base/counter.h
@@ -1,5 +1,3 @@
-// counter.h
-
/**
* Copyright (C) 2008-2012 10gen Inc.
*
@@ -66,4 +64,4 @@ public:
private:
AtomicInt64 _counter;
};
-}
+} // namespace mongo
diff --git a/src/mongo/base/shim.h b/src/mongo/base/shim.h
index 49a21dd81a4..025c6a2a65c 100644
--- a/src/mongo/base/shim.h
+++ b/src/mongo/base/shim.h
@@ -146,7 +146,7 @@ const bool checkShimsViaTUHook = false;
struct LibTUHookTypeBase { \
LibTUHookTypeBase(); \
}; \
- template <bool required = mongo::checkShimsViaTUHook> \
+ template <bool required = true> \
struct LibTUHookType : LibTUHookTypeBase {}; \
using LibTUHook = LibTUHookType<>; \
struct ImplTUHookTypeBase { \
@@ -166,7 +166,7 @@ const bool checkShimsViaTUHook = false;
return this; \
} \
MongoShimImplGuts* lib(const LibTUHook* const) { \
- MONGO_SHIM_TU_HOOK(LibTUHook); \
+ LibTUHook{}; \
return this; \
} \
MongoShimImplGuts* impl(const ImplTUHook* const) { \
diff --git a/src/mongo/client/SConscript b/src/mongo/client/SConscript
index 5f054e5588d..91d5091aa77 100644
--- a/src/mongo/client/SConscript
+++ b/src/mongo/client/SConscript
@@ -176,6 +176,8 @@ clientDriverEnv.Library(
LIBDEPS=[
'$BUILD_DIR/mongo/db/auth/authcommon',
'$BUILD_DIR/mongo/db/dbmessage',
+ '$BUILD_DIR/mongo/db/query/command_request_response',
+ '$BUILD_DIR/mongo/db/query/query_request',
'$BUILD_DIR/mongo/db/wire_version',
'$BUILD_DIR/mongo/db/write_concern_options',
'$BUILD_DIR/mongo/executor/connection_pool_stats',
@@ -314,7 +316,7 @@ env.CppUnitTest(
source='fetcher_test.cpp',
LIBDEPS=[
'fetcher',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_noop_init',
'$BUILD_DIR/mongo/executor/thread_pool_task_executor_test_fixture',
],
diff --git a/src/mongo/client/embedded/SConscript b/src/mongo/client/embedded/SConscript
index deb1c7e5181..eecf1e3387d 100644
--- a/src/mongo/client/embedded/SConscript
+++ b/src/mongo/client/embedded/SConscript
@@ -15,7 +15,7 @@ env.Library(
'$BUILD_DIR/mongo/transport/service_entry_point',
],
LIBDEPS_PRIVATE=[
- '$BUILD_DIR/mongo/db/auth/authcore',
+ '$BUILD_DIR/mongo/db/auth/auth',
'$BUILD_DIR/mongo/db/auth/authmongod',
'$BUILD_DIR/mongo/db/command_can_run_here',
'$BUILD_DIR/mongo/db/rw_concern_d',
@@ -104,7 +104,6 @@ env.Library(
'$BUILD_DIR/mongo/base',
],
LIBDEPS_PRIVATE=[
- '$BUILD_DIR/mongo/db/authz_manager_external_state_factory_d',
'$BUILD_DIR/mongo/db/catalog/catalog_impl',
'$BUILD_DIR/mongo/db/commands/fsync_locked',
'$BUILD_DIR/mongo/db/commands/mongod_fcv',
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript
index 921c8f01c9e..046fac61168 100644
--- a/src/mongo/db/SConscript
+++ b/src/mongo/db/SConscript
@@ -133,6 +133,7 @@ env.CppUnitTest(
'common',
'op_observer_d',
'service_context_d_test_fixture',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/repl/replmocks',
],
)
@@ -231,7 +232,7 @@ env.CppUnitTest(
'logical_session_id',
'logical_session_id_helpers',
'service_context',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_noop_init',
'$BUILD_DIR/mongo/unittest/concurrency',
'$BUILD_DIR/mongo/util/clock_source_mock',
@@ -536,10 +537,13 @@ env.Library(
'$BUILD_DIR/mongo/base',
],
LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/bson/mutable/mutable_bson',
'$BUILD_DIR/mongo/rpc/rpc',
+ '$BUILD_DIR/mongo/rpc/command_status',
'audit',
'command_generic_argument',
'commands/server_status_core',
+ 'namespace_string',
],
)
@@ -577,7 +581,7 @@ env.CppUnitTest(
'$BUILD_DIR/mongo/idl/idl_parser',
"commands",
"service_context_noop_init",
- "auth/authorization_manager_mock_init",
+ "auth/authmocks",
"repl/replmocks",
],
)
@@ -638,7 +642,7 @@ env.CppUnitTest(
'catalog_raii_test.cpp',
],
LIBDEPS=[
- 'auth/authorization_manager_mock_init',
+ 'auth/authmocks',
'catalog/database_holder_mock',
'catalog_raii',
'service_context_noop_init',
@@ -695,7 +699,7 @@ env.Library(
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
- '$BUILD_DIR/mongo/db/auth/authmongod',
+ '$BUILD_DIR/mongo/db/auth/auth',
'$BUILD_DIR/mongo/db/concurrency/lock_manager',
'$BUILD_DIR/mongo/db/ops/write_ops_parsers',
'$BUILD_DIR/mongo/db/s/sharding',
@@ -754,8 +758,8 @@ env.Library(
'$BUILD_DIR/mongo/base',
],
LIBDEPS_PRIVATE=[
- '$BUILD_DIR/mongo/db/auth/authcore',
- '$BUILD_DIR/mongo/db/auth/authmongod',
+ '$BUILD_DIR/mongo/db/auth/auth',
+ '$BUILD_DIR/mongo/db/auth/authprivilege',
'$BUILD_DIR/mongo/db/command_can_run_here',
'$BUILD_DIR/mongo/db/ops/write_ops_exec',
'$BUILD_DIR/mongo/db/rw_concern_d',
@@ -897,16 +901,6 @@ env.Library(
)
env.Library(
- target="authz_manager_external_state_factory_d",
- source=[
- "authz_manager_external_state_factory_d.cpp",
- ],
- LIBDEPS=[
- 'auth/authmongod',
- ],
-)
-
-env.Library(
target='query_exec',
source=[
'clientcursor.cpp',
@@ -1004,6 +998,7 @@ env.Library(
'stats/serveronly_stats',
'storage/oplog_hack',
'storage/storage_options',
+ 'update/update_driver',
],
)
@@ -1028,8 +1023,6 @@ env.Library(
"$BUILD_DIR/mongo/util/elapsed_tracker",
"$BUILD_DIR/mongo/util/net/network",
"$BUILD_DIR/third_party/shim_snappy",
- "auth/authmongod",
- "authz_manager_external_state_factory_d",
"background",
"catalog/catalog_impl",
"catalog/collection_options",
@@ -1110,6 +1103,7 @@ env.Library(
'dbhelpers',
'repair_database',
'repl/drop_pending_collection_reaper',
+ 'repl/repl_settings',
],
)
@@ -1136,7 +1130,8 @@ env.Library(
],
LIBDEPS=[
'logical_session_id',
- '$BUILD_DIR/mongo/db/auth/authcore',
+ '$BUILD_DIR/mongo/db/auth/auth',
+ '$BUILD_DIR/mongo/db/auth/authprivilege',
],
)
@@ -1162,7 +1157,7 @@ envWithAsio.CppUnitTest(
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
- '$BUILD_DIR/mongo/db/auth/authcore',
+ '$BUILD_DIR/mongo/db/auth/auth',
'$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/auth/authorization_session_for_test',
'$BUILD_DIR/mongo/db/service_context_noop_init',
@@ -1435,7 +1430,8 @@ env.Library(
'$BUILD_DIR/mongo/base',
],
LIBDEPS_PRIVATE=[
- '$BUILD_DIR/mongo/db/auth/authcore',
+ '$BUILD_DIR/mongo/db/auth/auth',
+ '$BUILD_DIR/mongo/db/auth/authprivilege',
'$BUILD_DIR/mongo/idl/idl_parser',
],
)
@@ -1560,7 +1556,8 @@ env.Library(
'service_context',
'signed_logical_time',
'time_proof_service',
- '$BUILD_DIR/mongo/db/auth/authcore',
+ '$BUILD_DIR/mongo/db/auth/auth',
+ '$BUILD_DIR/mongo/db/auth/authprivilege',
],
)
@@ -1612,6 +1609,7 @@ env.CppUnitTest(
'logical_time_validator_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/s/catalog/dist_lock_manager_mock',
'$BUILD_DIR/mongo/s/config_server_test_fixture',
'keys_collection_manager',
@@ -1639,6 +1637,7 @@ env.Library(
LIBDEPS= [
'logical_clock',
'signed_logical_time',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/s/sharding_mongod_test_fixture',
'$BUILD_DIR/mongo/util/clock_source_mock'
],
@@ -1662,6 +1661,7 @@ env.CppUnitTest(
'keys_collection_manager_sharding_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/s/catalog/dist_lock_manager_mock',
'$BUILD_DIR/mongo/s/config_server_test_fixture',
'keys_collection_manager',
@@ -1784,6 +1784,7 @@ env.CppUnitTest(
],
LIBDEPS=[
'query_exec',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/repl/mock_repl_coord_server_fixture',
'$BUILD_DIR/mongo/client/read_preference'
],
@@ -1795,6 +1796,7 @@ env.CppUnitTest(
'transaction_history_iterator_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/repl/mock_repl_coord_server_fixture',
'query_exec',
'service_context_d',
diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript
index ee7829fb043..38348507286 100644
--- a/src/mongo/db/auth/SConscript
+++ b/src/mongo/db/auth/SConscript
@@ -17,16 +17,45 @@ env.Library('auth_rolename', ['role_name.cpp'],
)
env.Library(
- target = 'authentication_restriction',
- source = [
+ target='authentication_restriction',
+ source=[
'restriction_environment.cpp',
],
- LIBDEPS = [
+ LIBDEPS=[
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/util/net/network',
],
)
+env.CppUnitTest(
+ target='restriction_test',
+ source='restriction_test.cpp',
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/base',
+ 'authentication_restriction',
+ ],
+)
+
+# The Auth library should consist only of the shimmed API for Auth usage and the implementations of
+# the data structures used in that API. No actual Auth subsystem implementation should exist in
+# this library.
+env.Library(
+ target='auth',
+ source=[
+ '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=[
@@ -37,55 +66,61 @@ env.Library(
],
)
-env.CppUnitTest(
- target = 'restriction_test',
- source = 'restriction_test.cpp',
- LIBDEPS = [
+env.Library(
+ target='user',
+ source=[
+ 'user.cpp',
+ ],
+ LIBDEPS=[
+ 'authprivilege',
'$BUILD_DIR/mongo/base',
- 'authentication_restriction',
+ '$BUILD_DIR/mongo/crypto/sha_block_${MONGO_CRYPTO}',
],
)
+env.Library(
+ target='auth_impl_internal_local',
+ source=[
+ 'authz_manager_external_state_local.cpp',
+ ],
+ LIBDEPS=[
+ 'auth_impl_internal',
+ ],
+)
-# Just the data structures used
env.Library(
- target='authcore',
+ target='auth_impl_internal',
source=[
- 'authorization_manager.cpp',
- 'authorization_session.cpp',
- 'auth_decorations.cpp',
+ 'authorization_manager_impl.cpp',
+ 'authorization_session_impl.cpp',
'authz_manager_external_state.cpp',
- 'authz_manager_external_state_local.cpp',
'authz_session_external_state.cpp',
'role_graph.cpp',
'role_graph_update.cpp',
'role_graph_builtin_roles.cpp',
- 'user.cpp',
'user_document_parser.cpp',
- 'user_management_commands_parser.cpp',
- 'user_set.cpp'
+ 'user_set.cpp',
],
LIBDEPS=[
- 'address_restriction',
- 'authprivilege',
- 'auth_rolename',
- 'authentication_restriction',
- 'sasl_options',
- 'user_name',
- '$BUILD_DIR/mongo/base',
- '$BUILD_DIR/mongo/base/secure_allocator',
- '$BUILD_DIR/mongo/bson/mutable/mutable_bson',
- '$BUILD_DIR/mongo/bson/util/bson_extract',
- '$BUILD_DIR/mongo/db/catalog/document_validation',
- '$BUILD_DIR/mongo/db/common',
- '$BUILD_DIR/mongo/db/global_settings',
- '$BUILD_DIR/mongo/db/namespace_string',
- '$BUILD_DIR/mongo/db/pipeline/lite_parsed_document_source',
- '$BUILD_DIR/mongo/db/service_context',
- '$BUILD_DIR/mongo/db/update/update_driver',
- '$BUILD_DIR/mongo/util/md5',
- '$BUILD_DIR/mongo/util/icu',
- '$BUILD_DIR/mongo/util/net/ssl_manager',
+ 'address_restriction',
+ 'auth',
+ 'auth_rolename',
+ 'authentication_restriction',
+ 'authprivilege',
+ 'sasl_options',
+ 'user',
+ '$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/base/secure_allocator',
+ '$BUILD_DIR/mongo/bson/mutable/mutable_bson',
+ '$BUILD_DIR/mongo/bson/util/bson_extract',
+ '$BUILD_DIR/mongo/db/catalog/document_validation',
+ '$BUILD_DIR/mongo/db/common',
+ '$BUILD_DIR/mongo/db/global_settings',
+ '$BUILD_DIR/mongo/db/namespace_string',
+ '$BUILD_DIR/mongo/db/pipeline/lite_parsed_document_source',
+ '$BUILD_DIR/mongo/db/update/update_driver',
+ '$BUILD_DIR/mongo/util/icu',
+ '$BUILD_DIR/mongo/util/net/ssl_manager',
],
)
@@ -94,11 +129,15 @@ env.Library(
source=[
'action_set.cpp',
'action_type.cpp',
+ 'impersonation_session.cpp',
'privilege.cpp',
'privilege_parser.cpp',
'resource_pattern.cpp',
+ 'user_management_commands_parser.cpp',
],
LIBDEPS=[
+ 'auth',
+ 'address_restriction',
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/db/common',
]
@@ -121,26 +160,12 @@ env.Library('authorization_manager_global',
'authorization_manager_global.cpp',
],
LIBDEPS=[
- 'authcore',
+ 'auth',
'$BUILD_DIR/mongo/db/server_options_core',
'$BUILD_DIR/mongo/db/service_context',
])
env.Library(
- target='authorization_manager_mock_init',
- source=[
- 'authorization_manager_mock_init.cpp'
- ],
- LIBDEPS=[
- 'authcore',
- 'authmocks',
- '$BUILD_DIR/mongo/executor/thread_pool_task_executor',
- '$BUILD_DIR/mongo/executor/network_interface_thread_pool',
- '$BUILD_DIR/mongo/executor/network_interface_factory'
- ],
-)
-
-env.Library(
target='authservercommon',
source=[
'authz_session_external_state_server_common.cpp',
@@ -148,8 +173,9 @@ env.Library(
'security_key.cpp',
],
LIBDEPS=[
+ 'auth',
'authcommon',
- 'authcore',
+ 'auth_impl_internal',
'authorization_manager_global',
'saslauth',
'security_file',
@@ -187,11 +213,17 @@ env.Library(
'sasl_scram_server_conversation.cpp',
],
LIBDEPS=[
- 'authcore',
+ 'auth',
+ 'authprivilege',
'sasl_options',
+ 'user',
+ 'user_name',
+ '$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/base/secure_allocator',
+ '$BUILD_DIR/mongo/crypto/sha_block_${MONGO_CRYPTO}',
'$BUILD_DIR/mongo/db/commands/test_commands_enabled',
'$BUILD_DIR/mongo/util/icu',
+ '$BUILD_DIR/mongo/util/md5',
'$BUILD_DIR/mongo/util/net/network',
],
)
@@ -209,10 +241,10 @@ env.CppUnitTest(target='sasl_mechanism_registry_test',
env.Library('authmongod',
['authz_manager_external_state_d.cpp',
'authz_session_external_state_d.cpp',
- 'impersonation_session.cpp'
],
LIBDEPS=[
'authservercommon',
+ 'auth_impl_internal_local',
'$BUILD_DIR/mongo/db/db_raii',
'$BUILD_DIR/mongo/db/dbdirectclient',
'$BUILD_DIR/mongo/db/dbhelpers',
@@ -235,32 +267,35 @@ env.Library('authmongos',
env.Library(
target='authmocks',
source=[
- 'authz_manager_external_state_mock.cpp'
+ 'authz_manager_external_state_mock.cpp',
+ 'authz_session_external_state_mock.cpp',
],
LIBDEPS=[
'$BUILD_DIR/mongo/db/matcher/expressions',
'$BUILD_DIR/mongo/db/service_context',
'$BUILD_DIR/mongo/db/update/update_driver',
- 'authcore'
+ 'auth',
+ 'auth_impl_internal',
+ 'auth_impl_internal_local',
]
)
env.CppUnitTest('action_set_test', 'action_set_test.cpp',
- LIBDEPS=['authcore', 'authmocks'])
+ LIBDEPS=['auth', 'authmocks'])
env.CppUnitTest('privilege_parser_test', 'privilege_parser_test.cpp',
- LIBDEPS=['authcore', 'authmocks'])
+ LIBDEPS=['auth', 'authmocks'])
env.CppUnitTest('role_graph_test', 'role_graph_test.cpp',
- LIBDEPS=['authcore', 'authmocks'])
+ LIBDEPS=['auth', 'authmocks'])
env.CppUnitTest('user_document_parser_test', 'user_document_parser_test.cpp',
- LIBDEPS=['authcore', 'authmocks'])
+ LIBDEPS=['auth', 'authmocks'])
env.CppUnitTest('user_set_test', 'user_set_test.cpp',
- LIBDEPS=['authcore', 'authmocks'])
+ LIBDEPS=['auth', 'authmocks'])
env.CppUnitTest('authorization_manager_test', 'authorization_manager_test.cpp',
LIBDEPS=[
'$BUILD_DIR/mongo/transport/transport_layer_common',
'$BUILD_DIR/mongo/transport/transport_layer_mock',
- 'authcore',
- 'authmocks'
+ 'auth',
+ 'authmocks',
])
env.Library(
@@ -269,7 +304,8 @@ env.Library(
'authorization_session_for_test.cpp',
],
LIBDEPS=[
- 'authcore',
+ 'auth',
+ 'auth_impl_internal',
]
)
@@ -279,7 +315,7 @@ env.CppUnitTest(
'authorization_session_test.cpp',
],
LIBDEPS=[
- 'authcore',
+ 'auth',
'authmocks',
'saslauth',
'authorization_session_for_test',
@@ -322,6 +358,7 @@ env.CppUnitTest(
LIBDEPS_PRIVATE=[
'authmocks',
'saslauth',
+ 'authmocks',
'$BUILD_DIR/mongo/client/sasl_client',
'$BUILD_DIR/mongo/db/service_context_noop_init',
],
diff --git a/src/mongo/db/auth/auth_decorations.cpp b/src/mongo/db/auth/auth_decorations.cpp
index b0c1e79f4a9..c78117b91e6 100644
--- a/src/mongo/db/auth/auth_decorations.cpp
+++ b/src/mongo/db/auth/auth_decorations.cpp
@@ -36,7 +36,6 @@
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/client.h"
#include "mongo/db/service_context.h"
-#include "mongo/stdx/memory.h"
#include "mongo/util/assert_util.h"
namespace mongo {
@@ -87,7 +86,7 @@ AuthorizationManager* AuthorizationManager::get(ServiceContext& service) {
void AuthorizationManager::set(ServiceContext* service,
std::unique_ptr<AuthorizationManager> authzManager) {
getAuthorizationManager(service) = std::move(authzManager);
- service->registerClientObserver(stdx::make_unique<AuthzClientObserver>());
+ service->registerClientObserver(std::make_unique<AuthzClientObserver>());
}
AuthorizationSession* AuthorizationSession::get(Client* client) {
diff --git a/src/mongo/db/auth/authorization_manager.cpp b/src/mongo/db/auth/authorization_manager.cpp
index 0b0bedd461e..e20c771fe6e 100644
--- a/src/mongo/db/auth/authorization_manager.cpp
+++ b/src/mongo/db/auth/authorization_manager.cpp
@@ -1,30 +1,30 @@
/**
-* Copyright (C) 2012 10gen 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.
-*/
+ * 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.
+ */
#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kAccessControl
@@ -64,48 +64,9 @@
#include "mongo/util/log.h"
#include "mongo/util/mongoutils/str.h"
-namespace mongo {
-
-using std::begin;
-using std::end;
-using std::endl;
-using std::back_inserter;
-using std::string;
-using std::vector;
-
-AuthInfo internalSecurity;
-
-MONGO_INITIALIZER_WITH_PREREQUISITES(SetupInternalSecurityUser, ("EndStartupOptionStorage"))
-(InitializerContext* const context) try {
- User* user = new User(UserName("__system", "local"));
-
- user->incrementRefCount(); // Pin this user so the ref count never drops below 1.
- ActionSet allActions;
- allActions.addAllActions();
- PrivilegeVector privileges;
- RoleGraph::generateUniversalPrivileges(&privileges);
- user->addPrivileges(privileges);
-
- if (mongodGlobalParams.whitelistedClusterNetwork) {
- const auto& whitelist = *mongodGlobalParams.whitelistedClusterNetwork;
-
- auto restriction = stdx::make_unique<ClientSourceRestriction>(whitelist);
- auto restrictionSet = stdx::make_unique<RestrictionSet<>>(std::move(restriction));
- auto restrictionDocument =
- stdx::make_unique<RestrictionDocument<>>(std::move(restrictionSet));
-
- RestrictionDocuments clusterWhiteList(std::move(restrictionDocument));
+mongo::AuthInfo mongo::internalSecurity;
- user->setRestrictions(std::move(clusterWhiteList));
- }
-
-
- internalSecurity.user = user;
-
- return Status::OK();
-} catch (...) {
- return exceptionToStatus();
-}
+namespace mongo {
const std::string AuthorizationManager::USER_NAME_FIELD_NAME = "user";
const std::string AuthorizationManager::USER_DB_FIELD_NAME = "db";
@@ -138,643 +99,6 @@ const int AuthorizationManager::schemaVersion26Upgrade;
const int AuthorizationManager::schemaVersion26Final;
const int AuthorizationManager::schemaVersion28SCRAM;
-/**
- * Guard object for synchronizing accesses to data cached in AuthorizationManager instances.
- * This guard allows one thread to access the cache at a time, and provides an exception-safe
- * mechanism for a thread to release the cache mutex while performing network or disk operations
- * while allowing other readers to proceed.
- *
- * There are two ways to use this guard. One may simply instantiate the guard like a
- * std::lock_guard, and perform reads or writes of the cache.
- *
- * Alternatively, one may instantiate the guard, examine the cache, and then enter into an
- * update mode by first wait()ing until otherUpdateInFetchPhase() is false, and then
- * calling beginFetchPhase(). At this point, other threads may acquire the guard in the simple
- * manner and do reads, but other threads may not enter into a fetch phase. During the fetch
- * phase, the thread should perform required network or disk activity to determine what update
- * it will make to the cache. Then, it should call endFetchPhase(), to reacquire the user cache
- * mutex. At that point, the thread can make its modifications to the cache and let the guard
- * go out of scope.
- *
- * All updates by guards using a fetch-phase are totally ordered with respect to one another,
- * and all guards using no fetch phase are totally ordered with respect to one another, but
- * there is not a total ordering among all guard objects.
- *
- * The cached data has an associated counter, called the cache generation. If the cache
- * generation changes while a guard is in fetch phase, the fetched data should not be stored
- * into the cache, because some invalidation event occurred during the fetch phase.
- *
- * NOTE: It is not safe to enter fetch phase while holding a database lock. Fetch phase
- * operations are allowed to acquire database locks themselves, so entering fetch while holding
- * a database lock may lead to deadlock.
- */
-class AuthorizationManager::CacheGuard {
- MONGO_DISALLOW_COPYING(CacheGuard);
-
-public:
- enum FetchSynchronization { fetchSynchronizationAutomatic, fetchSynchronizationManual };
-
- /**
- * Constructs a cache guard, locking the mutex that synchronizes user cache accesses.
- */
- CacheGuard(AuthorizationManager* authzManager,
- const FetchSynchronization sync = fetchSynchronizationAutomatic)
- : _isThisGuardInFetchPhase(false),
- _authzManager(authzManager),
- _lock(authzManager->_cacheMutex) {
- if (fetchSynchronizationAutomatic == sync) {
- synchronizeWithFetchPhase();
- }
- }
-
- /**
- * Releases the mutex that synchronizes user cache access, if held, and notifies
- * any threads waiting for their own opportunity to update the user cache.
- */
- ~CacheGuard() {
- if (!_lock.owns_lock()) {
- _lock.lock();
- }
- if (_isThisGuardInFetchPhase) {
- fassert(17190, _authzManager->_isFetchPhaseBusy);
- _authzManager->_isFetchPhaseBusy = false;
- _authzManager->_fetchPhaseIsReady.notify_all();
- }
- }
-
- /**
- * Returns true of the authzManager reports that it is in fetch phase.
- */
- bool otherUpdateInFetchPhase() {
- return _authzManager->_isFetchPhaseBusy;
- }
-
- /**
- * Waits on the _authzManager->_fetchPhaseIsReady condition.
- */
- void wait() {
- fassert(17222, !_isThisGuardInFetchPhase);
- _authzManager->_fetchPhaseIsReady.wait(_lock);
- }
-
- /**
- * Enters fetch phase, releasing the _authzManager->_cacheMutex after recording the current
- * cache generation.
- */
- void beginFetchPhase() {
- fassert(17191, !_authzManager->_isFetchPhaseBusy);
- _isThisGuardInFetchPhase = true;
- _authzManager->_isFetchPhaseBusy = true;
- _startGeneration = _authzManager->_cacheGeneration;
- _lock.unlock();
- }
-
- /**
- * Exits the fetch phase, reacquiring the _authzManager->_cacheMutex.
- */
- void endFetchPhase() {
- _lock.lock();
- // We do not clear _authzManager->_isFetchPhaseBusy or notify waiters until
- // ~CacheGuard(), for two reasons. First, there's no value to notifying the waiters
- // before you're ready to release the mutex, because they'll just go to sleep on the
- // mutex. Second, in order to meaningfully check the preconditions of
- // isSameCacheGeneration(), we need a state that means "fetch phase was entered and now
- // has been exited." That state is _isThisGuardInFetchPhase == true and
- // _lock.owns_lock() == true.
- }
-
- /**
- * Returns true if _authzManager->_cacheGeneration remained the same while this guard was
- * in fetch phase. Behavior is undefined if this guard never entered fetch phase.
- *
- * If this returns true, do not update the cached data with this
- */
- bool isSameCacheGeneration() const {
- fassert(17223, _isThisGuardInFetchPhase);
- fassert(17231, _lock.owns_lock());
- return _startGeneration == _authzManager->_cacheGeneration;
- }
-
-private:
- void synchronizeWithFetchPhase() {
- while (otherUpdateInFetchPhase())
- wait();
- fassert(17192, !_authzManager->_isFetchPhaseBusy);
- _isThisGuardInFetchPhase = true;
- _authzManager->_isFetchPhaseBusy = true;
- }
-
- OID _startGeneration;
- bool _isThisGuardInFetchPhase;
- AuthorizationManager* _authzManager;
- stdx::unique_lock<stdx::mutex> _lock;
-};
-
-AuthorizationManager::AuthorizationManager(std::unique_ptr<AuthzManagerExternalState> externalState)
- : _authEnabled(false),
- _privilegeDocsExist(false),
- _externalState(std::move(externalState)),
- _version(schemaVersionInvalid),
- _isFetchPhaseBusy(false) {
- _updateCacheGeneration_inlock();
-}
-
-AuthorizationManager::~AuthorizationManager() {
- for (stdx::unordered_map<UserName, User*>::iterator it = _userCache.begin();
- it != _userCache.end();
- ++it) {
- fassert(17265, it->second != internalSecurity.user);
- delete it->second;
- }
-}
-
-std::unique_ptr<AuthorizationSession> AuthorizationManager::makeAuthorizationSession() {
- return stdx::make_unique<AuthorizationSession>(
- _externalState->makeAuthzSessionExternalState(this));
-}
-
-void AuthorizationManager::setShouldValidateAuthSchemaOnStartup(bool validate) {
- _startupAuthSchemaValidation = validate;
-}
-
-bool AuthorizationManager::shouldValidateAuthSchemaOnStartup() {
- return _startupAuthSchemaValidation;
-}
-
-Status AuthorizationManager::getAuthorizationVersion(OperationContext* opCtx, int* version) {
- CacheGuard guard(this, CacheGuard::fetchSynchronizationManual);
- int newVersion = _version;
- if (schemaVersionInvalid == newVersion) {
- while (guard.otherUpdateInFetchPhase())
- guard.wait();
- guard.beginFetchPhase();
- Status status = _externalState->getStoredAuthorizationVersion(opCtx, &newVersion);
- guard.endFetchPhase();
- if (!status.isOK()) {
- warning() << "Problem fetching the stored schema version of authorization data: "
- << redact(status);
- *version = schemaVersionInvalid;
- return status;
- }
-
- if (guard.isSameCacheGeneration()) {
- _version = newVersion;
- }
- }
- *version = newVersion;
- return Status::OK();
-}
-
-OID AuthorizationManager::getCacheGeneration() {
- CacheGuard guard(this, CacheGuard::fetchSynchronizationManual);
- return _cacheGeneration;
-}
-
-void AuthorizationManager::setAuthEnabled(bool enabled) {
- _authEnabled = enabled;
-}
-
-bool AuthorizationManager::isAuthEnabled() const {
- return _authEnabled;
-}
-
-bool AuthorizationManager::hasAnyPrivilegeDocuments(OperationContext* opCtx) {
- stdx::unique_lock<stdx::mutex> lk(_privilegeDocsExistMutex);
- if (_privilegeDocsExist) {
- // If we know that a user exists, don't re-check.
- return true;
- }
-
- lk.unlock();
- bool privDocsExist = _externalState->hasAnyPrivilegeDocuments(opCtx);
- lk.lock();
-
- if (privDocsExist) {
- _privilegeDocsExist = true;
- }
-
- return _privilegeDocsExist;
-}
-
-Status AuthorizationManager::getBSONForPrivileges(const PrivilegeVector& privileges,
- mutablebson::Element resultArray) {
- for (PrivilegeVector::const_iterator it = privileges.begin(); it != privileges.end(); ++it) {
- std::string errmsg;
- ParsedPrivilege privilege;
- if (!ParsedPrivilege::privilegeToParsedPrivilege(*it, &privilege, &errmsg)) {
- return Status(ErrorCodes::BadValue, errmsg);
- }
- resultArray.appendObject("privileges", privilege.toBSON()).transitional_ignore();
- }
- return Status::OK();
-}
-
-Status AuthorizationManager::getBSONForRole(RoleGraph* graph,
- const RoleName& roleName,
- mutablebson::Element result) {
- if (!graph->roleExists(roleName)) {
- return Status(ErrorCodes::RoleNotFound,
- mongoutils::str::stream() << roleName.getFullName()
- << "does not name an existing role");
- }
- std::string id = mongoutils::str::stream() << roleName.getDB() << "." << roleName.getRole();
- result.appendString("_id", id).transitional_ignore();
- result.appendString(ROLE_NAME_FIELD_NAME, roleName.getRole()).transitional_ignore();
- result.appendString(ROLE_DB_FIELD_NAME, roleName.getDB()).transitional_ignore();
-
- // Build privileges array
- mutablebson::Element privilegesArrayElement =
- result.getDocument().makeElementArray("privileges");
- result.pushBack(privilegesArrayElement).transitional_ignore();
- const PrivilegeVector& privileges = graph->getDirectPrivileges(roleName);
- Status status = getBSONForPrivileges(privileges, privilegesArrayElement);
- if (!status.isOK()) {
- return status;
- }
-
- // Build roles array
- mutablebson::Element rolesArrayElement = result.getDocument().makeElementArray("roles");
- result.pushBack(rolesArrayElement).transitional_ignore();
- for (RoleNameIterator roles = graph->getDirectSubordinates(roleName); roles.more();
- roles.next()) {
- const RoleName& subRole = roles.get();
- mutablebson::Element roleObj = result.getDocument().makeElementObject("");
- roleObj.appendString(ROLE_NAME_FIELD_NAME, subRole.getRole()).transitional_ignore();
- roleObj.appendString(ROLE_DB_FIELD_NAME, subRole.getDB()).transitional_ignore();
- rolesArrayElement.pushBack(roleObj).transitional_ignore();
- }
-
- return Status::OK();
-}
-
-Status AuthorizationManager::_initializeUserFromPrivilegeDocument(User* user,
- const BSONObj& privDoc) {
- V2UserDocumentParser parser;
- std::string userName = parser.extractUserNameFromUserDocument(privDoc);
- if (userName != user->getName().getUser()) {
- return Status(ErrorCodes::BadValue,
- mongoutils::str::stream() << "User name from privilege document \""
- << userName
- << "\" doesn't match name of provided User \""
- << user->getName().getUser()
- << "\"");
- }
-
- Status status = parser.initializeUserCredentialsFromUserDocument(user, privDoc);
- if (!status.isOK()) {
- return status;
- }
- status = parser.initializeUserRolesFromUserDocument(privDoc, user);
- if (!status.isOK()) {
- return status;
- }
- status = parser.initializeUserIndirectRolesFromUserDocument(privDoc, user);
- if (!status.isOK()) {
- return status;
- }
- status = parser.initializeUserPrivilegesFromUserDocument(privDoc, user);
- if (!status.isOK()) {
- return status;
- }
- status = parser.initializeAuthenticationRestrictionsFromUserDocument(privDoc, user);
- if (!status.isOK()) {
- return status;
- }
-
- return Status::OK();
-}
-
-Status AuthorizationManager::getUserDescription(OperationContext* opCtx,
- const UserName& userName,
- BSONObj* result) {
- return _externalState->getUserDescription(opCtx, userName, result);
-}
-
-Status AuthorizationManager::getRoleDescription(OperationContext* opCtx,
- const RoleName& roleName,
- PrivilegeFormat privileges,
- AuthenticationRestrictionsFormat restrictions,
- BSONObj* result) {
- return _externalState->getRoleDescription(opCtx, roleName, privileges, restrictions, result);
-}
-
-Status AuthorizationManager::getRolesDescription(OperationContext* opCtx,
- const std::vector<RoleName>& roleName,
- PrivilegeFormat privileges,
- AuthenticationRestrictionsFormat restrictions,
- BSONObj* result) {
- return _externalState->getRolesDescription(opCtx, roleName, privileges, restrictions, result);
-}
-
-
-Status AuthorizationManager::getRoleDescriptionsForDB(OperationContext* opCtx,
- const std::string dbname,
- PrivilegeFormat privileges,
- AuthenticationRestrictionsFormat restrictions,
- bool showBuiltinRoles,
- vector<BSONObj>* result) {
- return _externalState->getRoleDescriptionsForDB(
- opCtx, dbname, privileges, restrictions, showBuiltinRoles, result);
-}
-
-Status AuthorizationManager::acquireUser(OperationContext* opCtx,
- const UserName& userName,
- User** acquiredUser) {
- if (userName == internalSecurity.user->getName()) {
- *acquiredUser = internalSecurity.user;
- return Status::OK();
- }
-
- stdx::unordered_map<UserName, User*>::iterator it;
-
- CacheGuard guard(this, CacheGuard::fetchSynchronizationManual);
- while ((_userCache.end() == (it = _userCache.find(userName))) &&
- guard.otherUpdateInFetchPhase()) {
- guard.wait();
- }
-
- if (it != _userCache.end()) {
- fassert(16914, it->second);
- fassert(17003, it->second->isValid());
- fassert(17008, it->second->getRefCount() > 0);
- it->second->incrementRefCount();
- *acquiredUser = it->second;
- return Status::OK();
- }
-
- std::unique_ptr<User> user;
-
- int authzVersion = _version;
- guard.beginFetchPhase();
-
- // Number of times to retry a user document that fetches due to transient
- // AuthSchemaIncompatible errors. These errors should only ever occur during and shortly
- // after schema upgrades.
- static const int maxAcquireRetries = 2;
- Status status = Status::OK();
- for (int i = 0; i < maxAcquireRetries; ++i) {
- if (authzVersion == schemaVersionInvalid) {
- Status status = _externalState->getStoredAuthorizationVersion(opCtx, &authzVersion);
- if (!status.isOK())
- return status;
- }
-
- switch (authzVersion) {
- default:
- status = Status(ErrorCodes::BadValue,
- mongoutils::str::stream()
- << "Illegal value for authorization data schema version, "
- << authzVersion);
- break;
- case schemaVersion28SCRAM:
- case schemaVersion26Final:
- case schemaVersion26Upgrade:
- status = _fetchUserV2(opCtx, userName, &user);
- break;
- case schemaVersion24:
- status = Status(ErrorCodes::AuthSchemaIncompatible,
- mongoutils::str::stream()
- << "Authorization data schema version "
- << schemaVersion24
- << " not supported after MongoDB version 2.6.");
- break;
- }
- if (status.isOK())
- break;
- if (status != ErrorCodes::AuthSchemaIncompatible)
- return status;
-
- authzVersion = schemaVersionInvalid;
- }
- if (!status.isOK())
- return status;
-
- guard.endFetchPhase();
-
- user->incrementRefCount();
- // NOTE: It is not safe to throw an exception from here to the end of the method.
- if (guard.isSameCacheGeneration()) {
- _userCache.insert(std::make_pair(userName, user.get()));
- if (_version == schemaVersionInvalid)
- _version = authzVersion;
- } else {
- // If the cache generation changed while this thread was in fetch mode, the data
- // associated with the user may now be invalid, so we must mark it as such. The caller
- // may still opt to use the information for a short while, but not indefinitely.
- user->invalidate();
- }
- *acquiredUser = user.release();
-
- return Status::OK();
-}
-
-Status AuthorizationManager::_fetchUserV2(OperationContext* opCtx,
- const UserName& userName,
- std::unique_ptr<User>* acquiredUser) {
- BSONObj userObj;
- Status status = getUserDescription(opCtx, userName, &userObj);
- if (!status.isOK()) {
- return status;
- }
-
- // Put the new user into an unique_ptr temporarily in case there's an error while
- // initializing the user.
- auto user = stdx::make_unique<User>(userName);
-
- status = _initializeUserFromPrivilegeDocument(user.get(), userObj);
- if (!status.isOK()) {
- return status;
- }
- acquiredUser->reset(user.release());
- return Status::OK();
-}
-
-void AuthorizationManager::releaseUser(User* user) {
- if (user == internalSecurity.user) {
- return;
- }
-
- CacheGuard guard(this, CacheGuard::fetchSynchronizationManual);
- user->decrementRefCount();
- if (user->getRefCount() == 0) {
- // If it's been invalidated then it's not in the _userCache anymore.
- if (user->isValid()) {
- MONGO_COMPILER_VARIABLE_UNUSED bool erased = _userCache.erase(user->getName());
- dassert(erased);
- }
- delete user;
- }
-}
-
-void AuthorizationManager::invalidateUserByName(const UserName& userName) {
- CacheGuard guard(this, CacheGuard::fetchSynchronizationManual);
- _updateCacheGeneration_inlock();
- stdx::unordered_map<UserName, User*>::iterator it = _userCache.find(userName);
- if (it == _userCache.end()) {
- return;
- }
-
- User* user = it->second;
- _userCache.erase(it);
- user->invalidate();
-}
-
-void AuthorizationManager::invalidateUsersFromDB(const std::string& dbname) {
- CacheGuard guard(this, CacheGuard::fetchSynchronizationManual);
- _updateCacheGeneration_inlock();
- stdx::unordered_map<UserName, User*>::iterator it = _userCache.begin();
- while (it != _userCache.end()) {
- User* user = it->second;
- if (user->getName().getDB() == dbname) {
- _userCache.erase(it++);
- user->invalidate();
- } else {
- ++it;
- }
- }
-}
-
-void AuthorizationManager::invalidateUserCache() {
- CacheGuard guard(this, CacheGuard::fetchSynchronizationManual);
- _invalidateUserCache_inlock();
-}
-
-void AuthorizationManager::_invalidateUserCache_inlock() {
- _updateCacheGeneration_inlock();
- for (stdx::unordered_map<UserName, User*>::iterator it = _userCache.begin();
- it != _userCache.end();
- ++it) {
- fassert(17266, it->second != internalSecurity.user);
- it->second->invalidate();
- }
- _userCache.clear();
-
- // Reread the schema version before acquiring the next user.
- _version = schemaVersionInvalid;
-}
-
-Status AuthorizationManager::initialize(OperationContext* opCtx) {
- invalidateUserCache();
- Status status = _externalState->initialize(opCtx);
- if (!status.isOK())
- return status;
-
- return Status::OK();
-}
-
-namespace {
-bool isAuthzNamespace(const NamespaceString& nss) {
- return (nss == AuthorizationManager::rolesCollectionNamespace ||
- nss == AuthorizationManager::usersCollectionNamespace ||
- nss == AuthorizationManager::versionCollectionNamespace);
-}
-
-bool isAuthzCollection(StringData coll) {
- return (coll == AuthorizationManager::rolesCollectionNamespace.coll() ||
- coll == AuthorizationManager::usersCollectionNamespace.coll() ||
- coll == AuthorizationManager::versionCollectionNamespace.coll());
-}
-
-bool loggedCommandOperatesOnAuthzData(const NamespaceString& nss, const BSONObj& cmdObj) {
- if (nss != AuthorizationManager::adminCommandNamespace)
- return false;
- const StringData cmdName(cmdObj.firstElement().fieldNameStringData());
- if (cmdName == "drop") {
- return isAuthzCollection(cmdObj.firstElement().valueStringData());
- } else if (cmdName == "dropDatabase") {
- return true;
- } else if (cmdName == "renameCollection") {
- return isAuthzCollection(cmdObj.firstElement().str()) ||
- isAuthzCollection(cmdObj["to"].str());
- } else if (cmdName == "dropIndexes" || cmdName == "deleteIndexes") {
- return false;
- } else if (cmdName == "create") {
- return false;
- } else {
- return true;
- }
-}
-
-bool appliesToAuthzData(const char* op, const NamespaceString& nss, const BSONObj& o) {
- switch (*op) {
- case 'i':
- case 'u':
- case 'd':
- if (op[1] != '\0')
- return false; // "db" op type
- return isAuthzNamespace(nss);
- case 'c':
- return loggedCommandOperatesOnAuthzData(nss, o);
- break;
- case 'n':
- return false;
- default:
- return true;
- }
-}
-
-// Updates to users in the oplog are done by matching on the _id, which will always have the
-// form "<dbname>.<username>". This function extracts the UserName from that string.
-StatusWith<UserName> extractUserNameFromIdString(StringData idstr) {
- size_t splitPoint = idstr.find('.');
- if (splitPoint == string::npos) {
- return StatusWith<UserName>(ErrorCodes::FailedToParse,
- mongoutils::str::stream()
- << "_id entries for user documents must be of "
- "the form <dbname>.<username>. Found: "
- << idstr);
- }
- return StatusWith<UserName>(
- UserName(idstr.substr(splitPoint + 1), idstr.substr(0, splitPoint)));
-}
-
-} // namespace
-
-void AuthorizationManager::_updateCacheGeneration_inlock() {
- _cacheGeneration = OID::gen();
-}
-
-void AuthorizationManager::_invalidateRelevantCacheData(const char* op,
- const NamespaceString& ns,
- const BSONObj& o,
- const BSONObj* o2) {
- if (ns == AuthorizationManager::rolesCollectionNamespace ||
- ns == AuthorizationManager::versionCollectionNamespace) {
- invalidateUserCache();
- return;
- }
-
- if (*op == 'i' || *op == 'd' || *op == 'u') {
- // If you got into this function isAuthzNamespace() must have returned true, and we've
- // already checked that it's not the roles or version collection.
- invariant(ns == AuthorizationManager::usersCollectionNamespace);
-
- StatusWith<UserName> userName = (*op == 'u')
- ? extractUserNameFromIdString((*o2)["_id"].str())
- : extractUserNameFromIdString(o["_id"].str());
-
- if (!userName.isOK()) {
- warning() << "Invalidating user cache based on user being updated failed, will "
- "invalidate the entire cache instead: "
- << userName.getStatus();
- invalidateUserCache();
- return;
- }
- invalidateUserByName(userName.getValue());
- } else {
- invalidateUserCache();
- }
-}
-
-void AuthorizationManager::logOp(OperationContext* opCtx,
- const char* op,
- const NamespaceString& nss,
- const BSONObj& o,
- const BSONObj* o2) {
- if (appliesToAuthzData(op, nss, o)) {
- _externalState->logOp(opCtx, op, nss, o, o2);
- _invalidateRelevantCacheData(op, nss, o, o2);
- }
-}
+MONGO_DEFINE_SHIM(AuthorizationManager::create);
} // namespace mongo
diff --git a/src/mongo/db/auth/authorization_manager.h b/src/mongo/db/auth/authorization_manager.h
index c21d672c688..5d9506a9f18 100644
--- a/src/mongo/db/auth/authorization_manager.h
+++ b/src/mongo/db/auth/authorization_manager.h
@@ -1,30 +1,30 @@
/**
-* Copyright (C) 2013 10gen 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.
-*/
+ * 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
@@ -33,6 +33,7 @@
#include "mongo/base/disallow_copying.h"
#include "mongo/base/secure_allocator.h"
+#include "mongo/base/shim.h"
#include "mongo/base/status.h"
#include "mongo/bson/mutable/element.h"
#include "mongo/bson/oid.h"
@@ -79,17 +80,19 @@ enum class AuthenticationRestrictionsFormat {
* Contains server/cluster-wide information about Authorization.
*/
class AuthorizationManager {
- MONGO_DISALLOW_COPYING(AuthorizationManager);
+ AuthorizationManager(const AuthorizationManager&) = delete;
+ AuthorizationManager& operator=(const AuthorizationManager&) = delete;
public:
static AuthorizationManager* get(ServiceContext* service);
static AuthorizationManager* get(ServiceContext& service);
static void set(ServiceContext* service, std::unique_ptr<AuthorizationManager> authzManager);
- // The newly constructed AuthorizationManager takes ownership of "externalState"
- explicit AuthorizationManager(std::unique_ptr<AuthzManagerExternalState> externalState);
+ virtual ~AuthorizationManager() = default;
+
+ AuthorizationManager() = default;
- ~AuthorizationManager();
+ static MONGO_DECLARE_SHIM(()->std::unique_ptr<AuthorizationManager>) create;
static const std::string USER_NAME_FIELD_NAME;
static const std::string USER_DB_FIELD_NAME;
@@ -179,27 +182,27 @@ public:
/**
* Returns a new AuthorizationSession for use with this AuthorizationManager.
*/
- std::unique_ptr<AuthorizationSession> makeAuthorizationSession();
+ virtual std::unique_ptr<AuthorizationSession> makeAuthorizationSession() = 0;
/**
* Sets whether or not startup AuthSchema validation checks should be applied in this manager.
*/
- void setShouldValidateAuthSchemaOnStartup(bool validate);
+ virtual void setShouldValidateAuthSchemaOnStartup(bool validate) = 0;
/**
* Returns true if startup AuthSchema validation checks should be applied in this manager.
*/
- bool shouldValidateAuthSchemaOnStartup();
+ virtual bool shouldValidateAuthSchemaOnStartup() = 0;
/**
* Sets whether or not access control enforcement is enabled for this manager.
*/
- void setAuthEnabled(bool enabled);
+ virtual void setAuthEnabled(bool enabled) = 0;
/**
* Returns true if access control is enabled for this manager .
*/
- bool isAuthEnabled() const;
+ virtual bool isAuthEnabled() const = 0;
/**
* Returns via the output parameter "version" the version number of the authorization
@@ -208,12 +211,12 @@ public:
* returns a non-OK status. When returning a non-OK status, *version will be set to
* schemaVersionInvalid (0).
*/
- Status getAuthorizationVersion(OperationContext* opCtx, int* version);
+ virtual Status getAuthorizationVersion(OperationContext* opCtx, int* version) = 0;
/**
* Returns the user cache generation identifier.
*/
- OID getCacheGeneration();
+ virtual OID getCacheGeneration() = 0;
/**
* Returns true if there exists at least one privilege document in the system.
@@ -223,31 +226,23 @@ public:
* meaning that once this method returns true it will continue to return true for the
* lifetime of this process, even if all users are subsequently dropped from the system.
*/
- bool hasAnyPrivilegeDocuments(OperationContext* opCtx);
-
- // Checks to see if "doc" is a valid privilege document, assuming it is stored in the
- // "system.users" collection of database "dbname".
- //
- // Returns Status::OK() if the document is good, or Status(ErrorCodes::BadValue), otherwise.
- Status checkValidPrivilegeDocument(StringData dbname, const BSONObj& doc);
-
- // Given a database name and a readOnly flag return an ActionSet describing all the actions
- // that an old-style user with those attributes should be given.
- ActionSet getActionsForOldStyleUser(const std::string& dbname, bool readOnly) const;
+ virtual bool hasAnyPrivilegeDocuments(OperationContext* opCtx) = 0;
/**
* Delegates method call to the underlying AuthzManagerExternalState.
*/
- Status getUserDescription(OperationContext* opCtx, const UserName& userName, BSONObj* result);
+ virtual Status getUserDescription(OperationContext* opCtx,
+ const UserName& userName,
+ BSONObj* result) = 0;
/**
* Delegates method call to the underlying AuthzManagerExternalState.
*/
- Status getRoleDescription(OperationContext* opCtx,
- const RoleName& roleName,
- PrivilegeFormat privilegeFormat,
- AuthenticationRestrictionsFormat,
- BSONObj* result);
+ virtual Status getRoleDescription(OperationContext* opCtx,
+ const RoleName& roleName,
+ PrivilegeFormat privilegeFormat,
+ AuthenticationRestrictionsFormat,
+ BSONObj* result) = 0;
/**
* Convenience wrapper for getRoleDescription() defaulting formats to kOmit.
@@ -260,21 +255,21 @@ public:
/**
* Delegates method call to the underlying AuthzManagerExternalState.
*/
- Status getRolesDescription(OperationContext* opCtx,
- const std::vector<RoleName>& roleName,
- PrivilegeFormat privilegeFormat,
- AuthenticationRestrictionsFormat,
- BSONObj* result);
+ virtual Status getRolesDescription(OperationContext* opCtx,
+ const std::vector<RoleName>& roleName,
+ PrivilegeFormat privilegeFormat,
+ AuthenticationRestrictionsFormat,
+ BSONObj* result) = 0;
/**
* Delegates method call to the underlying AuthzManagerExternalState.
*/
- Status getRoleDescriptionsForDB(OperationContext* opCtx,
- const std::string dbname,
- PrivilegeFormat privilegeFormat,
- AuthenticationRestrictionsFormat,
- bool showBuiltinRoles,
- std::vector<BSONObj>* result);
+ virtual Status getRoleDescriptionsForDB(OperationContext* opCtx,
+ const std::string dbname,
+ PrivilegeFormat privilegeFormat,
+ AuthenticationRestrictionsFormat,
+ bool showBuiltinRoles,
+ std::vector<BSONObj>* result) = 0;
/**
* Returns the User object for the given userName in the out parameter "acquiredUser".
@@ -286,35 +281,37 @@ public:
* The AuthorizationManager retains ownership of the returned User object.
* On non-OK Status return values, acquiredUser will not be modified.
*/
- Status acquireUser(OperationContext* opCtx, const UserName& userName, User** acquiredUser);
+ virtual Status acquireUser(OperationContext* opCtx,
+ const UserName& userName,
+ User** acquiredUser) = 0;
/**
* Decrements the refcount of the given User object. If the refcount has gone to zero,
* deletes the User. Caller must stop using its pointer to "user" after calling this.
*/
- void releaseUser(User* user);
+ virtual void releaseUser(User* user) = 0;
/**
* Marks the given user as invalid and removes it from the user cache.
*/
- void invalidateUserByName(const UserName& user);
+ virtual void invalidateUserByName(const UserName& user) = 0;
/**
* Invalidates all users who's source is "dbname" and removes them from the user cache.
*/
- void invalidateUsersFromDB(const std::string& dbname);
+ virtual void invalidateUsersFromDB(const std::string& dbname) = 0;
/**
* Initializes the authorization manager. Depending on what version the authorization
* system is at, this may involve building up the user cache and/or the roles graph.
* Call this function at startup and after resynchronizing a slave/secondary.
*/
- Status initialize(OperationContext* opCtx);
+ virtual Status initialize(OperationContext* opCtx) = 0;
/**
* Invalidates all of the contents of the user cache.
*/
- void invalidateUserCache();
+ virtual void invalidateUserCache() = 0;
/**
* Parses privDoc and fully initializes the user object (credentials, roles, and privileges)
@@ -322,123 +319,17 @@ public:
* This should never be called from outside the AuthorizationManager - the only reason it's
* public instead of private is so it can be unit tested.
*/
- Status _initializeUserFromPrivilegeDocument(User* user, const BSONObj& privDoc);
+ virtual Status _initializeUserFromPrivilegeDocument(User* user, const BSONObj& privDoc) = 0;
/**
* Hook called by replication code to let the AuthorizationManager observe changes
* to relevant collections.
*/
- void logOp(OperationContext* opCtx,
- const char* opstr,
- const NamespaceString& nss,
- const BSONObj& obj,
- const BSONObj* patt);
-
-private:
- /**
- * Type used to guard accesses and updates to the user cache.
- */
- class CacheGuard;
- friend class AuthorizationManager::CacheGuard;
-
- /**
- * Invalidates all User objects in the cache and removes them from the cache.
- * Should only be called when already holding _cacheMutex.
- */
- void _invalidateUserCache_inlock();
-
- /**
- * Given the objects describing an oplog entry that affects authorization data, invalidates
- * the portion of the user cache that is affected by that operation. Should only be called
- * with oplog entries that have been pre-verified to actually affect authorization data.
- */
- void _invalidateRelevantCacheData(const char* op,
- const NamespaceString& ns,
- const BSONObj& o,
- const BSONObj* o2);
-
- /**
- * Updates _cacheGeneration to a new OID
- */
- void _updateCacheGeneration_inlock();
-
- /**
- * Fetches user information from a v2-schema user document for the named user,
- * and stores a pointer to a new user object into *acquiredUser on success.
- */
- Status _fetchUserV2(OperationContext* opCtx,
- const UserName& userName,
- std::unique_ptr<User>* acquiredUser);
-
- /**
- * True if AuthSchema startup checks should be applied in this AuthorizationManager.
- *
- * Defaults to true. Changes to its value are not synchronized, so it should only be set
- * at initalization-time.
- */
- bool _startupAuthSchemaValidation;
-
- /**
- * True if access control enforcement is enabled in this AuthorizationManager.
- *
- * Defaults to false. Changes to its value are not synchronized, so it should only be set
- * at initalization-time.
- */
- bool _authEnabled;
-
- /**
- * A cache of whether there are any users set up for the cluster.
- */
- bool _privilegeDocsExist;
-
- // Protects _privilegeDocsExist
- mutable stdx::mutex _privilegeDocsExistMutex;
-
- std::unique_ptr<AuthzManagerExternalState> _externalState;
-
- /**
- * Cached value of the authorization schema version.
- *
- * May be set by acquireUser() and getAuthorizationVersion(). Invalidated by
- * invalidateUserCache().
- *
- * Reads and writes guarded by CacheGuard.
- */
- int _version;
-
- /**
- * Caches User objects with information about user privileges, to avoid the need to
- * go to disk to read user privilege documents whenever possible. Every User object
- * has a reference count - the AuthorizationManager must not delete a User object in the
- * cache unless its reference count is zero.
- */
- stdx::unordered_map<UserName, User*> _userCache;
-
- /**
- * Current generation of cached data. Updated every time part of the cache gets
- * invalidated. Protected by CacheGuard.
- */
- OID _cacheGeneration;
-
- /**
- * True if there is an update to the _userCache in progress, and that update is currently in
- * the "fetch phase", during which it does not hold the _cacheMutex.
- *
- * Manipulated via CacheGuard.
- */
- bool _isFetchPhaseBusy;
-
- /**
- * Protects _userCache, _cacheGeneration, _version and _isFetchPhaseBusy. Manipulated
- * via CacheGuard.
- */
- stdx::mutex _cacheMutex;
-
- /**
- * Condition used to signal that it is OK for another CacheGuard to enter a fetch phase.
- * Manipulated via CacheGuard.
- */
- stdx::condition_variable _fetchPhaseIsReady;
+ virtual void logOp(OperationContext* opCtx,
+ const char* opstr,
+ const NamespaceString& nss,
+ const BSONObj& obj,
+ const BSONObj* patt) = 0;
};
} // namespace mongo
diff --git a/src/mongo/db/auth/authorization_manager_global.cpp b/src/mongo/db/auth/authorization_manager_global.cpp
index 9738f7b2932..352981b7574 100644
--- a/src/mongo/db/auth/authorization_manager_global.cpp
+++ b/src/mongo/db/auth/authorization_manager_global.cpp
@@ -32,6 +32,7 @@
#include "mongo/base/init.h"
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/authorization_manager_global.h"
+#include "mongo/db/auth/authorization_manager_impl.h"
#include "mongo/db/auth/authz_manager_external_state.h"
#include "mongo/db/server_options.h"
#include "mongo/db/server_parameters.h"
@@ -92,14 +93,9 @@ MONGO_EXPORT_STARTUP_SERVER_PARAMETER(startupAuthSchemaValidation, bool, true);
GlobalInitializerRegisterer authorizationManagerInitializer(
"CreateAuthorizationManager",
- {"SetupInternalSecurityUser",
- "OIDGeneration",
- "CreateAuthorizationExternalStateFactory",
- "EndStartupOptionStorage",
- "ServiceContext"},
+ {"SetupInternalSecurityUser", "OIDGeneration", "EndStartupOptionStorage", "ServiceContext"},
[](InitializerContext* context) {
- auto authzManager =
- stdx::make_unique<AuthorizationManager>(AuthzManagerExternalState::create());
+ auto authzManager = AuthorizationManager::create();
authzManager->setAuthEnabled(serverGlobalParams.authState ==
ServerGlobalParams::AuthState::kEnabled);
authzManager->setShouldValidateAuthSchemaOnStartup(startupAuthSchemaValidation);
diff --git a/src/mongo/db/auth/authorization_manager_impl.cpp b/src/mongo/db/auth/authorization_manager_impl.cpp
new file mode 100644
index 00000000000..bc8970484fa
--- /dev/null
+++ b/src/mongo/db/auth/authorization_manager_impl.cpp
@@ -0,0 +1,765 @@
+/**
+ * Copyright (C) 2018 10gen 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.
+ */
+
+#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kAccessControl
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/auth/authorization_manager_impl.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "mongo/base/init.h"
+#include "mongo/base/status.h"
+#include "mongo/bson/mutable/document.h"
+#include "mongo/bson/mutable/element.h"
+#include "mongo/bson/util/bson_extract.h"
+#include "mongo/crypto/mechanism_scram.h"
+#include "mongo/db/auth/action_set.h"
+#include "mongo/db/auth/address_restriction.h"
+#include "mongo/db/auth/authorization_session.h"
+#include "mongo/db/auth/authorization_session_impl.h"
+#include "mongo/db/auth/authz_manager_external_state.h"
+#include "mongo/db/auth/privilege.h"
+#include "mongo/db/auth/privilege_parser.h"
+#include "mongo/db/auth/role_graph.h"
+#include "mongo/db/auth/sasl_options.h"
+#include "mongo/db/auth/sasl_options.h"
+#include "mongo/db/auth/user.h"
+#include "mongo/db/auth/user_document_parser.h"
+#include "mongo/db/auth/user_name.h"
+#include "mongo/db/auth/user_name_hash.h"
+#include "mongo/db/global_settings.h"
+#include "mongo/db/jsobj.h"
+#include "mongo/db/mongod_options.h"
+#include "mongo/platform/compiler.h"
+#include "mongo/stdx/memory.h"
+#include "mongo/stdx/mutex.h"
+#include "mongo/stdx/unordered_map.h"
+#include "mongo/util/assert_util.h"
+#include "mongo/util/log.h"
+#include "mongo/util/mongoutils/str.h"
+
+namespace mongo {
+namespace {
+
+using std::begin;
+using std::end;
+using std::endl;
+using std::back_inserter;
+using std::string;
+using std::vector;
+
+
+MONGO_INITIALIZER_WITH_PREREQUISITES(SetupInternalSecurityUser, ("EndStartupOptionStorage"))
+(InitializerContext* const context) try {
+ User* user = new User(UserName("__system", "local"));
+
+ user->incrementRefCount(); // Pin this user so the ref count never drops below 1.
+ ActionSet allActions;
+ allActions.addAllActions();
+ PrivilegeVector privileges;
+ RoleGraph::generateUniversalPrivileges(&privileges);
+ user->addPrivileges(privileges);
+
+ if (mongodGlobalParams.whitelistedClusterNetwork) {
+ const auto& whitelist = *mongodGlobalParams.whitelistedClusterNetwork;
+
+ auto restriction = stdx::make_unique<ClientSourceRestriction>(whitelist);
+ auto restrictionSet = stdx::make_unique<RestrictionSet<>>(std::move(restriction));
+ auto restrictionDocument =
+ stdx::make_unique<RestrictionDocument<>>(std::move(restrictionSet));
+
+ RestrictionDocuments clusterWhiteList(std::move(restrictionDocument));
+
+ user->setRestrictions(std::move(clusterWhiteList));
+ }
+
+
+ internalSecurity.user = user;
+
+ return Status::OK();
+} catch (...) {
+ return exceptionToStatus();
+}
+} // namespace
+
+
+MONGO_REGISTER_SHIM(AuthorizationManager::create)()->std::unique_ptr<AuthorizationManager> {
+ return std::make_unique<AuthorizationManagerImpl>();
+}
+
+/**
+ * Guard object for synchronizing accesses to data cached in AuthorizationManager instances.
+ * This guard allows one thread to access the cache at a time, and provides an exception-safe
+ * mechanism for a thread to release the cache mutex while performing network or disk operations
+ * while allowing other readers to proceed.
+ *
+ * There are two ways to use this guard. One may simply instantiate the guard like a
+ * std::lock_guard, and perform reads or writes of the cache.
+ *
+ * Alternatively, one may instantiate the guard, examine the cache, and then enter into an
+ * update mode by first wait()ing until otherUpdateInFetchPhase() is false, and then
+ * calling beginFetchPhase(). At this point, other threads may acquire the guard in the simple
+ * manner and do reads, but other threads may not enter into a fetch phase. During the fetch
+ * phase, the thread should perform required network or disk activity to determine what update
+ * it will make to the cache. Then, it should call endFetchPhase(), to reacquire the user cache
+ * mutex. At that point, the thread can make its modifications to the cache and let the guard
+ * go out of scope.
+ *
+ * All updates by guards using a fetch-phase are totally ordered with respect to one another,
+ * and all guards using no fetch phase are totally ordered with respect to one another, but
+ * there is not a total ordering among all guard objects.
+ *
+ * The cached data has an associated counter, called the cache generation. If the cache
+ * generation changes while a guard is in fetch phase, the fetched data should not be stored
+ * into the cache, because some invalidation event occurred during the fetch phase.
+ *
+ * NOTE: It is not safe to enter fetch phase while holding a database lock. Fetch phase
+ * operations are allowed to acquire database locks themselves, so entering fetch while holding
+ * a database lock may lead to deadlock.
+ */
+class AuthorizationManagerImpl::CacheGuard {
+ MONGO_DISALLOW_COPYING(CacheGuard);
+
+public:
+ enum FetchSynchronization { fetchSynchronizationAutomatic, fetchSynchronizationManual };
+
+ /**
+ * Constructs a cache guard, locking the mutex that synchronizes user cache accesses.
+ */
+ CacheGuard(AuthorizationManagerImpl* authzManager,
+ const FetchSynchronization sync = fetchSynchronizationAutomatic)
+ : _isThisGuardInFetchPhase(false),
+ _authzManager(authzManager),
+ _lock(authzManager->_cacheMutex) {
+ if (fetchSynchronizationAutomatic == sync) {
+ synchronizeWithFetchPhase();
+ }
+ }
+
+ /**
+ * Releases the mutex that synchronizes user cache access, if held, and notifies
+ * any threads waiting for their own opportunity to update the user cache.
+ */
+ ~CacheGuard() {
+ if (!_lock.owns_lock()) {
+ _lock.lock();
+ }
+ if (_isThisGuardInFetchPhase) {
+ fassert(17190, _authzManager->_isFetchPhaseBusy);
+ _authzManager->_isFetchPhaseBusy = false;
+ _authzManager->_fetchPhaseIsReady.notify_all();
+ }
+ }
+
+ /**
+ * Returns true of the authzManager reports that it is in fetch phase.
+ */
+ bool otherUpdateInFetchPhase() {
+ return _authzManager->_isFetchPhaseBusy;
+ }
+
+ /**
+ * Waits on the _authzManager->_fetchPhaseIsReady condition.
+ */
+ void wait() {
+ fassert(17222, !_isThisGuardInFetchPhase);
+ _authzManager->_fetchPhaseIsReady.wait(_lock);
+ }
+
+ /**
+ * Enters fetch phase, releasing the _authzManager->_cacheMutex after recording the current
+ * cache generation.
+ */
+ void beginFetchPhase() {
+ fassert(17191, !_authzManager->_isFetchPhaseBusy);
+ _isThisGuardInFetchPhase = true;
+ _authzManager->_isFetchPhaseBusy = true;
+ _startGeneration = _authzManager->_cacheGeneration;
+ _lock.unlock();
+ }
+
+ /**
+ * Exits the fetch phase, reacquiring the _authzManager->_cacheMutex.
+ */
+ void endFetchPhase() {
+ _lock.lock();
+ // We do not clear _authzManager->_isFetchPhaseBusy or notify waiters until
+ // ~CacheGuard(), for two reasons. First, there's no value to notifying the waiters
+ // before you're ready to release the mutex, because they'll just go to sleep on the
+ // mutex. Second, in order to meaningfully check the preconditions of
+ // isSameCacheGeneration(), we need a state that means "fetch phase was entered and now
+ // has been exited." That state is _isThisGuardInFetchPhase == true and
+ // _lock.owns_lock() == true.
+ }
+
+ /**
+ * Returns true if _authzManager->_cacheGeneration remained the same while this guard was
+ * in fetch phase. Behavior is undefined if this guard never entered fetch phase.
+ *
+ * If this returns true, do not update the cached data with this
+ */
+ bool isSameCacheGeneration() const {
+ fassert(17223, _isThisGuardInFetchPhase);
+ fassert(17231, _lock.owns_lock());
+ return _startGeneration == _authzManager->_cacheGeneration;
+ }
+
+private:
+ void synchronizeWithFetchPhase() {
+ while (otherUpdateInFetchPhase())
+ wait();
+ fassert(17192, !_authzManager->_isFetchPhaseBusy);
+ _isThisGuardInFetchPhase = true;
+ _authzManager->_isFetchPhaseBusy = true;
+ }
+
+ OID _startGeneration;
+ bool _isThisGuardInFetchPhase;
+ AuthorizationManagerImpl* _authzManager;
+ stdx::unique_lock<stdx::mutex> _lock;
+};
+
+AuthorizationManagerImpl::AuthorizationManagerImpl()
+ : AuthorizationManagerImpl(AuthzManagerExternalState::create(),
+ InstallMockForTestingOrAuthImpl{}) {}
+
+AuthorizationManagerImpl::AuthorizationManagerImpl(
+ std::unique_ptr<AuthzManagerExternalState> externalState, InstallMockForTestingOrAuthImpl)
+ : _authEnabled(false),
+ _privilegeDocsExist(false),
+ _externalState(std::move(externalState)),
+ _version(schemaVersionInvalid),
+ _isFetchPhaseBusy(false) {
+ _updateCacheGeneration_inlock();
+}
+
+AuthorizationManagerImpl::~AuthorizationManagerImpl() {
+ for (stdx::unordered_map<UserName, User*>::iterator it = _userCache.begin();
+ it != _userCache.end();
+ ++it) {
+ fassert(17265, it->second != internalSecurity.user);
+ delete it->second;
+ }
+}
+
+std::unique_ptr<AuthorizationSession> AuthorizationManagerImpl::makeAuthorizationSession() {
+ return std::make_unique<AuthorizationSessionImpl>(
+ _externalState->makeAuthzSessionExternalState(this),
+ AuthorizationSessionImpl::InstallMockForTestingOrAuthImpl{});
+}
+
+void AuthorizationManagerImpl::setShouldValidateAuthSchemaOnStartup(bool validate) {
+ _startupAuthSchemaValidation = validate;
+}
+
+bool AuthorizationManagerImpl::shouldValidateAuthSchemaOnStartup() {
+ return _startupAuthSchemaValidation;
+}
+
+Status AuthorizationManagerImpl::getAuthorizationVersion(OperationContext* opCtx, int* version) {
+ CacheGuard guard(this, CacheGuard::fetchSynchronizationManual);
+ int newVersion = _version;
+ if (schemaVersionInvalid == newVersion) {
+ while (guard.otherUpdateInFetchPhase())
+ guard.wait();
+ guard.beginFetchPhase();
+ Status status = _externalState->getStoredAuthorizationVersion(opCtx, &newVersion);
+ guard.endFetchPhase();
+ if (!status.isOK()) {
+ warning() << "Problem fetching the stored schema version of authorization data: "
+ << redact(status);
+ *version = schemaVersionInvalid;
+ return status;
+ }
+
+ if (guard.isSameCacheGeneration()) {
+ _version = newVersion;
+ }
+ }
+ *version = newVersion;
+ return Status::OK();
+}
+
+OID AuthorizationManagerImpl::getCacheGeneration() {
+ CacheGuard guard(this, CacheGuard::fetchSynchronizationManual);
+ return _cacheGeneration;
+}
+
+void AuthorizationManagerImpl::setAuthEnabled(bool enabled) {
+ _authEnabled = enabled;
+}
+
+bool AuthorizationManagerImpl::isAuthEnabled() const {
+ return _authEnabled;
+}
+
+bool AuthorizationManagerImpl::hasAnyPrivilegeDocuments(OperationContext* opCtx) {
+ stdx::unique_lock<stdx::mutex> lk(_privilegeDocsExistMutex);
+ if (_privilegeDocsExist) {
+ // If we know that a user exists, don't re-check.
+ return true;
+ }
+
+ lk.unlock();
+ bool privDocsExist = _externalState->hasAnyPrivilegeDocuments(opCtx);
+ lk.lock();
+
+ if (privDocsExist) {
+ _privilegeDocsExist = true;
+ }
+
+ return _privilegeDocsExist;
+}
+
+Status AuthorizationManager::getBSONForPrivileges(const PrivilegeVector& privileges,
+ mutablebson::Element resultArray) {
+ for (PrivilegeVector::const_iterator it = privileges.begin(); it != privileges.end(); ++it) {
+ std::string errmsg;
+ ParsedPrivilege privilege;
+ if (!ParsedPrivilege::privilegeToParsedPrivilege(*it, &privilege, &errmsg)) {
+ return Status(ErrorCodes::BadValue, errmsg);
+ }
+ resultArray.appendObject("privileges", privilege.toBSON()).transitional_ignore();
+ }
+ return Status::OK();
+}
+
+Status AuthorizationManager::getBSONForRole(RoleGraph* graph,
+ const RoleName& roleName,
+ mutablebson::Element result) {
+ if (!graph->roleExists(roleName)) {
+ return Status(ErrorCodes::RoleNotFound,
+ mongoutils::str::stream() << roleName.getFullName()
+ << "does not name an existing role");
+ }
+ std::string id = mongoutils::str::stream() << roleName.getDB() << "." << roleName.getRole();
+ result.appendString("_id", id).transitional_ignore();
+ result.appendString(ROLE_NAME_FIELD_NAME, roleName.getRole()).transitional_ignore();
+ result.appendString(ROLE_DB_FIELD_NAME, roleName.getDB()).transitional_ignore();
+
+ // Build privileges array
+ mutablebson::Element privilegesArrayElement =
+ result.getDocument().makeElementArray("privileges");
+ result.pushBack(privilegesArrayElement).transitional_ignore();
+ const PrivilegeVector& privileges = graph->getDirectPrivileges(roleName);
+ Status status = getBSONForPrivileges(privileges, privilegesArrayElement);
+ if (!status.isOK()) {
+ return status;
+ }
+
+ // Build roles array
+ mutablebson::Element rolesArrayElement = result.getDocument().makeElementArray("roles");
+ result.pushBack(rolesArrayElement).transitional_ignore();
+ for (RoleNameIterator roles = graph->getDirectSubordinates(roleName); roles.more();
+ roles.next()) {
+ const RoleName& subRole = roles.get();
+ mutablebson::Element roleObj = result.getDocument().makeElementObject("");
+ roleObj.appendString(ROLE_NAME_FIELD_NAME, subRole.getRole()).transitional_ignore();
+ roleObj.appendString(ROLE_DB_FIELD_NAME, subRole.getDB()).transitional_ignore();
+ rolesArrayElement.pushBack(roleObj).transitional_ignore();
+ }
+
+ return Status::OK();
+}
+
+Status AuthorizationManagerImpl::_initializeUserFromPrivilegeDocument(User* user,
+ const BSONObj& privDoc) {
+ V2UserDocumentParser parser;
+ std::string userName = parser.extractUserNameFromUserDocument(privDoc);
+ if (userName != user->getName().getUser()) {
+ return Status(ErrorCodes::BadValue,
+ mongoutils::str::stream() << "User name from privilege document \""
+ << userName
+ << "\" doesn't match name of provided User \""
+ << user->getName().getUser()
+ << "\"");
+ }
+
+ Status status = parser.initializeUserCredentialsFromUserDocument(user, privDoc);
+ if (!status.isOK()) {
+ return status;
+ }
+ status = parser.initializeUserRolesFromUserDocument(privDoc, user);
+ if (!status.isOK()) {
+ return status;
+ }
+ status = parser.initializeUserIndirectRolesFromUserDocument(privDoc, user);
+ if (!status.isOK()) {
+ return status;
+ }
+ status = parser.initializeUserPrivilegesFromUserDocument(privDoc, user);
+ if (!status.isOK()) {
+ return status;
+ }
+ status = parser.initializeAuthenticationRestrictionsFromUserDocument(privDoc, user);
+ if (!status.isOK()) {
+ return status;
+ }
+
+ return Status::OK();
+}
+
+Status AuthorizationManagerImpl::getUserDescription(OperationContext* opCtx,
+ const UserName& userName,
+ BSONObj* result) {
+ return _externalState->getUserDescription(opCtx, userName, result);
+}
+
+Status AuthorizationManagerImpl::getRoleDescription(OperationContext* opCtx,
+ const RoleName& roleName,
+ PrivilegeFormat privileges,
+ AuthenticationRestrictionsFormat restrictions,
+ BSONObj* result) {
+ return _externalState->getRoleDescription(opCtx, roleName, privileges, restrictions, result);
+}
+
+Status AuthorizationManagerImpl::getRolesDescription(OperationContext* opCtx,
+ const std::vector<RoleName>& roleName,
+ PrivilegeFormat privileges,
+ AuthenticationRestrictionsFormat restrictions,
+ BSONObj* result) {
+ return _externalState->getRolesDescription(opCtx, roleName, privileges, restrictions, result);
+}
+
+
+Status AuthorizationManagerImpl::getRoleDescriptionsForDB(
+ OperationContext* opCtx,
+ const std::string dbname,
+ PrivilegeFormat privileges,
+ AuthenticationRestrictionsFormat restrictions,
+ bool showBuiltinRoles,
+ vector<BSONObj>* result) {
+ return _externalState->getRoleDescriptionsForDB(
+ opCtx, dbname, privileges, restrictions, showBuiltinRoles, result);
+}
+
+Status AuthorizationManagerImpl::acquireUser(OperationContext* opCtx,
+ const UserName& userName,
+ User** acquiredUser) {
+ if (userName == internalSecurity.user->getName()) {
+ *acquiredUser = internalSecurity.user;
+ return Status::OK();
+ }
+
+ stdx::unordered_map<UserName, User*>::iterator it;
+
+ CacheGuard guard(this, CacheGuard::fetchSynchronizationManual);
+ while ((_userCache.end() == (it = _userCache.find(userName))) &&
+ guard.otherUpdateInFetchPhase()) {
+ guard.wait();
+ }
+
+ if (it != _userCache.end()) {
+ fassert(16914, it->second);
+ fassert(17003, it->second->isValid());
+ fassert(17008, it->second->getRefCount() > 0);
+ it->second->incrementRefCount();
+ *acquiredUser = it->second;
+ return Status::OK();
+ }
+
+ std::unique_ptr<User> user;
+
+ int authzVersion = _version;
+ guard.beginFetchPhase();
+
+ // Number of times to retry a user document that fetches due to transient
+ // AuthSchemaIncompatible errors. These errors should only ever occur during and shortly
+ // after schema upgrades.
+ static const int maxAcquireRetries = 2;
+ Status status = Status::OK();
+ for (int i = 0; i < maxAcquireRetries; ++i) {
+ if (authzVersion == schemaVersionInvalid) {
+ Status status = _externalState->getStoredAuthorizationVersion(opCtx, &authzVersion);
+ if (!status.isOK())
+ return status;
+ }
+
+ switch (authzVersion) {
+ default:
+ status = Status(ErrorCodes::BadValue,
+ mongoutils::str::stream()
+ << "Illegal value for authorization data schema version, "
+ << authzVersion);
+ break;
+ case schemaVersion28SCRAM:
+ case schemaVersion26Final:
+ case schemaVersion26Upgrade:
+ status = _fetchUserV2(opCtx, userName, &user);
+ break;
+ case schemaVersion24:
+ status = Status(ErrorCodes::AuthSchemaIncompatible,
+ mongoutils::str::stream()
+ << "Authorization data schema version "
+ << schemaVersion24
+ << " not supported after MongoDB version 2.6.");
+ break;
+ }
+ if (status.isOK())
+ break;
+ if (status != ErrorCodes::AuthSchemaIncompatible)
+ return status;
+
+ authzVersion = schemaVersionInvalid;
+ }
+ if (!status.isOK())
+ return status;
+
+ guard.endFetchPhase();
+
+ user->incrementRefCount();
+ // NOTE: It is not safe to throw an exception from here to the end of the method.
+ if (guard.isSameCacheGeneration()) {
+ _userCache.insert(std::make_pair(userName, user.get()));
+ if (_version == schemaVersionInvalid)
+ _version = authzVersion;
+ } else {
+ // If the cache generation changed while this thread was in fetch mode, the data
+ // associated with the user may now be invalid, so we must mark it as such. The caller
+ // may still opt to use the information for a short while, but not indefinitely.
+ user->invalidate();
+ }
+ *acquiredUser = user.release();
+
+ return Status::OK();
+}
+
+Status AuthorizationManagerImpl::_fetchUserV2(OperationContext* opCtx,
+ const UserName& userName,
+ std::unique_ptr<User>* acquiredUser) {
+ BSONObj userObj;
+ Status status = getUserDescription(opCtx, userName, &userObj);
+ if (!status.isOK()) {
+ return status;
+ }
+
+ // Put the new user into an unique_ptr temporarily in case there's an error while
+ // initializing the user.
+ auto user = stdx::make_unique<User>(userName);
+
+ status = _initializeUserFromPrivilegeDocument(user.get(), userObj);
+ if (!status.isOK()) {
+ return status;
+ }
+ acquiredUser->reset(user.release());
+ return Status::OK();
+}
+
+void AuthorizationManagerImpl::releaseUser(User* user) {
+ if (user == internalSecurity.user) {
+ return;
+ }
+
+ CacheGuard guard(this, CacheGuard::fetchSynchronizationManual);
+ user->decrementRefCount();
+ if (user->getRefCount() == 0) {
+ // If it's been invalidated then it's not in the _userCache anymore.
+ if (user->isValid()) {
+ MONGO_COMPILER_VARIABLE_UNUSED bool erased = _userCache.erase(user->getName());
+ dassert(erased);
+ }
+ delete user;
+ }
+}
+
+void AuthorizationManagerImpl::invalidateUserByName(const UserName& userName) {
+ CacheGuard guard(this, CacheGuard::fetchSynchronizationManual);
+ _updateCacheGeneration_inlock();
+ stdx::unordered_map<UserName, User*>::iterator it = _userCache.find(userName);
+ if (it == _userCache.end()) {
+ return;
+ }
+
+ User* user = it->second;
+ _userCache.erase(it);
+ user->invalidate();
+}
+
+void AuthorizationManagerImpl::invalidateUsersFromDB(const std::string& dbname) {
+ CacheGuard guard(this, CacheGuard::fetchSynchronizationManual);
+ _updateCacheGeneration_inlock();
+ stdx::unordered_map<UserName, User*>::iterator it = _userCache.begin();
+ while (it != _userCache.end()) {
+ User* user = it->second;
+ if (user->getName().getDB() == dbname) {
+ _userCache.erase(it++);
+ user->invalidate();
+ } else {
+ ++it;
+ }
+ }
+}
+
+void AuthorizationManagerImpl::invalidateUserCache() {
+ CacheGuard guard(this, CacheGuard::fetchSynchronizationManual);
+ _invalidateUserCache_inlock();
+}
+
+void AuthorizationManagerImpl::_invalidateUserCache_inlock() {
+ _updateCacheGeneration_inlock();
+ for (stdx::unordered_map<UserName, User*>::iterator it = _userCache.begin();
+ it != _userCache.end();
+ ++it) {
+ fassert(17266, it->second != internalSecurity.user);
+ it->second->invalidate();
+ }
+ _userCache.clear();
+
+ // Reread the schema version before acquiring the next user.
+ _version = schemaVersionInvalid;
+}
+
+Status AuthorizationManagerImpl::initialize(OperationContext* opCtx) {
+ invalidateUserCache();
+ Status status = _externalState->initialize(opCtx);
+ if (!status.isOK())
+ return status;
+
+ return Status::OK();
+}
+
+namespace {
+bool isAuthzNamespace(const NamespaceString& nss) {
+ return (nss == AuthorizationManager::rolesCollectionNamespace ||
+ nss == AuthorizationManager::usersCollectionNamespace ||
+ nss == AuthorizationManager::versionCollectionNamespace);
+}
+
+bool isAuthzCollection(StringData coll) {
+ return (coll == AuthorizationManager::rolesCollectionNamespace.coll() ||
+ coll == AuthorizationManager::usersCollectionNamespace.coll() ||
+ coll == AuthorizationManager::versionCollectionNamespace.coll());
+}
+
+bool loggedCommandOperatesOnAuthzData(const NamespaceString& nss, const BSONObj& cmdObj) {
+ if (nss != AuthorizationManager::adminCommandNamespace)
+ return false;
+ const StringData cmdName(cmdObj.firstElement().fieldNameStringData());
+ if (cmdName == "drop") {
+ return isAuthzCollection(cmdObj.firstElement().valueStringData());
+ } else if (cmdName == "dropDatabase") {
+ return true;
+ } else if (cmdName == "renameCollection") {
+ return isAuthzCollection(cmdObj.firstElement().str()) ||
+ isAuthzCollection(cmdObj["to"].str());
+ } else if (cmdName == "dropIndexes" || cmdName == "deleteIndexes") {
+ return false;
+ } else if (cmdName == "create") {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+bool appliesToAuthzData(const char* op, const NamespaceString& nss, const BSONObj& o) {
+ switch (*op) {
+ case 'i':
+ case 'u':
+ case 'd':
+ if (op[1] != '\0')
+ return false; // "db" op type
+ return isAuthzNamespace(nss);
+ case 'c':
+ return loggedCommandOperatesOnAuthzData(nss, o);
+ break;
+ case 'n':
+ return false;
+ default:
+ return true;
+ }
+}
+
+// Updates to users in the oplog are done by matching on the _id, which will always have the
+// form "<dbname>.<username>". This function extracts the UserName from that string.
+StatusWith<UserName> extractUserNameFromIdString(StringData idstr) {
+ size_t splitPoint = idstr.find('.');
+ if (splitPoint == string::npos) {
+ return StatusWith<UserName>(ErrorCodes::FailedToParse,
+ mongoutils::str::stream()
+ << "_id entries for user documents must be of "
+ "the form <dbname>.<username>. Found: "
+ << idstr);
+ }
+ return StatusWith<UserName>(
+ UserName(idstr.substr(splitPoint + 1), idstr.substr(0, splitPoint)));
+}
+
+} // namespace
+
+void AuthorizationManagerImpl::_updateCacheGeneration_inlock() {
+ _cacheGeneration = OID::gen();
+}
+
+void AuthorizationManagerImpl::_invalidateRelevantCacheData(const char* op,
+ const NamespaceString& ns,
+ const BSONObj& o,
+ const BSONObj* o2) {
+ if (ns == AuthorizationManager::rolesCollectionNamespace ||
+ ns == AuthorizationManager::versionCollectionNamespace) {
+ invalidateUserCache();
+ return;
+ }
+
+ if (*op == 'i' || *op == 'd' || *op == 'u') {
+ // If you got into this function isAuthzNamespace() must have returned true, and we've
+ // already checked that it's not the roles or version collection.
+ invariant(ns == AuthorizationManager::usersCollectionNamespace);
+
+ StatusWith<UserName> userName = (*op == 'u')
+ ? extractUserNameFromIdString((*o2)["_id"].str())
+ : extractUserNameFromIdString(o["_id"].str());
+
+ if (!userName.isOK()) {
+ warning() << "Invalidating user cache based on user being updated failed, will "
+ "invalidate the entire cache instead: "
+ << userName.getStatus();
+ invalidateUserCache();
+ return;
+ }
+ invalidateUserByName(userName.getValue());
+ } else {
+ invalidateUserCache();
+ }
+}
+
+void AuthorizationManagerImpl::logOp(OperationContext* opCtx,
+ const char* op,
+ const NamespaceString& nss,
+ const BSONObj& o,
+ const BSONObj* o2) {
+ if (appliesToAuthzData(op, nss, o)) {
+ _externalState->logOp(opCtx, op, nss, o, o2);
+ _invalidateRelevantCacheData(op, nss, o, o2);
+ }
+}
+
+} // namespace mongo
diff --git a/src/mongo/db/auth/authorization_manager_impl.h b/src/mongo/db/auth/authorization_manager_impl.h
new file mode 100644
index 00000000000..09f3b4ae885
--- /dev/null
+++ b/src/mongo/db/auth/authorization_manager_impl.h
@@ -0,0 +1,246 @@
+/**
+ * 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 "mongo/db/auth/authorization_manager.h"
+
+#include <memory>
+#include <string>
+
+#include "mongo/base/disallow_copying.h"
+#include "mongo/base/secure_allocator.h"
+#include "mongo/base/status.h"
+#include "mongo/bson/mutable/element.h"
+#include "mongo/bson/oid.h"
+#include "mongo/db/auth/action_set.h"
+#include "mongo/db/auth/privilege_format.h"
+#include "mongo/db/auth/resource_pattern.h"
+#include "mongo/db/auth/role_graph.h"
+#include "mongo/db/auth/user.h"
+#include "mongo/db/auth/user_name.h"
+#include "mongo/db/auth/user_name_hash.h"
+#include "mongo/db/jsobj.h"
+#include "mongo/db/namespace_string.h"
+#include "mongo/db/server_options.h"
+#include "mongo/stdx/condition_variable.h"
+#include "mongo/stdx/functional.h"
+#include "mongo/stdx/mutex.h"
+#include "mongo/stdx/unordered_map.h"
+
+namespace mongo {
+class AuthorizationSession;
+class AuthzManagerExternalState;
+class OperationContext;
+class ServiceContext;
+class UserDocumentParser;
+
+/**
+ * Contains server/cluster-wide information about Authorization.
+ */
+class AuthorizationManagerImpl : public AuthorizationManager {
+public:
+ ~AuthorizationManagerImpl() override;
+
+ AuthorizationManagerImpl();
+
+ struct InstallMockForTestingOrAuthImpl {
+ explicit InstallMockForTestingOrAuthImpl() = default;
+ };
+
+ AuthorizationManagerImpl(std::unique_ptr<AuthzManagerExternalState> externalState,
+ InstallMockForTestingOrAuthImpl);
+
+ std::unique_ptr<AuthorizationSession> makeAuthorizationSession() override;
+
+ void setShouldValidateAuthSchemaOnStartup(bool validate) override;
+
+ bool shouldValidateAuthSchemaOnStartup() override;
+
+ void setAuthEnabled(bool enabled) override;
+
+ bool isAuthEnabled() const override;
+
+ Status getAuthorizationVersion(OperationContext* opCtx, int* version) override;
+
+ OID getCacheGeneration() override;
+
+ bool hasAnyPrivilegeDocuments(OperationContext* opCtx) override;
+
+ Status getUserDescription(OperationContext* opCtx,
+ const UserName& userName,
+ BSONObj* result) override;
+
+ Status getRoleDescription(OperationContext* opCtx,
+ const RoleName& roleName,
+ PrivilegeFormat privilegeFormat,
+ AuthenticationRestrictionsFormat,
+ BSONObj* result) override;
+
+ Status getRolesDescription(OperationContext* opCtx,
+ const std::vector<RoleName>& roleName,
+ PrivilegeFormat privilegeFormat,
+ AuthenticationRestrictionsFormat,
+ BSONObj* result) override;
+
+ Status getRoleDescriptionsForDB(OperationContext* opCtx,
+ const std::string dbname,
+ PrivilegeFormat privilegeFormat,
+ AuthenticationRestrictionsFormat,
+ bool showBuiltinRoles,
+ std::vector<BSONObj>* result) override;
+
+ Status acquireUser(OperationContext* opCtx,
+ const UserName& userName,
+ User** acquiredUser) override;
+
+ void releaseUser(User* user) override;
+
+ void invalidateUserByName(const UserName& user) override;
+
+ void invalidateUsersFromDB(const std::string& dbname) override;
+
+ Status initialize(OperationContext* opCtx) override;
+
+ void invalidateUserCache() override;
+
+ Status _initializeUserFromPrivilegeDocument(User* user, const BSONObj& privDoc) override;
+
+ void logOp(OperationContext* opCtx,
+ const char* opstr,
+ const NamespaceString& nss,
+ const BSONObj& obj,
+ const BSONObj* patt) override;
+
+private:
+ /**
+ * Type used to guard accesses and updates to the user cache.
+ */
+ class CacheGuard;
+ friend class AuthorizationManagerImpl::CacheGuard;
+
+ /**
+ * Invalidates all User objects in the cache and removes them from the cache.
+ * Should only be called when already holding _cacheMutex.
+ */
+ void _invalidateUserCache_inlock();
+
+ /**
+ * Given the objects describing an oplog entry that affects authorization data, invalidates
+ * the portion of the user cache that is affected by that operation. Should only be called
+ * with oplog entries that have been pre-verified to actually affect authorization data.
+ */
+ void _invalidateRelevantCacheData(const char* op,
+ const NamespaceString& ns,
+ const BSONObj& o,
+ const BSONObj* o2);
+
+ /**
+ * Updates _cacheGeneration to a new OID
+ */
+ void _updateCacheGeneration_inlock();
+
+ /**
+ * Fetches user information from a v2-schema user document for the named user,
+ * and stores a pointer to a new user object into *acquiredUser on success.
+ */
+ Status _fetchUserV2(OperationContext* opCtx,
+ const UserName& userName,
+ std::unique_ptr<User>* acquiredUser);
+
+ /**
+ * True if AuthSchema startup checks should be applied in this AuthorizationManager.
+ *
+ * Defaults to true. Changes to its value are not synchronized, so it should only be set
+ * at initalization-time.
+ */
+ bool _startupAuthSchemaValidation;
+
+ /**
+ * True if access control enforcement is enabled in this AuthorizationManager.
+ *
+ * Defaults to false. Changes to its value are not synchronized, so it should only be set
+ * at initalization-time.
+ */
+ bool _authEnabled;
+
+ /**
+ * A cache of whether there are any users set up for the cluster.
+ */
+ bool _privilegeDocsExist;
+
+ // Protects _privilegeDocsExist
+ mutable stdx::mutex _privilegeDocsExistMutex;
+
+ std::unique_ptr<AuthzManagerExternalState> _externalState;
+
+ /**
+ * Cached value of the authorization schema version.
+ *
+ * May be set by acquireUser() and getAuthorizationVersion(). Invalidated by
+ * invalidateUserCache().
+ *
+ * Reads and writes guarded by CacheGuard.
+ */
+ int _version;
+
+ /**
+ * Caches User objects with information about user privileges, to avoid the need to
+ * go to disk to read user privilege documents whenever possible. Every User object
+ * has a reference count - the AuthorizationManager must not delete a User object in the
+ * cache unless its reference count is zero.
+ */
+ stdx::unordered_map<UserName, User*> _userCache;
+
+ /**
+ * Current generation of cached data. Updated every time part of the cache gets
+ * invalidated. Protected by CacheGuard.
+ */
+ OID _cacheGeneration;
+
+ /**
+ * True if there is an update to the _userCache in progress, and that update is currently in
+ * the "fetch phase", during which it does not hold the _cacheMutex.
+ *
+ * Manipulated via CacheGuard.
+ */
+ bool _isFetchPhaseBusy;
+
+ /**
+ * Protects _userCache, _cacheGeneration, _version and _isFetchPhaseBusy. Manipulated
+ * via CacheGuard.
+ */
+ stdx::mutex _cacheMutex;
+
+ /**
+ * Condition used to signal that it is OK for another CacheGuard to enter a fetch phase.
+ * Manipulated via CacheGuard.
+ */
+ stdx::condition_variable _fetchPhaseIsReady;
+};
+} // namespace mongo
diff --git a/src/mongo/db/auth/authorization_manager_mock_init.cpp b/src/mongo/db/auth/authorization_manager_mock_init.cpp
deleted file mode 100644
index fd19cef1160..00000000000
--- a/src/mongo/db/auth/authorization_manager_mock_init.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2016 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/base/init.h"
-#include "mongo/db/auth/authorization_manager.h"
-#include "mongo/db/auth/authz_manager_external_state.h"
-#include "mongo/db/auth/authz_manager_external_state_mock.h"
-#include "mongo/stdx/memory.h"
-
-
-// This file provides mock initialization for tests which depend upon,
-// but do not use, the auth subsystem.
-// TODO: Remove this file once all unused inclusion of auth has been removed.
-
-namespace mongo {
-namespace {
-
-std::unique_ptr<AuthzManagerExternalState> createAuthzManagerExternalStateMock() {
- return stdx::make_unique<AuthzManagerExternalStateMock>();
-}
-
-MONGO_INITIALIZER(CreateAuthorizationExternalStateFactory)(InitializerContext* context) {
- AuthzManagerExternalState::create = &createAuthzManagerExternalStateMock;
- return Status::OK();
-}
-
-} // namespace
-} // namespace mongo
diff --git a/src/mongo/db/auth/authorization_manager_test.cpp b/src/mongo/db/auth/authorization_manager_test.cpp
index 90cd5a6b243..c382e0e8e00 100644
--- a/src/mongo/db/auth/authorization_manager_test.cpp
+++ b/src/mongo/db/auth/authorization_manager_test.cpp
@@ -38,6 +38,7 @@
#include "mongo/db/auth/action_set.h"
#include "mongo/db/auth/action_type.h"
#include "mongo/db/auth/authorization_manager.h"
+#include "mongo/db/auth/authorization_manager_impl.h"
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/auth/authz_manager_external_state_mock.h"
#include "mongo/db/auth/authz_session_external_state_mock.h"
@@ -174,7 +175,9 @@ public:
void setUp() override {
auto localExternalState = stdx::make_unique<AuthzManagerExternalStateMock>();
externalState = localExternalState.get();
- authzManager = stdx::make_unique<AuthorizationManager>(std::move(localExternalState));
+ authzManager = stdx::make_unique<AuthorizationManagerImpl>(
+ std::move(localExternalState),
+ AuthorizationManagerImpl::InstallMockForTestingOrAuthImpl{});
externalState->setAuthorizationManager(authzManager.get());
authzManager->setAuthEnabled(true);
@@ -369,7 +372,9 @@ public:
stdx::make_unique<AuthzManagerExternalStateMockWithExplicitUserPrivileges>();
externalState = localExternalState.get();
externalState->setAuthzVersion(AuthorizationManager::schemaVersion26Final);
- authzManager = stdx::make_unique<AuthorizationManager>(std::move(localExternalState));
+ authzManager = stdx::make_unique<AuthorizationManagerImpl>(
+ std::move(localExternalState),
+ AuthorizationManagerImpl::InstallMockForTestingOrAuthImpl{});
externalState->setAuthorizationManager(authzManager.get());
authzManager->setAuthEnabled(true);
}
diff --git a/src/mongo/db/auth/authorization_session.cpp b/src/mongo/db/auth/authorization_session.cpp
index 8c71e6bdcea..6965c5c9809 100644
--- a/src/mongo/db/auth/authorization_session.cpp
+++ b/src/mongo/db/auth/authorization_session.cpp
@@ -57,1019 +57,14 @@
namespace mongo {
-namespace dps = ::mongo::dotted_path_support;
-using std::vector;
-
-namespace {
-const std::string ADMIN_DBNAME = "admin";
-
-// Checks if this connection has the privileges necessary to create or modify the view 'viewNs'
-// to be a view on 'viewOnNs' with pipeline 'viewPipeline'. Call this function after verifying
-// that the user has the 'createCollection' or 'collMod' action, respectively.
-Status checkAuthForCreateOrModifyView(AuthorizationSession* authzSession,
- const NamespaceString& viewNs,
- const NamespaceString& viewOnNs,
- const BSONArray& viewPipeline,
- bool isMongos) {
- // It's safe to allow a user to create or modify a view if they can't read it anyway.
- if (!authzSession->isAuthorizedForActionsOnNamespace(viewNs, ActionType::find)) {
- return Status::OK();
- }
-
- // This check performs some validation but it is not exhaustive and may allow for an invalid
- // pipeline specification. In this case the authorization check will succeed but the pipeline
- // will fail to parse later in Command::run().
- return authzSession->checkAuthForAggregate(
- viewOnNs,
- BSON("aggregate" << viewOnNs.coll() << "pipeline" << viewPipeline << "cursor" << BSONObj()),
- isMongos);
-}
-
-/** Deleter for User*.
- * Will release a User* back to its owning AuthorizationManager on destruction.
- * If a borrowing UserSet and the iterator it uses to store the User* is provided, this
- * deleter will release the User* from the set if the iterator still points to the deleting User*.
- */
-class UserReleaser {
-public:
- explicit UserReleaser(AuthorizationManager* owner) : _owner(owner), _borrower(nullptr) {}
- UserReleaser(AuthorizationManager* owner, UserSet* borrower, UserSet::iterator borrowerIt)
- : _owner(owner), _borrower(borrower), _it(borrowerIt) {}
-
- void operator()(User* user) {
- // Remove the user from the borrower if it hasn't already been swapped out.
- if (_borrower && *_it == user) {
- fassert(40546, _borrower->removeAt(_it) == user);
- }
- _owner->releaseUser(user);
- }
-
-protected:
- AuthorizationManager* _owner;
- UserSet* _borrower;
- UserSet::iterator _it;
-};
-/** Holder for User*s. If this Holder falls out of scope while holding a User*, it will release
- * the User* from its AuthorizationManager, and extract it from a UserSet if the set still contains
- * it. Use this object to guard User*s which will need to be destroyed in the event of an exception.
- */
-using UserHolder = std::unique_ptr<User, UserReleaser>;
-
-} // namespace
-
-AuthorizationSession::ScopedImpersonate::ScopedImpersonate(AuthorizationSession* authSession,
- std::vector<UserName>* users,
- std::vector<RoleName>* roles)
- : _authSession(*authSession), _users(*users), _roles(*roles) {
- swap();
-}
-
-AuthorizationSession::ScopedImpersonate::~ScopedImpersonate() {
- swap();
-}
+AuthorizationSession::~AuthorizationSession() = default;
void AuthorizationSession::ScopedImpersonate::swap() {
+ auto impersonations = _authSession._getImpersonations();
using std::swap;
- swap(_authSession._impersonatedUserNames, _users);
- swap(_authSession._impersonatedRoleNames, _roles);
-}
-
-AuthorizationSession::AuthorizationSession(std::unique_ptr<AuthzSessionExternalState> externalState)
- : _externalState(std::move(externalState)), _impersonationFlag(false) {}
-
-AuthorizationSession::~AuthorizationSession() {
- for (UserSet::iterator it = _authenticatedUsers.begin(); it != _authenticatedUsers.end();
- ++it) {
- getAuthorizationManager().releaseUser(*it);
- }
-}
-
-AuthorizationManager& AuthorizationSession::getAuthorizationManager() {
- return _externalState->getAuthorizationManager();
-}
-
-void AuthorizationSession::startRequest(OperationContext* opCtx) {
- _externalState->startRequest(opCtx);
- _refreshUserInfoAsNeeded(opCtx);
-}
-
-Status AuthorizationSession::addAndAuthorizeUser(OperationContext* opCtx,
- const UserName& userName) {
- User* user;
- AuthorizationManager* authzManager = AuthorizationManager::get(opCtx->getServiceContext());
- Status status = authzManager->acquireUser(opCtx, userName, &user);
- if (!status.isOK()) {
- return status;
- }
-
- UserHolder userHolder(user, UserReleaser(authzManager));
-
- const auto& restrictionSet = userHolder->getRestrictions();
- if (opCtx->getClient() == nullptr) {
- return Status(ErrorCodes::AuthenticationFailed,
- "Unable to evaluate restrictions, OperationContext has no Client");
- }
-
- Status restrictionStatus =
- restrictionSet.validate(RestrictionEnvironment::get(*opCtx->getClient()));
- if (!restrictionStatus.isOK()) {
- log() << "Failed to acquire user '" << userName
- << "' because of unmet authentication restrictions: " << restrictionStatus.reason();
- return AuthorizationManager::authenticationFailedStatus;
- }
-
- // Calling add() on the UserSet may return a user that was replaced because it was from the
- // same database.
- userHolder.reset(_authenticatedUsers.add(userHolder.release()));
-
- // If there are any users and roles in the impersonation data, clear it out.
- clearImpersonatedUserData();
-
- _buildAuthenticatedRolesVector();
- return Status::OK();
-}
-
-User* AuthorizationSession::lookupUser(const UserName& name) {
- return _authenticatedUsers.lookup(name);
-}
-
-User* AuthorizationSession::getSingleUser() {
- UserName userName;
-
- auto userNameItr = getAuthenticatedUserNames();
- if (userNameItr.more()) {
- userName = userNameItr.next();
- if (userNameItr.more()) {
- uasserted(ErrorCodes::Unauthorized, "too many users are authenticated");
- }
- } else {
- uasserted(ErrorCodes::Unauthorized, "there are no users authenticated");
- }
-
- return lookupUser(userName);
-}
-
-void AuthorizationSession::logoutDatabase(const std::string& dbname) {
- User* removedUser = _authenticatedUsers.removeByDBName(dbname);
- if (removedUser) {
- getAuthorizationManager().releaseUser(removedUser);
- }
- clearImpersonatedUserData();
- _buildAuthenticatedRolesVector();
-}
-
-bool AuthorizationSession::isAuthenticated() {
- return _authenticatedUsers.begin() != _authenticatedUsers.end();
-}
-
-UserNameIterator AuthorizationSession::getAuthenticatedUserNames() {
- return _authenticatedUsers.getNames();
-}
-
-RoleNameIterator AuthorizationSession::getAuthenticatedRoleNames() {
- return makeRoleNameIterator(_authenticatedRoleNames.begin(), _authenticatedRoleNames.end());
-}
-
-std::string AuthorizationSession::getAuthenticatedUserNamesToken() {
- std::string ret;
- for (UserNameIterator nameIter = getAuthenticatedUserNames(); nameIter.more();
- nameIter.next()) {
- ret += '\0'; // Using a NUL byte which isn't valid in usernames to separate them.
- ret += nameIter->getFullName();
- }
-
- return ret;
-}
-
-void AuthorizationSession::grantInternalAuthorization() {
- _authenticatedUsers.add(internalSecurity.user);
- _buildAuthenticatedRolesVector();
-}
-
-PrivilegeVector AuthorizationSession::getDefaultPrivileges() {
- PrivilegeVector defaultPrivileges;
-
- // If localhost exception is active (and no users exist),
- // return a vector of the minimum privileges required to bootstrap
- // a system and add the first user.
- if (_externalState->shouldAllowLocalhost()) {
- ResourcePattern adminDBResource = ResourcePattern::forDatabaseName(ADMIN_DBNAME);
- ActionSet setupAdminUserActionSet;
- setupAdminUserActionSet.addAction(ActionType::createUser);
- setupAdminUserActionSet.addAction(ActionType::grantRole);
- Privilege setupAdminUserPrivilege = Privilege(adminDBResource, setupAdminUserActionSet);
-
- ResourcePattern externalDBResource = ResourcePattern::forDatabaseName("$external");
- Privilege setupExternalUserPrivilege =
- Privilege(externalDBResource, ActionType::createUser);
-
- ActionSet setupServerConfigActionSet;
-
- // If this server is an arbiter, add specific privileges meant to circumvent
- // the behavior of an arbiter in an authenticated replset. See SERVER-5479.
- if (_externalState->serverIsArbiter()) {
- setupServerConfigActionSet.addAction(ActionType::getCmdLineOpts);
- setupServerConfigActionSet.addAction(ActionType::getParameter);
- setupServerConfigActionSet.addAction(ActionType::serverStatus);
- setupServerConfigActionSet.addAction(ActionType::shutdown);
- }
-
- setupServerConfigActionSet.addAction(ActionType::addShard);
- setupServerConfigActionSet.addAction(ActionType::replSetConfigure);
- setupServerConfigActionSet.addAction(ActionType::replSetGetStatus);
- Privilege setupServerConfigPrivilege =
- Privilege(ResourcePattern::forClusterResource(), setupServerConfigActionSet);
-
- Privilege::addPrivilegeToPrivilegeVector(&defaultPrivileges, setupAdminUserPrivilege);
- Privilege::addPrivilegeToPrivilegeVector(&defaultPrivileges, setupExternalUserPrivilege);
- Privilege::addPrivilegeToPrivilegeVector(&defaultPrivileges, setupServerConfigPrivilege);
- return defaultPrivileges;
- }
-
- return defaultPrivileges;
-}
-
-Status AuthorizationSession::checkAuthForAggregate(const NamespaceString& nss,
- const BSONObj& cmdObj,
- bool isMongos) {
- if (!nss.isValid()) {
- return Status(ErrorCodes::InvalidNamespace,
- mongoutils::str::stream() << "Invalid input namespace, " << nss.ns());
- }
-
- // If this connection does not need to be authenticated (for instance, if auth is disabled),
- // return Status::OK() immediately.
- if (_externalState->shouldIgnoreAuthChecks()) {
- return Status::OK();
- }
-
- // We require at least one authenticated user when running aggregate with auth enabled.
- if (!isAuthenticated()) {
- return Status(ErrorCodes::Unauthorized, "unauthorized");
- }
-
- auto statusWithAggRequest = AggregationRequest::parseFromBSON(nss, cmdObj);
- if (!statusWithAggRequest.isOK()) {
- return statusWithAggRequest.getStatus();
- }
- AggregationRequest aggRequest = std::move(statusWithAggRequest.getValue());
-
- const auto& pipeline = aggRequest.getPipeline();
-
- // If the aggregation pipeline is empty, confirm the user is authorized for find on 'nss'.
- if (pipeline.empty()) {
- if (!isAuthorizedForPrivilege(
- Privilege(ResourcePattern::forExactNamespace(nss), ActionType::find))) {
- return Status(ErrorCodes::Unauthorized, "unauthorized");
- }
-
- return Status::OK();
- }
-
- // Confirm the user is authorized for the pipeline's initial document source. We confirm a user
- // is authorized incrementally rather than once for the entire pipeline. This will prevent a
- // malicious user, who doesn't have access to the initial document source, from consuming the
- // resources needed to parse a potentially large pipeline.
- auto liteParsedFirstDocumentSource = LiteParsedDocumentSource::parse(aggRequest, pipeline[0]);
- if (!liteParsedFirstDocumentSource->isInitialSource() &&
- !isAuthorizedForPrivilege(
- Privilege(ResourcePattern::forExactNamespace(nss), ActionType::find))) {
- return Status(ErrorCodes::Unauthorized, "unauthorized");
- }
-
- // We have done the work to lite parse the first stage. Given that, we check required privileges
- // for it using 'liteParsedFirstDocumentSource' regardless of whether is an initial source or
- // not.
- if (!isAuthorizedForPrivileges(liteParsedFirstDocumentSource->requiredPrivileges(isMongos))) {
- return Status(ErrorCodes::Unauthorized, "unauthorized");
- }
-
- // Confirm privileges for the remainder of the pipepline. Start with the second stage as we have
- // already authorized the first.
- auto pipelineIter = pipeline.begin() + 1;
-
- for (; pipelineIter != pipeline.end(); ++pipelineIter) {
- auto liteParsedDocSource = LiteParsedDocumentSource::parse(aggRequest, *pipelineIter);
- if (!isAuthorizedForPrivileges(liteParsedDocSource->requiredPrivileges(isMongos))) {
- return Status(ErrorCodes::Unauthorized, "unauthorized");
- }
- }
-
- return Status::OK();
-}
-
-Status AuthorizationSession::checkAuthForFind(const NamespaceString& ns, bool hasTerm) {
- if (MONGO_unlikely(ns.isCommand())) {
- return Status(ErrorCodes::InternalError,
- str::stream() << "Checking query auth on command namespace " << ns.ns());
- }
- if (!isAuthorizedForActionsOnNamespace(ns, ActionType::find)) {
- return Status(ErrorCodes::Unauthorized,
- str::stream() << "not authorized for query on " << ns.ns());
- }
-
- // Only internal clients (such as other nodes in a replica set) are allowed to use
- // the 'term' field in a find operation. Use of this field could trigger changes
- // in the receiving server's replication state and should be protected.
- if (hasTerm &&
- !isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(),
- ActionType::internal)) {
- return Status(ErrorCodes::Unauthorized,
- str::stream() << "not authorized for query with term on " << ns.ns());
- }
-
- return Status::OK();
-}
-
-Status AuthorizationSession::checkAuthForGetMore(const NamespaceString& ns,
- long long cursorID,
- bool hasTerm) {
- // Since users can only getMore their own cursors, we verify that a user either is authenticated
- // or does not need to be.
- if (!_externalState->shouldIgnoreAuthChecks() && !isAuthenticated()) {
- return Status(ErrorCodes::Unauthorized,
- str::stream() << "not authorized for getMore on " << ns.db());
- }
-
- // Only internal clients (such as other nodes in a replica set) are allowed to use
- // the 'term' field in a getMore operation. Use of this field could trigger changes
- // in the receiving server's replication state and should be protected.
- if (hasTerm &&
- !isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(),
- ActionType::internal)) {
- return Status(ErrorCodes::Unauthorized,
- str::stream() << "not authorized for getMore with term on " << ns.ns());
- }
-
- return Status::OK();
-}
-
-Status AuthorizationSession::checkAuthForInsert(OperationContext* opCtx,
- const NamespaceString& ns,
- const BSONObj& document) {
- if (ns.coll() == "system.indexes"_sd) {
- BSONElement nsElement = document["ns"];
- if (nsElement.type() != String) {
- return Status(nsElement.type() == BSONType::EOO ? ErrorCodes::NoSuchKey
- : ErrorCodes::TypeMismatch,
- "Cannot authorize inserting into "
- "system.indexes documents without a string-typed \"ns\" field.");
- }
- NamespaceString indexNS(nsElement.valueStringData());
- if (!isAuthorizedForActionsOnNamespace(indexNS, ActionType::createIndex)) {
- return Status(ErrorCodes::Unauthorized,
- str::stream() << "not authorized to create index on " << indexNS.ns());
- }
- } else {
- ActionSet required{ActionType::insert};
- if (documentValidationDisabled(opCtx)) {
- required.addAction(ActionType::bypassDocumentValidation);
- }
- if (!isAuthorizedForActionsOnNamespace(ns, required)) {
- return Status(ErrorCodes::Unauthorized,
- str::stream() << "not authorized for insert on " << ns.ns());
- }
- }
-
- return Status::OK();
-}
-
-Status AuthorizationSession::checkAuthForUpdate(OperationContext* opCtx,
- const NamespaceString& ns,
- const BSONObj& query,
- const BSONObj& update,
- bool upsert) {
- ActionSet required{ActionType::update};
- StringData operationType = "update"_sd;
-
- if (upsert) {
- required.addAction(ActionType::insert);
- operationType = "upsert"_sd;
- }
-
- if (documentValidationDisabled(opCtx)) {
- required.addAction(ActionType::bypassDocumentValidation);
- }
-
- if (!isAuthorizedForActionsOnNamespace(ns, required)) {
- return Status(ErrorCodes::Unauthorized,
- str::stream() << "not authorized for " << operationType << " on " << ns.ns());
- }
-
- return Status::OK();
-}
-
-Status AuthorizationSession::checkAuthForDelete(OperationContext* opCtx,
- const NamespaceString& ns,
- const BSONObj& query) {
- if (!isAuthorizedForActionsOnNamespace(ns, ActionType::remove)) {
- return Status(ErrorCodes::Unauthorized,
- str::stream() << "not authorized to remove from " << ns.ns());
- }
- return Status::OK();
-}
-
-Status AuthorizationSession::checkAuthForKillCursors(const NamespaceString& ns,
- UserNameIterator cursorOwner) {
- if (isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(),
- ActionType::killAnyCursor)) {
- return Status::OK();
- }
-
- if (ns.isListCollectionsCursorNS()) {
- // listCollections: Target the database being enumerated.
- if (isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(ns.db()),
- ActionType::killAnyCursor)) {
- return Status::OK();
- }
- const bool canKill =
- isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(ns.db()),
- ActionType::killCursors) ||
- isAuthorizedToListCollections(ns.db());
- if (canKill && isCoauthorizedWith(cursorOwner)) {
- return Status::OK();
- }
- return Status(ErrorCodes::Unauthorized,
- str::stream() << "not authorized to kill listCollections cursor on "
- << ns.ns());
- } else if (ns.isListIndexesCursorNS()) {
-
- // listIndexes: Target the underlying collection.
- NamespaceString targetNS = ns.getTargetNSForListIndexes();
- if (isAuthorizedForActionsOnNamespace(targetNS, ActionType::killAnyCursor)) {
- return Status::OK();
- }
- const bool canKill = isAuthorizedForActionsOnNamespace(targetNS, ActionType::killCursors) ||
- isAuthorizedForActionsOnNamespace(targetNS, ActionType::listIndexes);
- if (canKill && isCoauthorizedWith(cursorOwner)) {
- return Status::OK();
- }
-
- return Status(ErrorCodes::Unauthorized,
- str::stream() << "not authorized to kill listIndexes cursor on " << ns.ns());
- } else {
-
- // Otherwise: Target the collection as named.
- if (isAuthorizedForActionsOnNamespace(ns, ActionType::killAnyCursor)) {
- return Status::OK();
- }
- const bool canKill = isAuthorizedForActionsOnNamespace(ns, ActionType::killCursors) ||
- isAuthorizedForActionsOnNamespace(ns, ActionType::find);
- if (canKill && isCoauthorizedWith(cursorOwner)) {
- return Status::OK();
- }
- return Status(ErrorCodes::Unauthorized,
- str::stream() << "not authorized to kill cursor on " << ns.ns());
- }
-}
-
-Status AuthorizationSession::checkAuthForCreate(const NamespaceString& ns,
- const BSONObj& cmdObj,
- bool isMongos) {
- if (cmdObj["capped"].trueValue() &&
- !isAuthorizedForActionsOnNamespace(ns, ActionType::convertToCapped)) {
- return Status(ErrorCodes::Unauthorized, "unauthorized");
- }
-
- const bool hasCreateCollectionAction =
- isAuthorizedForActionsOnNamespace(ns, ActionType::createCollection);
-
- // If attempting to create a view, check for additional required privileges.
- if (cmdObj["viewOn"]) {
- // You need the createCollection action on this namespace; the insert action is not
- // sufficient.
- if (!hasCreateCollectionAction) {
- return Status(ErrorCodes::Unauthorized, "unauthorized");
- }
-
- // Parse the viewOn namespace and the pipeline. If no pipeline was specified, use the empty
- // pipeline.
- NamespaceString viewOnNs(ns.db(), cmdObj["viewOn"].checkAndGetStringData());
- auto pipeline =
- cmdObj.hasField("pipeline") ? BSONArray(cmdObj["pipeline"].Obj()) : BSONArray();
- return checkAuthForCreateOrModifyView(this, ns, viewOnNs, pipeline, isMongos);
- }
-
- // To create a regular collection, ActionType::createCollection or ActionType::insert are
- // both acceptable.
- if (hasCreateCollectionAction || isAuthorizedForActionsOnNamespace(ns, ActionType::insert)) {
- return Status::OK();
- }
-
- return Status(ErrorCodes::Unauthorized, "unauthorized");
-}
-
-Status AuthorizationSession::checkAuthForCollMod(const NamespaceString& ns,
- const BSONObj& cmdObj,
- bool isMongos) {
- if (!isAuthorizedForActionsOnNamespace(ns, ActionType::collMod)) {
- return Status(ErrorCodes::Unauthorized, "unauthorized");
- }
-
- // Check for additional required privileges if attempting to modify a view. When auth is
- // enabled, users must specify both "viewOn" and "pipeline" together. This prevents a user from
- // exposing more information in the original underlying namespace by only changing "pipeline",
- // or looking up more information via the original pipeline by only changing "viewOn".
- const bool hasViewOn = cmdObj.hasField("viewOn");
- const bool hasPipeline = cmdObj.hasField("pipeline");
- if (hasViewOn != hasPipeline) {
- return Status(
- ErrorCodes::InvalidOptions,
- "Must specify both 'viewOn' and 'pipeline' when modifying a view and auth is enabled");
- }
- if (hasViewOn) {
- NamespaceString viewOnNs(ns.db(), cmdObj["viewOn"].checkAndGetStringData());
- auto viewPipeline = BSONArray(cmdObj["pipeline"].Obj());
- return checkAuthForCreateOrModifyView(this, ns, viewOnNs, viewPipeline, isMongos);
- }
-
- return Status::OK();
-}
-
-Status AuthorizationSession::checkAuthorizedToGrantPrivilege(const Privilege& privilege) {
- const ResourcePattern& resource = privilege.getResourcePattern();
- if (resource.isDatabasePattern() || resource.isExactNamespacePattern()) {
- if (!isAuthorizedForActionsOnResource(
- ResourcePattern::forDatabaseName(resource.databaseToMatch()),
- ActionType::grantRole)) {
- return Status(ErrorCodes::Unauthorized,
- str::stream() << "Not authorized to grant privileges on the "
- << resource.databaseToMatch()
- << "database");
- }
- } else if (!isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName("admin"),
- ActionType::grantRole)) {
- return Status(ErrorCodes::Unauthorized,
- "To grant privileges affecting multiple databases or the cluster,"
- " must be authorized to grant roles from the admin database");
- }
- return Status::OK();
-}
-
-
-Status AuthorizationSession::checkAuthorizedToRevokePrivilege(const Privilege& privilege) {
- const ResourcePattern& resource = privilege.getResourcePattern();
- if (resource.isDatabasePattern() || resource.isExactNamespacePattern()) {
- if (!isAuthorizedForActionsOnResource(
- ResourcePattern::forDatabaseName(resource.databaseToMatch()),
- ActionType::revokeRole)) {
- return Status(ErrorCodes::Unauthorized,
- str::stream() << "Not authorized to revoke privileges on the "
- << resource.databaseToMatch()
- << "database");
- }
- } else if (!isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName("admin"),
- ActionType::revokeRole)) {
- return Status(ErrorCodes::Unauthorized,
- "To revoke privileges affecting multiple databases or the cluster,"
- " must be authorized to revoke roles from the admin database");
- }
- return Status::OK();
-}
-
-bool AuthorizationSession::isAuthorizedToParseNamespaceElement(const BSONElement& element) {
- const bool isUUID = element.type() == BinData && element.binDataType() == BinDataType::newUUID;
-
- uassert(ErrorCodes::InvalidNamespace,
- "Failed to parse namespace element",
- element.type() == String || isUUID);
-
- if (isUUID) {
- return isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(),
- ActionType::useUUID);
- }
-
- return true;
-}
-
-bool AuthorizationSession::isAuthorizedToCreateRole(
- const struct auth::CreateOrUpdateRoleArgs& args) {
- // A user is allowed to create a role under either of two conditions.
-
- // The user may create a role if the authorization system says they are allowed to.
- if (isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(args.roleName.getDB()),
- ActionType::createRole)) {
- return true;
- }
-
- // The user may create a role if the localhost exception is enabled, and they already own the
- // role. This implies they have obtained the role through an external authorization mechanism.
- if (_externalState->shouldAllowLocalhost()) {
- for (const User* const user : _authenticatedUsers) {
- if (user->hasRole(args.roleName)) {
- return true;
- }
- }
- log() << "Not authorized to create the first role in the system '" << args.roleName
- << "' using the localhost exception. The user needs to acquire the role through "
- "external authentication first.";
- }
-
- return false;
-}
-
-bool AuthorizationSession::isAuthorizedToGrantRole(const RoleName& role) {
- return isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(role.getDB()),
- ActionType::grantRole);
-}
-
-bool AuthorizationSession::isAuthorizedToRevokeRole(const RoleName& role) {
- return isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(role.getDB()),
- ActionType::revokeRole);
-}
-
-bool AuthorizationSession::isAuthorizedForPrivilege(const Privilege& privilege) {
- if (_externalState->shouldIgnoreAuthChecks())
- return true;
-
- return _isAuthorizedForPrivilege(privilege);
-}
-
-bool AuthorizationSession::isAuthorizedForPrivileges(const vector<Privilege>& privileges) {
- if (_externalState->shouldIgnoreAuthChecks())
- return true;
-
- for (size_t i = 0; i < privileges.size(); ++i) {
- if (!_isAuthorizedForPrivilege(privileges[i]))
- return false;
- }
-
- return true;
-}
-
-bool AuthorizationSession::isAuthorizedForActionsOnResource(const ResourcePattern& resource,
- ActionType action) {
- return isAuthorizedForPrivilege(Privilege(resource, action));
-}
-
-bool AuthorizationSession::isAuthorizedForActionsOnResource(const ResourcePattern& resource,
- const ActionSet& actions) {
- return isAuthorizedForPrivilege(Privilege(resource, actions));
-}
-
-bool AuthorizationSession::isAuthorizedForActionsOnNamespace(const NamespaceString& ns,
- ActionType action) {
- return isAuthorizedForPrivilege(Privilege(ResourcePattern::forExactNamespace(ns), action));
-}
-
-bool AuthorizationSession::isAuthorizedForActionsOnNamespace(const NamespaceString& ns,
- const ActionSet& actions) {
- return isAuthorizedForPrivilege(Privilege(ResourcePattern::forExactNamespace(ns), actions));
-}
-
-static const int resourceSearchListCapacity = 5;
-/**
- * Builds from "target" an exhaustive list of all ResourcePatterns that match "target".
- *
- * Stores the resulting list into resourceSearchList, and returns the length.
- *
- * The seach lists are as follows, depending on the type of "target":
- *
- * target is ResourcePattern::forAnyResource():
- * searchList = { ResourcePattern::forAnyResource(), ResourcePattern::forAnyResource() }
- * target is the ResourcePattern::forClusterResource():
- * searchList = { ResourcePattern::forAnyResource(), ResourcePattern::forClusterResource() }
- * target is a database, db:
- * searchList = { ResourcePattern::forAnyResource(),
- * ResourcePattern::forAnyNormalResource(),
- * db }
- * target is a non-system collection, db.coll:
- * searchList = { ResourcePattern::forAnyResource(),
- * ResourcePattern::forAnyNormalResource(),
- * db,
- * coll,
- * db.coll }
- * target is a system collection, db.system.coll:
- * searchList = { ResourcePattern::forAnyResource(),
- * system.coll,
- * db.system.coll }
- */
-static int buildResourceSearchList(const ResourcePattern& target,
- ResourcePattern resourceSearchList[resourceSearchListCapacity]) {
- int size = 0;
- resourceSearchList[size++] = ResourcePattern::forAnyResource();
- if (target.isExactNamespacePattern()) {
- if (!target.ns().isSystem()) {
- // Some databases should not be matchable with ResourcePattern::forAnyNormalResource.
- // 'local' and 'config' are used to store special system collections, which user level
- // administrators should not be able to manipulate.
- if (target.ns().db() != "local" && target.ns().db() != "config") {
- resourceSearchList[size++] = ResourcePattern::forAnyNormalResource();
- }
- resourceSearchList[size++] = ResourcePattern::forDatabaseName(target.ns().db());
- }
- resourceSearchList[size++] = ResourcePattern::forCollectionName(target.ns().coll());
- } else if (target.isDatabasePattern()) {
- resourceSearchList[size++] = ResourcePattern::forAnyNormalResource();
- }
- resourceSearchList[size++] = target;
- dassert(size <= resourceSearchListCapacity);
- return size;
-}
-
-bool AuthorizationSession::isAuthorizedToChangeAsUser(const UserName& userName,
- ActionType actionType) {
- User* user = lookupUser(userName);
- if (!user) {
- return false;
- }
- ResourcePattern resourceSearchList[resourceSearchListCapacity];
- const int resourceSearchListLength = buildResourceSearchList(
- ResourcePattern::forDatabaseName(userName.getDB()), resourceSearchList);
-
- ActionSet actions;
- for (int i = 0; i < resourceSearchListLength; ++i) {
- actions.addAllActionsFromSet(user->getActionsForResource(resourceSearchList[i]));
- }
- return actions.contains(actionType);
-}
-
-bool AuthorizationSession::isAuthorizedToChangeOwnPasswordAsUser(const UserName& userName) {
- return AuthorizationSession::isAuthorizedToChangeAsUser(userName,
- ActionType::changeOwnPassword);
-}
-
-bool AuthorizationSession::isAuthorizedToChangeOwnCustomDataAsUser(const UserName& userName) {
- return AuthorizationSession::isAuthorizedToChangeAsUser(userName,
- ActionType::changeOwnCustomData);
-}
-
-bool AuthorizationSession::isAuthorizedToListCollections(StringData dbname) {
- // Check for the listCollections ActionType on the database or find on system.namespaces for
- // pre 3.0 systems.
-
- return AuthorizationSession::isAuthorizedForActionsOnResource(
- ResourcePattern::forDatabaseName(dbname), ActionType::listCollections) ||
- AuthorizationSession::isAuthorizedForActionsOnResource(
- ResourcePattern::forExactNamespace(NamespaceString(dbname, "system.namespaces")),
- ActionType::find);
-}
-
-bool AuthorizationSession::isAuthenticatedAsUserWithRole(const RoleName& roleName) {
- for (UserSet::iterator it = _authenticatedUsers.begin(); it != _authenticatedUsers.end();
- ++it) {
- if ((*it)->hasRole(roleName)) {
- return true;
- }
- }
- return false;
-}
-
-void AuthorizationSession::_refreshUserInfoAsNeeded(OperationContext* opCtx) {
- AuthorizationManager& authMan = getAuthorizationManager();
- UserSet::iterator it = _authenticatedUsers.begin();
- while (it != _authenticatedUsers.end()) {
- User* user = *it;
-
- if (!user->isValid()) {
- // Make a good faith effort to acquire an up-to-date user object, since the one
- // we've cached is marked "out-of-date."
- UserName name = user->getName();
- User* updatedUser;
-
- Status status = authMan.acquireUser(opCtx, name, &updatedUser);
- switch (status.code()) {
- case ErrorCodes::OK: {
-
- // Verify the updated user object's authentication restrictions.
- UserHolder userHolder(user, UserReleaser(&authMan, &_authenticatedUsers, it));
- UserHolder updatedUserHolder(updatedUser, UserReleaser(&authMan));
- try {
- const auto& restrictionSet =
- updatedUserHolder->getRestrictions(); // Owned by updatedUser
- invariant(opCtx->getClient());
- Status restrictionStatus = restrictionSet.validate(
- RestrictionEnvironment::get(*opCtx->getClient()));
- if (!restrictionStatus.isOK()) {
- log() << "Removed user " << name
- << " with unmet authentication restrictions from session cache of"
- << " user information. Restriction failed because: "
- << restrictionStatus.reason();
- // If we remove from the UserSet, we cannot increment the iterator.
- continue;
- }
- } catch (...) {
- log() << "Evaluating authentication restrictions for " << name
- << " resulted in an unknown exception. Removing user from the"
- << " session cache.";
- continue;
- }
-
- // Success! Replace the old User object with the updated one.
- fassert(17067,
- _authenticatedUsers.replaceAt(it, updatedUserHolder.release()) ==
- userHolder.get());
- LOG(1) << "Updated session cache of user information for " << name;
- break;
- }
- case ErrorCodes::UserNotFound: {
- // User does not exist anymore; remove it from _authenticatedUsers.
- fassert(17068, _authenticatedUsers.removeAt(it) == user);
- authMan.releaseUser(user);
- log() << "Removed deleted user " << name
- << " from session cache of user information.";
- continue; // No need to advance "it" in this case.
- }
- case ErrorCodes::UnsupportedFormat: {
- // An auth subsystem has explicitly indicated a failure.
- fassert(40555, _authenticatedUsers.removeAt(it) == user);
- authMan.releaseUser(user);
- log() << "Removed user " << name
- << " from session cache of user information because of refresh failure:"
- << " '" << status << "'.";
- continue; // No need to advance "it" in this case.
- }
- default:
- // Unrecognized error; assume that it's transient, and continue working with the
- // out-of-date privilege data.
- warning() << "Could not fetch updated user privilege information for " << name
- << "; continuing to use old information. Reason is "
- << redact(status);
- break;
- }
- }
- ++it;
- }
- _buildAuthenticatedRolesVector();
-}
-
-void AuthorizationSession::_buildAuthenticatedRolesVector() {
- _authenticatedRoleNames.clear();
- for (UserSet::iterator it = _authenticatedUsers.begin(); it != _authenticatedUsers.end();
- ++it) {
- RoleNameIterator roles = (*it)->getIndirectRoles();
- while (roles.more()) {
- RoleName roleName = roles.next();
- _authenticatedRoleNames.push_back(RoleName(roleName.getRole(), roleName.getDB()));
- }
- }
-}
-
-bool AuthorizationSession::_isAuthorizedForPrivilege(const Privilege& privilege) {
- const ResourcePattern& target(privilege.getResourcePattern());
-
- ResourcePattern resourceSearchList[resourceSearchListCapacity];
- const int resourceSearchListLength = buildResourceSearchList(target, resourceSearchList);
-
- ActionSet unmetRequirements = privilege.getActions();
-
- PrivilegeVector defaultPrivileges = getDefaultPrivileges();
- for (PrivilegeVector::iterator it = defaultPrivileges.begin(); it != defaultPrivileges.end();
- ++it) {
- for (int i = 0; i < resourceSearchListLength; ++i) {
- if (!(it->getResourcePattern() == resourceSearchList[i]))
- continue;
-
- ActionSet userActions = it->getActions();
- unmetRequirements.removeAllActionsFromSet(userActions);
-
- if (unmetRequirements.empty())
- return true;
- }
- }
-
- for (UserSet::iterator it = _authenticatedUsers.begin(); it != _authenticatedUsers.end();
- ++it) {
- User* user = *it;
- for (int i = 0; i < resourceSearchListLength; ++i) {
- ActionSet userActions = user->getActionsForResource(resourceSearchList[i]);
- unmetRequirements.removeAllActionsFromSet(userActions);
-
- if (unmetRequirements.empty())
- return true;
- }
- }
-
- return false;
-}
-
-void AuthorizationSession::setImpersonatedUserData(std::vector<UserName> usernames,
- std::vector<RoleName> roles) {
- _impersonatedUserNames = usernames;
- _impersonatedRoleNames = roles;
- _impersonationFlag = true;
-}
-
-bool AuthorizationSession::isCoauthorizedWithClient(Client* opClient) {
- auto getUserNames = [](AuthorizationSession* authSession) {
- if (authSession->isImpersonating()) {
- return authSession->getImpersonatedUserNames();
- } else {
- return authSession->getAuthenticatedUserNames();
- }
- };
-
- UserNameIterator it = getUserNames(this);
- while (it.more()) {
- UserNameIterator opIt = getUserNames(AuthorizationSession::get(opClient));
- while (opIt.more()) {
- if (it.get() == opIt.get()) {
- return true;
- }
- opIt.next();
- }
- it.next();
- }
-
- return false;
-}
-
-bool AuthorizationSession::isCoauthorizedWith(UserNameIterator userNameIter) {
- if (!getAuthorizationManager().isAuthEnabled()) {
- return true;
- }
- if (!userNameIter.more() && !isAuthenticated()) {
- return true;
- }
-
- for (; userNameIter.more(); userNameIter.next()) {
- for (UserNameIterator thisUserNameIter = getAuthenticatedUserNames();
- thisUserNameIter.more();
- thisUserNameIter.next()) {
- if (*userNameIter == *thisUserNameIter) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-UserNameIterator AuthorizationSession::getImpersonatedUserNames() {
- return makeUserNameIterator(_impersonatedUserNames.begin(), _impersonatedUserNames.end());
-}
-
-RoleNameIterator AuthorizationSession::getImpersonatedRoleNames() {
- return makeRoleNameIterator(_impersonatedRoleNames.begin(), _impersonatedRoleNames.end());
-}
-
-bool AuthorizationSession::isUsingLocalhostBypass() {
- return getAuthorizationManager().isAuthEnabled() && _externalState->shouldAllowLocalhost();
-}
-
-// Clear the vectors of impersonated usernames and roles.
-void AuthorizationSession::clearImpersonatedUserData() {
- _impersonatedUserNames.clear();
- _impersonatedRoleNames.clear();
- _impersonationFlag = false;
-}
-
-
-bool AuthorizationSession::isImpersonating() const {
- return _impersonationFlag;
+ swap(*std::get<0>(impersonations), _users);
+ swap(*std::get<1>(impersonations), _roles);
}
+MONGO_DEFINE_SHIM(AuthorizationSession::create);
} // namespace mongo
-
-auto mongo::checkCursorSessionPrivilege(OperationContext* const opCtx,
- const boost::optional<LogicalSessionId> cursorSessionId)
- -> Status {
- if (!AuthorizationSession::exists(opCtx->getClient())) {
- return Status::OK();
- }
- auto* const authSession = AuthorizationSession::get(opCtx->getClient());
-
- auto authHasImpersonatePrivilege = [authSession] {
- return authSession->isAuthorizedForPrivilege(
- Privilege(ResourcePattern::forClusterResource(), ActionType::impersonate));
- };
-
- auto authIsOn = [authSession] {
- return authSession->getAuthorizationManager().isAuthEnabled();
- };
-
- auto sessionIdToStringOrNone =
- [](const boost::optional<LogicalSessionId>& sessionId) -> std::string {
- if (sessionId) {
- return str::stream() << *sessionId;
- }
- return "none";
- };
-
- // If the cursor has a session then one of the following must be true:
- // 1: context session id must match cursor session id.
- // 2: user must be magic special (__system, or background task, etc).
-
- // We do not check the user's ID against the cursor's notion of a user ID, since higher level
- // auth checks will check that for us anyhow.
- if (authIsOn() && // If the authorization is not on, then we permit anybody to do anything.
- cursorSessionId != opCtx->getLogicalSessionId() && // If the cursor's session doesn't match
- // the Operation Context's session, then
- // we should forbid the operation even
- // when the cursor has no session.
- authSession->isAuthenticated() && // Unless, for some reason a user isn't actually using
- // this Operation Context (which implies a background
- // job)
- !authHasImpersonatePrivilege() // Or if the user has an impersonation privilege, in which
- // case, the user gets to sidestep certain checks.
- ) {
- return Status{ErrorCodes::Unauthorized,
- str::stream() << "Cursor session id ("
- << sessionIdToStringOrNone(cursorSessionId)
- << ") is not the same as the operation context's session id ("
- << sessionIdToStringOrNone(opCtx->getLogicalSessionId())
- << ")"};
- }
-
- return Status::OK();
-}
diff --git a/src/mongo/db/auth/authorization_session.h b/src/mongo/db/auth/authorization_session.h
index e260d859651..9b561c467d4 100644
--- a/src/mongo/db/auth/authorization_session.h
+++ b/src/mongo/db/auth/authorization_session.h
@@ -1,5 +1,5 @@
/**
-* Copyright (C) 2012 10gen Inc.
+* Copyright (C) 2018 10gen 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,
@@ -32,7 +32,6 @@
#include <string>
#include <vector>
-#include "mongo/base/disallow_copying.h"
#include "mongo/base/status.h"
#include "mongo/db/auth/action_set.h"
#include "mongo/db/auth/action_type.h"
@@ -48,7 +47,7 @@ namespace mongo {
namespace auth {
struct CreateOrUpdateRoleArgs;
-}
+} // namespace auth
class Client;
/**
@@ -66,9 +65,15 @@ class Client;
* the lifetime of the operation.
*/
class AuthorizationSession {
- MONGO_DISALLOW_COPYING(AuthorizationSession);
+ AuthorizationSession(const AuthorizationSession&) = delete;
+ AuthorizationSession& operator=(const AuthorizationSession&) = delete;
public:
+ static MONGO_DECLARE_SHIM(
+ (AuthorizationManager * authzManager)->std::unique_ptr<AuthorizationSession>) create;
+
+ AuthorizationSession() = default;
+
/**
* Provides a way to swap out impersonate data for the duration of the ScopedImpersonate's
* lifetime.
@@ -77,8 +82,14 @@ public:
public:
ScopedImpersonate(AuthorizationSession* authSession,
std::vector<UserName>* users,
- std::vector<RoleName>* roles);
- ~ScopedImpersonate();
+ std::vector<RoleName>* roles)
+ : _authSession(*authSession), _users(*users), _roles(*roles) {
+ swap();
+ }
+
+ ~ScopedImpersonate() {
+ this->swap();
+ }
private:
void swap();
@@ -118,245 +129,242 @@ public:
static void set(Client* client, std::unique_ptr<AuthorizationSession> session);
// Takes ownership of the externalState.
- explicit AuthorizationSession(std::unique_ptr<AuthzSessionExternalState> externalState);
- ~AuthorizationSession();
+ virtual ~AuthorizationSession() = 0;
- AuthorizationManager& getAuthorizationManager();
+ virtual AuthorizationManager& getAuthorizationManager() = 0;
// Should be called at the beginning of every new request. This performs the checks
// necessary to determine if localhost connections should be given full access.
// TODO: try to eliminate the need for this call.
- void startRequest(OperationContext* opCtx);
+ virtual void startRequest(OperationContext* opCtx) = 0;
/**
* Adds the User identified by "UserName" to the authorization session, acquiring privileges
* for it in the process.
*/
- Status addAndAuthorizeUser(OperationContext* opCtx, const UserName& userName);
+ virtual Status addAndAuthorizeUser(OperationContext* opCtx, const UserName& userName) = 0;
// Returns the authenticated user with the given name. Returns NULL
// if no such user is found.
// The user remains in the _authenticatedUsers set for this AuthorizationSession,
// and ownership of the user stays with the AuthorizationManager
- User* lookupUser(const UserName& name);
+ virtual User* lookupUser(const UserName& name) = 0;
// Returns the single user on this auth session. If no user is authenticated, or if
// multiple users are authenticated, this method will throw an exception.
- User* getSingleUser();
+ virtual User* getSingleUser() = 0;
// Is authenticated as at least one user.
- bool isAuthenticated();
+ virtual bool isAuthenticated() = 0;
// Gets an iterator over the names of all authenticated users stored in this manager.
- UserNameIterator getAuthenticatedUserNames();
+ virtual UserNameIterator getAuthenticatedUserNames() = 0;
// Gets an iterator over the roles of all authenticated users stored in this manager.
- RoleNameIterator getAuthenticatedRoleNames();
+ virtual RoleNameIterator getAuthenticatedRoleNames() = 0;
// Returns a std::string representing all logged-in users on the current session.
// WARNING: this std::string will contain NUL bytes so don't call c_str()!
- std::string getAuthenticatedUserNamesToken();
+ virtual std::string getAuthenticatedUserNamesToken() = 0;
// Removes any authenticated principals whose authorization credentials came from the given
// database, and revokes any privileges that were granted via that principal.
- void logoutDatabase(const std::string& dbname);
+ virtual void logoutDatabase(const std::string& dbname) = 0;
// Adds the internalSecurity user to the set of authenticated users.
// Used to grant internal threads full access.
- void grantInternalAuthorization();
+ virtual void grantInternalAuthorization() = 0;
// Generates a vector of default privileges that are granted to any user,
// regardless of which roles that user does or does not possess.
// If localhost exception is active, the permissions include the ability to create
// the first user and the ability to run the commands needed to bootstrap the system
// into a state where the first user can be created.
- PrivilegeVector getDefaultPrivileges();
+ virtual PrivilegeVector getDefaultPrivileges() = 0;
// Checks if this connection has the privileges necessary to perform a find operation
// on the supplied namespace identifier.
- Status checkAuthForFind(const NamespaceString& ns, bool hasTerm);
+ virtual Status checkAuthForFind(const NamespaceString& ns, bool hasTerm) = 0;
// Checks if this connection has the privileges necessary to perform a getMore operation on
// the identified cursor, supposing that cursor is associated with the supplied namespace
// identifier.
- Status checkAuthForGetMore(const NamespaceString& ns, long long cursorID, bool hasTerm);
+ virtual Status checkAuthForGetMore(const NamespaceString& ns,
+ long long cursorID,
+ bool hasTerm) = 0;
// Checks if this connection has the privileges necessary to perform the given update on the
// given namespace.
- Status checkAuthForUpdate(OperationContext* opCtx,
- const NamespaceString& ns,
- const BSONObj& query,
- const BSONObj& update,
- bool upsert);
+ virtual Status checkAuthForUpdate(OperationContext* opCtx,
+ const NamespaceString& ns,
+ const BSONObj& query,
+ const BSONObj& update,
+ bool upsert) = 0;
// Checks if this connection has the privileges necessary to insert the given document
// to the given namespace. Correctly interprets inserts to system.indexes and performs
// the proper auth checks for index building.
- Status checkAuthForInsert(OperationContext* opCtx,
- const NamespaceString& ns,
- const BSONObj& document);
+ virtual Status checkAuthForInsert(OperationContext* opCtx,
+ const NamespaceString& ns,
+ const BSONObj& document) = 0;
// Checks if this connection has the privileges necessary to perform a delete on the given
// namespace.
- Status checkAuthForDelete(OperationContext* opCtx,
- const NamespaceString& ns,
- const BSONObj& query);
+ virtual Status checkAuthForDelete(OperationContext* opCtx,
+ const NamespaceString& ns,
+ const BSONObj& query) = 0;
// Checks if this connection has the privileges necessary to perform a killCursor on
// the identified cursor, supposing that cursor is associated with the supplied namespace
// identifier.
- Status checkAuthForKillCursors(const NamespaceString& cursorNss, UserNameIterator cursorOwner);
+ virtual Status checkAuthForKillCursors(const NamespaceString& cursorNss,
+ UserNameIterator cursorOwner) = 0;
// Checks if this connection has the privileges necessary to run the aggregation pipeline
// specified in 'cmdObj' on the namespace 'ns' either directly on mongoD or via mongoS.
- Status checkAuthForAggregate(const NamespaceString& ns, const BSONObj& cmdObj, bool isMongos);
+ virtual Status checkAuthForAggregate(const NamespaceString& ns,
+ const BSONObj& cmdObj,
+ bool isMongos) = 0;
// Checks if this connection has the privileges necessary to create 'ns' with the options
// supplied in 'cmdObj' either directly on mongoD or via mongoS.
- Status checkAuthForCreate(const NamespaceString& ns, const BSONObj& cmdObj, bool isMongos);
+ virtual Status checkAuthForCreate(const NamespaceString& ns,
+ const BSONObj& cmdObj,
+ bool isMongos) = 0;
// Checks if this connection has the privileges necessary to modify 'ns' with the options
// supplied in 'cmdObj' either directly on mongoD or via mongoS.
- Status checkAuthForCollMod(const NamespaceString& ns, const BSONObj& cmdObj, bool isMongos);
+ virtual Status checkAuthForCollMod(const NamespaceString& ns,
+ const BSONObj& cmdObj,
+ bool isMongos) = 0;
// Checks if this connection has the privileges necessary to grant the given privilege
// to a role.
- Status checkAuthorizedToGrantPrivilege(const Privilege& privilege);
+ virtual Status checkAuthorizedToGrantPrivilege(const Privilege& privilege) = 0;
// Checks if this connection has the privileges necessary to revoke the given privilege
// from a role.
- Status checkAuthorizedToRevokePrivilege(const Privilege& privilege);
+ virtual Status checkAuthorizedToRevokePrivilege(const Privilege& privilege) = 0;
// Checks if this connection is using the localhost bypass
- bool isUsingLocalhostBypass();
+ virtual bool isUsingLocalhostBypass() = 0;
// Checks if this connection has the privileges necessary to parse a namespace from a
// given BSONElement.
- bool isAuthorizedToParseNamespaceElement(const BSONElement& elem);
+ virtual bool isAuthorizedToParseNamespaceElement(const BSONElement& elem) = 0;
// Checks if this connection has the privileges necessary to create a new role
- bool isAuthorizedToCreateRole(const auth::CreateOrUpdateRoleArgs& args);
+ virtual bool isAuthorizedToCreateRole(const auth::CreateOrUpdateRoleArgs& args) = 0;
// Utility function for isAuthorizedForActionsOnResource(
// ResourcePattern::forDatabaseName(role.getDB()), ActionType::grantAnyRole)
- bool isAuthorizedToGrantRole(const RoleName& role);
+ virtual bool isAuthorizedToGrantRole(const RoleName& role) = 0;
// Utility function for isAuthorizedForActionsOnResource(
// ResourcePattern::forDatabaseName(role.getDB()), ActionType::grantAnyRole)
- bool isAuthorizedToRevokeRole(const RoleName& role);
+ virtual bool isAuthorizedToRevokeRole(const RoleName& role) = 0;
// Utility function for isAuthorizedToChangeOwnPasswordAsUser and
// isAuthorizedToChangeOwnCustomDataAsUser
- bool isAuthorizedToChangeAsUser(const UserName& userName, ActionType actionType);
+ virtual bool isAuthorizedToChangeAsUser(const UserName& userName, ActionType actionType) = 0;
// Returns true if the current session is authenticated as the given user and that user
// is allowed to change his/her own password
- bool isAuthorizedToChangeOwnPasswordAsUser(const UserName& userName);
+ virtual bool isAuthorizedToChangeOwnPasswordAsUser(const UserName& userName) = 0;
// Returns true if the current session is authorized to list the collections in the given
// database.
- bool isAuthorizedToListCollections(StringData dbname);
+ virtual bool isAuthorizedToListCollections(StringData dbname) = 0;
// Returns true if the current session is authenticated as the given user and that user
// is allowed to change his/her own customData.
- bool isAuthorizedToChangeOwnCustomDataAsUser(const UserName& userName);
+ virtual bool isAuthorizedToChangeOwnCustomDataAsUser(const UserName& userName) = 0;
// Returns true if any of the authenticated users on this session have the given role.
// NOTE: this does not refresh any of the users even if they are marked as invalid.
- bool isAuthenticatedAsUserWithRole(const RoleName& roleName);
+ virtual bool isAuthenticatedAsUserWithRole(const RoleName& roleName) = 0;
// Returns true if this session is authorized for the given Privilege.
//
// Contains all the authorization logic including handling things like the localhost
// exception.
- bool isAuthorizedForPrivilege(const Privilege& privilege);
+ virtual bool isAuthorizedForPrivilege(const Privilege& privilege) = 0;
// Like isAuthorizedForPrivilege, above, except returns true if the session is authorized
// for all of the listed privileges.
- bool isAuthorizedForPrivileges(const std::vector<Privilege>& privileges);
+ virtual bool isAuthorizedForPrivileges(const std::vector<Privilege>& privileges) = 0;
// Utility function for isAuthorizedForPrivilege(Privilege(resource, action)).
- bool isAuthorizedForActionsOnResource(const ResourcePattern& resource, ActionType action);
+ virtual bool isAuthorizedForActionsOnResource(const ResourcePattern& resource,
+ ActionType action) = 0;
// Utility function for isAuthorizedForPrivilege(Privilege(resource, actions)).
- bool isAuthorizedForActionsOnResource(const ResourcePattern& resource,
- const ActionSet& actions);
+ virtual bool isAuthorizedForActionsOnResource(const ResourcePattern& resource,
+ const ActionSet& actions) = 0;
// Utility function for
// isAuthorizedForActionsOnResource(ResourcePattern::forExactNamespace(ns), action).
- bool isAuthorizedForActionsOnNamespace(const NamespaceString& ns, ActionType action);
+ virtual bool isAuthorizedForActionsOnNamespace(const NamespaceString& ns,
+ ActionType action) = 0;
// Utility function for
// isAuthorizedForActionsOnResource(ResourcePattern::forExactNamespace(ns), actions).
- bool isAuthorizedForActionsOnNamespace(const NamespaceString& ns, const ActionSet& actions);
+ virtual bool isAuthorizedForActionsOnNamespace(const NamespaceString& ns,
+ const ActionSet& actions) = 0;
// Replaces the data for users that a system user is impersonating with new data.
// The auditing system adds these users and their roles to each audit record in the log.
- void setImpersonatedUserData(std::vector<UserName> usernames, std::vector<RoleName> roles);
+ virtual void setImpersonatedUserData(std::vector<UserName> usernames,
+ std::vector<RoleName> roles) = 0;
// Gets an iterator over the names of all users that the system user is impersonating.
- UserNameIterator getImpersonatedUserNames();
+ virtual UserNameIterator getImpersonatedUserNames() = 0;
// Gets an iterator over the roles of all users that the system user is impersonating.
- RoleNameIterator getImpersonatedRoleNames();
+ virtual RoleNameIterator getImpersonatedRoleNames() = 0;
// Clears the data for impersonated users.
- void clearImpersonatedUserData();
+ virtual void clearImpersonatedUserData() = 0;
// Returns true if the session and 'opClient's AuthorizationSession share an
// authenticated user. If either object has impersonated users,
// those users will be considered as 'authenticated' for the purpose of this check.
//
// The existence of 'opClient' must be guaranteed through locks taken by the caller.
- bool isCoauthorizedWithClient(Client* opClient);
+ virtual bool isCoauthorizedWithClient(Client* opClient) = 0;
// Returns true if the session and 'userNameIter' share an authenticated user, or if both have
// no authenticated users. Impersonated users are not considered as 'authenticated' for the
// purpose of this check. This always returns true if auth is not enabled.
- bool isCoauthorizedWith(UserNameIterator userNameIter);
+ virtual bool isCoauthorizedWith(UserNameIterator userNameIter) = 0;
// Tells whether impersonation is active or not. This state is set when
// setImpersonatedUserData is called and cleared when clearImpersonatedUserData is
// called.
- bool isImpersonating() const;
-
-protected:
- // Builds a vector of all roles held by users who are authenticated on this connection. The
- // vector is stored in _authenticatedRoleNames. This function is called when users are
- // logged in or logged out, as well as when the user cache is determined to be out of date.
- void _buildAuthenticatedRolesVector();
-
- // All Users who have been authenticated on this connection.
- UserSet _authenticatedUsers;
+ virtual bool isImpersonating() const = 0;
- // The roles of the authenticated users. This vector is generated when the authenticated
- // users set is changed.
- std::vector<RoleName> _authenticatedRoleNames;
+ // Returns a status encoding whether the current session in the specified `opCtx` has privilege
+ // to access a cursor in the specified `cursorSessionId` parameter. Returns `Status::OK()`,
+ // when the session is accessible. Returns a `mongo::Status` with information regarding the
+ // nature of session inaccessibility when the session is not accessible.
+ virtual Status checkCursorSessionPrivilege(
+ OperationContext* const opCtx, boost::optional<LogicalSessionId> cursorSessionId) = 0;
-private:
- // If any users authenticated on this session are marked as invalid this updates them with
- // up-to-date information. May require a read lock on the "admin" db to read the user data.
- void _refreshUserInfoAsNeeded(OperationContext* opCtx);
-
-
- // Checks if this connection is authorized for the given Privilege, ignoring whether or not
- // we should even be doing authorization checks in general. Note: this may acquire a read
- // lock on the admin database (to update out-of-date user privilege information).
- bool _isAuthorizedForPrivilege(const Privilege& privilege);
-
- std::unique_ptr<AuthzSessionExternalState> _externalState;
-
- // A vector of impersonated UserNames and a vector of those users' RoleNames.
- // These are used in the auditing system. They are not used for authz checks.
- std::vector<UserName> _impersonatedUserNames;
- std::vector<RoleName> _impersonatedRoleNames;
- bool _impersonationFlag;
+protected:
+ virtual std::tuple<std::vector<UserName>*, std::vector<RoleName>*> _getImpersonations() = 0;
};
// Returns a status encoding whether the current session in the specified `opCtx` has privilege to
// access a cursor in the specified `cursorSessionId` parameter. Returns `Status::OK()`, when the
// session is accessible. Returns a `mongo::Status` with information regarding the nature of
// session inaccessibility when the session is not accessible.
-Status checkCursorSessionPrivilege(OperationContext* const opCtx,
- const boost::optional<LogicalSessionId> cursorSessionId);
+inline Status checkCursorSessionPrivilege(OperationContext* const opCtx,
+ const boost::optional<LogicalSessionId> cursorSessionId) {
+ if (!AuthorizationSession::exists(opCtx->getClient())) {
+ return Status::OK();
+ }
+ auto* const authSession = AuthorizationSession::get(opCtx->getClient());
+ return authSession->checkCursorSessionPrivilege(opCtx, cursorSessionId);
+}
+
} // namespace mongo
diff --git a/src/mongo/db/auth/authorization_session_for_test.h b/src/mongo/db/auth/authorization_session_for_test.h
index f57e8669692..6e9f63418de 100644
--- a/src/mongo/db/auth/authorization_session_for_test.h
+++ b/src/mongo/db/auth/authorization_session_for_test.h
@@ -32,15 +32,16 @@
#include <vector>
#include "mongo/db/auth/authorization_session.h"
+#include "mongo/db/auth/authorization_session_impl.h"
#include "mongo/db/auth/user.h"
namespace mongo {
-class AuthorizationSessionForTest : public AuthorizationSession {
+class AuthorizationSessionForTest : public AuthorizationSessionImpl {
MONGO_DISALLOW_COPYING(AuthorizationSessionForTest);
public:
- using AuthorizationSession::AuthorizationSession;
+ using AuthorizationSessionImpl::AuthorizationSessionImpl;
// A database name used for testing purposes, deliberately named to minimize collisions with
// other test users.
diff --git a/src/mongo/db/auth/authorization_session_impl.cpp b/src/mongo/db/auth/authorization_session_impl.cpp
new file mode 100644
index 00000000000..11966d78a92
--- /dev/null
+++ b/src/mongo/db/auth/authorization_session_impl.cpp
@@ -0,0 +1,1063 @@
+/**
+ * Copyright (C) 2018 10gen 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.
+ */
+
+#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kAccessControl
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/auth/authorization_session_impl.h"
+
+#include <string>
+#include <vector>
+
+#include "mongo/base/status.h"
+#include "mongo/db/auth/action_set.h"
+#include "mongo/db/auth/action_type.h"
+#include "mongo/db/auth/authorization_manager.h"
+#include "mongo/db/auth/authz_session_external_state.h"
+#include "mongo/db/auth/privilege.h"
+#include "mongo/db/auth/restriction_environment.h"
+#include "mongo/db/auth/security_key.h"
+#include "mongo/db/auth/user_management_commands_parser.h"
+#include "mongo/db/bson/dotted_path_support.h"
+#include "mongo/db/catalog/document_validation.h"
+#include "mongo/db/client.h"
+#include "mongo/db/jsobj.h"
+#include "mongo/db/namespace_string.h"
+#include "mongo/db/pipeline/aggregation_request.h"
+#include "mongo/db/pipeline/lite_parsed_pipeline.h"
+#include "mongo/util/assert_util.h"
+#include "mongo/util/log.h"
+#include "mongo/util/mongoutils/str.h"
+
+namespace mongo {
+
+namespace dps = ::mongo::dotted_path_support;
+using std::vector;
+
+MONGO_REGISTER_SHIM(AuthorizationSession::create)
+(AuthorizationManager* authzManager)->std::unique_ptr<AuthorizationSession> {
+ return std::make_unique<AuthorizationSessionImpl>(
+ AuthzSessionExternalState::create(authzManager),
+ AuthorizationSessionImpl::InstallMockForTestingOrAuthImpl{});
+}
+
+namespace {
+const std::string ADMIN_DBNAME = "admin";
+
+// Checks if this connection has the privileges necessary to create or modify the view 'viewNs'
+// to be a view on 'viewOnNs' with pipeline 'viewPipeline'. Call this function after verifying
+// that the user has the 'createCollection' or 'collMod' action, respectively.
+Status checkAuthForCreateOrModifyView(AuthorizationSession* authzSession,
+ const NamespaceString& viewNs,
+ const NamespaceString& viewOnNs,
+ const BSONArray& viewPipeline,
+ bool isMongos) {
+ // It's safe to allow a user to create or modify a view if they can't read it anyway.
+ if (!authzSession->isAuthorizedForActionsOnNamespace(viewNs, ActionType::find)) {
+ return Status::OK();
+ }
+
+ // This check performs some validation but it is not exhaustive and may allow for an invalid
+ // pipeline specification. In this case the authorization check will succeed but the pipeline
+ // will fail to parse later in Command::run().
+ return authzSession->checkAuthForAggregate(
+ viewOnNs,
+ BSON("aggregate" << viewOnNs.coll() << "pipeline" << viewPipeline << "cursor" << BSONObj()),
+ isMongos);
+}
+
+/** Deleter for User*.
+ * Will release a User* back to its owning AuthorizationManager on destruction.
+ * If a borrowing UserSet and the iterator it uses to store the User* is provided, this
+ * deleter will release the User* from the set if the iterator still points to the deleting User*.
+ */
+class UserReleaser {
+public:
+ explicit UserReleaser(AuthorizationManager* owner) : _owner(owner), _borrower(nullptr) {}
+ UserReleaser(AuthorizationManager* owner, UserSet* borrower, UserSet::iterator borrowerIt)
+ : _owner(owner), _borrower(borrower), _it(borrowerIt) {}
+
+ void operator()(User* user) {
+ // Remove the user from the borrower if it hasn't already been swapped out.
+ if (_borrower && *_it == user) {
+ fassert(40546, _borrower->removeAt(_it) == user);
+ }
+ _owner->releaseUser(user);
+ }
+
+protected:
+ AuthorizationManager* _owner;
+ UserSet* _borrower;
+ UserSet::iterator _it;
+};
+/** Holder for User*s. If this Holder falls out of scope while holding a User*, it will release
+ * the User* from its AuthorizationManager, and extract it from a UserSet if the set still contains
+ * it. Use this object to guard User*s which will need to be destroyed in the event of an exception.
+ */
+using UserHolder = std::unique_ptr<User, UserReleaser>;
+
+} // namespace
+
+AuthorizationSessionImpl::AuthorizationSessionImpl(
+ std::unique_ptr<AuthzSessionExternalState> externalState, InstallMockForTestingOrAuthImpl)
+ : _externalState(std::move(externalState)), _impersonationFlag(false) {}
+
+AuthorizationSessionImpl::~AuthorizationSessionImpl() {
+ for (auto& user : _authenticatedUsers) {
+ getAuthorizationManager().releaseUser(user);
+ }
+}
+
+AuthorizationManager& AuthorizationSessionImpl::getAuthorizationManager() {
+ return _externalState->getAuthorizationManager();
+}
+
+void AuthorizationSessionImpl::startRequest(OperationContext* opCtx) {
+ _externalState->startRequest(opCtx);
+ _refreshUserInfoAsNeeded(opCtx);
+}
+
+Status AuthorizationSessionImpl::addAndAuthorizeUser(OperationContext* opCtx,
+ const UserName& userName) {
+ User* user;
+ AuthorizationManager* authzManager = AuthorizationManager::get(opCtx->getServiceContext());
+ Status status = authzManager->acquireUser(opCtx, userName, &user);
+ if (!status.isOK()) {
+ return status;
+ }
+
+ UserHolder userHolder(user, UserReleaser(authzManager));
+
+ const auto& restrictionSet = userHolder->getRestrictions();
+ if (opCtx->getClient() == nullptr) {
+ return Status(ErrorCodes::AuthenticationFailed,
+ "Unable to evaluate restrictions, OperationContext has no Client");
+ }
+
+ Status restrictionStatus =
+ restrictionSet.validate(RestrictionEnvironment::get(*opCtx->getClient()));
+ if (!restrictionStatus.isOK()) {
+ log() << "Failed to acquire user '" << userName
+ << "' because of unmet authentication restrictions: " << restrictionStatus.reason();
+ return AuthorizationManager::authenticationFailedStatus;
+ }
+
+ // Calling add() on the UserSet may return a user that was replaced because it was from the
+ // same database.
+ userHolder.reset(_authenticatedUsers.add(userHolder.release()));
+
+ // If there are any users and roles in the impersonation data, clear it out.
+ clearImpersonatedUserData();
+
+ _buildAuthenticatedRolesVector();
+ return Status::OK();
+}
+
+User* AuthorizationSessionImpl::lookupUser(const UserName& name) {
+ return _authenticatedUsers.lookup(name);
+}
+
+User* AuthorizationSessionImpl::getSingleUser() {
+ UserName userName;
+
+ auto userNameItr = getAuthenticatedUserNames();
+ if (userNameItr.more()) {
+ userName = userNameItr.next();
+ if (userNameItr.more()) {
+ uasserted(ErrorCodes::Unauthorized, "too many users are authenticated");
+ }
+ } else {
+ uasserted(ErrorCodes::Unauthorized, "there are no users authenticated");
+ }
+
+ return lookupUser(userName);
+}
+
+void AuthorizationSessionImpl::logoutDatabase(const std::string& dbname) {
+ User* removedUser = _authenticatedUsers.removeByDBName(dbname);
+ if (removedUser) {
+ getAuthorizationManager().releaseUser(removedUser);
+ }
+ clearImpersonatedUserData();
+ _buildAuthenticatedRolesVector();
+}
+
+UserNameIterator AuthorizationSessionImpl::getAuthenticatedUserNames() {
+ return _authenticatedUsers.getNames();
+}
+
+RoleNameIterator AuthorizationSessionImpl::getAuthenticatedRoleNames() {
+ return makeRoleNameIterator(_authenticatedRoleNames.begin(), _authenticatedRoleNames.end());
+}
+
+std::string AuthorizationSessionImpl::getAuthenticatedUserNamesToken() {
+ std::string ret;
+ for (UserNameIterator nameIter = getAuthenticatedUserNames(); nameIter.more();
+ nameIter.next()) {
+ ret += '\0'; // Using a NUL byte which isn't valid in usernames to separate them.
+ ret += nameIter->getFullName();
+ }
+
+ return ret;
+}
+
+void AuthorizationSessionImpl::grantInternalAuthorization() {
+ _authenticatedUsers.add(internalSecurity.user);
+ _buildAuthenticatedRolesVector();
+}
+
+PrivilegeVector AuthorizationSessionImpl::getDefaultPrivileges() {
+ PrivilegeVector defaultPrivileges;
+
+ // If localhost exception is active (and no users exist),
+ // return a vector of the minimum privileges required to bootstrap
+ // a system and add the first user.
+ if (_externalState->shouldAllowLocalhost()) {
+ ResourcePattern adminDBResource = ResourcePattern::forDatabaseName(ADMIN_DBNAME);
+ ActionSet setupAdminUserActionSet;
+ setupAdminUserActionSet.addAction(ActionType::createUser);
+ setupAdminUserActionSet.addAction(ActionType::grantRole);
+ Privilege setupAdminUserPrivilege = Privilege(adminDBResource, setupAdminUserActionSet);
+
+ ResourcePattern externalDBResource = ResourcePattern::forDatabaseName("$external");
+ Privilege setupExternalUserPrivilege =
+ Privilege(externalDBResource, ActionType::createUser);
+
+ ActionSet setupServerConfigActionSet;
+
+ // If this server is an arbiter, add specific privileges meant to circumvent
+ // the behavior of an arbiter in an authenticated replset. See SERVER-5479.
+ if (_externalState->serverIsArbiter()) {
+ setupServerConfigActionSet.addAction(ActionType::getCmdLineOpts);
+ setupServerConfigActionSet.addAction(ActionType::getParameter);
+ setupServerConfigActionSet.addAction(ActionType::serverStatus);
+ setupServerConfigActionSet.addAction(ActionType::shutdown);
+ }
+
+ setupServerConfigActionSet.addAction(ActionType::addShard);
+ setupServerConfigActionSet.addAction(ActionType::replSetConfigure);
+ setupServerConfigActionSet.addAction(ActionType::replSetGetStatus);
+ Privilege setupServerConfigPrivilege =
+ Privilege(ResourcePattern::forClusterResource(), setupServerConfigActionSet);
+
+ Privilege::addPrivilegeToPrivilegeVector(&defaultPrivileges, setupAdminUserPrivilege);
+ Privilege::addPrivilegeToPrivilegeVector(&defaultPrivileges, setupExternalUserPrivilege);
+ Privilege::addPrivilegeToPrivilegeVector(&defaultPrivileges, setupServerConfigPrivilege);
+ return defaultPrivileges;
+ }
+
+ return defaultPrivileges;
+}
+
+Status AuthorizationSessionImpl::checkAuthForAggregate(const NamespaceString& nss,
+ const BSONObj& cmdObj,
+ bool isMongos) {
+ if (!nss.isValid()) {
+ return Status(ErrorCodes::InvalidNamespace,
+ mongoutils::str::stream() << "Invalid input namespace, " << nss.ns());
+ }
+
+ // If this connection does not need to be authenticated (for instance, if auth is disabled),
+ // return Status::OK() immediately.
+ if (_externalState->shouldIgnoreAuthChecks()) {
+ return Status::OK();
+ }
+
+ // We require at least one authenticated user when running aggregate with auth enabled.
+ if (!isAuthenticated()) {
+ return Status(ErrorCodes::Unauthorized, "unauthorized");
+ }
+
+ auto statusWithAggRequest = AggregationRequest::parseFromBSON(nss, cmdObj);
+ if (!statusWithAggRequest.isOK()) {
+ return statusWithAggRequest.getStatus();
+ }
+ AggregationRequest aggRequest = std::move(statusWithAggRequest.getValue());
+
+ const auto& pipeline = aggRequest.getPipeline();
+
+ // If the aggregation pipeline is empty, confirm the user is authorized for find on 'nss'.
+ if (pipeline.empty()) {
+ if (!isAuthorizedForPrivilege(
+ Privilege(ResourcePattern::forExactNamespace(nss), ActionType::find))) {
+ return Status(ErrorCodes::Unauthorized, "unauthorized");
+ }
+
+ return Status::OK();
+ }
+
+ // Confirm the user is authorized for the pipeline's initial document source. We confirm a user
+ // is authorized incrementally rather than once for the entire pipeline. This will prevent a
+ // malicious user, who doesn't have access to the initial document source, from consuming the
+ // resources needed to parse a potentially large pipeline.
+ auto liteParsedFirstDocumentSource = LiteParsedDocumentSource::parse(aggRequest, pipeline[0]);
+ if (!liteParsedFirstDocumentSource->isInitialSource() &&
+ !isAuthorizedForPrivilege(
+ Privilege(ResourcePattern::forExactNamespace(nss), ActionType::find))) {
+ return Status(ErrorCodes::Unauthorized, "unauthorized");
+ }
+
+ // We have done the work to lite parse the first stage. Given that, we check required privileges
+ // for it using 'liteParsedFirstDocumentSource' regardless of whether is an initial source or
+ // not.
+ if (!isAuthorizedForPrivileges(liteParsedFirstDocumentSource->requiredPrivileges(isMongos))) {
+ return Status(ErrorCodes::Unauthorized, "unauthorized");
+ }
+
+ // Confirm privileges for the remainder of the pipepline. Start with the second stage as we have
+ // already authorized the first.
+ auto pipelineIter = pipeline.begin() + 1;
+
+ for (; pipelineIter != pipeline.end(); ++pipelineIter) {
+ auto liteParsedDocSource = LiteParsedDocumentSource::parse(aggRequest, *pipelineIter);
+ if (!isAuthorizedForPrivileges(liteParsedDocSource->requiredPrivileges(isMongos))) {
+ return Status(ErrorCodes::Unauthorized, "unauthorized");
+ }
+ }
+
+ return Status::OK();
+}
+
+Status AuthorizationSessionImpl::checkAuthForFind(const NamespaceString& ns, bool hasTerm) {
+ if (MONGO_unlikely(ns.isCommand())) {
+ return Status(ErrorCodes::InternalError,
+ str::stream() << "Checking query auth on command namespace " << ns.ns());
+ }
+ if (!isAuthorizedForActionsOnNamespace(ns, ActionType::find)) {
+ return Status(ErrorCodes::Unauthorized,
+ str::stream() << "not authorized for query on " << ns.ns());
+ }
+
+ // Only internal clients (such as other nodes in a replica set) are allowed to use
+ // the 'term' field in a find operation. Use of this field could trigger changes
+ // in the receiving server's replication state and should be protected.
+ if (hasTerm &&
+ !isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(),
+ ActionType::internal)) {
+ return Status(ErrorCodes::Unauthorized,
+ str::stream() << "not authorized for query with term on " << ns.ns());
+ }
+
+ return Status::OK();
+}
+
+Status AuthorizationSessionImpl::checkAuthForGetMore(const NamespaceString& ns,
+ long long cursorID,
+ bool hasTerm) {
+ // Since users can only getMore their own cursors, we verify that a user either is authenticated
+ // or does not need to be.
+ if (!_externalState->shouldIgnoreAuthChecks() && !isAuthenticated()) {
+ return Status(ErrorCodes::Unauthorized,
+ str::stream() << "not authorized for getMore on " << ns.db());
+ }
+
+ // Only internal clients (such as other nodes in a replica set) are allowed to use
+ // the 'term' field in a getMore operation. Use of this field could trigger changes
+ // in the receiving server's replication state and should be protected.
+ if (hasTerm &&
+ !isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(),
+ ActionType::internal)) {
+ return Status(ErrorCodes::Unauthorized,
+ str::stream() << "not authorized for getMore with term on " << ns.ns());
+ }
+
+ return Status::OK();
+}
+
+Status AuthorizationSessionImpl::checkAuthForInsert(OperationContext* opCtx,
+ const NamespaceString& ns,
+ const BSONObj& document) {
+ if (ns.coll() == "system.indexes"_sd) {
+ BSONElement nsElement = document["ns"];
+ if (nsElement.type() != String) {
+ return Status(nsElement.type() == BSONType::EOO ? ErrorCodes::NoSuchKey
+ : ErrorCodes::TypeMismatch,
+ "Cannot authorize inserting into "
+ "system.indexes documents without a string-typed \"ns\" field.");
+ }
+ NamespaceString indexNS(nsElement.valueStringData());
+ if (!isAuthorizedForActionsOnNamespace(indexNS, ActionType::createIndex)) {
+ return Status(ErrorCodes::Unauthorized,
+ str::stream() << "not authorized to create index on " << indexNS.ns());
+ }
+ } else {
+ ActionSet required{ActionType::insert};
+ if (documentValidationDisabled(opCtx)) {
+ required.addAction(ActionType::bypassDocumentValidation);
+ }
+ if (!isAuthorizedForActionsOnNamespace(ns, required)) {
+ return Status(ErrorCodes::Unauthorized,
+ str::stream() << "not authorized for insert on " << ns.ns());
+ }
+ }
+
+ return Status::OK();
+}
+
+Status AuthorizationSessionImpl::checkAuthForUpdate(OperationContext* opCtx,
+ const NamespaceString& ns,
+ const BSONObj& query,
+ const BSONObj& update,
+ bool upsert) {
+ ActionSet required{ActionType::update};
+ StringData operationType = "update"_sd;
+
+ if (upsert) {
+ required.addAction(ActionType::insert);
+ operationType = "upsert"_sd;
+ }
+
+ if (documentValidationDisabled(opCtx)) {
+ required.addAction(ActionType::bypassDocumentValidation);
+ }
+
+ if (!isAuthorizedForActionsOnNamespace(ns, required)) {
+ return Status(ErrorCodes::Unauthorized,
+ str::stream() << "not authorized for " << operationType << " on " << ns.ns());
+ }
+
+ return Status::OK();
+}
+
+Status AuthorizationSessionImpl::checkAuthForDelete(OperationContext* opCtx,
+ const NamespaceString& ns,
+ const BSONObj& query) {
+ if (!isAuthorizedForActionsOnNamespace(ns, ActionType::remove)) {
+ return Status(ErrorCodes::Unauthorized,
+ str::stream() << "not authorized to remove from " << ns.ns());
+ }
+ return Status::OK();
+}
+
+Status AuthorizationSessionImpl::checkAuthForKillCursors(const NamespaceString& ns,
+ UserNameIterator cursorOwner) {
+ if (isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(),
+ ActionType::killAnyCursor)) {
+ return Status::OK();
+ }
+
+ if (ns.isListCollectionsCursorNS()) {
+ // listCollections: Target the database being enumerated.
+ if (isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(ns.db()),
+ ActionType::killAnyCursor)) {
+ return Status::OK();
+ }
+ const bool canKill =
+ isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(ns.db()),
+ ActionType::killCursors) ||
+ isAuthorizedToListCollections(ns.db());
+ if (canKill && isCoauthorizedWith(cursorOwner)) {
+ return Status::OK();
+ }
+ return Status(ErrorCodes::Unauthorized,
+ str::stream() << "not authorized to kill listCollections cursor on "
+ << ns.ns());
+ } else if (ns.isListIndexesCursorNS()) {
+
+ // listIndexes: Target the underlying collection.
+ NamespaceString targetNS = ns.getTargetNSForListIndexes();
+ if (isAuthorizedForActionsOnNamespace(targetNS, ActionType::killAnyCursor)) {
+ return Status::OK();
+ }
+ const bool canKill = isAuthorizedForActionsOnNamespace(targetNS, ActionType::killCursors) ||
+ isAuthorizedForActionsOnNamespace(targetNS, ActionType::listIndexes);
+ if (canKill && isCoauthorizedWith(cursorOwner)) {
+ return Status::OK();
+ }
+
+ return Status(ErrorCodes::Unauthorized,
+ str::stream() << "not authorized to kill listIndexes cursor on " << ns.ns());
+ } else {
+
+ // Otherwise: Target the collection as named.
+ if (isAuthorizedForActionsOnNamespace(ns, ActionType::killAnyCursor)) {
+ return Status::OK();
+ }
+ const bool canKill = isAuthorizedForActionsOnNamespace(ns, ActionType::killCursors) ||
+ isAuthorizedForActionsOnNamespace(ns, ActionType::find);
+ if (canKill && isCoauthorizedWith(cursorOwner)) {
+ return Status::OK();
+ }
+ return Status(ErrorCodes::Unauthorized,
+ str::stream() << "not authorized to kill cursor on " << ns.ns());
+ }
+}
+
+Status AuthorizationSessionImpl::checkAuthForCreate(const NamespaceString& ns,
+ const BSONObj& cmdObj,
+ bool isMongos) {
+ if (cmdObj["capped"].trueValue() &&
+ !isAuthorizedForActionsOnNamespace(ns, ActionType::convertToCapped)) {
+ return Status(ErrorCodes::Unauthorized, "unauthorized");
+ }
+
+ const bool hasCreateCollectionAction =
+ isAuthorizedForActionsOnNamespace(ns, ActionType::createCollection);
+
+ // If attempting to create a view, check for additional required privileges.
+ if (cmdObj["viewOn"]) {
+ // You need the createCollection action on this namespace; the insert action is not
+ // sufficient.
+ if (!hasCreateCollectionAction) {
+ return Status(ErrorCodes::Unauthorized, "unauthorized");
+ }
+
+ // Parse the viewOn namespace and the pipeline. If no pipeline was specified, use the empty
+ // pipeline.
+ NamespaceString viewOnNs(ns.db(), cmdObj["viewOn"].checkAndGetStringData());
+ auto pipeline =
+ cmdObj.hasField("pipeline") ? BSONArray(cmdObj["pipeline"].Obj()) : BSONArray();
+ return checkAuthForCreateOrModifyView(this, ns, viewOnNs, pipeline, isMongos);
+ }
+
+ // To create a regular collection, ActionType::createCollection or ActionType::insert are
+ // both acceptable.
+ if (hasCreateCollectionAction || isAuthorizedForActionsOnNamespace(ns, ActionType::insert)) {
+ return Status::OK();
+ }
+
+ return Status(ErrorCodes::Unauthorized, "unauthorized");
+}
+
+Status AuthorizationSessionImpl::checkAuthForCollMod(const NamespaceString& ns,
+ const BSONObj& cmdObj,
+ bool isMongos) {
+ if (!isAuthorizedForActionsOnNamespace(ns, ActionType::collMod)) {
+ return Status(ErrorCodes::Unauthorized, "unauthorized");
+ }
+
+ // Check for additional required privileges if attempting to modify a view. When auth is
+ // enabled, users must specify both "viewOn" and "pipeline" together. This prevents a user from
+ // exposing more information in the original underlying namespace by only changing "pipeline",
+ // or looking up more information via the original pipeline by only changing "viewOn".
+ const bool hasViewOn = cmdObj.hasField("viewOn");
+ const bool hasPipeline = cmdObj.hasField("pipeline");
+ if (hasViewOn != hasPipeline) {
+ return Status(
+ ErrorCodes::InvalidOptions,
+ "Must specify both 'viewOn' and 'pipeline' when modifying a view and auth is enabled");
+ }
+ if (hasViewOn) {
+ NamespaceString viewOnNs(ns.db(), cmdObj["viewOn"].checkAndGetStringData());
+ auto viewPipeline = BSONArray(cmdObj["pipeline"].Obj());
+ return checkAuthForCreateOrModifyView(this, ns, viewOnNs, viewPipeline, isMongos);
+ }
+
+ return Status::OK();
+}
+
+Status AuthorizationSessionImpl::checkAuthorizedToGrantPrivilege(const Privilege& privilege) {
+ const ResourcePattern& resource = privilege.getResourcePattern();
+ if (resource.isDatabasePattern() || resource.isExactNamespacePattern()) {
+ if (!isAuthorizedForActionsOnResource(
+ ResourcePattern::forDatabaseName(resource.databaseToMatch()),
+ ActionType::grantRole)) {
+ return Status(ErrorCodes::Unauthorized,
+ str::stream() << "Not authorized to grant privileges on the "
+ << resource.databaseToMatch()
+ << "database");
+ }
+ } else if (!isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName("admin"),
+ ActionType::grantRole)) {
+ return Status(ErrorCodes::Unauthorized,
+ "To grant privileges affecting multiple databases or the cluster,"
+ " must be authorized to grant roles from the admin database");
+ }
+ return Status::OK();
+}
+
+
+Status AuthorizationSessionImpl::checkAuthorizedToRevokePrivilege(const Privilege& privilege) {
+ const ResourcePattern& resource = privilege.getResourcePattern();
+ if (resource.isDatabasePattern() || resource.isExactNamespacePattern()) {
+ if (!isAuthorizedForActionsOnResource(
+ ResourcePattern::forDatabaseName(resource.databaseToMatch()),
+ ActionType::revokeRole)) {
+ return Status(ErrorCodes::Unauthorized,
+ str::stream() << "Not authorized to revoke privileges on the "
+ << resource.databaseToMatch()
+ << "database");
+ }
+ } else if (!isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName("admin"),
+ ActionType::revokeRole)) {
+ return Status(ErrorCodes::Unauthorized,
+ "To revoke privileges affecting multiple databases or the cluster,"
+ " must be authorized to revoke roles from the admin database");
+ }
+ return Status::OK();
+}
+
+bool AuthorizationSessionImpl::isAuthorizedToParseNamespaceElement(const BSONElement& element) {
+ const bool isUUID = element.type() == BinData && element.binDataType() == BinDataType::newUUID;
+
+ uassert(ErrorCodes::InvalidNamespace,
+ "Failed to parse namespace element",
+ element.type() == String || isUUID);
+
+ if (isUUID) {
+ return isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(),
+ ActionType::useUUID);
+ }
+
+ return true;
+}
+
+bool AuthorizationSessionImpl::isAuthorizedToCreateRole(
+ const struct auth::CreateOrUpdateRoleArgs& args) {
+ // A user is allowed to create a role under either of two conditions.
+
+ // The user may create a role if the authorization system says they are allowed to.
+ if (isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(args.roleName.getDB()),
+ ActionType::createRole)) {
+ return true;
+ }
+
+ // The user may create a role if the localhost exception is enabled, and they already own the
+ // role. This implies they have obtained the role through an external authorization mechanism.
+ if (_externalState->shouldAllowLocalhost()) {
+ for (const User* const user : _authenticatedUsers) {
+ if (user->hasRole(args.roleName)) {
+ return true;
+ }
+ }
+ log() << "Not authorized to create the first role in the system '" << args.roleName
+ << "' using the localhost exception. The user needs to acquire the role through "
+ "external authentication first.";
+ }
+
+ return false;
+}
+
+bool AuthorizationSessionImpl::isAuthorizedToGrantRole(const RoleName& role) {
+ return isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(role.getDB()),
+ ActionType::grantRole);
+}
+
+bool AuthorizationSessionImpl::isAuthorizedToRevokeRole(const RoleName& role) {
+ return isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(role.getDB()),
+ ActionType::revokeRole);
+}
+
+bool AuthorizationSessionImpl::isAuthorizedForPrivilege(const Privilege& privilege) {
+ if (_externalState->shouldIgnoreAuthChecks())
+ return true;
+
+ return _isAuthorizedForPrivilege(privilege);
+}
+
+bool AuthorizationSessionImpl::isAuthorizedForPrivileges(const vector<Privilege>& privileges) {
+ if (_externalState->shouldIgnoreAuthChecks())
+ return true;
+
+ for (size_t i = 0; i < privileges.size(); ++i) {
+ if (!_isAuthorizedForPrivilege(privileges[i]))
+ return false;
+ }
+
+ return true;
+}
+
+bool AuthorizationSessionImpl::isAuthorizedForActionsOnResource(const ResourcePattern& resource,
+ ActionType action) {
+ return isAuthorizedForPrivilege(Privilege(resource, action));
+}
+
+bool AuthorizationSessionImpl::isAuthorizedForActionsOnResource(const ResourcePattern& resource,
+ const ActionSet& actions) {
+ return isAuthorizedForPrivilege(Privilege(resource, actions));
+}
+
+bool AuthorizationSessionImpl::isAuthorizedForActionsOnNamespace(const NamespaceString& ns,
+ ActionType action) {
+ return isAuthorizedForPrivilege(Privilege(ResourcePattern::forExactNamespace(ns), action));
+}
+
+bool AuthorizationSessionImpl::isAuthorizedForActionsOnNamespace(const NamespaceString& ns,
+ const ActionSet& actions) {
+ return isAuthorizedForPrivilege(Privilege(ResourcePattern::forExactNamespace(ns), actions));
+}
+
+static const int resourceSearchListCapacity = 5;
+/**
+ * Builds from "target" an exhaustive list of all ResourcePatterns that match "target".
+ *
+ * Stores the resulting list into resourceSearchList, and returns the length.
+ *
+ * The seach lists are as follows, depending on the type of "target":
+ *
+ * target is ResourcePattern::forAnyResource():
+ * searchList = { ResourcePattern::forAnyResource(), ResourcePattern::forAnyResource() }
+ * target is the ResourcePattern::forClusterResource():
+ * searchList = { ResourcePattern::forAnyResource(), ResourcePattern::forClusterResource() }
+ * target is a database, db:
+ * searchList = { ResourcePattern::forAnyResource(),
+ * ResourcePattern::forAnyNormalResource(),
+ * db }
+ * target is a non-system collection, db.coll:
+ * searchList = { ResourcePattern::forAnyResource(),
+ * ResourcePattern::forAnyNormalResource(),
+ * db,
+ * coll,
+ * db.coll }
+ * target is a system collection, db.system.coll:
+ * searchList = { ResourcePattern::forAnyResource(),
+ * system.coll,
+ * db.system.coll }
+ */
+static int buildResourceSearchList(const ResourcePattern& target,
+ ResourcePattern resourceSearchList[resourceSearchListCapacity]) {
+ int size = 0;
+ resourceSearchList[size++] = ResourcePattern::forAnyResource();
+ if (target.isExactNamespacePattern()) {
+ if (!target.ns().isSystem()) {
+ // Some databases should not be matchable with ResourcePattern::forAnyNormalResource.
+ // 'local' and 'config' are used to store special system collections, which user level
+ // administrators should not be able to manipulate.
+ if (target.ns().db() != "local" && target.ns().db() != "config") {
+ resourceSearchList[size++] = ResourcePattern::forAnyNormalResource();
+ }
+ resourceSearchList[size++] = ResourcePattern::forDatabaseName(target.ns().db());
+ }
+ resourceSearchList[size++] = ResourcePattern::forCollectionName(target.ns().coll());
+ } else if (target.isDatabasePattern()) {
+ resourceSearchList[size++] = ResourcePattern::forAnyNormalResource();
+ }
+ resourceSearchList[size++] = target;
+ dassert(size <= resourceSearchListCapacity);
+ return size;
+}
+
+bool AuthorizationSessionImpl::isAuthorizedToChangeAsUser(const UserName& userName,
+ ActionType actionType) {
+ User* user = lookupUser(userName);
+ if (!user) {
+ return false;
+ }
+ ResourcePattern resourceSearchList[resourceSearchListCapacity];
+ const int resourceSearchListLength = buildResourceSearchList(
+ ResourcePattern::forDatabaseName(userName.getDB()), resourceSearchList);
+
+ ActionSet actions;
+ for (int i = 0; i < resourceSearchListLength; ++i) {
+ actions.addAllActionsFromSet(user->getActionsForResource(resourceSearchList[i]));
+ }
+ return actions.contains(actionType);
+}
+
+bool AuthorizationSessionImpl::isAuthorizedToChangeOwnPasswordAsUser(const UserName& userName) {
+ return AuthorizationSessionImpl::isAuthorizedToChangeAsUser(userName,
+ ActionType::changeOwnPassword);
+}
+
+bool AuthorizationSessionImpl::isAuthorizedToChangeOwnCustomDataAsUser(const UserName& userName) {
+ return AuthorizationSessionImpl::isAuthorizedToChangeAsUser(userName,
+ ActionType::changeOwnCustomData);
+}
+
+bool AuthorizationSessionImpl::isAuthorizedToListCollections(StringData dbname) {
+ // Check for the listCollections ActionType on the database or find on system.namespaces for
+ // pre 3.0 systems.
+
+ return AuthorizationSessionImpl::isAuthorizedForActionsOnResource(
+ ResourcePattern::forDatabaseName(dbname), ActionType::listCollections) ||
+ AuthorizationSessionImpl::isAuthorizedForActionsOnResource(
+ ResourcePattern::forExactNamespace(NamespaceString(dbname, "system.namespaces")),
+ ActionType::find);
+}
+
+bool AuthorizationSessionImpl::isAuthenticatedAsUserWithRole(const RoleName& roleName) {
+ for (UserSet::iterator it = _authenticatedUsers.begin(); it != _authenticatedUsers.end();
+ ++it) {
+ if ((*it)->hasRole(roleName)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AuthorizationSessionImpl::isAuthenticated() {
+ return _authenticatedUsers.begin() != _authenticatedUsers.end();
+}
+
+void AuthorizationSessionImpl::_refreshUserInfoAsNeeded(OperationContext* opCtx) {
+ AuthorizationManager& authMan = getAuthorizationManager();
+ UserSet::iterator it = _authenticatedUsers.begin();
+ while (it != _authenticatedUsers.end()) {
+ User* user = *it;
+
+ if (!user->isValid()) {
+ // Make a good faith effort to acquire an up-to-date user object, since the one
+ // we've cached is marked "out-of-date."
+ UserName name = user->getName();
+ User* updatedUser;
+
+ Status status = authMan.acquireUser(opCtx, name, &updatedUser);
+ switch (status.code()) {
+ case ErrorCodes::OK: {
+
+ // Verify the updated user object's authentication restrictions.
+ UserHolder userHolder(user, UserReleaser(&authMan, &_authenticatedUsers, it));
+ UserHolder updatedUserHolder(updatedUser, UserReleaser(&authMan));
+ try {
+ const auto& restrictionSet =
+ updatedUserHolder->getRestrictions(); // Owned by updatedUser
+ invariant(opCtx->getClient());
+ Status restrictionStatus = restrictionSet.validate(
+ RestrictionEnvironment::get(*opCtx->getClient()));
+ if (!restrictionStatus.isOK()) {
+ log() << "Removed user " << name
+ << " with unmet authentication restrictions from session cache of"
+ << " user information. Restriction failed because: "
+ << restrictionStatus.reason();
+ // If we remove from the UserSet, we cannot increment the iterator.
+ continue;
+ }
+ } catch (...) {
+ log() << "Evaluating authentication restrictions for " << name
+ << " resulted in an unknown exception. Removing user from the"
+ << " session cache.";
+ continue;
+ }
+
+ // Success! Replace the old User object with the updated one.
+ fassert(17067,
+ _authenticatedUsers.replaceAt(it, updatedUserHolder.release()) ==
+ userHolder.get());
+ LOG(1) << "Updated session cache of user information for " << name;
+ break;
+ }
+ case ErrorCodes::UserNotFound: {
+ // User does not exist anymore; remove it from _authenticatedUsers.
+ fassert(17068, _authenticatedUsers.removeAt(it) == user);
+ authMan.releaseUser(user);
+ log() << "Removed deleted user " << name
+ << " from session cache of user information.";
+ continue; // No need to advance "it" in this case.
+ }
+ case ErrorCodes::UnsupportedFormat: {
+ // An auth subsystem has explicitly indicated a failure.
+ fassert(40555, _authenticatedUsers.removeAt(it) == user);
+ authMan.releaseUser(user);
+ log() << "Removed user " << name
+ << " from session cache of user information because of refresh failure:"
+ << " '" << status << "'.";
+ continue; // No need to advance "it" in this case.
+ }
+ default:
+ // Unrecognized error; assume that it's transient, and continue working with the
+ // out-of-date privilege data.
+ warning() << "Could not fetch updated user privilege information for " << name
+ << "; continuing to use old information. Reason is "
+ << redact(status);
+ break;
+ }
+ }
+ ++it;
+ }
+ _buildAuthenticatedRolesVector();
+}
+
+void AuthorizationSessionImpl::_buildAuthenticatedRolesVector() {
+ _authenticatedRoleNames.clear();
+ for (UserSet::iterator it = _authenticatedUsers.begin(); it != _authenticatedUsers.end();
+ ++it) {
+ RoleNameIterator roles = (*it)->getIndirectRoles();
+ while (roles.more()) {
+ RoleName roleName = roles.next();
+ _authenticatedRoleNames.push_back(RoleName(roleName.getRole(), roleName.getDB()));
+ }
+ }
+}
+
+bool AuthorizationSessionImpl::_isAuthorizedForPrivilege(const Privilege& privilege) {
+ const ResourcePattern& target(privilege.getResourcePattern());
+
+ ResourcePattern resourceSearchList[resourceSearchListCapacity];
+ const int resourceSearchListLength = buildResourceSearchList(target, resourceSearchList);
+
+ ActionSet unmetRequirements = privilege.getActions();
+
+ PrivilegeVector defaultPrivileges = getDefaultPrivileges();
+ for (PrivilegeVector::iterator it = defaultPrivileges.begin(); it != defaultPrivileges.end();
+ ++it) {
+ for (int i = 0; i < resourceSearchListLength; ++i) {
+ if (!(it->getResourcePattern() == resourceSearchList[i]))
+ continue;
+
+ ActionSet userActions = it->getActions();
+ unmetRequirements.removeAllActionsFromSet(userActions);
+
+ if (unmetRequirements.empty())
+ return true;
+ }
+ }
+
+ for (UserSet::iterator it = _authenticatedUsers.begin(); it != _authenticatedUsers.end();
+ ++it) {
+ User* user = *it;
+ for (int i = 0; i < resourceSearchListLength; ++i) {
+ ActionSet userActions = user->getActionsForResource(resourceSearchList[i]);
+ unmetRequirements.removeAllActionsFromSet(userActions);
+
+ if (unmetRequirements.empty())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void AuthorizationSessionImpl::setImpersonatedUserData(std::vector<UserName> usernames,
+ std::vector<RoleName> roles) {
+ _impersonatedUserNames = usernames;
+ _impersonatedRoleNames = roles;
+ _impersonationFlag = true;
+}
+
+bool AuthorizationSessionImpl::isCoauthorizedWithClient(Client* opClient) {
+ auto getUserNames = [](AuthorizationSession* authSession) {
+ if (authSession->isImpersonating()) {
+ return authSession->getImpersonatedUserNames();
+ } else {
+ return authSession->getAuthenticatedUserNames();
+ }
+ };
+
+ UserNameIterator it = getUserNames(this);
+ while (it.more()) {
+ UserNameIterator opIt = getUserNames(AuthorizationSession::get(opClient));
+ while (opIt.more()) {
+ if (it.get() == opIt.get()) {
+ return true;
+ }
+ opIt.next();
+ }
+ it.next();
+ }
+
+ return false;
+}
+
+bool AuthorizationSessionImpl::isCoauthorizedWith(UserNameIterator userNameIter) {
+ if (!getAuthorizationManager().isAuthEnabled()) {
+ return true;
+ }
+ if (!userNameIter.more() && !isAuthenticated()) {
+ return true;
+ }
+
+ for (; userNameIter.more(); userNameIter.next()) {
+ for (UserNameIterator thisUserNameIter = getAuthenticatedUserNames();
+ thisUserNameIter.more();
+ thisUserNameIter.next()) {
+ if (*userNameIter == *thisUserNameIter) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+UserNameIterator AuthorizationSessionImpl::getImpersonatedUserNames() {
+ return makeUserNameIterator(_impersonatedUserNames.begin(), _impersonatedUserNames.end());
+}
+
+RoleNameIterator AuthorizationSessionImpl::getImpersonatedRoleNames() {
+ return makeRoleNameIterator(_impersonatedRoleNames.begin(), _impersonatedRoleNames.end());
+}
+
+bool AuthorizationSessionImpl::isUsingLocalhostBypass() {
+ return getAuthorizationManager().isAuthEnabled() && _externalState->shouldAllowLocalhost();
+}
+
+// Clear the vectors of impersonated usernames and roles.
+void AuthorizationSessionImpl::clearImpersonatedUserData() {
+ _impersonatedUserNames.clear();
+ _impersonatedRoleNames.clear();
+ _impersonationFlag = false;
+}
+
+
+bool AuthorizationSessionImpl::isImpersonating() const {
+ return _impersonationFlag;
+}
+
+auto AuthorizationSessionImpl::checkCursorSessionPrivilege(
+ OperationContext* const opCtx, const boost::optional<LogicalSessionId> cursorSessionId)
+ -> Status {
+ auto nobodyIsLoggedIn = [authSession = this] {
+ return !authSession->isAuthenticated();
+ };
+
+ auto authHasImpersonatePrivilege = [authSession = this] {
+ return authSession->isAuthorizedForPrivilege(
+ Privilege(ResourcePattern::forClusterResource(), ActionType::impersonate));
+ };
+
+ auto authIsOn = [authSession = this] {
+ return authSession->getAuthorizationManager().isAuthEnabled();
+ };
+
+ auto sessionIdToStringOrNone =
+ [](const boost::optional<LogicalSessionId>& sessionId) -> std::string {
+ if (sessionId) {
+ return str::stream() << *sessionId;
+ }
+ return "none";
+ };
+
+ // If the cursor has a session then one of the following must be true:
+ // 1: context session id must match cursor session id.
+ // 2: user must be magic special (__system, or background task, etc).
+
+ // We do not check the user's ID against the cursor's notion of a user ID, since higher level
+ // auth checks will check that for us anyhow.
+ if (authIsOn() && // If the authorization is not on, then we permit anybody to do anything.
+ cursorSessionId != opCtx->getLogicalSessionId() && // If the cursor's session doesn't match
+ // the Operation Context's session, then
+ // we should forbid the operation even
+ // when the cursor has no session.
+ !nobodyIsLoggedIn() && // Unless, for some reason a user isn't actually using this
+ // Operation Context (which implies a background job
+ !authHasImpersonatePrivilege() // Or if the user has an impersonation privilege, in which
+ // case, the user gets to sidestep certain checks.
+ ) {
+ return Status{ErrorCodes::Unauthorized,
+ str::stream() << "Cursor session id ("
+ << sessionIdToStringOrNone(cursorSessionId)
+ << ") is not the same as the operation context's session id ("
+ << sessionIdToStringOrNone(opCtx->getLogicalSessionId())
+ << ")"};
+ }
+
+ return Status::OK();
+}
+
+} // namespace mongo
diff --git a/src/mongo/db/auth/authorization_session_impl.h b/src/mongo/db/auth/authorization_session_impl.h
new file mode 100644
index 00000000000..d11dbb3e348
--- /dev/null
+++ b/src/mongo/db/auth/authorization_session_impl.h
@@ -0,0 +1,232 @@
+/**
+ * Copyright (C) 2018 10gen 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 "authorization_session.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "mongo/base/disallow_copying.h"
+#include "mongo/base/status.h"
+#include "mongo/db/auth/action_set.h"
+#include "mongo/db/auth/action_type.h"
+#include "mongo/db/auth/authorization_manager.h"
+#include "mongo/db/auth/authz_session_external_state.h"
+#include "mongo/db/auth/privilege.h"
+#include "mongo/db/auth/user_name.h"
+#include "mongo/db/auth/user_set.h"
+#include "mongo/db/namespace_string.h"
+
+namespace mongo {
+
+namespace auth {
+
+struct CreateOrUpdateRoleArgs;
+}
+class Client;
+
+/**
+ * Contains all the authorization logic for a single client connection. It contains a set of
+ * the users which have been authenticated, as well as a set of privileges that have been
+ * granted to those users to perform various actions.
+ *
+ * An AuthorizationSession object is present within every mongo::Client object.
+ *
+ * Users in the _authenticatedUsers cache may get marked as invalid by the AuthorizationManager,
+ * for instance if their privileges are changed by a user or role modification command. At the
+ * beginning of every user-initiated operation startRequest() gets called which updates
+ * the cached information about any users who have been marked as invalid. This guarantees that
+ * every operation looks at one consistent view of each user for every auth check required over
+ * the lifetime of the operation.
+ */
+class AuthorizationSessionImpl : public AuthorizationSession {
+public:
+ struct InstallMockForTestingOrAuthImpl {
+ explicit InstallMockForTestingOrAuthImpl() = default;
+ };
+ explicit AuthorizationSessionImpl(std::unique_ptr<AuthzSessionExternalState> externalState,
+ InstallMockForTestingOrAuthImpl);
+
+ ~AuthorizationSessionImpl() override;
+
+ AuthorizationManager& getAuthorizationManager() override;
+
+ void startRequest(OperationContext* opCtx) override;
+
+ Status addAndAuthorizeUser(OperationContext* opCtx, const UserName& userName) override;
+
+ User* lookupUser(const UserName& name) override;
+
+ bool isAuthenticated() override;
+
+ User* getSingleUser() override;
+
+ UserNameIterator getAuthenticatedUserNames() override;
+
+ RoleNameIterator getAuthenticatedRoleNames() override;
+
+ std::string getAuthenticatedUserNamesToken() override;
+
+ void logoutDatabase(const std::string& dbname) override;
+
+ void grantInternalAuthorization() override;
+
+ PrivilegeVector getDefaultPrivileges() override;
+
+ Status checkAuthForFind(const NamespaceString& ns, bool hasTerm) override;
+
+ Status checkAuthForGetMore(const NamespaceString& ns,
+ long long cursorID,
+ bool hasTerm) override;
+
+ Status checkAuthForUpdate(OperationContext* opCtx,
+ const NamespaceString& ns,
+ const BSONObj& query,
+ const BSONObj& update,
+ bool upsert) override;
+
+ Status checkAuthForInsert(OperationContext* opCtx,
+ const NamespaceString& ns,
+ const BSONObj& document) override;
+
+ Status checkAuthForDelete(OperationContext* opCtx,
+ const NamespaceString& ns,
+ const BSONObj& query) override;
+
+ Status checkAuthForKillCursors(const NamespaceString& cursorNss,
+ UserNameIterator cursorOwner) override;
+
+ Status checkAuthForAggregate(const NamespaceString& ns,
+ const BSONObj& cmdObj,
+ bool isMongos) override;
+
+ Status checkAuthForCreate(const NamespaceString& ns,
+ const BSONObj& cmdObj,
+ bool isMongos) override;
+
+ Status checkAuthForCollMod(const NamespaceString& ns,
+ const BSONObj& cmdObj,
+ bool isMongos) override;
+
+ Status checkAuthorizedToGrantPrivilege(const Privilege& privilege) override;
+
+ Status checkAuthorizedToRevokePrivilege(const Privilege& privilege) override;
+
+ bool isUsingLocalhostBypass() override;
+
+ bool isAuthorizedToParseNamespaceElement(const BSONElement& elem) override;
+
+ bool isAuthorizedToCreateRole(const auth::CreateOrUpdateRoleArgs& args) override;
+
+ bool isAuthorizedToGrantRole(const RoleName& role) override;
+
+ bool isAuthorizedToRevokeRole(const RoleName& role) override;
+
+ bool isAuthorizedToChangeAsUser(const UserName& userName, ActionType actionType) override;
+
+ bool isAuthorizedToChangeOwnPasswordAsUser(const UserName& userName) override;
+
+ bool isAuthorizedToListCollections(StringData dbname) override;
+
+ bool isAuthorizedToChangeOwnCustomDataAsUser(const UserName& userName) override;
+
+ bool isAuthenticatedAsUserWithRole(const RoleName& roleName) override;
+
+ bool isAuthorizedForPrivilege(const Privilege& privilege) override;
+
+ bool isAuthorizedForPrivileges(const std::vector<Privilege>& privileges) override;
+
+ bool isAuthorizedForActionsOnResource(const ResourcePattern& resource,
+ ActionType action) override;
+
+ bool isAuthorizedForActionsOnResource(const ResourcePattern& resource,
+ const ActionSet& actions) override;
+
+ bool isAuthorizedForActionsOnNamespace(const NamespaceString& ns, ActionType action) override;
+
+ bool isAuthorizedForActionsOnNamespace(const NamespaceString& ns,
+ const ActionSet& actions) override;
+
+ void setImpersonatedUserData(std::vector<UserName> usernames,
+ std::vector<RoleName> roles) override;
+
+ UserNameIterator getImpersonatedUserNames() override;
+
+ RoleNameIterator getImpersonatedRoleNames() override;
+
+ void clearImpersonatedUserData() override;
+
+ bool isCoauthorizedWithClient(Client* opClient) override;
+
+ bool isCoauthorizedWith(UserNameIterator userNameIter) override;
+
+ bool isImpersonating() const override;
+
+ Status checkCursorSessionPrivilege(OperationContext* const opCtx,
+ boost::optional<LogicalSessionId> cursorSessionId) override;
+
+protected:
+ // Builds a vector of all roles held by users who are authenticated on this connection. The
+ // vector is stored in _authenticatedRoleNames. This function is called when users are
+ // logged in or logged out, as well as when the user cache is determined to be out of date.
+ void _buildAuthenticatedRolesVector();
+
+ // All Users who have been authenticated on this connection.
+ UserSet _authenticatedUsers;
+
+ // The roles of the authenticated users. This vector is generated when the authenticated
+ // users set is changed.
+ std::vector<RoleName> _authenticatedRoleNames;
+
+private:
+ // If any users authenticated on this session are marked as invalid this updates them with
+ // up-to-date information. May require a read lock on the "admin" db to read the user data.
+ void _refreshUserInfoAsNeeded(OperationContext* opCtx);
+
+
+ // Checks if this connection is authorized for the given Privilege, ignoring whether or not
+ // we should even be doing authorization checks in general. Note: this may acquire a read
+ // lock on the admin database (to update out-of-date user privilege information).
+ bool _isAuthorizedForPrivilege(const Privilege& privilege);
+
+ std::tuple<std::vector<UserName>*, std::vector<RoleName>*> _getImpersonations() override {
+ return std::make_tuple(&_impersonatedUserNames, &_impersonatedRoleNames);
+ }
+
+ std::unique_ptr<AuthzSessionExternalState> _externalState;
+
+ // A vector of impersonated UserNames and a vector of those users' RoleNames.
+ // These are used in the auditing system. They are not used for authz checks.
+ std::vector<UserName> _impersonatedUserNames;
+ std::vector<RoleName> _impersonatedRoleNames;
+ bool _impersonationFlag;
+};
+} // namespace mongo
diff --git a/src/mongo/db/auth/authorization_session_test.cpp b/src/mongo/db/auth/authorization_session_test.cpp
index 7933bb8f46b..2ee3659629f 100644
--- a/src/mongo/db/auth/authorization_session_test.cpp
+++ b/src/mongo/db/auth/authorization_session_test.cpp
@@ -37,6 +37,7 @@
#include "mongo/crypto/sha256_block.h"
#include "mongo/db/auth/action_type.h"
#include "mongo/db/auth/authorization_manager.h"
+#include "mongo/db/auth/authorization_manager_impl.h"
#include "mongo/db/auth/authorization_session_for_test.h"
#include "mongo/db/auth/authz_manager_external_state_mock.h"
#include "mongo/db/auth/authz_session_external_state_mock.h"
@@ -105,13 +106,16 @@ public:
auto localManagerState = stdx::make_unique<FailureCapableAuthzManagerExternalStateMock>();
managerState = localManagerState.get();
managerState->setAuthzVersion(AuthorizationManager::schemaVersion26Final);
- auto uniqueAuthzManager =
- stdx::make_unique<AuthorizationManager>(std::move(localManagerState));
+ auto uniqueAuthzManager = std::make_unique<AuthorizationManagerImpl>(
+ std::move(localManagerState),
+ AuthorizationManagerImpl::InstallMockForTestingOrAuthImpl{});
authzManager = uniqueAuthzManager.get();
AuthorizationManager::set(&serviceContext, std::move(uniqueAuthzManager));
- auto localSessionState = stdx::make_unique<AuthzSessionExternalStateMock>(authzManager);
+ auto localSessionState = std::make_unique<AuthzSessionExternalStateMock>(authzManager);
sessionState = localSessionState.get();
- authzSession = stdx::make_unique<AuthorizationSessionForTest>(std::move(localSessionState));
+ authzSession = std::make_unique<AuthorizationSessionForTest>(
+ std::move(localSessionState),
+ AuthorizationSessionImpl::InstallMockForTestingOrAuthImpl{});
authzManager->setAuthEnabled(true);
credentials =
diff --git a/src/mongo/db/auth/authz_manager_external_state.cpp b/src/mongo/db/auth/authz_manager_external_state.cpp
index f0a30f51a9d..1eef2c854d2 100644
--- a/src/mongo/db/auth/authz_manager_external_state.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state.cpp
@@ -35,7 +35,7 @@
namespace mongo {
-stdx::function<std::unique_ptr<AuthzManagerExternalState>()> AuthzManagerExternalState::create;
+MONGO_DEFINE_SHIM(AuthzManagerExternalState::create);
AuthzManagerExternalState::AuthzManagerExternalState() = default;
AuthzManagerExternalState::~AuthzManagerExternalState() = default;
diff --git a/src/mongo/db/auth/authz_manager_external_state.h b/src/mongo/db/auth/authz_manager_external_state.h
index 51d2e7a4808..83ba92fd037 100644
--- a/src/mongo/db/auth/authz_manager_external_state.h
+++ b/src/mongo/db/auth/authz_manager_external_state.h
@@ -33,6 +33,7 @@
#include <vector>
#include "mongo/base/disallow_copying.h"
+#include "mongo/base/shim.h"
#include "mongo/base/status.h"
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/privilege_format.h"
@@ -53,10 +54,11 @@ class OperationContext;
* easier to test as well as to allow different implementations for mongos and mongod.
*/
class AuthzManagerExternalState {
- MONGO_DISALLOW_COPYING(AuthzManagerExternalState);
+ AuthzManagerExternalState(const AuthzManagerExternalState&) = delete;
+ AuthzManagerExternalState& operator=(const AuthzManagerExternalState&) = delete;
public:
- static stdx::function<std::unique_ptr<AuthzManagerExternalState>()> create;
+ static MONGO_DECLARE_SHIM(()->std::unique_ptr<AuthzManagerExternalState>) create;
virtual ~AuthzManagerExternalState();
diff --git a/src/mongo/db/auth/authz_manager_external_state_d.cpp b/src/mongo/db/auth/authz_manager_external_state_d.cpp
index 0e259a9d11c..1454076a12b 100644
--- a/src/mongo/db/auth/authz_manager_external_state_d.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state_d.cpp
@@ -91,4 +91,9 @@ Status AuthzManagerExternalStateMongod::findOne(OperationContext* opCtx,
<< query);
}
+MONGO_REGISTER_SHIM(AuthzManagerExternalState::create)
+()->std::unique_ptr<AuthzManagerExternalState> {
+ return std::make_unique<AuthzManagerExternalStateMongod>();
+}
+
} // namespace mongo
diff --git a/src/mongo/db/auth/authz_manager_external_state_mock.cpp b/src/mongo/db/auth/authz_manager_external_state_mock.cpp
index fec42b1bf88..d755d61c556 100644
--- a/src/mongo/db/auth/authz_manager_external_state_mock.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state_mock.cpp
@@ -47,6 +47,12 @@
#include "mongo/util/mongoutils/str.h"
namespace mongo {
+
+MONGO_REGISTER_SHIM(AuthzManagerExternalState::create)
+()->std::unique_ptr<AuthzManagerExternalState> {
+ return std::make_unique<AuthzManagerExternalStateMock>();
+}
+
namespace {
void addRoleNameToObjectElement(mutablebson::Element object, const RoleName& role) {
fassert(17175, object.appendString(AuthorizationManager::ROLE_NAME_FIELD_NAME, role.getRole()));
diff --git a/src/mongo/db/auth/authz_manager_external_state_s.cpp b/src/mongo/db/auth/authz_manager_external_state_s.cpp
index 14fef957ec9..9514a58c33b 100644
--- a/src/mongo/db/auth/authz_manager_external_state_s.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state_s.cpp
@@ -51,6 +51,12 @@
#include "mongo/util/stringutils.h"
namespace mongo {
+
+MONGO_REGISTER_SHIM(AuthzManagerExternalState::create)
+()->std::unique_ptr<AuthzManagerExternalState> {
+ return std::make_unique<AuthzManagerExternalStateMongos>();
+}
+
namespace {
/**
diff --git a/src/mongo/db/auth/authz_session_external_state.cpp b/src/mongo/db/auth/authz_session_external_state.cpp
index edc3a589d88..5985a1d54fe 100644
--- a/src/mongo/db/auth/authz_session_external_state.cpp
+++ b/src/mongo/db/auth/authz_session_external_state.cpp
@@ -45,4 +45,6 @@ AuthorizationManager& AuthzSessionExternalState::getAuthorizationManager() {
return *_authzManager;
}
+MONGO_DEFINE_SHIM(AuthzSessionExternalState::create);
+
} // namespace mongo
diff --git a/src/mongo/db/auth/authz_session_external_state.h b/src/mongo/db/auth/authz_session_external_state.h
index ba43be8050b..bd8cde24fea 100644
--- a/src/mongo/db/auth/authz_session_external_state.h
+++ b/src/mongo/db/auth/authz_session_external_state.h
@@ -47,9 +47,13 @@ class OperationContext;
* easier to test as well as to allow different implementations in mongos and mongod.
*/
class AuthzSessionExternalState {
- MONGO_DISALLOW_COPYING(AuthzSessionExternalState);
+ AuthzSessionExternalState(const AuthzSessionExternalState&) = delete;
+ AuthzSessionExternalState& operator=(const AuthzSessionExternalState&) = delete;
public:
+ static MONGO_DECLARE_SHIM(
+ (AuthorizationManager * authzManager)->std::unique_ptr<AuthzSessionExternalState>) create;
+
virtual ~AuthzSessionExternalState();
AuthorizationManager& getAuthorizationManager();
diff --git a/src/mongo/db/auth/authz_session_external_state_d.cpp b/src/mongo/db/auth/authz_session_external_state_d.cpp
index 0c8689feb10..5c5ef29f899 100644
--- a/src/mongo/db/auth/authz_session_external_state_d.cpp
+++ b/src/mongo/db/auth/authz_session_external_state_d.cpp
@@ -66,4 +66,9 @@ bool AuthzSessionExternalStateMongod::serverIsArbiter() const {
repl::ReplicationCoordinator::get(getGlobalServiceContext())->getMemberState().arbiter());
}
+MONGO_REGISTER_SHIM(AuthzSessionExternalState::create)
+(AuthorizationManager* const authzManager)->std::unique_ptr<AuthzSessionExternalState> {
+ return std::make_unique<AuthzSessionExternalStateMongod>(authzManager);
+}
+
} // namespace mongo
diff --git a/src/mongo/db/authz_manager_external_state_factory_d.cpp b/src/mongo/db/auth/authz_session_external_state_mock.cpp
index 12a9ec19c43..34bf3855204 100644
--- a/src/mongo/db/authz_manager_external_state_factory_d.cpp
+++ b/src/mongo/db/auth/authz_session_external_state_mock.cpp
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2008-2014 MongoDB Inc.
+ * Copyright (C) 2018 10gen 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,
@@ -26,27 +26,11 @@
* it in the license file.
*/
-#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kCommand
-
-#include "mongo/platform/basic.h"
-
-#include "mongo/base/init.h"
-#include "mongo/db/auth/authz_manager_external_state_d.h"
-#include "mongo/stdx/memory.h"
+#include "mongo/db/auth/authz_session_external_state_mock.h"
namespace mongo {
-using std::unique_ptr;
-
-namespace {
-
-unique_ptr<AuthzManagerExternalState> createAuthzManagerExternalStateMongod() {
- return stdx::make_unique<AuthzManagerExternalStateMongod>();
+MONGO_REGISTER_SHIM(AuthzSessionExternalState::create)
+(AuthorizationManager* const authzManager)->std::unique_ptr<AuthzSessionExternalState> {
+ return std::make_unique<AuthzSessionExternalStateMock>(authzManager);
}
-
-MONGO_INITIALIZER(CreateAuthorizationExternalStateFactory)(InitializerContext* context) {
- AuthzManagerExternalState::create = &createAuthzManagerExternalStateMongod;
- return Status::OK();
-}
-
-} // namespace
} // namespace mongo
diff --git a/src/mongo/db/auth/authz_session_external_state_mock.h b/src/mongo/db/auth/authz_session_external_state_mock.h
index d577d7b2e4c..0713d18f6dd 100644
--- a/src/mongo/db/auth/authz_session_external_state_mock.h
+++ b/src/mongo/db/auth/authz_session_external_state_mock.h
@@ -39,7 +39,8 @@ namespace mongo {
* Mock of the AuthzSessionExternalState class used only for testing.
*/
class AuthzSessionExternalStateMock : public AuthzSessionExternalState {
- MONGO_DISALLOW_COPYING(AuthzSessionExternalStateMock);
+ AuthzSessionExternalStateMock(const AuthzSessionExternalStateMock&) = delete;
+ AuthzSessionExternalStateMock& operator=(const AuthzSessionExternalStateMock&) = delete;
public:
AuthzSessionExternalStateMock(AuthorizationManager* authzManager)
diff --git a/src/mongo/db/auth/authz_session_external_state_s.cpp b/src/mongo/db/auth/authz_session_external_state_s.cpp
index 47ac9598735..8f42eb3b30d 100644
--- a/src/mongo/db/auth/authz_session_external_state_s.cpp
+++ b/src/mongo/db/auth/authz_session_external_state_s.cpp
@@ -46,4 +46,9 @@ void AuthzSessionExternalStateMongos::startRequest(OperationContext* opCtx) {
_checkShouldAllowLocalhost(opCtx);
}
+MONGO_REGISTER_SHIM(AuthzSessionExternalState::create)
+(AuthorizationManager* const authzManager)->std::unique_ptr<AuthzSessionExternalState> {
+ return std::make_unique<AuthzSessionExternalStateMongos>(authzManager);
+}
+
} // namespace mongo
diff --git a/src/mongo/db/auth/sasl_authentication_session_test.cpp b/src/mongo/db/auth/sasl_authentication_session_test.cpp
index 4babe8c816b..8497edcac37 100644
--- a/src/mongo/db/auth/sasl_authentication_session_test.cpp
+++ b/src/mongo/db/auth/sasl_authentication_session_test.cpp
@@ -13,6 +13,7 @@
#include "mongo/client/sasl_client_session.h"
#include "mongo/crypto/mechanism_scram.h"
#include "mongo/db/auth/authorization_manager.h"
+#include "mongo/db/auth/authorization_manager_impl.h"
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/auth/authz_manager_external_state_mock.h"
#include "mongo/db/auth/authz_session_external_state_mock.h"
@@ -68,8 +69,9 @@ SaslConversation::SaslConversation(std::string mech)
: opClient(serviceContext.makeClient("saslTest")),
opCtx(serviceContext.makeOperationContext(opClient.get())),
authManagerExternalState(new AuthzManagerExternalStateMock),
- authManager(new AuthorizationManager(
- std::unique_ptr<AuthzManagerExternalState>(authManagerExternalState))),
+ authManager(new AuthorizationManagerImpl(
+ std::unique_ptr<AuthzManagerExternalState>(authManagerExternalState),
+ AuthorizationManagerImpl::InstallMockForTestingOrAuthImpl{})),
authSession(authManager->makeAuthorizationSession()),
mechanism(mech) {
diff --git a/src/mongo/db/auth/sasl_mechanism_registry_test.cpp b/src/mongo/db/auth/sasl_mechanism_registry_test.cpp
index fba7482b033..bdce3b21199 100644
--- a/src/mongo/db/auth/sasl_mechanism_registry_test.cpp
+++ b/src/mongo/db/auth/sasl_mechanism_registry_test.cpp
@@ -29,6 +29,7 @@
#include "mongo/db/auth/sasl_mechanism_registry.h"
#include "mongo/crypto/mechanism_scram.h"
#include "mongo/db/auth/authorization_manager.h"
+#include "mongo/db/auth/authorization_manager_impl.h"
#include "mongo/db/auth/authz_manager_external_state_mock.h"
#include "mongo/db/operation_context_noop.h"
#include "mongo/db/service_context_noop.h"
@@ -135,8 +136,9 @@ public:
: opClient(serviceContext.makeClient("mechanismRegistryTest")),
opCtx(serviceContext.makeOperationContext(opClient.get())),
authManagerExternalState(new AuthzManagerExternalStateMock()),
- authManager(new AuthorizationManager(
- std::unique_ptr<AuthzManagerExternalStateMock>(authManagerExternalState))) {
+ authManager(new AuthorizationManagerImpl(
+ std::unique_ptr<AuthzManagerExternalStateMock>(authManagerExternalState),
+ AuthorizationManagerImpl::InstallMockForTestingOrAuthImpl{})) {
AuthorizationManager::set(&serviceContext,
std::unique_ptr<AuthorizationManager>(authManager));
diff --git a/src/mongo/db/auth/sasl_scram_test.cpp b/src/mongo/db/auth/sasl_scram_test.cpp
index 3ec3cb5c5d9..2a347b6d464 100644
--- a/src/mongo/db/auth/sasl_scram_test.cpp
+++ b/src/mongo/db/auth/sasl_scram_test.cpp
@@ -36,7 +36,9 @@
#include "mongo/crypto/sha1_block.h"
#include "mongo/crypto/sha256_block.h"
#include "mongo/db/auth/authorization_manager.h"
+#include "mongo/db/auth/authorization_manager_impl.h"
#include "mongo/db/auth/authorization_session.h"
+#include "mongo/db/auth/authorization_session_impl.h"
#include "mongo/db/auth/authz_manager_external_state_mock.h"
#include "mongo/db/auth/authz_session_external_state_mock.h"
#include "mongo/db/auth/sasl_mechanism_registry.h"
@@ -189,15 +191,18 @@ protected:
opCtx = serviceContext->makeOperationContext(client.get());
auto uniqueAuthzManagerExternalStateMock =
- stdx::make_unique<AuthzManagerExternalStateMock>();
+ std::make_unique<AuthzManagerExternalStateMock>();
authzManagerExternalState = uniqueAuthzManagerExternalStateMock.get();
- authzManager = new AuthorizationManager(std::move(uniqueAuthzManagerExternalStateMock));
- authzSession = stdx::make_unique<AuthorizationSession>(
- stdx::make_unique<AuthzSessionExternalStateMock>(authzManager));
- AuthorizationManager::set(serviceContext.get(),
- std::unique_ptr<AuthorizationManager>(authzManager));
-
- saslClientSession = stdx::make_unique<NativeSaslClientSession>();
+ auto newManager = std::make_unique<AuthorizationManagerImpl>(
+ std::move(uniqueAuthzManagerExternalStateMock),
+ AuthorizationManagerImpl::InstallMockForTestingOrAuthImpl{});
+ authzSession = std::make_unique<AuthorizationSessionImpl>(
+ std::make_unique<AuthzSessionExternalStateMock>(newManager.get()),
+ AuthorizationSessionImpl::InstallMockForTestingOrAuthImpl{});
+ authzManager = newManager.get();
+ AuthorizationManager::set(serviceContext.get(), std::move(newManager));
+
+ saslClientSession = std::make_unique<NativeSaslClientSession>();
saslClientSession->setParameter(NativeSaslClientSession::parameterMechanism,
saslServerSession->mechanismName());
saslClientSession->setParameter(NativeSaslClientSession::parameterServiceName, "mongodb");
diff --git a/src/mongo/db/auth/user.cpp b/src/mongo/db/auth/user.cpp
index c233e8a1d8b..5dc6ac9cf90 100644
--- a/src/mongo/db/auth/user.cpp
+++ b/src/mongo/db/auth/user.cpp
@@ -1,5 +1,4 @@
/* Copyright 2013 10gen 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,
@@ -77,14 +76,6 @@ const User::SCRAMCredentials<SHA256Block>& User::CredentialData::scram<SHA256Blo
return scram_sha256;
}
-const UserName& User::getName() const {
- return _name;
-}
-
-const SHA256Block& User::getDigest() const {
- return _digest;
-}
-
RoleNameIterator User::getRoles() const {
return makeRoleNameIteratorForContainer(_roles);
}
diff --git a/src/mongo/db/auth/user.h b/src/mongo/db/auth/user.h
index 3af4f6abbf3..5fb67ccd08c 100644
--- a/src/mongo/db/auth/user.h
+++ b/src/mongo/db/auth/user.h
@@ -106,12 +106,17 @@ public:
/**
* Returns the user name for this user.
*/
- const UserName& getName() const;
+ const UserName& getName() const {
+ return _name;
+ }
/**
* Returns a digest of the user's identity
*/
- const SHA256Block& getDigest() const;
+ const SHA256Block& getDigest() const {
+ return _digest;
+ }
+
/**
* Returns an iterator over the names of the user's direct roles
diff --git a/src/mongo/db/catalog/SConscript b/src/mongo/db/catalog/SConscript
index 47c0b0f662e..259ea12ab77 100644
--- a/src/mongo/db/catalog/SConscript
+++ b/src/mongo/db/catalog/SConscript
@@ -34,6 +34,7 @@ env.CppUnitTest(
source = 'collection_test.cpp',
LIBDEPS=[
'catalog_helpers',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/db_raii',
'$BUILD_DIR/mongo/db/namespace_string',
'$BUILD_DIR/mongo/db/repl/repl_coordinator_interface',
@@ -142,6 +143,7 @@ env.CppUnitTest(
LIBDEPS=[
'database',
'index_create',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/concurrency/lock_manager',
'$BUILD_DIR/mongo/db/db_raii',
'$BUILD_DIR/mongo/db/namespace_string',
@@ -224,7 +226,7 @@ env.Library(
'database_holder_mock.cpp',
],
LIBDEPS=[
- 'database_holder',
+ 'database_holder',
'$BUILD_DIR/mongo/base',
],
)
@@ -288,6 +290,7 @@ env.Library(
],
LIBDEPS_PRIVATE=[
'$BUILD_DIR/mongo/db/logical_clock',
+ '$BUILD_DIR/mongo/db/repl/repl_settings',
'$BUILD_DIR/mongo/db/storage/mmap_v1/mmap_v1_options',
'$BUILD_DIR/mongo/db/storage/storage_engine_common',
],
@@ -326,6 +329,7 @@ env.CppUnitTest(
],
LIBDEPS=[
'catalog_helpers',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/db_raii',
'$BUILD_DIR/mongo/db/namespace_string',
'$BUILD_DIR/mongo/db/repl/repl_coordinator_interface',
@@ -343,6 +347,7 @@ env.CppUnitTest(
LIBDEPS=[
'catalog_helpers',
'uuid_catalog',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/db_raii',
'$BUILD_DIR/mongo/db/namespace_string',
'$BUILD_DIR/mongo/db/repl/repl_coordinator_interface',
@@ -360,6 +365,7 @@ env.CppUnitTest(
LIBDEPS=[
'catalog_helpers',
'index_create',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/db_raii',
'$BUILD_DIR/mongo/db/namespace_string',
'$BUILD_DIR/mongo/db/repl/drop_pending_collection_reaper',
@@ -378,6 +384,7 @@ env.CppUnitTest(
],
LIBDEPS=[
'catalog_helpers',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/db_raii',
'$BUILD_DIR/mongo/db/namespace_string',
'$BUILD_DIR/mongo/db/repl/drop_pending_collection_reaper',
diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript
index b95489f622c..ba821f8ed68 100644
--- a/src/mongo/db/commands/SConscript
+++ b/src/mongo/db/commands/SConscript
@@ -36,11 +36,14 @@ env.Library(
'$BUILD_DIR/mongo/db/commands',
],
LIBDEPS_PRIVATE=[
- '$BUILD_DIR/mongo/db/auth/authcore',
+ '$BUILD_DIR/mongo/db/auth/auth',
+ '$BUILD_DIR/mongo/db/auth/authprivilege',
+ '$BUILD_DIR/mongo/db/server_options_core',
'$BUILD_DIR/mongo/db/stats/counters',
'$BUILD_DIR/mongo/transport/message_compressor',
'$BUILD_DIR/mongo/transport/service_executor',
'$BUILD_DIR/mongo/util/net/network',
+ '$BUILD_DIR/mongo/util/net/ssl_manager',
'$BUILD_DIR/mongo/util/processinfo',
'server_status_core',
],
@@ -52,7 +55,7 @@ env.Library(
"write_commands/write_commands_common.cpp",
],
LIBDEPS=[
- '$BUILD_DIR/mongo/db/auth/authcore',
+ '$BUILD_DIR/mongo/db/auth/auth',
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/db/auth/authprivilege',
'$BUILD_DIR/mongo/db/commands',
@@ -86,12 +89,14 @@ env.Library(
"rename_collection_common.cpp",
],
LIBDEPS_PRIVATE=[
- '$BUILD_DIR/mongo/db/auth/authcore',
+ '$BUILD_DIR/mongo/bson/mutable/mutable_bson',
+ '$BUILD_DIR/mongo/db/auth/auth',
'$BUILD_DIR/mongo/db/auth/authprivilege',
'$BUILD_DIR/mongo/db/commands',
'$BUILD_DIR/mongo/db/commands/test_commands_enabled',
'$BUILD_DIR/mongo/db/common',
'$BUILD_DIR/mongo/db/log_process_details',
+ '$BUILD_DIR/mongo/db/mongohasher',
'$BUILD_DIR/mongo/logger/parse_log_component_settings',
],
)
@@ -120,6 +125,7 @@ env.Library(
],
LIBDEPS_PRIVATE=[
'$BUILD_DIR/mongo/db/audit',
+ '$BUILD_DIR/mongo/db/auth/sasl_options',
'$BUILD_DIR/mongo/db/commands',
'$BUILD_DIR/mongo/db/commands/test_commands_enabled',
'$BUILD_DIR/mongo/db/common',
@@ -285,7 +291,8 @@ env.Library(
LIBDEPS_PRIVATE=[
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/client/clientdriver',
- '$BUILD_DIR/mongo/db/auth/authmongod',
+ '$BUILD_DIR/mongo/db/auth/auth',
+ '$BUILD_DIR/mongo/db/auth/authprivilege',
'$BUILD_DIR/mongo/db/background',
'$BUILD_DIR/mongo/db/catalog/catalog_helpers',
'$BUILD_DIR/mongo/db/catalog/catalog_impl',
@@ -319,6 +326,7 @@ env.Library(
'kill_op_cmd_base.cpp'
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authprivilege',
'$BUILD_DIR/mongo/db/audit',
'$BUILD_DIR/mongo/db/commands',
'$BUILD_DIR/mongo/db/auth/authorization_manager_global',
@@ -350,7 +358,9 @@ env.Library(
'$BUILD_DIR/mongo/db/commands',
],
LIBDEPS_PRIVATE=[
- '$BUILD_DIR/mongo/db/auth/authcore',
+ '$BUILD_DIR/mongo/db/auth/auth',
+ '$BUILD_DIR/mongo/db/auth/authprivilege',
+ '$BUILD_DIR/mongo/db/server_options_core',
],
)
@@ -380,6 +390,7 @@ env.CppUnitTest(
"index_filter_commands_test.cpp",
],
LIBDEPS=[
+ "$BUILD_DIR/mongo/db/auth/authmocks",
"$BUILD_DIR/mongo/db/query/query_planner",
"$BUILD_DIR/mongo/db/query/query_test_service_context",
"$BUILD_DIR/mongo/db/serveronly",
@@ -394,6 +405,7 @@ env.CppUnitTest(
"mr_test.cpp",
],
LIBDEPS=[
+ "$BUILD_DIR/mongo/db/auth/authmocks",
"$BUILD_DIR/mongo/db/repl/replmocks",
"$BUILD_DIR/mongo/db/repl/storage_interface_impl",
"$BUILD_DIR/mongo/db/serveronly",
@@ -410,6 +422,7 @@ env.CppUnitTest(
"plan_cache_commands_test.cpp",
],
LIBDEPS=[
+ "$BUILD_DIR/mongo/db/auth/authmocks",
"$BUILD_DIR/mongo/db/query/query_planner",
"$BUILD_DIR/mongo/db/query/query_test_service_context",
"$BUILD_DIR/mongo/db/serveronly",
diff --git a/src/mongo/db/exec/SConscript b/src/mongo/db/exec/SConscript
index c0c075d8cef..a5ffcde4cbb 100644
--- a/src/mongo/db/exec/SConscript
+++ b/src/mongo/db/exec/SConscript
@@ -57,6 +57,7 @@ env.CppUnitTest(
"queued_data_stage_test.cpp",
],
LIBDEPS = [
+ "$BUILD_DIR/mongo/db/auth/authmocks",
"$BUILD_DIR/mongo/db/query_exec",
"$BUILD_DIR/mongo/db/serveronly",
"$BUILD_DIR/mongo/db/service_context_d",
@@ -71,6 +72,7 @@ env.CppUnitTest(
"sort_test.cpp",
],
LIBDEPS = [
+ "$BUILD_DIR/mongo/db/auth/authmocks",
"$BUILD_DIR/mongo/db/query_exec",
"$BUILD_DIR/mongo/db/serveronly",
"$BUILD_DIR/mongo/db/service_context_d",
@@ -87,6 +89,7 @@ env.CppUnitTest(
"projection_exec_test.cpp",
],
LIBDEPS = [
+ "$BUILD_DIR/mongo/db/auth/authmocks",
"$BUILD_DIR/mongo/db/query_exec",
"$BUILD_DIR/mongo/db/query/collation/collator_interface_mock",
"$BUILD_DIR/mongo/db/query/query_test_service_context",
diff --git a/src/mongo/db/free_mon/SConscript b/src/mongo/db/free_mon/SConscript
index ac990e7e8aa..10f73e3f399 100644
--- a/src/mongo/db/free_mon/SConscript
+++ b/src/mongo/db/free_mon/SConscript
@@ -63,7 +63,7 @@ else:
'free_mon',
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/db/commands',
- '$BUILD_DIR/mongo/db/auth/authcore',
+ '$BUILD_DIR/mongo/db/auth/auth',
'$BUILD_DIR/mongo/db/auth/authprivilege',
],
)
@@ -77,6 +77,7 @@ fmEnv.CppUnitTest(
'free_mon_storage_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/repl/replmocks',
'$BUILD_DIR/mongo/db/repl/storage_interface_impl',
'$BUILD_DIR/mongo/db/serveronly',
diff --git a/src/mongo/db/ftdc/SConscript b/src/mongo/db/ftdc/SConscript
index fd84a46cdb3..4822907a540 100644
--- a/src/mongo/db/ftdc/SConscript
+++ b/src/mongo/db/ftdc/SConscript
@@ -69,7 +69,8 @@ env.Library(
'ftdc_server'
],
LIBDEPS_PRIVATE=[
- '$BUILD_DIR/mongo/db/auth/authcore',
+ '$BUILD_DIR/mongo/db/auth/auth',
+ '$BUILD_DIR/mongo/db/auth/authprivilege',
],
)
diff --git a/src/mongo/db/logical_session_cache_test.cpp b/src/mongo/db/logical_session_cache_test.cpp
index 3d1b625aff1..10dcc9d8e4a 100644
--- a/src/mongo/db/logical_session_cache_test.cpp
+++ b/src/mongo/db/logical_session_cache_test.cpp
@@ -28,15 +28,15 @@
#include "mongo/platform/basic.h"
+#include "mongo/db/logical_session_cache_impl.h"
+
+#include "mongo/bson/oid.h"
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/authorization_session_for_test.h"
#include "mongo/db/auth/authz_manager_external_state_mock.h"
#include "mongo/db/auth/authz_session_external_state_mock.h"
-
-#include "mongo/bson/oid.h"
#include "mongo/db/auth/user_name.h"
#include "mongo/db/logical_session_cache.h"
-#include "mongo/db/logical_session_cache_impl.h"
#include "mongo/db/logical_session_id.h"
#include "mongo/db/logical_session_id_helpers.h"
#include "mongo/db/operation_context_noop.h"
@@ -69,11 +69,7 @@ public:
_sessions(std::make_shared<MockSessionsCollectionImpl>()) {}
void setUp() override {
- auto localManagerState = stdx::make_unique<AuthzManagerExternalStateMock>();
- localManagerState.get()->setAuthzVersion(AuthorizationManager::schemaVersion28SCRAM);
- auto uniqueAuthzManager =
- stdx::make_unique<AuthorizationManager>(std::move(localManagerState));
- AuthorizationManager::set(&serviceContext, std::move(uniqueAuthzManager));
+ AuthorizationManager::set(&serviceContext, AuthorizationManager::create());
auto client = serviceContext.makeClient("testClient");
_opCtx = client->makeOperationContext();
diff --git a/src/mongo/db/logical_session_id_test.cpp b/src/mongo/db/logical_session_id_test.cpp
index 6a62b9a972c..3d1d1e0563e 100644
--- a/src/mongo/db/logical_session_id_test.cpp
+++ b/src/mongo/db/logical_session_id_test.cpp
@@ -38,6 +38,7 @@
#include "mongo/db/auth/action_set.h"
#include "mongo/db/auth/action_type.h"
#include "mongo/db/auth/authorization_manager.h"
+#include "mongo/db/auth/authorization_manager_impl.h"
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/auth/authorization_session_for_test.h"
#include "mongo/db/auth/authz_manager_external_state_mock.h"
@@ -76,31 +77,33 @@ public:
session = transportLayer.createSession();
client = serviceContext.makeClient("testClient", session);
RestrictionEnvironment::set(
- session, stdx::make_unique<RestrictionEnvironment>(SockAddr(), SockAddr()));
+ session, std::make_unique<RestrictionEnvironment>(SockAddr(), SockAddr()));
_opCtx = client->makeOperationContext();
- auto localManagerState = stdx::make_unique<AuthzManagerExternalStateMock>();
+ auto localManagerState = std::make_unique<AuthzManagerExternalStateMock>();
managerState = localManagerState.get();
managerState->setAuthzVersion(AuthorizationManager::schemaVersion26Final);
- auto uniqueAuthzManager =
- stdx::make_unique<AuthorizationManager>(std::move(localManagerState));
+ auto uniqueAuthzManager = std::make_unique<AuthorizationManagerImpl>(
+ std::move(localManagerState),
+ AuthorizationManagerImpl::InstallMockForTestingOrAuthImpl{});
authzManager = uniqueAuthzManager.get();
AuthorizationManager::set(&serviceContext, std::move(uniqueAuthzManager));
- auto localSessionState = stdx::make_unique<AuthzSessionExternalStateMock>(authzManager);
+ auto localSessionState = std::make_unique<AuthzSessionExternalStateMock>(authzManager);
sessionState = localSessionState.get();
- auto localauthzSession =
- stdx::make_unique<AuthorizationSessionForTest>(std::move(localSessionState));
+ auto localauthzSession = std::make_unique<AuthorizationSessionForTest>(
+ std::move(localSessionState),
+ AuthorizationSessionImpl::InstallMockForTestingOrAuthImpl{});
authzSession = localauthzSession.get();
AuthorizationSession::set(client.get(), std::move(localauthzSession));
authzManager->setAuthEnabled(true);
auto localServiceLiason =
- stdx::make_unique<MockServiceLiason>(std::make_shared<MockServiceLiasonImpl>());
+ std::make_unique<MockServiceLiason>(std::make_shared<MockServiceLiasonImpl>());
auto localSessionsCollection = stdx::make_unique<MockSessionsCollection>(
std::make_shared<MockSessionsCollectionImpl>());
- auto localLogicalSessionCache = stdx::make_unique<LogicalSessionCacheImpl>(
+ auto localLogicalSessionCache = std::make_unique<LogicalSessionCacheImpl>(
std::move(localServiceLiason), std::move(localSessionsCollection), nullptr);
LogicalSessionCache::set(&serviceContext, std::move(localLogicalSessionCache));
diff --git a/src/mongo/db/ops/SConscript b/src/mongo/db/ops/SConscript
index 1e077f4f4ab..f26866db08b 100644
--- a/src/mongo/db/ops/SConscript
+++ b/src/mongo/db/ops/SConscript
@@ -67,6 +67,7 @@ env.CppUnitTest(
target='write_ops_retryability_test',
source='write_ops_retryability_test.cpp',
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/query_exec',
'$BUILD_DIR/mongo/db/repl/mock_repl_coord_server_fixture',
'$BUILD_DIR/mongo/db/repl/oplog_entry',
diff --git a/src/mongo/db/pipeline/SConscript b/src/mongo/db/pipeline/SConscript
index 02f5c3a0520..ff3eebda9bb 100644
--- a/src/mongo/db/pipeline/SConscript
+++ b/src/mongo/db/pipeline/SConscript
@@ -224,7 +224,7 @@ env.CppUnitTest(
'sequential_document_cache_test.cpp',
],
LIBDEPS=[
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/repl/oplog_entry',
'$BUILD_DIR/mongo/db/repl/replmocks',
'$BUILD_DIR/mongo/db/service_context',
@@ -241,7 +241,7 @@ env.CppUnitTest(
target='document_source_facet_test',
source='document_source_facet_test.cpp',
LIBDEPS=[
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_noop_init',
'$BUILD_DIR/mongo/s/is_mongos',
'pipeline',
@@ -351,7 +351,7 @@ env.CppUnitTest(
target='tee_buffer_test',
source='tee_buffer_test.cpp',
LIBDEPS=[
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_noop_init',
'$BUILD_DIR/mongo/s/is_mongos',
'document_source_mock',
@@ -392,7 +392,7 @@ env.CppUnitTest(
'pipeline_test.cpp',
],
LIBDEPS=[
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/query/collation/collator_interface_mock',
'$BUILD_DIR/mongo/db/repl/replmocks',
'$BUILD_DIR/mongo/db/service_context',
@@ -503,7 +503,7 @@ env.CppUnitTest(
source='resume_token_test.cpp',
LIBDEPS=[
'$BUILD_DIR/mongo/db/service_context_noop_init',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'document_sources_idl',
],
)
diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript
index 3638d5ba00b..37f68acfc2d 100644
--- a/src/mongo/db/query/SConscript
+++ b/src/mongo/db/query/SConscript
@@ -116,6 +116,7 @@ env.CppUnitTest(
],
LIBDEPS=[
"query_test_service_context",
+ "$BUILD_DIR/mongo/db/auth/authmocks",
"$BUILD_DIR/mongo/db/query_exec",
"$BUILD_DIR/mongo/db/serveronly",
"$BUILD_DIR/mongo/db/service_context_d",
@@ -398,6 +399,7 @@ env.CppUnitTest(
],
LIBDEPS=[
"query_planner_test_fixture",
+ "$BUILD_DIR/mongo/db/auth/authmocks",
"$BUILD_DIR/mongo/db/query_exec",
"$BUILD_DIR/mongo/db/serveronly",
"$BUILD_DIR/mongo/db/service_context_d",
diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript
index 01039bcf869..6b752b1d013 100644
--- a/src/mongo/db/repl/SConscript
+++ b/src/mongo/db/repl/SConscript
@@ -15,6 +15,7 @@ env.Library(
LIBDEPS_PRIVATE=[
'dbcheck',
'repl_coordinator_interface',
+ 'repl_settings',
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/db/background',
'$BUILD_DIR/mongo/db/catalog/catalog_helpers',
@@ -52,6 +53,7 @@ env.CppUnitTest(
'oplog_entry',
'replmocks',
'storage_interface_impl',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_d_test_fixture',
'$BUILD_DIR/mongo/rpc/command_status',
],
@@ -63,6 +65,7 @@ env.CppUnitTest(
'oplog_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_d_test_fixture',
'$BUILD_DIR/mongo/unittest/concurrency',
'$BUILD_DIR/mongo/util/concurrency/thread_pool',
@@ -83,6 +86,7 @@ env.CppUnitTest(
'oplog_entry',
'replmocks',
'storage_interface_impl',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_d_test_fixture',
'$BUILD_DIR/mongo/rpc/command_status',
],
@@ -263,6 +267,7 @@ env.CppUnitTest(
'oplog_interface_local',
'replmocks',
'storage_interface_impl',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_d_test_fixture',
],
)
@@ -301,6 +306,7 @@ env.CppUnitTest(
'replication_consistency_markers_impl',
'replmocks',
'storage_interface_impl',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_d_test_fixture',
],
)
@@ -328,6 +334,7 @@ env.CppUnitTest(
'replmocks',
'replication_recovery',
'storage_interface_impl',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_d_test_fixture',
],
)
@@ -356,6 +363,7 @@ env.CppUnitTest(
'replication_process',
'replmocks',
'storage_interface_impl',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_d_test_fixture',
],
)
@@ -383,6 +391,7 @@ env.CppUnitTest(
'drop_pending_collection_reaper',
'replmocks',
'storage_interface_impl',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_d_test_fixture',
],
)
@@ -442,6 +451,7 @@ env.CppUnitTest(
'oplog_interface_local',
'replmocks',
'storage_interface_impl',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_d_test_fixture',
'$BUILD_DIR/mongo/unittest/concurrency',
],
@@ -520,7 +530,7 @@ env.Library(
LIBDEPS=[
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/client/clientdriver',
- '$BUILD_DIR/mongo/db/auth/authcore',
+ '$BUILD_DIR/mongo/db/auth/auth',
'$BUILD_DIR/mongo/db/auth/authorization_manager_global',
'$BUILD_DIR/mongo/util/net/network',
],
@@ -561,6 +571,7 @@ env.CppUnitTest(
'rs_rollback_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'oplog_interface_local',
'rollback_test_fixture',
'rs_rollback',
@@ -598,6 +609,7 @@ env.CppUnitTest(
'rollback_impl',
'rollback_test_fixture',
'$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
],
)
@@ -640,6 +652,7 @@ env.Library(
'oplog_entry',
'oplogreader',
'repl_coordinator_interface',
+ 'repl_settings',
'storage_interface',
],
LIBDEPS_PRIVATE=[
@@ -653,7 +666,8 @@ env.Library(
'idempotency_test_fixture.cpp',
],
LIBDEPS=[
- 'sync_tail_test_fixture'
+ 'sync_tail_test_fixture',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
],
)
@@ -678,6 +692,7 @@ env.CppUnitTest(
'sync_tail_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/dbdirectclient',
'$BUILD_DIR/mongo/db/commands/mongod_fcv',
'idempotency_test_fixture',
@@ -759,8 +774,11 @@ env.CppUnitTest(
LIBDEPS=[
'topology_coordinator',
'replica_set_messages',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_noop_init',
+ '$BUILD_DIR/mongo/executor/network_interface_factory',
+ '$BUILD_DIR/mongo/executor/network_interface_mock',
+ '$BUILD_DIR/mongo/executor/network_interface_thread_pool',
],
)
@@ -816,10 +834,13 @@ env.Library(
'service_context_repl_mock_init',
'topology_coordinator',
'$BUILD_DIR/mongo/db/auth/authorization_manager_global',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/executor/network_interface_mock',
+ '$BUILD_DIR/mongo/executor/network_interface_factory',
+ '$BUILD_DIR/mongo/executor/network_interface_thread_pool',
'$BUILD_DIR/mongo/executor/thread_pool_task_executor',
'$BUILD_DIR/mongo/unittest/unittest',
+
],
)
@@ -842,7 +863,7 @@ env.CppUnitTest(
LIBDEPS=[
'repl_coordinator_impl',
'replmocks',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_noop_init',
],
)
@@ -867,7 +888,7 @@ env.CppUnitTest(
'repl_coordinator_impl',
'replmocks',
'$BUILD_DIR/mongo/db/service_context_noop_init',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/executor/thread_pool_task_executor_test_fixture',
],
)
@@ -882,7 +903,7 @@ env.CppUnitTest(
'replica_set_messages',
'replmocks',
'$BUILD_DIR/mongo/db/service_context_noop_init',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/executor/thread_pool_task_executor_test_fixture',
],
)
@@ -896,7 +917,7 @@ env.CppUnitTest(
'repl_coordinator_impl',
'replica_set_messages',
'replmocks',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_noop_init',
],
)
@@ -912,7 +933,7 @@ env.CppUnitTest(
'replica_set_messages',
'replmocks',
'$BUILD_DIR/mongo/db/service_context_noop_init',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/executor/thread_pool_task_executor_test_fixture',
],
)
@@ -1030,8 +1051,9 @@ env.CppUnitTest('isself_test',
'isself_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/serveronly',
- "$BUILD_DIR/mongo/db/service_context_d",
+ '$BUILD_DIR/mongo/db/service_context_d',
'isself',
],
)
@@ -1044,7 +1066,8 @@ env.Library(
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
- '$BUILD_DIR/mongo/db/auth/authcore',
+ '$BUILD_DIR/mongo/db/auth/auth',
+ '$BUILD_DIR/mongo/db/auth/authprivilege',
'$BUILD_DIR/mongo/db/commands',
'$BUILD_DIR/mongo/db/lasterror',
'$BUILD_DIR/mongo/db/repl/repl_coordinator_interface',
@@ -1167,7 +1190,7 @@ env.CppUnitTest(
source='reporter_test.cpp',
LIBDEPS=[
'reporter',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/executor/thread_pool_task_executor_test_fixture',
'$BUILD_DIR/mongo/db/service_context_noop_init',
'$BUILD_DIR/mongo/unittest/task_executor_proxy',
@@ -1252,7 +1275,7 @@ env.CppUnitTest(
LIBDEPS=[
'collection_cloner',
'base_cloner_test_fixture',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/auth/authorization_manager_global',
'$BUILD_DIR/mongo/db/service_context_noop_init',
'$BUILD_DIR/mongo/unittest/task_executor_proxy',
@@ -1279,7 +1302,7 @@ env.CppUnitTest(
LIBDEPS=[
'database_cloner',
'base_cloner_test_fixture',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/commands/list_collections_filter',
'$BUILD_DIR/mongo/db/service_context_noop_init',
'$BUILD_DIR/mongo/unittest/task_executor_proxy',
@@ -1304,7 +1327,7 @@ env.CppUnitTest(
'databases_cloner',
'oplog_entry',
'replmocks',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_noop_init',
'$BUILD_DIR/mongo/executor/thread_pool_task_executor_test_fixture',
'$BUILD_DIR/mongo/unittest/task_executor_proxy',
@@ -1317,7 +1340,7 @@ env.Library(
'task_runner.cpp',
],
LIBDEPS=[
- '$BUILD_DIR/mongo/db/auth/authcore',
+ '$BUILD_DIR/mongo/db/auth/auth',
'$BUILD_DIR/mongo/util/concurrency/thread_pool',
],
)
@@ -1331,7 +1354,7 @@ env.Library(
'replmocks',
'service_context_repl_mock_init',
'task_runner',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/auth/authorization_manager_global',
'$BUILD_DIR/mongo/db/service_context',
'$BUILD_DIR/mongo/unittest/concurrency',
@@ -1397,7 +1420,7 @@ env.CppUnitTest(
LIBDEPS=[
'multiapplier',
'service_context_repl_mock_init',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/executor/thread_pool_task_executor_test_fixture',
'$BUILD_DIR/mongo/unittest/task_executor_proxy',
],
@@ -1475,7 +1498,7 @@ env.CppUnitTest(
'initial_syncer_test.cpp',
],
LIBDEPS=[
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/commands/feature_compatibility_parsers',
'$BUILD_DIR/mongo/db/query/command_request_response',
'$BUILD_DIR/mongo/executor/thread_pool_task_executor_test_fixture',
@@ -1543,13 +1566,14 @@ env.Library(
LIBDEPS=[
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/client/clientdriver',
- '$BUILD_DIR/mongo/db/auth/authcore',
+ '$BUILD_DIR/mongo/db/auth/auth',
'$BUILD_DIR/mongo/db/auth/saslauth',
'$BUILD_DIR/mongo/db/dbhelpers',
'$BUILD_DIR/mongo/db/query_exec',
'oplog',
'oplogreader',
'repl_coordinator_interface',
+ 'repl_settings',
'replica_set_messages',
],
LIBDEPS_PRIVATE=[
@@ -1567,7 +1591,7 @@ env.Library(
LIBDEPS=[
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/client/clientdriver',
- '$BUILD_DIR/mongo/db/auth/authcore',
+ '$BUILD_DIR/mongo/db/auth/auth',
'$BUILD_DIR/mongo/db/catalog/catalog_helpers',
'$BUILD_DIR/mongo/db/cloner',
'$BUILD_DIR/mongo/db/concurrency/lock_manager',
diff --git a/src/mongo/db/repl/topology_coordinator_v1_test.cpp b/src/mongo/db/repl/topology_coordinator_v1_test.cpp
index 43ee132afa9..1cdff1562fe 100644
--- a/src/mongo/db/repl/topology_coordinator_v1_test.cpp
+++ b/src/mongo/db/repl/topology_coordinator_v1_test.cpp
@@ -74,16 +74,16 @@ public:
virtual void setUp() {
_options = TopologyCoordinator::Options{};
_options.maxSyncSourceLagSecs = Seconds{100};
- _topo.reset(new TopologyCoordinator(_options));
+ _topo = std::make_unique<TopologyCoordinator>(_options);
_now = Date_t();
_selfIndex = -1;
- _cbData.reset(new executor::TaskExecutor::CallbackArgs(
- NULL, executor::TaskExecutor::CallbackHandle(), Status::OK()));
+ _cbData = std::make_unique<executor::TaskExecutor::CallbackArgs>(
+ nullptr, executor::TaskExecutor::CallbackHandle(), Status::OK());
}
virtual void tearDown() {
- _topo.reset(NULL);
- _cbData.reset(NULL);
+ _topo = nullptr;
+ _cbData = nullptr;
}
protected:
diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript
index 0c3d7918cb6..09c4b590cca 100644
--- a/src/mongo/db/s/SConscript
+++ b/src/mongo/db/s/SConscript
@@ -74,6 +74,7 @@ env.CppUnitTest(
],
LIBDEPS=[
'sharding_runtime_d',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/s/config_server_test_fixture',
]
)
@@ -173,6 +174,7 @@ env.CppUnitTest(
'balancer/type_migration_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/s/config_server_test_fixture',
'$BUILD_DIR/mongo/util/version_impl',
'balancer',
@@ -297,6 +299,7 @@ env.CppUnitTest(
],
LIBDEPS=[
'sharding_runtime_d',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/query/query_request',
'$BUILD_DIR/mongo/s/catalog/dist_lock_manager_mock',
'$BUILD_DIR/mongo/s/catalog/sharding_catalog_client_impl',
@@ -315,6 +318,7 @@ env.CppUnitTest(
],
LIBDEPS=[
'$BUILD_DIR/mongo/client/remote_command_targeter_mock',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/repl/replmocks',
'$BUILD_DIR/mongo/db/serveronly',
'$BUILD_DIR/mongo/executor/network_test_env',
@@ -329,6 +333,7 @@ env.CppUnitTest(
'shard_metadata_util_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/s/shard_server_test_fixture',
'sharding',
],
@@ -340,6 +345,7 @@ env.CppUnitTest(
'split_vector_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/dbdirectclient',
'$BUILD_DIR/mongo/s/shard_server_test_fixture',
'sharding',
@@ -352,6 +358,7 @@ env.CppUnitTest(
'session_catalog_migration_source_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/repl/mock_repl_coord_server_fixture',
'sharding',
]
@@ -363,6 +370,7 @@ env.CppUnitTest(
'session_catalog_migration_destination_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/ops/write_ops_exec',
'$BUILD_DIR/mongo/s/catalog/sharding_catalog_client_mock',
'$BUILD_DIR/mongo/s/shard_server_test_fixture',
@@ -389,6 +397,7 @@ env.CppUnitTest(
'config/sharding_catalog_manager_split_chunk_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/s/config_server_test_fixture',
'$BUILD_DIR/mongo/util/version_impl',
]
diff --git a/src/mongo/db/storage/ephemeral_for_test/SConscript b/src/mongo/db/storage/ephemeral_for_test/SConscript
index 13e16746684..0b1c846d3a6 100644
--- a/src/mongo/db/storage/ephemeral_for_test/SConscript
+++ b/src/mongo/db/storage/ephemeral_for_test/SConscript
@@ -79,7 +79,7 @@ env.CppUnitTest(
'storage_ephemeral_for_test_core',
],
LIBDEPS_PRIVATE=[
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/repl/service_context_repl_mock_init',
],
)
diff --git a/src/mongo/db/storage/kv/SConscript b/src/mongo/db/storage/kv/SConscript
index 1735a8c010a..d8e8f7665f7 100644
--- a/src/mongo/db/storage/kv/SConscript
+++ b/src/mongo/db/storage/kv/SConscript
@@ -118,7 +118,7 @@ env.CppUnitTest(
'$BUILD_DIR/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_record_store',
],
LIBDEPS_PRIVATE=[
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init'
+ '$BUILD_DIR/mongo/db/auth/authmocks'
],
)
@@ -136,7 +136,7 @@ env.CppUnitTest(
'$BUILD_DIR/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_record_store',
],
LIBDEPS_PRIVATE=[
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init'
+ '$BUILD_DIR/mongo/db/auth/authmocks'
],
)
@@ -146,6 +146,7 @@ env.CppUnitTest(
'kv_storage_engine_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/catalog/collection_options',
'$BUILD_DIR/mongo/db/namespace_string',
'$BUILD_DIR/mongo/db/repair_database',
diff --git a/src/mongo/db/storage/mmap_v1/SConscript b/src/mongo/db/storage/mmap_v1/SConscript
index c879be79a24..857bcfac99f 100644
--- a/src/mongo/db/storage/mmap_v1/SConscript
+++ b/src/mongo/db/storage/mmap_v1/SConscript
@@ -220,6 +220,7 @@ if mmapv1:
source=['mmap_v1_init_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/serveronly',
'$BUILD_DIR/mongo/db/service_context',
'$BUILD_DIR/mongo/db/service_context_d',
diff --git a/src/mongo/db/storage/mobile/SConscript b/src/mongo/db/storage/mobile/SConscript
index 1f481c23d0a..5ff2276f1c0 100644
--- a/src/mongo/db/storage/mobile/SConscript
+++ b/src/mongo/db/storage/mobile/SConscript
@@ -91,7 +91,7 @@ env.CppUnitTest(
'storage_mobile_core',
],
LIBDEPS_PRIVATE=[
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/repl/service_context_repl_mock_init',
],
)
diff --git a/src/mongo/db/storage/wiredtiger/SConscript b/src/mongo/db/storage/wiredtiger/SConscript
index 142a108aaa7..25b49ee34fe 100644
--- a/src/mongo/db/storage/wiredtiger/SConscript
+++ b/src/mongo/db/storage/wiredtiger/SConscript
@@ -120,6 +120,7 @@ if wiredtiger:
source=['wiredtiger_init_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/serveronly',
'$BUILD_DIR/mongo/db/service_context',
'$BUILD_DIR/mongo/db/service_context_d',
@@ -168,7 +169,7 @@ if wiredtiger:
)
# All of these tests fail to compile under undefined behavior
- # sanitizer due to unexpressed circular dependency edges. In particualr
+ # sanitizer due to unexpressed circular dependency edges. In particular
# they all need a definition from the 'catalog'.
if not using_ubsan:
wtEnv.CppUnitTest(
@@ -217,7 +218,7 @@ if wiredtiger:
'wiredtiger_kv_engine_test.cpp',
],
LIBDEPS=[
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/storage/kv/kv_engine_test_harness',
'storage_wiredtiger_mock',
],
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit_test.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit_test.cpp
index 62b9e188c34..bd910986ad5 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit_test.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit_test.cpp
@@ -27,6 +27,7 @@
*/
#include "mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h"
+
#include "mongo/base/checked_cast.h"
#include "mongo/db/storage/recovery_unit_test_harness.h"
#include "mongo/db/storage/wiredtiger/wiredtiger_kv_engine.h"
@@ -103,7 +104,7 @@ private:
};
std::unique_ptr<HarnessHelper> makeHarnessHelper() {
- return stdx::make_unique<WiredTigerRecoveryUnitHarnessHelper>();
+ return std::make_unique<WiredTigerRecoveryUnitHarnessHelper>();
}
MONGO_INITIALIZER(RegisterHarnessFactory)(InitializerContext* const) {
diff --git a/src/mongo/db/views/SConscript b/src/mongo/db/views/SConscript
index 01e99381b7e..3eed93ef638 100644
--- a/src/mongo/db/views/SConscript
+++ b/src/mongo/db/views/SConscript
@@ -44,7 +44,7 @@ env.CppUnitTest(
],
LIBDEPS=[
'views',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/query/collation/collator_interface_mock',
'$BUILD_DIR/mongo/db/query/query_test_service_context',
'$BUILD_DIR/mongo/db/service_context_noop_init',
diff --git a/src/mongo/dbtests/SConscript b/src/mongo/dbtests/SConscript
index 2bc24a869ad..05515cbca53 100644
--- a/src/mongo/dbtests/SConscript
+++ b/src/mongo/dbtests/SConscript
@@ -118,7 +118,7 @@ dbtest = env.Program(
],
LIBDEPS=[
"$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils",
- "$BUILD_DIR/mongo/db/auth/authmocks",
+ "$BUILD_DIR/mongo/db/auth/authmongod",
"$BUILD_DIR/mongo/db/bson/dotted_path_support",
"$BUILD_DIR/mongo/db/commands/mongod",
"$BUILD_DIR/mongo/db/commands/test_commands_enabled",
diff --git a/src/mongo/executor/SConscript b/src/mongo/executor/SConscript
index 4b75702604e..6a6e061bf12 100644
--- a/src/mongo/executor/SConscript
+++ b/src/mongo/executor/SConscript
@@ -144,6 +144,7 @@ env.Library(target='network_test_env',
source=['network_test_env.cpp',],
LIBDEPS=[
'$BUILD_DIR/mongo/db/commands',
+ '$BUILD_DIR/mongo/db/query/command_request_response',
'network_interface_mock',
'task_executor_interface',
])
@@ -286,7 +287,7 @@ env.CppIntegrationTest(
'$BUILD_DIR/mongo/executor/thread_pool_task_executor',
'$BUILD_DIR/mongo/executor/network_interface_thread_pool',
'$BUILD_DIR/mongo/executor/network_interface_factory',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_noop_init',
'$BUILD_DIR/mongo/rpc/command_status',
'$BUILD_DIR/mongo/util/version_impl',
diff --git a/src/mongo/rpc/SConscript b/src/mongo/rpc/SConscript
index 637c62ffaa7..b588608bdee 100644
--- a/src/mongo/rpc/SConscript
+++ b/src/mongo/rpc/SConscript
@@ -132,13 +132,12 @@ env.Library(
],
)
-env.Clone().InjectModule("enterprise").Library(
+env.Library(
target=[
'metadata',
],
source=[
'metadata.cpp',
- 'metadata/audit_metadata.cpp',
'metadata/config_server_metadata.cpp',
'metadata/egress_metadata_hook_list.cpp',
'metadata/logical_time_metadata.cpp',
@@ -149,6 +148,7 @@ env.Clone().InjectModule("enterprise").Library(
],
LIBDEPS=[
'client_metadata',
+ 'audit_metadata',
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/bson/util/bson_extract',
'$BUILD_DIR/mongo/client/read_preference',
@@ -158,6 +158,23 @@ env.Clone().InjectModule("enterprise").Library(
],
)
+env.Clone().InjectModule("enterprise").Library(
+ target=[
+ 'audit_metadata',
+ ],
+ 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',
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/base',
+ ],
+)
+
env.CppUnitTest(
target=[
'rpc_metadata_test',
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript
index 5f0f3d9e934..c884eef62ef 100644
--- a/src/mongo/s/SConscript
+++ b/src/mongo/s/SConscript
@@ -364,6 +364,7 @@ env.CppUnitTest(
'shard_key_pattern_test.cpp',
],
LIBDEPS=[
+ "$BUILD_DIR/mongo/db/auth/authmocks",
'$BUILD_DIR/mongo/db/s/sharding',
'$BUILD_DIR/mongo/db/serveronly',
'catalog_cache_test_fixture',
diff --git a/src/mongo/s/catalog/SConscript b/src/mongo/s/catalog/SConscript
index e0b1f9b936a..88d3a3eb090 100644
--- a/src/mongo/s/catalog/SConscript
+++ b/src/mongo/s/catalog/SConscript
@@ -126,6 +126,7 @@ env.CppUnitTest(
'replset_dist_lock_manager_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/s/catalog/dist_lock_catalog_mock',
'$BUILD_DIR/mongo/s/catalog/sharding_catalog_client_mock',
'$BUILD_DIR/mongo/s/shard_server_test_fixture',
diff --git a/src/mongo/s/client/SConscript b/src/mongo/s/client/SConscript
index 69a9389e784..a8079187d31 100644
--- a/src/mongo/s/client/SConscript
+++ b/src/mongo/s/client/SConscript
@@ -98,6 +98,7 @@ env.CppUnitTest(
'shard_local_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/repl/replmocks',
'$BUILD_DIR/mongo/db/service_context_d_test_fixture',
'shard_local',
diff --git a/src/mongo/s/commands/SConscript b/src/mongo/s/commands/SConscript
index ca9d7596330..88dc1fbb3ed 100644
--- a/src/mongo/s/commands/SConscript
+++ b/src/mongo/s/commands/SConscript
@@ -95,7 +95,8 @@ env.Library(
env.Idlc('cluster_multicast.idl')[0],
],
LIBDEPS_PRIVATE=[
- '$BUILD_DIR/mongo/db/auth/authmongos',
+ '$BUILD_DIR/mongo/db/auth/auth',
+ '$BUILD_DIR/mongo/db/auth/saslauth',
'$BUILD_DIR/mongo/db/commands/core',
'$BUILD_DIR/mongo/db/commands/current_op_common',
'$BUILD_DIR/mongo/db/commands/servers',
@@ -125,7 +126,7 @@ env.CppUnitTest(
],
LIBDEPS=[
'shared_cluster_commands',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_noop_init',
'$BUILD_DIR/mongo/db/logical_time',
'$BUILD_DIR/mongo/unittest/unittest',
@@ -140,7 +141,7 @@ env.CppUnitTest(
LIBDEPS=[
'shared_cluster_commands',
'$BUILD_DIR/mongo/s/catalog_cache_test_fixture',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_noop_init',
'$BUILD_DIR/mongo/db/logical_clock',
'$BUILD_DIR/mongo/unittest/unittest',
@@ -154,7 +155,8 @@ env.CppUnitTest(
],
LIBDEPS=[
'cluster_commands',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
+ '$BUILD_DIR/mongo/db/auth/saslauth',
'$BUILD_DIR/mongo/db/service_context_noop_init',
'$BUILD_DIR/mongo/s/catalog_cache_test_fixture',
],
diff --git a/src/mongo/s/query/SConscript b/src/mongo/s/query/SConscript
index aa9a1713255..cd9a6c903c4 100644
--- a/src/mongo/s/query/SConscript
+++ b/src/mongo/s/query/SConscript
@@ -29,7 +29,7 @@ env.CppUnitTest(
],
LIBDEPS=[
'cluster_query',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_noop_init',
'$BUILD_DIR/mongo/s/catalog_cache_test_fixture',
],
@@ -76,7 +76,7 @@ env.CppUnitTest(
],
LIBDEPS=[
'router_exec_stage',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_noop_init',
],
)
@@ -115,7 +115,7 @@ env.CppUnitTest(
LIBDEPS=[
'async_results_merger',
'cluster_client_cursor',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/query/query_request',
'$BUILD_DIR/mongo/db/service_context_noop_init',
'$BUILD_DIR/mongo/executor/thread_pool_task_executor_test_fixture',
@@ -130,7 +130,7 @@ env.CppUnitTest(
],
LIBDEPS=[
'async_results_merger',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/query/query_request',
'$BUILD_DIR/mongo/db/service_context_noop_init',
'$BUILD_DIR/mongo/s/sharding_router_test_fixture',
@@ -157,7 +157,7 @@ env.CppUnitTest(
],
LIBDEPS=[
'store_possible_cursor',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/query/query_test_service_context',
'$BUILD_DIR/mongo/db/service_context_noop_init',
'$BUILD_DIR/mongo/util/clock_source_mock',
@@ -171,7 +171,8 @@ env.Library(
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
- '$BUILD_DIR/mongo/db/auth/authcore',
+ '$BUILD_DIR/mongo/db/auth/auth',
+ '$BUILD_DIR/mongo/db/auth/authprivilege',
'$BUILD_DIR/mongo/db/generic_cursor',
'$BUILD_DIR/mongo/db/kill_sessions',
'$BUILD_DIR/mongo/db/logical_session_cache',
@@ -211,7 +212,7 @@ env.CppUnitTest(
],
LIBDEPS=[
'cluster_client_cursor',
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/service_context_noop_init',
],
)
diff --git a/src/mongo/s/server.cpp b/src/mongo/s/server.cpp
index 3c68ef51462..7d8f848921b 100644
--- a/src/mongo/s/server.cpp
+++ b/src/mongo/s/server.cpp
@@ -528,6 +528,7 @@ ExitCode main(ServiceContext* serviceContext) {
return runMongosServer(serviceContext);
}
+namespace {
MONGO_INITIALIZER_GENERAL(ForkServer, ("EndStartupOptionHandling"), ("default"))
(InitializerContext* context) {
forkServerOrDie();
@@ -546,11 +547,6 @@ MONGO_INITIALIZER_WITH_PREREQUISITES(SetFeatureCompatibilityVersion40, ("EndStar
return Status::OK();
}
-MONGO_INITIALIZER(CreateAuthorizationExternalStateFactory)(InitializerContext* context) {
- AuthzManagerExternalState::create = &createAuthzManagerExternalStateMongos;
- return Status::OK();
-}
-
ServiceContextRegistrar serviceContextCreator([]() {
auto service = std::make_unique<ServiceContextNoop>();
service->setTickSource(std::make_unique<SystemTickSource>());
@@ -559,7 +555,6 @@ ServiceContextRegistrar serviceContextCreator([]() {
return service;
});
-
#ifdef MONGO_CONFIG_SSL
MONGO_INITIALIZER_GENERAL(setSSLManagerType, MONGO_NO_PREREQUISITES, ("SSLManager"))
(InitializerContext* context) {
@@ -612,6 +607,7 @@ ExitCode mongoSMain(int argc, char* argv[], char** envp) {
}
}
+} // namespace
} // namespace mongo
#if defined(_WIN32)
diff --git a/src/mongo/s/write_ops/SConscript b/src/mongo/s/write_ops/SConscript
index b9dda858343..fd10368b310 100644
--- a/src/mongo/s/write_ops/SConscript
+++ b/src/mongo/s/write_ops/SConscript
@@ -70,7 +70,7 @@ env.CppUnitTest(
'write_op_test.cpp',
],
LIBDEPS=[
- '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/s/sharding_router_test_fixture',
'cluster_write_op',
]
diff --git a/src/mongo/shell/shell_utils.cpp b/src/mongo/shell/shell_utils.cpp
index 962e4ef2a43..5a9742d3935 100644
--- a/src/mongo/shell/shell_utils.cpp
+++ b/src/mongo/shell/shell_utils.cpp
@@ -1,4 +1,3 @@
-// mongo/shell/shell_utils.cpp
/*
* Copyright 2010 10gen Inc.
*
@@ -443,4 +442,4 @@ bool fileExists(const std::string& file) {
stdx::mutex& mongoProgramOutputMutex(*(new stdx::mutex()));
}
-}
+} // namespace mongo