Skip to content

Commit

Permalink
provide domain authz for expanded role lookup (#2351)
Browse files Browse the repository at this point in the history
  • Loading branch information
havetisyan authored Oct 15, 2023
1 parent 584fa5f commit 5963140
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 13 deletions.
1 change: 1 addition & 0 deletions core/zms/src/main/rdl/Role.rdli
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ resource DomainRoleMembers GET "/domain/{domainName}/member" {
// 1. authenticated principal is the same as the check principal
// 2. system authorized ("access", "sys.auth:meta.role.lookup")
// 3. service admin ("update", "{principal}")
// 4. domain authorized ("access", "{domainName}:meta.role.lookup") if domainName is provided
resource DomainRoleMember GET "/role?principal={principal}&domain={domainName}&expand={expand}" (name=getPrincipalRoles) {
ResourceName principal (optional); //If not present, will return roles for the user making the call
DomainName domainName (optional); //If not present, will return roles from all domains
Expand Down
19 changes: 17 additions & 2 deletions servers/zms/src/main/java/com/yahoo/athenz/zms/ZMSImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -3661,24 +3661,39 @@ public DomainRoleMember getPrincipalRoles(ResourceContext context, String princi
// if we're asked to expand all groups and delegated roles then
// we're going to carry out an authorization check

if (expand == Boolean.TRUE && !isAllowedExpandedRoleLookup(((RsrcCtxWrapper) context).principal(), principal)) {
if (expand == Boolean.TRUE && !isAllowedExpandedRoleLookup(((RsrcCtxWrapper) context).principal(), principal, domainName)) {
throw ZMSUtils.forbiddenError("principal is not authorized to request expanded role lookup", caller);
}

return dbService.getPrincipalRoles(principal, domainName, expand);
}

boolean isAllowedExpandedRoleLookup(Principal principal, final String checkPrincipal) {
boolean isAllowedExpandedRoleLookup(Principal principal, final String checkPrincipal, final String domainName) {

// Expanded role lookup requires one of these authorization checks
// 1. authenticated principal is the same as the check principal
// 2. system authorized ("access", "sys.auth:meta.role.lookup")
// 3. service admin ("update", "{principal}")
// 4. domain authorized ("access", "{domain}:meta.role.lookup") if domain is provided

if (checkPrincipal.equals(principal.getFullName())) {
return true;
}

// if the domain is provided then we're going to check to see if the principal
// is authorized for role lookup access within the domain

if (!StringUtil.isEmpty(domainName)) {
AthenzDomain requestDomain = getAthenzDomain(domainName, true);
if (requestDomain != null) {
AccessStatus accessStatus = evaluateAccess(requestDomain, principal.getFullName(), "access",
domainName + ":meta.role.lookup", null, null, principal);
if (accessStatus == AccessStatus.ALLOWED) {
return true;
}
}
}

// if the check principal is another user, then this is not allowed
// unless the principal is authorized at system level

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1120,7 +1120,7 @@ public DomainRoleMembers getDomainRoleMembers(
@GET
@Path("/role")
@Produces(MediaType.APPLICATION_JSON)
@Operation(description = "Fetch all the roles across domains by either calling or specified principal The optional expand argument will include all direct and indirect roles, however, it will force authorization that you must be either the principal or for service accounts have update access to the service identity: 1. authenticated principal is the same as the check principal 2. system authorized (\"access\", \"sys.auth:meta.role.lookup\") 3. service admin (\"update\", \"{principal}\")")
@Operation(description = "Fetch all the roles across domains by either calling or specified principal The optional expand argument will include all direct and indirect roles, however, it will force authorization that you must be either the principal or for service accounts have update access to the service identity: 1. authenticated principal is the same as the check principal 2. system authorized (\"access\", \"sys.auth:meta.role.lookup\") 3. service admin (\"update\", \"{principal}\") 4. domain authorized (\"access\", \"{domainName}:meta.role.lookup\") if domainName is provided")
public DomainRoleMember getPrincipalRoles(
@Parameter(description = "If not present, will return roles for the user making the call", required = false) @QueryParam("principal") String principal,
@Parameter(description = "If not present, will return roles from all domains", required = false) @QueryParam("domain") String domainName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -437,21 +437,21 @@ public void testIsAllowedExpandedRoleLookup() {
// without any setup, the principal will only work if the checkPrincipal
// matches the principal

assertTrue(zmsImpl.isAllowedExpandedRoleLookup(principal, "user.john"));
assertFalse(zmsImpl.isAllowedExpandedRoleLookup(principal, "user.jane"));
assertTrue(zmsImpl.isAllowedExpandedRoleLookup(principal, "user.john", null));
assertFalse(zmsImpl.isAllowedExpandedRoleLookup(principal, "user.jane", ""));

// invalid principals should return failure

assertFalse(zmsImpl.isAllowedExpandedRoleLookup(principal, "unknown-domain"));
assertFalse(zmsImpl.isAllowedExpandedRoleLookup(principal, "unknown-domain", null));

// asking for a domain that doesn't exist, must return failure

assertFalse(zmsImpl.isAllowedExpandedRoleLookup(principal, "unknown-domain.service"));
assertFalse(zmsImpl.isAllowedExpandedRoleLookup(principal, "unknown-domain.service", ""));

// let's create the domain and without proper access, it still returns failure

createDomain("domain1");
assertFalse(zmsImpl.isAllowedExpandedRoleLookup(principal, domainName + ".api"));
createDomain(domainName);
assertFalse(zmsImpl.isAllowedExpandedRoleLookup(principal, domainName + ".api", null));

// now let's grant user.john update access over the service

Expand All @@ -467,12 +467,12 @@ public void testIsAllowedExpandedRoleLookup() {

// now our access check should work

assertTrue(zmsImpl.isAllowedExpandedRoleLookup(principal, domainName + ".api"));
assertTrue(zmsImpl.isAllowedExpandedRoleLookup(principal, domainName + ".api", ""));

// delete the policy and verify that it fails again

zmsImpl.deletePolicy(ctx, domainName, "service-policy", auditRef);
assertFalse(zmsImpl.isAllowedExpandedRoleLookup(principal, domainName + ".api"));
assertFalse(zmsImpl.isAllowedExpandedRoleLookup(principal, domainName + ".api", null));

// now let's set up the user as system role lookup user

Expand All @@ -485,9 +485,63 @@ public void testIsAllowedExpandedRoleLookup() {

// now our access check should work

assertTrue(zmsImpl.isAllowedExpandedRoleLookup(principal, domainName + ".api"));
assertTrue(zmsImpl.isAllowedExpandedRoleLookup(principal, domainName + ".api", null));

zmsImpl.deleteTopLevelDomain(ctx,"domain1", auditRef);
// clean up our system domain

zmsImpl.deletePolicy(ctx, "sys.auth", "service-policy", auditRef);
zmsImpl.deleteRole(ctx, "sys.auth", "service-role", auditRef);

zmsImpl.deleteTopLevelDomain(ctx, domainName, auditRef);
}

@Test
public void testIsAllowedExpandedRoleLookupForDomainAdmins() {

final String domainName = "domain1";

Authority principalAuthority = new com.yahoo.athenz.common.server.debug.DebugPrincipalAuthority();
String unsignedCreds = "v=U1;d=user;n=john";
Principal principal = SimplePrincipal.create("user", "john", unsignedCreds + ";s=signature",
0, principalAuthority);
assertNotNull(principal);

ZMSImpl zmsImpl = zmsTestInitializer.getZms();
RsrcCtxWrapper ctx = zmsTestInitializer.getMockDomRsrcCtx();
final String auditRef = zmsTestInitializer.getAuditRef();

// without the domain being present, we should get failure since the
// principal does not match our check principal name

assertFalse(zmsImpl.isAllowedExpandedRoleLookup(principal, "user.jane", domainName));

// let's create the domain and without proper access, it still returns failure

createDomain(domainName);
assertFalse(zmsImpl.isAllowedExpandedRoleLookup(principal, domainName + ".api", domainName));

// now let's grant user.john update access over the domain

List<RoleMember> roleMembers = new ArrayList<>();
roleMembers.add(new RoleMember().setMemberName("user.john"));

Role role = zmsTestInitializer.createRoleObject(domainName, "domain-role", null, roleMembers);
zmsImpl.putRole(ctx, domainName, "domain-role", auditRef, false, role);

Policy policy = zmsTestInitializer.createPolicyObject(domainName, "domain-policy", "domain-role",
"access", domainName + ":meta.role.lookup", AssertionEffect.ALLOW);
zmsImpl.putPolicy(ctx, domainName, "domain-policy", auditRef, false, policy);

// now our access check should work

assertTrue(zmsImpl.isAllowedExpandedRoleLookup(principal, domainName + ".api", domainName));

// delete the policy and verify that it fails again

zmsImpl.deletePolicy(ctx, domainName, "domain-policy", auditRef);
assertFalse(zmsImpl.isAllowedExpandedRoleLookup(principal, domainName + ".api", domainName));

zmsImpl.deleteTopLevelDomain(ctx, domainName, auditRef);
}

@Test
Expand Down

0 comments on commit 5963140

Please sign in to comment.