summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
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