Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

extend principal role lookup api with expand option #2232

Merged
merged 1 commit into from
Jul 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions clients/go/zms/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1289,9 +1289,9 @@ func (client ZMSClient) GetDomainRoleMembers(domainName DomainName) (*DomainRole
}
}

func (client ZMSClient) GetPrincipalRoles(principal ResourceName, domainName DomainName) (*DomainRoleMember, error) {
func (client ZMSClient) GetPrincipalRoles(principal ResourceName, domainName DomainName, expand *bool) (*DomainRoleMember, error) {
var data *DomainRoleMember
url := client.URL + "/role" + encodeParams(encodeStringParam("principal", string(principal), ""), encodeStringParam("domain", string(domainName), ""))
url := client.URL + "/role" + encodeParams(encodeStringParam("principal", string(principal), ""), encodeStringParam("domain", string(domainName), ""), encodeOptionalBoolParam("expand", expand))
resp, err := client.httpGet(url, nil)
if err != nil {
return data, err
Expand Down
12 changes: 12 additions & 0 deletions clients/go/zms/model.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion clients/go/zms/zms_schema.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -3063,15 +3063,28 @@ public DomainRoleMembers getDomainRoleMembers(String domainName) {
* @return Member with roles in all requested domains
*/
public DomainRoleMember getPrincipalRoles(String principal, String domainName) {
return getPrincipalRoles(principal, domainName, null);
}

/**
* Fetch all the roles across domains by either calling or specified principal. The expand
* argument specifies to include any group and/or delegated role membership as well.
* @param principal - Requested principal. If null will return roles for the user making the call
* @param domainName - Requested domain. If null will return roles from all domains
* @param expand - Optional. Include all group and delegated role membership as well.
* @return Member with roles in all requested domains
*/
public DomainRoleMember getPrincipalRoles(String principal, String domainName, Boolean expand) {
updatePrincipal();
try {
return client.getPrincipalRoles(principal, domainName);
return client.getPrincipalRoles(principal, domainName, expand);
} catch (ResourceException ex) {
throw new ZMSClientException(ex.getCode(), ex.getData());
} catch (Exception ex) {
throw new ZMSClientException(ResourceException.BAD_REQUEST, ex.getMessage());
}
}

/**
* Set the role system meta parameters
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1128,7 +1128,7 @@ public DomainRoleMembers getDomainRoleMembers(String domainName) throws URISynta
}
}

public DomainRoleMember getPrincipalRoles(String principal, String domainName) throws URISyntaxException, IOException {
public DomainRoleMember getPrincipalRoles(String principal, String domainName, Boolean expand) throws URISyntaxException, IOException {
UriTemplateBuilder uriTemplateBuilder = new UriTemplateBuilder(baseUrl, "/role");
URIBuilder uriBuilder = new URIBuilder(uriTemplateBuilder.getUri());
if (principal != null) {
Expand All @@ -1137,6 +1137,9 @@ public DomainRoleMember getPrincipalRoles(String principal, String domainName) t
if (domainName != null) {
uriBuilder.setParameter("domain", domainName);
}
if (expand != null) {
uriBuilder.setParameter("expand", String.valueOf(expand));
}
HttpUriRequest httpUriRequest = RequestBuilder.get()
.setUri(uriBuilder.build())
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3484,11 +3484,12 @@ public void testGetPrincipalRoles() throws URISyntaxException, IOException {
DomainRoleMember domainRoleMember = new DomainRoleMember();
domainRoleMember.setMemberName("currentPrincipalName");
domainRoleMember.setMemberRoles(memberRoles);
Mockito.when(c.getPrincipalRoles(null, null))
Mockito.when(c.getPrincipalRoles(null, null, null))
.thenReturn(domainRoleMember)
.thenThrow(new ZMSClientException(401, "fail"))
.thenThrow(new IllegalArgumentException("other-error"));


DomainRoleMember retMember = client.getPrincipalRoles(null, null);
assertNotNull(retMember);
assertEquals(retMember.getMemberName(), "currentPrincipalName");
Expand All @@ -3501,6 +3502,14 @@ public void testGetPrincipalRoles() throws URISyntaxException, IOException {
assertEquals(retMember.getMemberRoles().get(2).getDomainName(), "domain2");
assertEquals(retMember.getMemberRoles().get(2).getRoleName(), "role3");

// retry the same operation with expand option enabled

Mockito.when(c.getPrincipalRoles(null, null, Boolean.TRUE))
.thenReturn(domainRoleMember);

retMember = client.getPrincipalRoles(null, null, Boolean.TRUE);
assertNotNull(retMember);

// second time it fails with zms client exception

try {
Expand Down
13 changes: 13 additions & 0 deletions core/zms/src/main/java/com/yahoo/athenz/zms/MemberRole.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ public class MemberRole {
@RdlOptional
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public String pendingState;
@RdlOptional
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public String trustRoleName;

public MemberRole setRoleName(String roleName) {
this.roleName = roleName;
Expand Down Expand Up @@ -121,6 +124,13 @@ public MemberRole setPendingState(String pendingState) {
public String getPendingState() {
return pendingState;
}
public MemberRole setTrustRoleName(String trustRoleName) {
this.trustRoleName = trustRoleName;
return this;
}
public String getTrustRoleName() {
return trustRoleName;
}

@Override
public boolean equals(Object another) {
Expand Down Expand Up @@ -162,6 +172,9 @@ public boolean equals(Object another) {
if (pendingState == null ? a.pendingState != null : !pendingState.equals(a.pendingState)) {
return false;
}
if (trustRoleName == null ? a.trustRoleName != null : !trustRoleName.equals(a.trustRoleName)) {
return false;
}
}
return true;
}
Expand Down
6 changes: 4 additions & 2 deletions core/zms/src/main/java/com/yahoo/athenz/zms/ZMSSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,8 @@ private static Schema build() {
.field("requestPrincipal", "EntityName", true, "pending members only - name of the principal requesting the change")
.field("requestTime", "Timestamp", true, "for pending membership requests, the request time")
.field("systemDisabled", "Int32", true, "user disabled by system based on configured role setting")
.field("pendingState", "String", true, "for pending membership requests, the request state - e.g. add, delete");
.field("pendingState", "String", true, "for pending membership requests, the request state - e.g. add, delete")
.field("trustRoleName", "ResourceName", true, "name of the role that handles the membership delegation for the role specified in roleName");

sb.structType("DomainRoleMember")
.field("memberName", "MemberName", false, "name of the member")
Expand Down Expand Up @@ -1438,10 +1439,11 @@ private static Schema build() {
;

sb.resource("DomainRoleMember", "GET", "/role")
.comment("Fetch all the roles across domains by either calling or specified principal")
.comment("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}\")")
.name("getPrincipalRoles")
.queryParam("principal", "principal", "ResourceName", null, "If not present, will return roles for the user making the call")
.queryParam("domain", "domainName", "DomainName", null, "If not present, will return roles from all domains")
.queryParam("expand", "expand", "Bool", false, "expand to include group and delegated trust role membership")
.auth("", "", true)
.expected("OK")
.exception("BAD_REQUEST", "ResourceError", "")
Expand Down
9 changes: 8 additions & 1 deletion core/zms/src/main/rdl/Role.rdli
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,16 @@ resource DomainRoleMembers GET "/domain/{domainName}/member" {
}

// Fetch all the roles across domains by either calling or specified principal
resource DomainRoleMember GET "/role?principal={principal}&domain={domainName}" (name=getPrincipalRoles) {
// 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}")
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
Bool expand (optional, default=false); //expand to include group and delegated trust role membership
authenticate;
exceptions {
ResourceError BAD_REQUEST;
Expand Down
1 change: 1 addition & 0 deletions core/zms/src/main/rdl/Role.tdl
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ type MemberRole Struct {
Timestamp requestTime (optional); //for pending membership requests, the request time
Int32 systemDisabled (optional); //user disabled by system based on configured role setting
String pendingState (optional); //for pending membership requests, the request state - e.g. add, delete
ResourceName trustRoleName (optional); //name of the role that handles the membership delegation for the role specified in roleName
}

type DomainRoleMember Struct {
Expand Down
161 changes: 161 additions & 0 deletions core/zms/src/test/java/com/yahoo/athenz/zms/MemberRoleTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
* Copyright The Athenz Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.yahoo.athenz.zms;

import com.yahoo.rdl.Timestamp;
import org.testng.annotations.Test;

import static org.testng.Assert.*;

public class MemberRoleTest {

@Test
public void testMemberRole() {

MemberRole mbr1 = new MemberRole();
mbr1.setRoleName("role1");
mbr1.setExpiration(Timestamp.fromMillis(100));
mbr1.setActive(false);
mbr1.setAuditRef("audit-ref");
mbr1.setDomainName("athenz");
mbr1.setMemberName("mbr");
mbr1.setRequestTime(Timestamp.fromMillis(100));
mbr1.setRequestPrincipal("user.admin");
mbr1.setSystemDisabled(1);
mbr1.setReviewReminder(Timestamp.fromMillis(100));
mbr1.setPendingState("ADD");
mbr1.setTrustRoleName("domain:role.trust");

assertEquals("role1", mbr1.getRoleName());
assertEquals(Timestamp.fromMillis(100), mbr1.getExpiration());
assertEquals(Timestamp.fromMillis(100), mbr1.getRequestTime());
assertFalse(mbr1.getActive());
assertEquals(mbr1.getAuditRef(), "audit-ref");
assertEquals(mbr1.getDomainName(), "athenz");
assertEquals(mbr1.getMemberName(), "mbr");
assertEquals(mbr1.getRequestPrincipal(), "user.admin");
assertEquals(mbr1.getSystemDisabled(), Integer.valueOf(1));
assertEquals(Timestamp.fromMillis(100), mbr1.getReviewReminder());
assertEquals(mbr1.getPendingState(), "ADD");
assertEquals(mbr1.getTrustRoleName(), "domain:role.trust");

assertEquals(mbr1, mbr1);
assertNotEquals(null, mbr1);
assertNotEquals("data", mbr1);

MemberRole mbr2 = new MemberRole()
.setRoleName("role1")
.setExpiration(Timestamp.fromMillis(100))
.setActive(false)
.setAuditRef("audit-ref")
.setDomainName("athenz")
.setMemberName("mbr")
.setRequestTime(Timestamp.fromMillis(100))
.setRequestPrincipal("user.admin")
.setSystemDisabled(1)
.setReviewReminder(Timestamp.fromMillis(100))
.setPendingState("ADD")
.setTrustRoleName("domain:role.trust");

assertEquals(mbr1, mbr2);

mbr2.setMemberName("mbr2");
assertNotEquals(mbr1, mbr2);
mbr2.setMemberName(null);
assertNotEquals(mbr1, mbr2);
mbr2.setMemberName("mbr");
assertEquals(mbr1, mbr2);

mbr2.setRoleName("role2");
assertNotEquals(mbr1, mbr2);
mbr2.setRoleName(null);
assertNotEquals(mbr1, mbr2);
mbr2.setRoleName("role1");
assertEquals(mbr1, mbr2);

mbr2.setAuditRef("audit-ref2");
assertNotEquals(mbr1, mbr2);
mbr2.setAuditRef(null);
assertNotEquals(mbr1, mbr2);
mbr2.setAuditRef("audit-ref");
assertEquals(mbr1, mbr2);

mbr2.setDomainName("athenz2");
assertNotEquals(mbr1, mbr2);
mbr2.setDomainName(null);
assertNotEquals(mbr1, mbr2);
mbr2.setDomainName("athenz");
assertEquals(mbr1, mbr2);

mbr2.setExpiration(Timestamp.fromMillis(101));
assertNotEquals(mbr1, mbr2);
mbr2.setExpiration(null);
assertNotEquals(mbr1, mbr2);
mbr2.setExpiration(Timestamp.fromMillis(100));
assertEquals(mbr1, mbr2);

mbr2.setRequestTime(Timestamp.fromMillis(101));
assertNotEquals(mbr1, mbr2);
mbr2.setRequestTime(null);
assertNotEquals(mbr1, mbr2);
mbr2.setRequestTime(Timestamp.fromMillis(100));
assertEquals(mbr1, mbr2);

mbr2.setReviewReminder(Timestamp.fromMillis(101));
assertNotEquals(mbr1, mbr2);
mbr2.setReviewReminder(null);
assertNotEquals(mbr1, mbr2);
mbr2.setReviewReminder(Timestamp.fromMillis(100));
assertEquals(mbr1, mbr2);

mbr2.setRequestPrincipal("athenz2");
assertNotEquals(mbr1, mbr2);
mbr2.setRequestPrincipal(null);
assertNotEquals(mbr1, mbr2);
mbr2.setRequestPrincipal("user.admin");
assertEquals(mbr1, mbr2);

mbr2.setSystemDisabled(2);
assertNotEquals(mbr1, mbr2);
mbr2.setSystemDisabled(null);
assertNotEquals(mbr1, mbr2);
mbr2.setSystemDisabled(1);
assertEquals(mbr1, mbr2);

mbr2.setActive(true);
assertNotEquals(mbr1, mbr2);
mbr2.setActive(null);
assertNotEquals(mbr1, mbr2);
mbr2.setActive(false);
assertEquals(mbr1, mbr2);

mbr2.setPendingState("DELETE");
assertNotEquals(mbr1, mbr2);
mbr2.setPendingState(null);
assertNotEquals(mbr1, mbr2);
mbr2.setPendingState("ADD");
assertEquals(mbr1, mbr2);

mbr2.setTrustRoleName("domain:role.trust2");
assertNotEquals(mbr1, mbr2);
mbr2.setTrustRoleName(null);
assertNotEquals(mbr1, mbr2);
mbr2.setTrustRoleName("domain:role.trust");
assertEquals(mbr1, mbr2);
}

}
Loading