diff options
author | Ola Aunrønning <olaa@verizonmedia.com> | 2022-03-04 14:27:06 +0100 |
---|---|---|
committer | Ola Aunrønning <olaa@verizonmedia.com> | 2022-03-04 14:27:06 +0100 |
commit | 810de0a30b9dc658769deb21c5579f88afdbd528 (patch) | |
tree | ffc2bbc9667718b9f2cf89a5f833e704be9daa6b | |
parent | ff570e8ff3f6e08f7851289efe292b4aa1acedfc (diff) |
Fetch audit log and pending membership requests for athenz role
Athenz synchronizer accepts tenant name
ZMSClient membership requests can be rejected
11 files changed, 253 insertions, 56 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AccessControlService.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AccessControlService.java index b270c27092f..1dd6eb543ef 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AccessControlService.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AccessControlService.java @@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.controller.api.integration.athenz; import com.yahoo.config.provision.TenantName; +import com.yahoo.vespa.athenz.api.AthenzRoleInformation; import com.yahoo.vespa.athenz.api.AthenzUser; import com.yahoo.vespa.athenz.api.OAuthCredentials; @@ -16,10 +17,9 @@ import java.util.Collection; */ public interface AccessControlService { boolean approveDataPlaneAccess(AthenzUser user, Instant expiry); - boolean approveSshAccess(TenantName tenantName, Instant expiry, OAuthCredentials oAuthCredentials); + boolean decideSshAccess(TenantName tenantName, Instant expiry, OAuthCredentials oAuthCredentials, boolean approve); boolean requestSshAccess(TenantName tenantName); - boolean hasPendingAccessRequests(TenantName tenantName); - boolean hasPreapprovedAccess(TenantName tenantName); + AthenzRoleInformation getAccessRoleInformation(TenantName tenantName); void setPreapprovedAccess(TenantName tenantName, boolean preapproved); Collection<AthenzUser> listMembers(); } diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzAccessControlService.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzAccessControlService.java index 6b91f49af8e..415a087d990 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzAccessControlService.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzAccessControlService.java @@ -7,6 +7,7 @@ import com.yahoo.vespa.athenz.api.AthenzDomain; import com.yahoo.vespa.athenz.api.AthenzGroup; import com.yahoo.vespa.athenz.api.AthenzIdentity; import com.yahoo.vespa.athenz.api.AthenzRole; +import com.yahoo.vespa.athenz.api.AthenzRoleInformation; import com.yahoo.vespa.athenz.api.AthenzUser; import com.yahoo.vespa.athenz.api.OAuthCredentials; import com.yahoo.vespa.athenz.client.zms.ZmsClient; @@ -45,7 +46,7 @@ public class AthenzAccessControlService implements AccessControlService { } Map<AthenzIdentity, String> users = zmsClient.listPendingRoleApprovals(dataPlaneAccessRole); if (users.containsKey(user)) { - zmsClient.approvePendingRoleMembership(dataPlaneAccessRole, user, expiry, Optional.empty(), Optional.empty()); + zmsClient.decidePendingRoleMembership(dataPlaneAccessRole, user, expiry, Optional.empty(), Optional.empty(), true); return true; } return false; @@ -64,19 +65,19 @@ public class AthenzAccessControlService implements AccessControlService { * @return Whether the ssh access role has any pending role membership requests */ @Override - public boolean hasPendingAccessRequests(TenantName tenantName) { + public AthenzRoleInformation getAccessRoleInformation(TenantName tenantName) { var role = sshRole(tenantName); if (!vespaZmsClient.listRoles(role.domain()).contains(role)) - return false; - var pendingApprovals = vespaZmsClient.listPendingRoleApprovals(role); - return pendingApprovals.containsKey(vespaTeam); + vespaZmsClient.createRole(role, Map.of()); + + return vespaZmsClient.getFullRoleInformation(role); } /** * @return true if access has been granted - false if already member */ @Override - public boolean approveSshAccess(TenantName tenantName, Instant expiry, OAuthCredentials oAuthCredentials) { + public boolean decideSshAccess(TenantName tenantName, Instant expiry, OAuthCredentials oAuthCredentials, boolean approve) { var role = sshRole(tenantName); if (!vespaZmsClient.listRoles(role.domain()).contains(role)) @@ -85,11 +86,13 @@ public class AthenzAccessControlService implements AccessControlService { if (vespaZmsClient.getMembership(role, vespaTeam)) return false; - if (!hasPendingAccessRequests(tenantName)) { - vespaZmsClient.addRoleMember(role, vespaTeam, Optional.empty()); - } - vespaZmsClient.approvePendingRoleMembership(role, vespaTeam, expiry, Optional.empty(), Optional.of(oAuthCredentials)); - athenzInstanceSynchronizer.synchronizeInstances(); + var roleInformation = vespaZmsClient.getFullRoleInformation(role); + if (roleInformation.getPendingRequest().isEmpty()) + return false; + var reason = roleInformation.getPendingRequest().get().getReason(); + + vespaZmsClient.decidePendingRoleMembership(role, vespaTeam, expiry, Optional.of(reason), Optional.of(oAuthCredentials), approve); + athenzInstanceSynchronizer.synchronizeInstances(tenantName); return true; } @@ -110,15 +113,6 @@ public class AthenzAccessControlService implements AccessControlService { return true; } - public boolean hasPreapprovedAccess(TenantName tenantName) { - var role = sshRole(tenantName); - - if (!vespaZmsClient.listRoles(role.domain()).contains(role)) - return true; // true by default - - return !vespaZmsClient.isSelfServeRole(role); - } - public void setPreapprovedAccess(TenantName tenantName, boolean preapprovedAccess) { var role = sshRole(tenantName); diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzInstanceSynchronizer.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzInstanceSynchronizer.java index fb2375d3ea2..3b9166d4363 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzInstanceSynchronizer.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzInstanceSynchronizer.java @@ -1,6 +1,8 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.api.integration.athenz; +import com.yahoo.config.provision.TenantName; + /** * @author olaa * @@ -8,6 +10,6 @@ package com.yahoo.vespa.hosted.controller.api.integration.athenz; */ public interface AthenzInstanceSynchronizer { - void synchronizeInstances(); + void synchronizeInstances(TenantName tenant); } diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzInstanceSynchronizerMock.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzInstanceSynchronizerMock.java index 484fb3d6dd2..1f0403a0b44 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzInstanceSynchronizerMock.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzInstanceSynchronizerMock.java @@ -1,10 +1,12 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.api.integration.athenz; +import com.yahoo.config.provision.TenantName; + /** * @author olaa */ public class AthenzInstanceSynchronizerMock implements AthenzInstanceSynchronizer { @Override - public void synchronizeInstances() {} + public void synchronizeInstances(TenantName tenant) {} } diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/MockAccessControlService.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/MockAccessControlService.java index 505ee97bdf5..c14ca2bdc80 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/MockAccessControlService.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/MockAccessControlService.java @@ -3,12 +3,16 @@ package com.yahoo.vespa.hosted.controller.api.integration.athenz; import com.yahoo.config.provision.TenantName; +import com.yahoo.vespa.athenz.api.AthenzDomain; +import com.yahoo.vespa.athenz.api.AthenzRoleInformation; import com.yahoo.vespa.athenz.api.AthenzUser; import com.yahoo.vespa.athenz.api.OAuthCredentials; import java.time.Instant; import java.util.Collection; import java.util.HashSet; +import java.util.List; +import java.util.Optional; import java.util.Set; public class MockAccessControlService implements AccessControlService { @@ -31,7 +35,7 @@ public class MockAccessControlService implements AccessControlService { } @Override - public boolean approveSshAccess(TenantName tenantName, Instant expiry, OAuthCredentials oAuthCredentials) { + public boolean decideSshAccess(TenantName tenantName, Instant expiry, OAuthCredentials oAuthCredentials, boolean approve) { return false; } @@ -41,13 +45,8 @@ public class MockAccessControlService implements AccessControlService { } @Override - public boolean hasPendingAccessRequests(TenantName tenantName) { - return false; - } - - @Override - public boolean hasPreapprovedAccess(TenantName tenantName) { - return false; + public AthenzRoleInformation getAccessRoleInformation(TenantName tenantName) { + return new AthenzRoleInformation(new AthenzDomain("test-domain"), "tenant-role", false, false, Optional.empty(), List.of()); } @Override diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java index 62a999bb7a6..5f567e8b84a 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java @@ -8,6 +8,7 @@ import com.yahoo.vespa.athenz.api.AthenzIdentity; import com.yahoo.vespa.athenz.api.AthenzPolicy; import com.yahoo.vespa.athenz.api.AthenzResourceName; import com.yahoo.vespa.athenz.api.AthenzRole; +import com.yahoo.vespa.athenz.api.AthenzRoleInformation; import com.yahoo.vespa.athenz.api.AthenzService; import com.yahoo.vespa.athenz.api.OAuthCredentials; import com.yahoo.vespa.athenz.client.zms.RoleAction; @@ -201,7 +202,7 @@ public class ZmsClientMock implements ZmsClient { } @Override - public void approvePendingRoleMembership(AthenzRole athenzRole, AthenzIdentity athenzIdentity, Instant expiry, Optional<String> reason, Optional<OAuthCredentials> oAuthCredentials) { + public void decidePendingRoleMembership(AthenzRole athenzRole, AthenzIdentity athenzIdentity, Instant expiry, Optional<String> reason, Optional<OAuthCredentials> oAuthCredentials, boolean approve) { } @Override @@ -256,8 +257,8 @@ public class ZmsClientMock implements ZmsClient { public void createSubdomain(AthenzDomain parent, String name) {} @Override - public boolean isSelfServeRole(AthenzRole role) { - return false; + public AthenzRoleInformation getFullRoleInformation(AthenzRole role) { + return new AthenzRoleInformation(role.domain(), role.roleName(), true, true, Optional.empty(), List.of()); } @Override diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java index 3bcf62fde21..ef851311e63 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java @@ -417,11 +417,26 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { return ErrorResponse.badRequest("Can only see access requests for cloud tenants"); var accessControlService = controller.serviceRegistry().accessControlService(); - var pendingRequests = accessControlService.hasPendingAccessRequests(TenantName.from(tenantName)); - var preapprovedAccess = accessControlService.hasPreapprovedAccess(TenantName.from(tenantName)); + var accessRoleInformation = accessControlService.getAccessRoleInformation(TenantName.from(tenantName)); + var preapprovedAccess = !accessRoleInformation.isSelfServe() && !accessRoleInformation.isReviewEnabled(); var slime = new Slime(); - slime.setObject().setBool("hasPendingRequests", pendingRequests); - slime.setObject().setBool("preapprovedAccess", preapprovedAccess); + var cursor = slime.setObject(); + cursor.setBool("preapprovedAccess", preapprovedAccess); + accessRoleInformation.getPendingRequest() + .ifPresent(membershipRequest -> { + var requestCursor = cursor.setObject("pendingRequest"); + requestCursor.setString("requestTime", membershipRequest.getCreationTime()); + requestCursor.setString("reason", membershipRequest.getReason()); + }); + var auditLogCursor = cursor.setArray("auditLog"); + accessRoleInformation.getAuditLog() + .forEach(auditLogEntry -> { + var entryCursor = auditLogCursor.addObject(); + entryCursor.setString("created", auditLogEntry.getCreationTime()); + entryCursor.setString("approver", auditLogEntry.getApprover()); + entryCursor.setString("reason", auditLogEntry.getReason()); + entryCursor.setString("status", auditLogEntry.getAction()); + }); return new SlimeJsonResponse(slime); } @@ -448,8 +463,9 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { var expiry = inspector.field("expiry").valid() ? Instant.ofEpochMilli(inspector.field("expiry").asLong()) : Instant.now().plus(1, ChronoUnit.DAYS); + var approve = inspector.field("approve").asBool(); - controller.serviceRegistry().accessControlService().approveSshAccess(tenant, expiry, OAuthCredentials.fromAuth0RequestContext(request.getJDiscRequest().context())); + controller.serviceRegistry().accessControlService().decideSshAccess(tenant, expiry, OAuthCredentials.fromAuth0RequestContext(request.getJDiscRequest().context()), approve); return new MessageResponse("OK"); } diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AthenzRoleInformation.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AthenzRoleInformation.java new file mode 100644 index 00000000000..dcc3452a69a --- /dev/null +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AthenzRoleInformation.java @@ -0,0 +1,121 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.athenz.api; + +import com.yahoo.vespa.athenz.client.zms.bindings.RoleEntity; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * @author olaa + */ +public class AthenzRoleInformation extends AthenzRole { + + private final boolean isSelfServe; + private final boolean reviewEnabled; + private final Optional<MembershipRequest> pendingRequest; + private final List<AuditLogEntry> auditLog; + + public AthenzRoleInformation(AthenzDomain domain, String roleName, boolean isSelfServe, boolean reviewEnabled, Optional<MembershipRequest> pendingRequest, List<AuditLogEntry> auditLog) { + super(domain, roleName); + this.isSelfServe = isSelfServe; + this.reviewEnabled = reviewEnabled; + this.pendingRequest = pendingRequest; + this.auditLog = auditLog; + } + + public boolean isSelfServe() { + return isSelfServe; + } + + public boolean isReviewEnabled() { + return reviewEnabled; + } + + public Optional<MembershipRequest> getPendingRequest() { + return pendingRequest; + } + + public List<AuditLogEntry> getAuditLog() { + return auditLog; + } + + public static AthenzRoleInformation fromRoleEntity(RoleEntity roleEntity) { + var role = fromResourceNameString(roleEntity.roleName()); + var isSelfServe = roleEntity.selfServe() != null && roleEntity.selfServe(); + var reviewEnabled = roleEntity.reviewEnabled() != null && roleEntity.reviewEnabled(); + var pendingRequest = roleEntity.roleMembers() + .stream() + .filter(member -> member.pendingApproval()) + .map(member -> new MembershipRequest(member.memberName(), member.auditRef(), member.requestTime(), member.active())) + .findFirst(); + var auditLog = roleEntity.auditLog() + .stream() + .map(entry -> new AuditLogEntry(entry.getAdmin(), entry.getAction(), entry.getAuditRef(), entry.getCreated())) + .collect(Collectors.toList()); + return new AthenzRoleInformation(role.domain(), role.roleName(), isSelfServe, reviewEnabled, pendingRequest, auditLog); + } + + + public static class MembershipRequest { + private final String memberName; + private final String reason; + private final String creationTime; + private final boolean active; + + public MembershipRequest(String memberName, String reason, String creationTime, boolean active) { + this.memberName = memberName; + this.reason = reason; + this.creationTime = creationTime; + this.active = active; + } + + public String getMemberName() { + return memberName; + } + + public String getReason() { + return reason; + } + + public String getCreationTime() { + return creationTime; + } + + public boolean isActive() { + return active; + } + } + + public static class AuditLogEntry { + private final String approver; + private final String action; + private final String reason; + private final String creationTime; + + public AuditLogEntry(String approver, String action, String reason, String creationTime) { + this.approver = approver; + this.action = action; + this.reason = reason; + this.creationTime = creationTime; + } + + public String getApprover() { + return approver; + } + + public String getAction() { + return action; + } + + public String getReason() { + return reason; + } + + public String getCreationTime() { + return creationTime; + } + } + +} diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/DefaultZmsClient.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/DefaultZmsClient.java index 23c530402b9..eef833c91a7 100644 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/DefaultZmsClient.java +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/DefaultZmsClient.java @@ -8,6 +8,7 @@ import com.yahoo.vespa.athenz.api.AthenzIdentity; import com.yahoo.vespa.athenz.api.AthenzPolicy; import com.yahoo.vespa.athenz.api.AthenzResourceName; import com.yahoo.vespa.athenz.api.AthenzRole; +import com.yahoo.vespa.athenz.api.AthenzRoleInformation; import com.yahoo.vespa.athenz.api.AthenzService; import com.yahoo.vespa.athenz.api.OAuthCredentials; import com.yahoo.vespa.athenz.client.ErrorHandler; @@ -301,10 +302,10 @@ public class DefaultZmsClient extends ClientBase implements ZmsClient { } @Override - public void approvePendingRoleMembership(AthenzRole athenzRole, AthenzIdentity athenzIdentity, Instant expiry, - Optional<String> reason, Optional<OAuthCredentials> oAuthCredentials) { + public void decidePendingRoleMembership(AthenzRole athenzRole, AthenzIdentity athenzIdentity, Instant expiry, + Optional<String> reason, Optional<OAuthCredentials> oAuthCredentials, boolean approve) { URI uri = zmsUrl.resolve(String.format("domain/%s/role/%s/member/%s/decision", athenzRole.domain().getName(), athenzRole.roleName(), athenzIdentity.getFullName())); - MembershipEntity membership = new MembershipEntity.RoleMembershipEntity(athenzIdentity.getFullName(), true, athenzRole.roleName(), Long.toString(expiry.getEpochSecond())); + MembershipEntity membership = new MembershipEntity.RoleMembershipEntity(athenzIdentity.getFullName(), approve, athenzRole.roleName(), Long.toString(expiry.getEpochSecond())); var requestBuilder = RequestBuilder.put() .setUri(uri) @@ -406,15 +407,11 @@ public class DefaultZmsClient extends ClientBase implements ZmsClient { execute(request, response -> readEntity(response, Void.class)); } - public boolean isSelfServeRole(AthenzRole role) { - URI uri = zmsUrl.resolve(String.format("domain/%s/role/%s", role.domain().getName(), role.roleName())); + public AthenzRoleInformation getFullRoleInformation(AthenzRole role) { + var uri = zmsUrl.resolve(String.format("domain/%s/role/%s?pending=true&auditLog=true", role.domain().getName(), role.roleName())); var request = RequestBuilder.get(uri).build(); var roleEntity = execute(request, response -> readEntity(response, RoleEntity.class)); - - if (roleEntity.selfServe() == null || roleEntity.reviewEnabled() == null) - return false; - - return roleEntity.selfServe() && roleEntity.reviewEnabled(); + return AthenzRoleInformation.fromRoleEntity(roleEntity); } private static Header createCookieHeader(OAuthCredentials oAuthCredentials) { diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/ZmsClient.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/ZmsClient.java index 611fe7aa451..3ff2ff843a0 100644 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/ZmsClient.java +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/ZmsClient.java @@ -7,6 +7,7 @@ import com.yahoo.vespa.athenz.api.AthenzIdentity; import com.yahoo.vespa.athenz.api.AthenzPolicy; import com.yahoo.vespa.athenz.api.AthenzResourceName; import com.yahoo.vespa.athenz.api.AthenzRole; +import com.yahoo.vespa.athenz.api.AthenzRoleInformation; import com.yahoo.vespa.athenz.api.AthenzService; import com.yahoo.vespa.athenz.api.OAuthCredentials; @@ -59,8 +60,8 @@ public interface ZmsClient extends AutoCloseable { Map<AthenzIdentity, String> listPendingRoleApprovals(AthenzRole athenzRole); - void approvePendingRoleMembership(AthenzRole athenzRole, AthenzIdentity athenzIdentity, Instant expiry, - Optional<String> reason, Optional<OAuthCredentials> oAuthCredentials); + void decidePendingRoleMembership(AthenzRole athenzRole, AthenzIdentity athenzIdentity, Instant expiry, + Optional<String> reason, Optional<OAuthCredentials> oAuthCredentials, boolean approve); List<AthenzIdentity> listMembers(AthenzRole athenzRole); @@ -80,7 +81,7 @@ public interface ZmsClient extends AutoCloseable { void createSubdomain(AthenzDomain parent, String name); - boolean isSelfServeRole(AthenzRole role); + AthenzRoleInformation getFullRoleInformation(AthenzRole role); void close(); } diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/RoleEntity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/RoleEntity.java index f0a498ed644..3ee0c717f19 100644 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/RoleEntity.java +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/RoleEntity.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.ArrayList; import java.util.List; /** @@ -17,16 +18,19 @@ public class RoleEntity { private final List<Member> roleMembers; private final Boolean selfServe; private final Boolean reviewEnabled; + private final List<AuditLogEntry> auditLog; @JsonCreator public RoleEntity(@JsonProperty("roleName") String roleName, @JsonProperty("roleMembers") List<Member> roleMembers, @JsonProperty("selfServe") Boolean selfServe, - @JsonProperty("reviewEnabled") Boolean reviewEnabled) { + @JsonProperty("reviewEnabled") Boolean reviewEnabled, + @JsonProperty("auditLog") List<AuditLogEntry> auditLog) { this.roleName = roleName; this.roleMembers = roleMembers; this.selfServe = selfServe; this.reviewEnabled = reviewEnabled; + this.auditLog = auditLog == null ? new ArrayList<>() : auditLog; } public String roleName() { @@ -45,19 +49,29 @@ public class RoleEntity { return reviewEnabled; } + public List<AuditLogEntry> auditLog() { + return auditLog; + } + @JsonIgnoreProperties(ignoreUnknown = true) public static final class Member { private final String memberName; private final boolean active; private final boolean approved; private final String auditRef; + private final String requestTime; @JsonCreator - public Member(@JsonProperty("memberName") String memberName, @JsonProperty("active") boolean active, @JsonProperty("approved") boolean approved, @JsonProperty("auditRef") String auditRef) { + public Member(@JsonProperty("memberName") String memberName, + @JsonProperty("active") boolean active, + @JsonProperty("approved") boolean approved, + @JsonProperty("auditRef") String auditRef, + @JsonProperty("requestTime") String requestTime) { this.memberName = memberName; this.active = active; this.approved = approved; this.auditRef = auditRef; + this.requestTime = requestTime; } public String memberName() { @@ -71,5 +85,55 @@ public class RoleEntity { public String auditRef() { return auditRef; } + + public String requestTime() { + return requestTime; + } + + public boolean active() { + return active; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class AuditLogEntry { + private final String member; + private final String admin; + private final String action; + private final String auditRef; + private final String created; + + @JsonCreator + public AuditLogEntry(@JsonProperty("member") String member, + @JsonProperty("admin") String admin, + @JsonProperty("created") String created, + @JsonProperty("action") String action, + @JsonProperty("auditRef") String auditRef) { + this.member = member; + this.admin = admin; + this.created = created; + this.action = action; + this.auditRef = auditRef; + } + + public String getMember() { + return member; + } + + public String getAdmin() { + return admin; + } + + public String getAction() { + return action; + } + + public String getAuditRef() { + return auditRef; + } + + public String getCreated() { + return created; + } } } |