summaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorJon Marius Venstad <jonmv@users.noreply.github.com>2020-08-06 15:51:12 +0200
committerGitHub <noreply@github.com>2020-08-06 15:51:12 +0200
commite483631af3d65e217234455fe68ce840fca989a3 (patch)
treefbbae1c48e20bff366beff80947fd2c45407224c /controller-server
parent0a5f59230dbece31964dccc132093e59786899cf (diff)
parent78d6797fc7a2ca768e2303f4eeba5050e4dc7593 (diff)
Merge pull request #14004 from vespa-engine/ogronnesby/keep-user-creating-tenant
keep which user created a tenant
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java12
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java6
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java1
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControl.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/CloudTenant.java12
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/SignatureFilterTest.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-without-applications.json1
8 files changed, 30 insertions, 9 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java
index 599fa962527..f2e6cd0e15f 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java
@@ -100,20 +100,22 @@ public abstract class LockedTenant {
/** A locked CloudTenant. */
public static class Cloud extends LockedTenant {
+ private final Optional<Principal> creator;
private final BiMap<PublicKey, Principal> developerKeys;
- private Cloud(TenantName name, BiMap<PublicKey, Principal> developerKeys) {
+ private Cloud(TenantName name, Optional<Principal> creator, BiMap<PublicKey, Principal> developerKeys) {
super(name);
this.developerKeys = ImmutableBiMap.copyOf(developerKeys);
+ this.creator = creator;
}
private Cloud(CloudTenant tenant) {
- this(tenant.name(), tenant.developerKeys());
+ this(tenant.name(), Optional.empty(), tenant.developerKeys());
}
@Override
public CloudTenant get() {
- return new CloudTenant(name, developerKeys);
+ return new CloudTenant(name, creator, developerKeys);
}
public Cloud withDeveloperKey(PublicKey key, Principal principal) {
@@ -121,13 +123,13 @@ public abstract class LockedTenant {
if (keys.containsKey(key))
throw new IllegalArgumentException("Key " + KeyUtils.toPem(key) + " is already owned by " + keys.get(key));
keys.put(key, principal);
- return new Cloud(name, keys);
+ return new Cloud(name, creator, keys);
}
public Cloud withoutDeveloperKey(PublicKey key) {
BiMap<PublicKey, Principal> keys = HashBiMap.create(developerKeys);
keys.remove(key);
- return new Cloud(name, keys);
+ return new Cloud(name, creator, keys);
}
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java
index 5e9d5c44d4c..2ed71b91850 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java
@@ -46,6 +46,8 @@ public class TenantSerializer {
private static final String athenzDomainField = "athenzDomain";
private static final String propertyField = "property";
private static final String propertyIdField = "propertyId";
+ private static final String creatorField = "creator";
+ private static final String createdAtField = "createdAt";
private static final String contactField = "contact";
private static final String contactUrlField = "contactUrl";
private static final String propertyUrlField = "propertyUrl";
@@ -88,6 +90,7 @@ public class TenantSerializer {
// field we continue to write the default value and stop reading it.
// TODO(ogronnesby, 2020-08-05): Remove when a version where we do not read the field has propagated.
var legacyBillingInfo = new BillingInfo("customer", "Vespa");
+ tenant.creator().ifPresent(creator -> root.setString(creatorField, creator.getName()));
developerKeysToSlime(tenant.developerKeys(), root.setArray(pemDeveloperKeysField));
toSlime(legacyBillingInfo, root.setObject(billingInfoField));
}
@@ -128,8 +131,9 @@ public class TenantSerializer {
private CloudTenant cloudTenantFrom(Inspector tenantObject) {
TenantName name = TenantName.from(tenantObject.field(nameField).asString());
+ Optional<Principal> creator = SlimeUtils.optionalString(tenantObject.field(creatorField)).map(SimplePrincipal::new);
BiMap<PublicKey, Principal> developerKeys = developerKeysFromSlime(tenantObject.field(pemDeveloperKeysField));
- return new CloudTenant(name, developerKeys);
+ return new CloudTenant(name, creator, developerKeys);
}
private BiMap<PublicKey, Principal> developerKeysFromSlime(Inspector array) {
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 c5fb507749c..427d1d66ee8 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
@@ -1635,6 +1635,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
case cloud: {
CloudTenant cloudTenant = (CloudTenant) tenant;
+ cloudTenant.creator().ifPresent(creator -> object.setString("creator", creator.getName()));
Cursor pemDeveloperKeysArray = object.setArray("pemDeveloperKeys");
cloudTenant.developerKeys().forEach((key, user) -> {
Cursor keyObject = pemDeveloperKeysArray.addObject();
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControl.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControl.java
index 4f410f60204..6d2b2d58e78 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControl.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControl.java
@@ -48,7 +48,7 @@ public class CloudAccessControl implements AccessControl {
requireTenantCreationAllowed((Auth0Credentials) credentials);
CloudTenantSpec spec = (CloudTenantSpec) tenantSpec;
- CloudTenant tenant = CloudTenant.create(spec.tenant());
+ CloudTenant tenant = CloudTenant.create(spec.tenant(), credentials.user());
for (Role role : Roles.tenantRoles(spec.tenant())) {
userManagement.createRole(role);
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/CloudTenant.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/CloudTenant.java
index d208a1e4e63..a74c39dc362 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/CloudTenant.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/CloudTenant.java
@@ -16,20 +16,28 @@ import java.util.Optional;
*/
public class CloudTenant extends Tenant {
+ private final Optional<Principal> creator;
private final BiMap<PublicKey, Principal> developerKeys;
/** Public for the serialization layer — do not use! */
- public CloudTenant(TenantName name, BiMap<PublicKey, Principal> developerKeys) {
+ public CloudTenant(TenantName name, Optional<Principal> creator, BiMap<PublicKey, Principal> developerKeys) {
super(name, Optional.empty());
+ this.creator = creator;
this.developerKeys = developerKeys;
}
/** Creates a tenant with the given name, provided it passes validation. */
- public static CloudTenant create(TenantName tenantName) {
+ public static CloudTenant create(TenantName tenantName, Principal creator) {
return new CloudTenant(requireName(tenantName),
+ Optional.ofNullable(creator),
ImmutableBiMap.of());
}
+ /** The user that created the tenant */
+ public Optional<Principal> creator() {
+ return creator;
+ }
+
/** Returns the set of developer keys and their corresponding developers for this tenant. */
public BiMap<PublicKey, Principal> developerKeys() { return developerKeys; }
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java
index 0f4ea3dd2ce..9f36275e196 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java
@@ -78,10 +78,12 @@ public class TenantSerializerTest {
@Test
public void cloud_tenant() {
CloudTenant tenant = new CloudTenant(TenantName.from("elderly-lady"),
+ Optional.of(new SimplePrincipal("foobar-user")),
ImmutableBiMap.of(publicKey, new SimplePrincipal("joe"),
otherPublicKey, new SimplePrincipal("jane")));
CloudTenant serialized = (CloudTenant) serializer.tenantFrom(serializer.toSlime(tenant));
assertEquals(tenant.name(), serialized.name());
+ assertEquals(tenant.creator(), serialized.creator());
assertEquals(tenant.developerKeys(), serialized.developerKeys());
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/SignatureFilterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/SignatureFilterTest.java
index 3c13962916a..28db2cf2224 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/SignatureFilterTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/SignatureFilterTest.java
@@ -27,6 +27,7 @@ import java.net.URI;
import java.net.http.HttpRequest;
import java.security.PrivateKey;
import java.security.PublicKey;
+import java.util.Optional;
import java.util.Set;
import static org.junit.Assert.assertEquals;
@@ -66,6 +67,7 @@ public class SignatureFilterTest {
signer = new RequestSigner(privateKey, id.serializedForm(), tester.clock());
tester.curator().writeTenant(new CloudTenant(appId.tenant(),
+ Optional.empty(),
ImmutableBiMap.of()));
tester.curator().writeApplication(new Application(appId, tester.clock().instant()));
}
@@ -104,6 +106,7 @@ public class SignatureFilterTest {
// Signed request gets a developer role when a matching developer key is stored for the tenant.
tester.curator().writeTenant(new CloudTenant(appId.tenant(),
+ Optional.empty(),
ImmutableBiMap.of(publicKey, () -> "user")));
verifySecurityContext(requestOf(signer.signed(request.copy(), Method.POST, () -> new ByteArrayInputStream(hiBytes)), hiBytes),
new SecurityContext(new SimplePrincipal("user"),
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-without-applications.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-without-applications.json
index 39b6cccbab0..bce3d185977 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-without-applications.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-without-applications.json
@@ -1,6 +1,7 @@
{
"tenant": "my-tenant",
"type": "CLOUD",
+ "creator": "administrator@tenant",
"pemDeveloperKeys": [],
"applications": []
}