aboutsummaryrefslogtreecommitdiffstats
path: root/vespa-athenz
diff options
context:
space:
mode:
authorMorten Tokle <mortent@verizonmedia.com>2021-05-10 11:55:15 +0200
committerMorten Tokle <mortent@verizonmedia.com>2021-06-01 14:37:48 +0200
commitd601a1cdb46ae3cce38feb431bcb8e44fe322cc8 (patch)
tree54b94f2bcff82853a3b2c7e2aacd61240240549e /vespa-athenz
parent2f67aed1f678d626ed9694a94041437c37e7d688 (diff)
Api to let operators request approval
Diffstat (limited to 'vespa-athenz')
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/DefaultZmsClient.java38
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/ZmsClient.java6
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/MembershipEntity.java51
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/MembershipResponseEntity.java28
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/RoleEntity.java50
5 files changed, 143 insertions, 30 deletions
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 f9fd1c5e7e9..7450950251c 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
@@ -5,6 +5,7 @@ import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.athenz.api.AthenzIdentity;
import com.yahoo.vespa.athenz.api.AthenzResourceName;
import com.yahoo.vespa.athenz.api.AthenzRole;
+import com.yahoo.vespa.athenz.api.AthenzUser;
import com.yahoo.vespa.athenz.api.OktaAccessToken;
import com.yahoo.vespa.athenz.api.OktaIdentityToken;
import com.yahoo.vespa.athenz.client.ErrorHandler;
@@ -12,23 +13,28 @@ import com.yahoo.vespa.athenz.client.common.ClientBase;
import com.yahoo.vespa.athenz.client.zms.bindings.AccessResponseEntity;
import com.yahoo.vespa.athenz.client.zms.bindings.AssertionEntity;
import com.yahoo.vespa.athenz.client.zms.bindings.DomainListResponseEntity;
-import com.yahoo.vespa.athenz.client.zms.bindings.MembershipResponseEntity;
+import com.yahoo.vespa.athenz.client.zms.bindings.MembershipEntity;
import com.yahoo.vespa.athenz.client.zms.bindings.PolicyEntity;
import com.yahoo.vespa.athenz.client.zms.bindings.ProviderResourceGroupRolesRequestEntity;
+import com.yahoo.vespa.athenz.client.zms.bindings.RoleEntity;
import com.yahoo.vespa.athenz.client.zms.bindings.TenancyRequestEntity;
import com.yahoo.vespa.athenz.identity.ServiceIdentityProvider;
+import com.yahoo.vespa.athenz.utils.AthenzIdentities;
import org.apache.http.Header;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
+import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import javax.net.ssl.SSLContext;
import java.net.URI;
+import java.time.Instant;
import java.util.Collections;
import java.util.List;
import java.util.OptionalInt;
import java.util.Set;
import java.util.function.Supplier;
+import java.util.stream.Collectors;
import static java.util.stream.Collectors.toList;
@@ -123,7 +129,7 @@ public class DefaultZmsClient extends ClientBase implements ZmsClient {
.setUri(uri)
.build();
return execute(request, response -> {
- MembershipResponseEntity membership = readEntity(response, MembershipResponseEntity.class);
+ MembershipEntity membership = readEntity(response, MembershipEntity.class);
return membership.isMember;
});
}
@@ -194,6 +200,34 @@ public class DefaultZmsClient extends ClientBase implements ZmsClient {
return true;
}
+ @Override
+ public List<AthenzUser> listPendingRoleApprovals(AthenzRole athenzRole) {
+ URI uri = zmsUrl.resolve(String.format("domain/%s/role/%s?pending=true", athenzRole.domain().getName(), athenzRole.roleName()));
+ HttpUriRequest request = RequestBuilder.get()
+ .setUri(uri)
+ .build();
+ RoleEntity roleEntity = execute(request, response -> readEntity(response, RoleEntity.class));
+ return roleEntity.roleMembers().stream()
+ .filter(RoleEntity.Member::pendingApproval)
+ .map(RoleEntity.Member::memberName)
+ .map(AthenzIdentities::from)
+ .filter(identity -> AthenzIdentities.USER_PRINCIPAL_DOMAIN.equals(identity.getDomain()))
+ .map(AthenzUser.class::cast)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public void approvePendingRoleMembership(AthenzRole athenzRole, AthenzUser athenzUser, Instant expiry) {
+ URI uri = zmsUrl.resolve(String.format("domain/%s/role/%s/member/%s/decision", athenzRole.domain().getName(), athenzRole.roleName(), athenzUser.getFullName()));
+ // TODO provide the shortest expiry of what is provided and requested (or verify this is done by ZMS)
+ MembershipEntity membership = new MembershipEntity(athenzUser.getFullName(), true, athenzRole.roleName(), null);
+ HttpUriRequest request = RequestBuilder.put()
+ .setUri(uri)
+ .setEntity(toJsonStringEntity(membership))
+ .build();
+ execute(request, response -> readEntity(response, Void.class));
+ }
+
private static Header createCookieHeaderWithOktaTokens(OktaIdentityToken identityToken, OktaAccessToken accessToken) {
return new BasicHeader("Cookie", String.format("okta_at=%s; okta_it=%s", accessToken.token(), identityToken.token()));
}
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 c7f865a58bb..8afa9000ed1 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
@@ -5,9 +5,11 @@ import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.athenz.api.AthenzIdentity;
import com.yahoo.vespa.athenz.api.AthenzResourceName;
import com.yahoo.vespa.athenz.api.AthenzRole;
+import com.yahoo.vespa.athenz.api.AthenzUser;
import com.yahoo.vespa.athenz.api.OktaAccessToken;
import com.yahoo.vespa.athenz.api.OktaIdentityToken;
+import java.time.Instant;
import java.util.List;
import java.util.Set;
@@ -42,5 +44,9 @@ public interface ZmsClient extends AutoCloseable {
boolean deletePolicyRule(AthenzDomain athenzDomain, String athenzPolicy, String action, AthenzResourceName resourceName, AthenzRole athenzRole);
+ List<AthenzUser> listPendingRoleApprovals(AthenzRole athenzRole);
+
+ void approvePendingRoleMembership(AthenzRole athenzRole, AthenzUser athenzUser, Instant expiry);
+
void close();
}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/MembershipEntity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/MembershipEntity.java
new file mode 100644
index 00000000000..b1e7df11638
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/MembershipEntity.java
@@ -0,0 +1,51 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.athenz.client.zms.bindings;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonGetter;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * @author bjorncs
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class MembershipEntity {
+ public final String memberName;
+ public final boolean isMember;
+ public final String roleName;
+ public final String expiration;
+
+ @JsonCreator
+ public MembershipEntity(@JsonProperty("memberName") String memberName,
+ @JsonProperty("isMember") boolean isMember,
+ @JsonProperty("roleName") String roleName,
+ @JsonProperty("expiration") String expiration) {
+ this.memberName = memberName;
+ this.isMember = isMember;
+ this.roleName = roleName;
+ this.expiration = expiration;
+ }
+
+ @JsonGetter("memberName")
+ public String memberName() {
+ return memberName;
+ }
+
+ @JsonGetter("isMember")
+ public boolean isMember() {
+ return isMember;
+ }
+
+ @JsonGetter("roleName")
+ public String roleName() {
+ return roleName;
+ }
+
+ @JsonGetter("expiration")
+ public String expiration() {
+ return expiration;
+ }
+}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/MembershipResponseEntity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/MembershipResponseEntity.java
deleted file mode 100644
index 499afb48f25..00000000000
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/MembershipResponseEntity.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.athenz.client.zms.bindings;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-/**
- * @author bjorncs
- */
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class MembershipResponseEntity {
- public final String memberName;
- public final boolean isMember;
- public final String roleName;
- public final String expiration;
-
- @JsonCreator
- public MembershipResponseEntity(@JsonProperty("memberName") String memberName,
- @JsonProperty("isMember") boolean isMember,
- @JsonProperty("roleName") String roleName,
- @JsonProperty("expiration") String expiration) {
- this.memberName = memberName;
- this.isMember = isMember;
- this.roleName = roleName;
- this.expiration = expiration;
- }
-}
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
new file mode 100644
index 00000000000..e5bcc4d977e
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/RoleEntity.java
@@ -0,0 +1,50 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+package com.yahoo.vespa.athenz.client.zms.bindings;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.List;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class RoleEntity {
+ private final String roleName;
+ private final List<Member> roleMembers;
+
+ @JsonCreator
+ public RoleEntity(@JsonProperty("roleName") String roleName, @JsonProperty("roleMembers") List<Member> roleMembers) {
+ this.roleName = roleName;
+ this.roleMembers = roleMembers;
+ }
+
+ public String roleName() {
+ return roleName;
+ }
+
+ public List<Member> roleMembers() {
+ return roleMembers;
+ }
+
+ public static final class Member {
+ private final String memberName;
+ private final boolean active;
+ private final boolean approved;
+
+ @JsonCreator
+ public Member(@JsonProperty("memberName") String memberName, @JsonProperty("active") boolean active, @JsonProperty("approved") boolean approved) {
+ this.memberName = memberName;
+ this.active = active;
+ this.approved = approved;
+ }
+
+ public String memberName() {
+ return memberName;
+ }
+
+ public boolean pendingApproval() {
+ return !approved;
+ }
+ }
+}