Skip to content

Commit 8535211

Browse files
varunravi98MongoDB Bot
authored andcommitted
SERVER-76883 Suppress 'role does not exist' warning log for LDAP group resolution (#28000)
GitOrigin-RevId: 30a3be92da7864d05713e4111500562398947de0
1 parent 101a418 commit 8535211

13 files changed

+619
-176
lines changed

src/mongo/db/auth/SConscript

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,7 @@ env.CppUnitTest(
570570
'builtin_roles_test.cpp',
571571
'oauth_discovery_factory_test.cpp',
572572
'privilege_parser_test.cpp',
573+
'resolve_role_option_test.cpp',
573574
'restriction_test.cpp',
574575
'sasl_authentication_session_test.cpp',
575576
'sasl_mechanism_registry_test.cpp',

src/mongo/db/auth/authorization_manager.h

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "mongo/db/auth/action_set.h"
3737
#include "mongo/db/auth/builtin_roles.h"
3838
#include "mongo/db/auth/privilege_format.h"
39+
#include "mongo/db/auth/resolve_role_option.h"
3940
#include "mongo/db/auth/resource_pattern.h"
4041
#include "mongo/db/auth/user.h"
4142
#include "mongo/db/database_name.h"
@@ -229,38 +230,6 @@ class AuthorizationManager {
229230
*/
230231
virtual Status rolesExist(OperationContext* opCtx, const std::vector<RoleName>& roleNames) = 0;
231232

232-
/**
233-
* Options for what data resolveRoles() should mine from the role tree.
234-
*
235-
* kRoles: Collect RoleNames in the "roles" field in each role document for subordinates.
236-
* kPrivileges: Examine the "privileges" field in each role document and
237-
* merge "actions" for identicate "resource" patterns.
238-
* kRestrictions: Collect the "authenticationRestrictions" field in each role document.
239-
*
240-
* kDirectOnly: If specified, only the RoleNames explicitly supplied to resolveRoles()
241-
* will be examined.
242-
* If not specified, then resolveRoles() will continue examining all
243-
* subordinate roles until the tree has been exhausted.
244-
*
245-
* kAll, kDirectRoles, kDirectPrivileges, kDirectRestrictions, and kDirectAll
246-
* exist as convenience aliases for combinations of the above flags.
247-
*/
248-
enum ResolveRoleOption : std::uint8_t {
249-
250-
kRoles = 0x01,
251-
kPrivileges = 0x02,
252-
kRestrictions = 0x04,
253-
kAll = kRoles | kPrivileges | kRestrictions,
254-
255-
// Only collect from the first pass.
256-
kDirectOnly = 0x10,
257-
258-
kDirectRoles = kRoles | kDirectOnly,
259-
kDirectPrivileges = kPrivileges | kDirectOnly,
260-
kDirectRestrictions = kRestrictions | kDirectOnly,
261-
kDirectAll = kAll | kDirectOnly,
262-
};
263-
264233
/**
265234
* Return type for resolveRoles().
266235
* Each member will be populated ONLY IF their corresponding Option flag was specifed.
@@ -272,6 +241,8 @@ class AuthorizationManager {
272241
boost::optional<RestrictionDocuments> restrictions;
273242
};
274243

244+
using ResolveRoleOption = auth::ResolveRoleOption;
245+
275246
/**
276247
* Delegates method call to the underlying AuthzManagerExternalState.
277248
*/

src/mongo/db/auth/authorization_manager_test.cpp

Lines changed: 132 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
namespace mongo {
6161
namespace {
6262

63+
using ResolveRoleOption = AuthorizationManager::ResolveRoleOption;
64+
6365
#ifdef MONGO_CONFIG_SSL
6466
// Construct a simple, structured X509 name equivalent to "CN=mongodb.com"
6567
SSLX509Name buildX509Name() {
@@ -113,32 +115,32 @@ class AuthorizationManagerTest : public ServiceContextTest {
113115
};
114116

115117
TEST_F(AuthorizationManagerTest, testAcquireV2User) {
116-
ASSERT_OK(externalState->insertPrivilegeDocument(opCtx.get(),
117-
BSON("_id"
118-
<< "admin.v2read"
119-
<< "user"
120-
<< "v2read"
121-
<< "db"
122-
<< "test"
123-
<< "credentials" << credentials << "roles"
124-
<< BSON_ARRAY(BSON("role"
125-
<< "read"
126-
<< "db"
127-
<< "test"))),
128-
BSONObj()));
129-
ASSERT_OK(externalState->insertPrivilegeDocument(opCtx.get(),
130-
BSON("_id"
131-
<< "admin.v2cluster"
132-
<< "user"
133-
<< "v2cluster"
134-
<< "db"
135-
<< "admin"
136-
<< "credentials" << credentials << "roles"
137-
<< BSON_ARRAY(BSON("role"
138-
<< "clusterAdmin"
139-
<< "db"
140-
<< "admin"))),
141-
BSONObj()));
118+
ASSERT_OK(externalState->insertUserDocument(opCtx.get(),
119+
BSON("_id"
120+
<< "admin.v2read"
121+
<< "user"
122+
<< "v2read"
123+
<< "db"
124+
<< "test"
125+
<< "credentials" << credentials << "roles"
126+
<< BSON_ARRAY(BSON("role"
127+
<< "read"
128+
<< "db"
129+
<< "test"))),
130+
BSONObj()));
131+
ASSERT_OK(externalState->insertUserDocument(opCtx.get(),
132+
BSON("_id"
133+
<< "admin.v2cluster"
134+
<< "user"
135+
<< "v2cluster"
136+
<< "db"
137+
<< "admin"
138+
<< "credentials" << credentials << "roles"
139+
<< BSON_ARRAY(BSON("role"
140+
<< "clusterAdmin"
141+
<< "db"
142+
<< "admin"))),
143+
BSONObj()));
142144

143145
auto swu = authzManager->acquireUser(opCtx.get(), {{"v2read", "test"}, boost::none});
144146
ASSERT_OK(swu.getStatus());
@@ -213,29 +215,30 @@ TEST_F(AuthorizationManagerTest, testLocalX509AuthenticationNoAuthorization) {
213215

214216
// Tests SERVER-21535, unrecognized actions should be ignored rather than causing errors.
215217
TEST_F(AuthorizationManagerTest, testAcquireV2UserWithUnrecognizedActions) {
216-
ASSERT_OK(externalState->insertPrivilegeDocument(
217-
opCtx.get(),
218-
BSON("_id"
219-
<< "admin.myUser"
220-
<< "user"
221-
<< "myUser"
222-
<< "db"
223-
<< "test"
224-
<< "credentials" << credentials << "roles"
225-
<< BSON_ARRAY(BSON("role"
226-
<< "myRole"
227-
<< "db"
228-
<< "test"))
229-
<< "inheritedPrivileges"
230-
<< BSON_ARRAY(BSON("resource" << BSON("db"
231-
<< "test"
232-
<< "collection"
233-
<< "")
234-
<< "actions"
235-
<< BSON_ARRAY("find"
236-
<< "fakeAction"
237-
<< "insert")))),
238-
BSONObj()));
218+
ASSERT_OK(
219+
externalState->insertUserDocument(opCtx.get(),
220+
BSON("_id"
221+
<< "admin.myUser"
222+
<< "user"
223+
<< "myUser"
224+
<< "db"
225+
<< "test"
226+
<< "credentials" << credentials << "roles"
227+
<< BSON_ARRAY(BSON("role"
228+
<< "myRole"
229+
<< "db"
230+
<< "test"))
231+
<< "inheritedPrivileges"
232+
<< BSON_ARRAY(BSON("resource"
233+
<< BSON("db"
234+
<< "test"
235+
<< "collection"
236+
<< "")
237+
<< "actions"
238+
<< BSON_ARRAY("find"
239+
<< "fakeAction"
240+
<< "insert")))),
241+
BSONObj()));
239242

240243
auto swu = authzManager->acquireUser(opCtx.get(), {{"myUser", "test"}, boost::none});
241244
ASSERT_OK(swu.getStatus());
@@ -306,7 +309,7 @@ TEST_F(AuthorizationManagerTest, testRefreshExternalV2User) {
306309
<< "test")};
307310

308311
for (const auto& userDoc : userDocs) {
309-
ASSERT_OK(externalState->insertPrivilegeDocument(opCtx.get(), userDoc, BSONObj()));
312+
ASSERT_OK(externalState->insertUserDocument(opCtx.get(), userDoc, BSONObj()));
310313
}
311314

312315
// Acquire these users to force the AuthorizationManager to load these users into the user
@@ -385,5 +388,84 @@ TEST_F(AuthorizationManagerTest, testRefreshExternalV2User) {
385388
}
386389
}
387390

391+
TEST_F(AuthorizationManagerTest, testAuthzManagerExternalStateResolveRoles) {
392+
BSONObj innerCustomRole{BSON("_id"
393+
<< "admin.innerTestRole"
394+
<< "db"
395+
<< "admin"
396+
<< "role"
397+
<< "innerTestRole"
398+
<< "roles"
399+
<< BSON_ARRAY(BSON("db"
400+
<< "test"
401+
<< "role"
402+
<< "read")))};
403+
BSONObj middleCustomRole{BSON("_id"
404+
<< "admin.middleTestRole"
405+
<< "db"
406+
<< "admin"
407+
<< "role"
408+
<< "middleTestRole"
409+
<< "roles" << BSON_ARRAY(innerCustomRole))};
410+
BSONObj outerCustomRole{BSON("_id"
411+
<< "admin.outerTestRole"
412+
<< "db"
413+
<< "admin"
414+
<< "role"
415+
<< "outerTestRole"
416+
<< "roles" << BSON_ARRAY(middleCustomRole) << "privileges"
417+
<< BSON_ARRAY(BSON("resource" << BSON("cluster" << true)
418+
<< "actions"
419+
<< BSON_ARRAY("shutdown")))
420+
<< "authenticationRestrictions"
421+
<< BSON_ARRAY(BSON("clientSource" << BSON_ARRAY("127.0.0.1/8"))))};
422+
std::vector<BSONObj> customRoleDocuments{innerCustomRole, middleCustomRole, outerCustomRole};
423+
424+
for (const auto& roleDoc : customRoleDocuments) {
425+
ASSERT_OK(externalState->insertRoleDocument(opCtx.get(), roleDoc, BSONObj()));
426+
}
427+
428+
// First, resolve all roles (but no privileges or restrictions).
429+
ResolveRoleOption option{ResolveRoleOption::kRoles()};
430+
std::vector<RoleName> roleNames{RoleName{"outerTestRole", "admin"}};
431+
auto swResolvedData = externalState->resolveRoles(opCtx.get(), roleNames, option);
432+
ASSERT_OK(swResolvedData.getStatus());
433+
auto resolvedData = swResolvedData.getValue();
434+
ASSERT_TRUE(resolvedData.roles.has_value());
435+
ASSERT_EQ(resolvedData.roles->size(), 3);
436+
ASSERT_FALSE(resolvedData.privileges.has_value());
437+
ASSERT_FALSE(resolvedData.restrictions.has_value());
438+
439+
// Resolve privileges and roles, no restrictions.
440+
option.setPrivileges(true /* shouldEnable */);
441+
swResolvedData = externalState->resolveRoles(opCtx.get(), roleNames, option);
442+
ASSERT_OK(swResolvedData.getStatus());
443+
resolvedData = swResolvedData.getValue();
444+
ASSERT_TRUE(resolvedData.roles.has_value());
445+
ASSERT_EQ(resolvedData.roles->size(), 3);
446+
ASSERT_TRUE(resolvedData.privileges.has_value());
447+
ASSERT_FALSE(resolvedData.restrictions.has_value());
448+
449+
// Resolve all roles, privileges, and restrictions.
450+
option.setRestrictions(true /* shouldEnable */);
451+
swResolvedData = externalState->resolveRoles(opCtx.get(), roleNames, option);
452+
ASSERT_OK(swResolvedData.getStatus());
453+
resolvedData = swResolvedData.getValue();
454+
ASSERT_TRUE(resolvedData.roles.has_value());
455+
ASSERT_EQ(resolvedData.roles->size(), 3);
456+
ASSERT_TRUE(resolvedData.privileges.has_value());
457+
ASSERT_TRUE(resolvedData.restrictions.has_value());
458+
459+
// Resolve only direct roles, privileges, and restrictions.
460+
option.setDirectOnly(true /* shouldEnable */);
461+
swResolvedData = externalState->resolveRoles(opCtx.get(), roleNames, option);
462+
ASSERT_OK(swResolvedData.getStatus());
463+
resolvedData = swResolvedData.getValue();
464+
ASSERT_TRUE(resolvedData.roles.has_value());
465+
ASSERT_EQ(resolvedData.roles->size(), 1);
466+
ASSERT_TRUE(resolvedData.privileges.has_value());
467+
ASSERT_TRUE(resolvedData.restrictions.has_value());
468+
}
469+
388470
} // namespace
389471
} // namespace mongo

0 commit comments

Comments
 (0)