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 /vespa-athenz | |
parent | ff570e8ff3f6e08f7851289efe292b4aa1acedfc (diff) |
Fetch audit log and pending membership requests for athenz role
Athenz synchronizer accepts tenant name
ZMSClient membership requests can be rejected
Diffstat (limited to 'vespa-athenz')
4 files changed, 198 insertions, 15 deletions
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; + } } } |