aboutsummaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@verizonmedia.com>2019-10-29 15:02:43 +0100
committerBjørn Christian Seime <bjorncs@verizonmedia.com>2019-10-29 15:52:39 +0100
commitb1dd451e2d24d36fa3932e8208969e9f8b938e11 (patch)
treee5a4485d6b190aa7738c15d0c0cb64d5e8e763f8 /controller-server
parent93b092487fe0ee071b83787f8073bbaeb00e9826 (diff)
Pass Okta identity token to Athenz tenancy operations
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/impl/AthenzFacade.java26
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/AthenzAccessControlRequests.java17
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/AthenzCredentials.java20
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java7
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/AthenzFilterMock.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerControllerTester.java4
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java7
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java107
8 files changed, 115 insertions, 76 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/impl/AthenzFacade.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/impl/AthenzFacade.java
index 304a47044a1..70c504dd220 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/impl/AthenzFacade.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/impl/AthenzFacade.java
@@ -12,6 +12,7 @@ import com.yahoo.vespa.athenz.api.AthenzResourceName;
import com.yahoo.vespa.athenz.api.AthenzRole;
import com.yahoo.vespa.athenz.api.AthenzService;
import com.yahoo.vespa.athenz.api.OktaAccessToken;
+import com.yahoo.vespa.athenz.api.OktaIdentityToken;
import com.yahoo.vespa.athenz.client.zms.RoleAction;
import com.yahoo.vespa.athenz.client.zms.ZmsClient;
import com.yahoo.vespa.athenz.client.zms.ZmsClientException;
@@ -85,7 +86,7 @@ public class AthenzFacade implements AccessControl {
}
else { // Create tenant resources in Athenz if domain is not already taken.
log("createTenancy(tenantDomain=%s, service=%s)", domain, service);
- zmsClient.createTenancy(domain, service, athenzCredentials.token());
+ zmsClient.createTenancy(domain, service, athenzCredentials.identityToken(), athenzCredentials.accessToken());
}
return tenant;
@@ -121,14 +122,14 @@ public class AthenzFacade implements AccessControl {
}
else { // Delete and recreate tenant, and optionally application, resources in Athenz otherwise.
log("createTenancy(tenantDomain=%s, service=%s)", newDomain, service);
- zmsClient.createTenancy(newDomain, service, athenzCredentials.token());
+ zmsClient.createTenancy(newDomain, service, athenzCredentials.identityToken(), athenzCredentials.accessToken());
for (Application application : applications)
- createApplication(newDomain, application.id().application(), athenzCredentials.token());
+ createApplication(newDomain, application.id().application(), athenzCredentials.identityToken(), athenzCredentials.accessToken());
log("deleteTenancy(tenantDomain=%s, service=%s)", oldDomain, service);
for (Application application : applications)
- deleteApplication(oldDomain, application.id().application(), athenzCredentials.token());
- zmsClient.deleteTenancy(oldDomain, service, athenzCredentials.token());
+ deleteApplication(oldDomain, application.id().application(), athenzCredentials.identityToken(), athenzCredentials.accessToken());
+ zmsClient.deleteTenancy(oldDomain, service, athenzCredentials.identityToken(), athenzCredentials.accessToken());
}
return tenant;
@@ -139,22 +140,22 @@ public class AthenzFacade implements AccessControl {
AthenzCredentials athenzCredentials = (AthenzCredentials) credentials;
log("deleteTenancy(tenantDomain=%s, service=%s)", athenzCredentials.domain(), service);
- zmsClient.deleteTenancy(athenzCredentials.domain(), service, athenzCredentials.token());
+ zmsClient.deleteTenancy(athenzCredentials.domain(), service, athenzCredentials.identityToken(), athenzCredentials.accessToken());
}
@Override
public void createApplication(TenantAndApplicationId id, Credentials credentials) {
AthenzCredentials athenzCredentials = (AthenzCredentials) credentials;
- createApplication(athenzCredentials.domain(), id.application(), athenzCredentials.token());
+ createApplication(athenzCredentials.domain(), id.application(), athenzCredentials.identityToken(), athenzCredentials.accessToken());
}
- private void createApplication(AthenzDomain domain, ApplicationName application, OktaAccessToken token) {
+ private void createApplication(AthenzDomain domain, ApplicationName application, OktaIdentityToken identityToken, OktaAccessToken accessToken) {
Set<RoleAction> tenantRoleActions = createTenantRoleActions();
log("createProviderResourceGroup(" +
"tenantDomain=%s, providerDomain=%s, service=%s, resourceGroup=%s, roleActions=%s)",
domain, service.getDomain().getName(), service.getName(), application, tenantRoleActions);
try {
- zmsClient.createProviderResourceGroup(domain, service, application.value(), tenantRoleActions, token);
+ zmsClient.createProviderResourceGroup(domain, service, application.value(), tenantRoleActions, identityToken, accessToken);
}
catch (ZmsClientException e) {
if (e.getErrorCode() == com.yahoo.jdisc.Response.Status.FORBIDDEN)
@@ -169,7 +170,8 @@ public class AthenzFacade implements AccessControl {
AthenzCredentials athenzCredentials = (AthenzCredentials) credentials;
log("deleteProviderResourceGroup(tenantDomain=%s, providerDomain=%s, service=%s, resourceGroup=%s)",
athenzCredentials.domain(), service.getDomain().getName(), service.getName(), id.application());
- zmsClient.deleteProviderResourceGroup(athenzCredentials.domain(), service, id.application().value(), athenzCredentials.token());
+ zmsClient.deleteProviderResourceGroup(athenzCredentials.domain(), service, id.application().value(),
+ athenzCredentials.identityToken(), athenzCredentials.accessToken());
}
@Override
@@ -182,10 +184,10 @@ public class AthenzFacade implements AccessControl {
.collect(Collectors.toUnmodifiableList());
}
- private void deleteApplication(AthenzDomain domain, ApplicationName application, OktaAccessToken token) {
+ private void deleteApplication(AthenzDomain domain, ApplicationName application, OktaIdentityToken identityToken, OktaAccessToken accessToken) {
log("deleteProviderResourceGroup(tenantDomain=%s, providerDomain=%s, service=%s, resourceGroup=%s)",
domain, service.getDomain().getName(), service.getName(), application);
- zmsClient.deleteProviderResourceGroup(domain, service, application.value(), token);
+ zmsClient.deleteProviderResourceGroup(domain, service, application.value(), identityToken, accessToken);
}
public boolean hasApplicationAccess(
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/AthenzAccessControlRequests.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/AthenzAccessControlRequests.java
index e658d65248e..38faab1483d 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/AthenzAccessControlRequests.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/AthenzAccessControlRequests.java
@@ -7,6 +7,7 @@ import com.yahoo.slime.Inspector;
import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.athenz.api.AthenzPrincipal;
import com.yahoo.vespa.athenz.api.OktaAccessToken;
+import com.yahoo.vespa.athenz.api.OktaIdentityToken;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.TenantController;
import com.yahoo.vespa.hosted.controller.api.identifiers.Property;
@@ -16,6 +17,7 @@ import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant;
import java.security.Principal;
import java.util.Objects;
import java.util.Optional;
+import java.util.function.Function;
/**
* Extracts access control data for Athenz or user tenants from HTTP requests.
@@ -44,13 +46,22 @@ public class AthenzAccessControlRequests implements AccessControlRequests {
return new AthenzCredentials(requireAthenzPrincipal(request),
tenants.get(tenant).map(AthenzTenant.class::cast).map(AthenzTenant::domain)
.orElseGet(() -> new AthenzDomain(required("athensDomain", requestObject))),
+ requireOktaIdentityToken(request),
requireOktaAccessToken(request));
}
+ private static OktaIdentityToken requireOktaIdentityToken(HttpRequest request) {
+ return requireToken(request, OktaIdentityToken::new, "okta.identity-token", "No Okta Identity Token provided");
+ }
+
private static OktaAccessToken requireOktaAccessToken(HttpRequest request) {
- return Optional.ofNullable(request.context().get("okta.access-token"))
- .map(attribute -> new OktaAccessToken((String) attribute))
- .orElseThrow(() -> new IllegalArgumentException("No Okta Access Token provided"));
+ return requireToken(request, OktaAccessToken::new, "okta.access-token", "No Okta Access Token provided");
+ }
+
+ private static <T> T requireToken(HttpRequest request, Function<String, T> tokenFactory, String attribute, String errorMessage) {
+ return Optional.ofNullable(request.context().get(attribute))
+ .map(value -> tokenFactory.apply((String) value))
+ .orElseThrow(() -> new IllegalArgumentException(errorMessage));
}
private static String required(String fieldName, Inspector object) {
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/AthenzCredentials.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/AthenzCredentials.java
index c9e3e249668..57c9e037f6a 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/AthenzCredentials.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/AthenzCredentials.java
@@ -3,8 +3,7 @@ package com.yahoo.vespa.hosted.controller.security;
import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.athenz.api.AthenzPrincipal;
import com.yahoo.vespa.athenz.api.OktaAccessToken;
-
-import java.util.Optional;
+import com.yahoo.vespa.athenz.api.OktaIdentityToken;
import static java.util.Objects.requireNonNull;
@@ -18,12 +17,15 @@ import static java.util.Objects.requireNonNull;
public class AthenzCredentials extends Credentials {
private final AthenzDomain domain;
- private final OktaAccessToken token;
+ private final OktaIdentityToken identityToken;
+ private final OktaAccessToken accessToken;
- public AthenzCredentials(AthenzPrincipal user, AthenzDomain domain, OktaAccessToken token) {
+ public AthenzCredentials(AthenzPrincipal user, AthenzDomain domain,
+ OktaIdentityToken identityToken, OktaAccessToken accessToken) {
super(user);
this.domain = requireNonNull(domain);
- this.token = requireNonNull(token);
+ this.accessToken = requireNonNull(accessToken);
+ this.identityToken = requireNonNull(identityToken);
}
@Override
@@ -32,7 +34,11 @@ public class AthenzCredentials extends Credentials {
/** Returns the Athenz domain of the tenant on whose behalf this request is made. */
public AthenzDomain domain() { return domain; }
- /** Returns the token proving access to the requested action under this domain. */
- public OktaAccessToken token() { return token; }
+ /** Returns the Okta access token required for Athenz tenancy operation */
+ public OktaAccessToken accessToken() { return accessToken; }
+
+ /** /** Returns the Okta identity token required for Athenz tenancy operation */
+ public OktaIdentityToken identityToken() { return identityToken; }
+
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java
index 6e204a418ad..a3b2861b387 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java
@@ -13,6 +13,7 @@ import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.athenz.api.AthenzPrincipal;
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.flags.InMemoryFlagSource;
import com.yahoo.vespa.hosted.controller.api.application.v4.model.DeployOptions;
import com.yahoo.vespa.hosted.controller.api.identifiers.Property;
@@ -258,7 +259,8 @@ public final class ControllerTester {
domain,
new Property("Property" + propertyId),
Optional.ofNullable(propertyId).map(Object::toString).map(PropertyId::new));
- AthenzCredentials credentials = new AthenzCredentials(new AthenzPrincipal(user), domain, new OktaAccessToken("okta-token"));
+ AthenzCredentials credentials = new AthenzCredentials(
+ new AthenzPrincipal(user), domain, new OktaIdentityToken("okta-identity-token"), new OktaAccessToken("okta-access-token"));
controller().tenants().create(tenantSpec, credentials);
if (contact.isPresent())
controller().tenants().lockOrThrow(name, LockedTenant.Athenz.class, tenant ->
@@ -279,7 +281,8 @@ public final class ControllerTester {
public Optional<Credentials> credentialsFor(TenantAndApplicationId id) {
return domainOf(id).map(domain -> new AthenzCredentials(new AthenzPrincipal(new AthenzUser("user")),
domain,
- new OktaAccessToken("okta-token")));
+ new OktaIdentityToken("okta-identity-token"),
+ new OktaAccessToken("okta-access-token")));
}
public Application createApplication(TenantName tenant, String applicationName, String instanceName) {
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/AthenzFilterMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/AthenzFilterMock.java
index 8eb64a00d40..6cc6ca012c7 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/AthenzFilterMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/AthenzFilterMock.java
@@ -25,6 +25,7 @@ import java.util.Optional;
public class AthenzFilterMock implements SecurityRequestFilter {
public static final String IDENTITY_HEADER_NAME = "Athenz-Identity";
+ public static final String OKTA_IDENTITY_TOKEN_HEADER_NAME = "Okta-Identity-Token";
public static final String OKTA_ACCESS_TOKEN_HEADER_NAME = "Okta-Access-Token";
private static final ObjectMapper mapper = new ObjectMapper();
@@ -47,6 +48,8 @@ public class AthenzFilterMock implements SecurityRequestFilter {
AthenzPrincipal principal = new AthenzPrincipal(identity);
request.setUserPrincipal(principal);
}
+ Optional.ofNullable(request.getHeader(OKTA_IDENTITY_TOKEN_HEADER_NAME))
+ .ifPresent(header -> request.setAttribute("okta.identity-token", header));
Optional.ofNullable(request.getHeader(OKTA_ACCESS_TOKEN_HEADER_NAME))
.ifPresent(header -> request.setAttribute("okta.access-token", header));
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerControllerTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerControllerTester.java
index 912d285fb52..110aaf2b1a6 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerControllerTester.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerControllerTester.java
@@ -11,6 +11,7 @@ import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.athenz.api.AthenzPrincipal;
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.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.api.application.v4.model.DeployOptions;
@@ -72,7 +73,8 @@ public class ContainerControllerTester {
public Application createApplication(String athensDomain, String tenant, String application, String instance) {
AthenzDomain domain1 = addTenantAthenzDomain(athensDomain, "user");
AthenzPrincipal user = new AthenzPrincipal(new AthenzUser("user"));
- AthenzCredentials credentials = new AthenzCredentials(user, domain1, new OktaAccessToken("okta-token"));
+ AthenzCredentials credentials = new AthenzCredentials(
+ user, domain1, new OktaIdentityToken("okta-identity-token"), new OktaAccessToken("okta-access-token"));
AthenzTenantSpec tenantSpec = new AthenzTenantSpec(TenantName.from(tenant),
domain1,
new Property("property1"),
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java
index f08dc18a58b..fb0e92ab7f4 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java
@@ -9,6 +9,7 @@ import com.yahoo.config.provision.SystemName;
import com.yahoo.vespa.athenz.api.AthenzIdentity;
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.hosted.controller.api.integration.athenz.AthenzClientFactoryMock;
import org.junit.After;
import org.junit.Before;
@@ -18,6 +19,7 @@ import java.nio.charset.CharacterCodingException;
import static com.yahoo.vespa.hosted.controller.integration.AthenzFilterMock.IDENTITY_HEADER_NAME;
import static com.yahoo.vespa.hosted.controller.integration.AthenzFilterMock.OKTA_ACCESS_TOKEN_HEADER_NAME;
+import static com.yahoo.vespa.hosted.controller.integration.AthenzFilterMock.OKTA_IDENTITY_TOKEN_HEADER_NAME;
import static org.junit.Assert.assertEquals;
/**
@@ -154,6 +156,11 @@ public class ControllerContainerTest {
return request;
}
+ protected static Request addOktaIdentityToken(Request request, OktaIdentityToken token) {
+ request.getHeaders().put(OKTA_IDENTITY_TOKEN_HEADER_NAME, token.token());
+ return request;
+ }
+
protected static Request addOktaAccessToken(Request request, OktaAccessToken token) {
request.getHeaders().put(OKTA_ACCESS_TOKEN_HEADER_NAME, token.token());
return request;
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
index eac60b72c6f..f7af8ff4ce4 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
@@ -21,6 +21,7 @@ import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.athenz.api.AthenzIdentity;
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.config.SlimeUtils;
import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.Instance;
@@ -47,7 +48,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.resource.MockTenantCost
import com.yahoo.vespa.hosted.controller.api.integration.resource.ResourceAllocation;
import com.yahoo.vespa.hosted.controller.api.integration.resource.ResourceSnapshot;
import com.yahoo.vespa.hosted.controller.api.integration.routing.RoutingEndpoint;
-import com.yahoo.vespa.hosted.controller.api.integration.routing.RoutingGeneratorMock;
import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockMeteringClient;
import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.application.Change;
@@ -85,7 +85,6 @@ import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
-import java.time.LocalDate;
import java.time.YearMonth;
import java.util.ArrayList;
import java.util.Base64;
@@ -151,7 +150,8 @@ public class ApplicationApiTest extends ControllerContainerTest {
private static final UserId USER_ID = new UserId("myuser");
private static final UserId OTHER_USER_ID = new UserId("otheruser");
private static final UserId HOSTED_VESPA_OPERATOR = new UserId("johnoperator");
- private static final OktaAccessToken OKTA_AT = new OktaAccessToken("dummy");
+ private static final OktaIdentityToken OKTA_IT = new OktaIdentityToken("okta-it");
+ private static final OktaAccessToken OKTA_AT = new OktaAccessToken("okta-at");
private static final ZoneId TEST_ZONE = ZoneId.from(Environment.test, RegionName.from("us-east-1"));
private static final ZoneId STAGING_ZONE = ZoneId.from(Environment.staging, RegionName.from("us-east-3"));
@@ -179,12 +179,12 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/tenant1", POST)
.userIdentity(USER_ID)
.data("{\"athensDomain\":\"domain1\", \"property\":\"property1\"}")
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
new File("tenant-without-applications.json"));
// PUT (modify) a tenant
tester.assertResponse(request("/application/v4/tenant/tenant1", PUT)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT)
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT)
.data("{\"athensDomain\":\"domain1\", \"property\":\"property1\"}"),
new File("tenant-without-applications.json"));
// GET the authenticated user (with associated tenants)
@@ -204,11 +204,11 @@ public class ApplicationApiTest extends ControllerContainerTest {
new File("tenant-list.json"));
// GET list of months for a tenant
- tester.assertResponse(request("/application/v4/tenant/tenant1/cost", GET).userIdentity(USER_ID).oktaAccessToken(OKTA_AT),
+ tester.assertResponse(request("/application/v4/tenant/tenant1/cost", GET).userIdentity(USER_ID).oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"months\":[]}");
// GET cost for a month for a tenant
- tester.assertResponse(request("/application/v4/tenant/tenant1/cost/2018-01", GET).userIdentity(USER_ID).oktaAccessToken(OKTA_AT),
+ tester.assertResponse(request("/application/v4/tenant/tenant1/cost/2018-01", GET).userIdentity(USER_ID).oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"month\":\"2018-01\",\"items\":[]}");
// Add another Athens domain, so we can try to create more tenants
@@ -219,13 +219,13 @@ public class ApplicationApiTest extends ControllerContainerTest {
// POST (add) a tenant with property ID
tester.assertResponse(request("/application/v4/tenant/tenant2", POST)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT)
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT)
.data("{\"athensDomain\":\"domain2\", \"property\":\"property2\", \"propertyId\":\"1234\"}"),
new File("tenant-without-applications-with-id.json"));
// PUT (modify) a tenant with property ID
tester.assertResponse(request("/application/v4/tenant/tenant2", PUT)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT)
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT)
.data("{\"athensDomain\":\"domain2\", \"property\":\"property2\", \"propertyId\":\"1234\"}"),
new File("tenant-without-applications-with-id.json"));
// GET a tenant with property ID and contact information
@@ -236,7 +236,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
// POST (create) an application
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1", POST)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
new File("instance-reference.json"));
// GET a tenant
tester.assertResponse(request("/application/v4/tenant/tenant1", GET).userIdentity(USER_ID),
@@ -345,7 +345,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/tenant2/application/application2/instance/default", POST)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
new File("instance-reference-2.json"));
ApplicationId app2 = ApplicationId.from("tenant2", "application2", "default");
@@ -416,7 +416,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
// DELETE application
tester.assertResponse(request("/application/v4/tenant/tenant2/application/application2", DELETE)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"message\":\"Deleted application tenant2.application2\"}");
// Set version 6.1 to broken to change compile version for.
@@ -577,7 +577,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
// DELETE application with active deployments fails
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1", DELETE)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
new File("delete-with-active-deployments.json"), 400);
// DELETE (deactivate) a deployment - dev
@@ -792,24 +792,24 @@ public class ApplicationApiTest extends ControllerContainerTest {
// DELETE all instances under an application to delete the application
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/default", DELETE)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"message\":\"Deleted instance tenant1.application1.default\"}");
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/my-user", DELETE)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"message\":\"Deleted instance tenant1.application1.my-user\"}");
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1", DELETE)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"message\":\"Deleted instance tenant1.application1.instance1\"}");
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/otheruser", DELETE)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"message\":\"Deleted instance tenant1.application1.otheruser\"}");
// DELETE a tenant
tester.assertResponse(request("/application/v4/tenant/tenant1", DELETE).userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
new File("tenant-without-applications.json"));
}
@@ -960,13 +960,13 @@ public class ApplicationApiTest extends ControllerContainerTest {
// Create tenant
tester.assertResponse(request("/application/v4/tenant/tenant1", POST).userIdentity(USER_ID)
.data("{\"athensDomain\":\"domain1\", \"property\":\"property1\"}")
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
new File("tenant-without-applications.json"));
// Create application
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1", POST)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
new File("instance-reference.json"));
// Grant deploy access
@@ -1081,7 +1081,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/doesnotexist/application/doesnotexist/metering", GET)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
new File("instance1-metering.json"));
}
@@ -1099,7 +1099,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/" + applicationId.tenant().value() + "/cost", GET)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"months\":[\"2019-09\",\"2019-10\"]}");
CostInfo costInfo1 = new CostInfo(applicationId, ZoneId.from("prod", "us-south-1"),
@@ -1119,7 +1119,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/" + applicationId.tenant().value() + "/cost/2019-09", GET)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
new File("cost-report.json"));
}
@@ -1131,7 +1131,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
// PUT (update) non-existing tenant returns 403 as tenant access cannot be determined when the tenant does not exist
tester.assertResponse(request("/application/v4/tenant/tenant1", PUT)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT)
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT)
.data("{\"athensDomain\":\"domain1\", \"property\":\"property1\"}"),
"{\n \"code\" : 403,\n \"message\" : \"Access denied\"\n}",
403);
@@ -1158,21 +1158,21 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/tenant1", POST)
.userIdentity(USER_ID)
.data("{\"athensDomain\":\"domain1\", \"property\":\"property1\"}")
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
new File("tenant-without-applications.json"));
// POST (add) another tenant under the same domain
tester.assertResponse(request("/application/v4/tenant/tenant2", POST)
.userIdentity(USER_ID)
.data("{\"athensDomain\":\"domain1\", \"property\":\"property1\"}")
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"error-code\":\"BAD_REQUEST\",\"message\":\"Could not create tenant 'tenant2': The Athens domain 'domain1' is already connected to tenant 'tenant1'\"}",
400);
// Add the same tenant again
tester.assertResponse(request("/application/v4/tenant/tenant1", POST)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT)
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT)
.data("{\"athensDomain\":\"domain1\", \"property\":\"property1\"}"),
"{\"error-code\":\"BAD_REQUEST\",\"message\":\"Tenant 'tenant1' already exists\"}",
400);
@@ -1181,7 +1181,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/my_tenant_2", POST)
.userIdentity(USER_ID)
.data("{\"athensDomain\":\"domain1\", \"property\":\"property1\"}")
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"error-code\":\"BAD_REQUEST\",\"message\":\"New tenant or application names must start with a letter, may contain no more than 20 characters, and may only contain lowercase letters, digits or dashes, but no double-dashes.\"}",
400);
@@ -1189,7 +1189,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/by-tenant2", POST)
.userIdentity(USER_ID)
.data("{\"athensDomain\":\"domain1\", \"property\":\"property1\"}")
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"error-code\":\"BAD_REQUEST\",\"message\":\"Athenz tenant name cannot have prefix 'by-'\"}",
400);
@@ -1197,19 +1197,19 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/hosted-vespa", POST)
.userIdentity(USER_ID)
.data("{\"athensDomain\":\"domain1\", \"property\":\"property1\"}")
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"error-code\":\"BAD_REQUEST\",\"message\":\"Tenant 'hosted-vespa' already exists\"}",
400);
// POST (create) an (empty) application
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1", POST)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
new File("instance-reference.json"));
// Create the same application again
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1", POST)
- .oktaAccessToken(OKTA_AT)
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT)
.userIdentity(USER_ID),
"{\"error-code\":\"BAD_REQUEST\",\"message\":\"Could not create 'tenant1.application1.instance1': Instance already exists\"}",
400);
@@ -1263,37 +1263,37 @@ public class ApplicationApiTest extends ControllerContainerTest {
// DELETE tenant which has an application
tester.assertResponse(request("/application/v4/tenant/tenant1", DELETE)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"error-code\":\"BAD_REQUEST\",\"message\":\"Could not delete tenant 'tenant1': This tenant has active applications\"}",
400);
// DELETE application
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1", DELETE)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"message\":\"Deleted instance tenant1.application1.instance1\"}");
// DELETE application again - should produce 404
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1", DELETE)
- .oktaAccessToken(OKTA_AT)
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT)
.userIdentity(USER_ID),
"{\"error-code\":\"NOT_FOUND\",\"message\":\"Could not delete instance 'tenant1.application1.instance1': Instance not found\"}",
404);
// GET cost of unknown tenant
- tester.assertResponse(request("/application/v4/tenant/no-such-tenant/cost", GET).userIdentity(USER_ID).oktaAccessToken(OKTA_AT),
+ tester.assertResponse(request("/application/v4/tenant/no-such-tenant/cost", GET).userIdentity(USER_ID).oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"error-code\":\"NOT_FOUND\",\"message\":\"Tenant 'no-such-tenant' does not exist\"}", 404);
- tester.assertResponse(request("/application/v4/tenant/no-such-tenant/cost/2018-01-01", GET).userIdentity(USER_ID).oktaAccessToken(OKTA_AT),
+ tester.assertResponse(request("/application/v4/tenant/no-such-tenant/cost/2018-01-01", GET).userIdentity(USER_ID).oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"error-code\":\"NOT_FOUND\",\"message\":\"Tenant 'no-such-tenant' does not exist\"}", 404);
// GET cost with invalid date string
- tester.assertResponse(request("/application/v4/tenant/tenant1/cost/not-a-valid-date", GET).userIdentity(USER_ID).oktaAccessToken(OKTA_AT),
+ tester.assertResponse(request("/application/v4/tenant/tenant1/cost/not-a-valid-date", GET).userIdentity(USER_ID).oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"error-code\":\"BAD_REQUEST\",\"message\":\"Could not parse year-month 'not-a-valid-date'\"}", 400);
// DELETE tenant
tester.assertResponse(request("/application/v4/tenant/tenant1", DELETE)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
new File("tenant-without-applications.json"));
// DELETE tenant again returns 403 as tenant access cannot be determined when the tenant does not exist
tester.assertResponse(request("/application/v4/tenant/tenant1", DELETE)
@@ -1308,7 +1308,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/my-tenant", POST)
.userIdentity(USER_ID)
.data("{\"athensDomain\":\"domain1\", \"property\":\"property1\"}")
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"error-code\":\"BAD_REQUEST\",\"message\":\"Tenant 'my-tenant' already exists\"}",
400);
}
@@ -1336,7 +1336,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
// Creating a tenant for an Athens domain the user is not admin for is disallowed
tester.assertResponse(request("/application/v4/tenant/tenant1", POST)
.data("{\"athensDomain\":\"domain1\", \"property\":\"property1\"}")
- .oktaAccessToken(OKTA_AT)
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT)
.userIdentity(unauthorizedUser),
"{\"error-code\":\"FORBIDDEN\",\"message\":\"The user 'user.othertenant' is not admin in Athenz domain 'domain1'\"}",
403);
@@ -1345,21 +1345,21 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/tenant1", POST)
.data("{\"athensDomain\":\"domain1\", \"property\":\"property1\"}")
.userIdentity(authorizedUser)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
new File("tenant-without-applications.json"),
200);
// Creating an application for an Athens domain the user is not admin for is disallowed
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1", POST)
.userIdentity(unauthorizedUser)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\n \"code\" : 403,\n \"message\" : \"Access denied\"\n}",
403);
// (Create it with the right tenant id)
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1", POST)
.userIdentity(authorizedUser)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
new File("instance-reference.json"),
200);
@@ -1380,28 +1380,28 @@ public class ApplicationApiTest extends ControllerContainerTest {
// Create another instance under the application
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/default", POST)
.userIdentity(authorizedUser)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
new File("instance-reference-default.json"),
200);
// Deleting the application when more than one instance is present is forbidden
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1", DELETE)
.userIdentity(authorizedUser)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"error-code\":\"BAD_REQUEST\",\"message\":\"Could not delete application; more than one instance present: [tenant1.application1, tenant1.application1.instance1]\"}",
400);
// Deleting one instance is OK
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/default", DELETE)
.userIdentity(authorizedUser)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"message\":\"Deleted instance tenant1.application1.default\"}",
200);
// (Deleting the application with the right tenant id)
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1", DELETE)
.userIdentity(authorizedUser)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"message\":\"Deleted application tenant1.application1\"}",
200);
@@ -1417,7 +1417,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/tenant1", PUT)
.data("{\"athensDomain\":\"domain2\", \"property\":\"property1\"}")
.userIdentity(authorizedUser)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
"{\"tenant\":\"tenant1\",\"type\":\"ATHENS\",\"athensDomain\":\"domain2\",\"property\":\"property1\",\"applications\":[]}",
200);
@@ -1851,11 +1851,11 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/tenant1", POST)
.userIdentity(USER_ID)
.data("{\"athensDomain\":\"domain1\", \"property\":\"property1\"}")
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
new File("tenant-without-applications.json"));
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1", POST)
.userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT),
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
new File("instance-reference.json"));
addScrewdriverUserToDeployRole(SCREWDRIVER_ID, ATHENZ_TENANT_DOMAIN,
new com.yahoo.vespa.hosted.controller.api.identifiers.ApplicationId("application1"));
@@ -1976,6 +1976,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
private final Request.Method method;
private byte[] data = new byte[0];
private AthenzIdentity identity;
+ private OktaIdentityToken oktaIdentityToken;
private OktaAccessToken oktaAccessToken;
private String contentType = "application/json";
private Map<String, List<String>> headers = new HashMap<>();
@@ -1994,6 +1995,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
private RequestBuilder userIdentity(UserId userId) { this.identity = HostedAthenzIdentities.from(userId); return this; }
private RequestBuilder screwdriverIdentity(ScrewdriverId screwdriverId) { this.identity = HostedAthenzIdentities.from(screwdriverId); return this; }
+ private RequestBuilder oktaIdentityToken(OktaIdentityToken oktaIdentityToken) { this.oktaIdentityToken = oktaIdentityToken; return this; }
private RequestBuilder oktaAccessToken(OktaAccessToken oktaAccessToken) { this.oktaAccessToken = oktaAccessToken; return this; }
private RequestBuilder contentType(String contentType) { this.contentType = contentType; return this; }
private RequestBuilder recursive(String recursive) { this.recursive = recursive; return this; }
@@ -2014,6 +2016,9 @@ public class ApplicationApiTest extends ControllerContainerTest {
if (identity != null) {
addIdentityToRequest(request, identity);
}
+ if (oktaIdentityToken != null) {
+ addOktaIdentityToken(request, oktaIdentityToken);
+ }
if (oktaAccessToken != null) {
addOktaAccessToken(request, oktaAccessToken);
}