aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorValerij Fredriksen <valerijf@yahooinc.com>2022-08-12 09:55:21 +0200
committerValerij Fredriksen <valerijf@yahooinc.com>2022-08-12 13:35:32 +0200
commit58bc70d49ca1bd442c54c06d13fb10ba2c5f8fbf (patch)
treec662ee0f47dcf9667c80af690ef6c3b504136c52
parent361cf0516ade8b465b0441f3f8cd409d7680163a (diff)
Add invalidateUserSessionsBefore to CloudTenant
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/CloudTenant.java11
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java26
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java5
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDbTest.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotifierTest.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java13
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/SignatureFilterTest.java6
7 files changed, 44 insertions, 23 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/CloudTenant.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/CloudTenant.java
index 54924b9c456..44f9c0ea3b8 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/CloudTenant.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/CloudTenant.java
@@ -25,17 +25,19 @@ public class CloudTenant extends Tenant {
private final TenantInfo info;
private final List<TenantSecretStore> tenantSecretStores;
private final ArchiveAccess archiveAccess;
+ private final Optional<Instant> invalidateUserSessionsBefore;
/** Public for the serialization layer — do not use! */
public CloudTenant(TenantName name, Instant createdAt, LastLoginInfo lastLoginInfo, Optional<Principal> creator,
BiMap<PublicKey, Principal> developerKeys, TenantInfo info,
- List<TenantSecretStore> tenantSecretStores, ArchiveAccess archiveAccess) {
+ List<TenantSecretStore> tenantSecretStores, ArchiveAccess archiveAccess, Optional<Instant> invalidateUserSessionsBefore) {
super(name, createdAt, lastLoginInfo, Optional.empty());
this.creator = creator;
this.developerKeys = developerKeys;
this.info = Objects.requireNonNull(info);
this.tenantSecretStores = tenantSecretStores;
this.archiveAccess = Objects.requireNonNull(archiveAccess);
+ this.invalidateUserSessionsBefore = invalidateUserSessionsBefore;
}
/** Creates a tenant with the given name, provided it passes validation. */
@@ -44,7 +46,7 @@ public class CloudTenant extends Tenant {
createdAt,
LastLoginInfo.EMPTY,
Optional.ofNullable(creator),
- ImmutableBiMap.of(), TenantInfo.empty(), List.of(), new ArchiveAccess());
+ ImmutableBiMap.of(), TenantInfo.empty(), List.of(), new ArchiveAccess(), Optional.empty());
}
/** The user that created the tenant */
@@ -75,6 +77,11 @@ public class CloudTenant extends Tenant {
return archiveAccess;
}
+ /** Returns instant before which all user sessions that have access to this tenant must be refreshed */
+ public Optional<Instant> invalidateUserSessionsBefore() {
+ return invalidateUserSessionsBefore;
+ }
+
@Override
public Type type() {
return Type.cloud;
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 4f58e87035b..ac7c6319c1b 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
@@ -129,25 +129,27 @@ public abstract class LockedTenant {
private final TenantInfo info;
private final List<TenantSecretStore> tenantSecretStores;
private final ArchiveAccess archiveAccess;
+ private final Optional<Instant> invalidateUserSessionsBefore;
private Cloud(TenantName name, Instant createdAt, LastLoginInfo lastLoginInfo, Optional<Principal> creator,
BiMap<PublicKey, Principal> developerKeys, TenantInfo info,
- List<TenantSecretStore> tenantSecretStores, ArchiveAccess archiveAccess) {
+ List<TenantSecretStore> tenantSecretStores, ArchiveAccess archiveAccess, Optional<Instant> invalidateUserSessionsBefore) {
super(name, createdAt, lastLoginInfo);
this.developerKeys = ImmutableBiMap.copyOf(developerKeys);
this.creator = creator;
this.info = info;
this.tenantSecretStores = tenantSecretStores;
this.archiveAccess = archiveAccess;
+ this.invalidateUserSessionsBefore = invalidateUserSessionsBefore;
}
private Cloud(CloudTenant tenant) {
- this(tenant.name(), tenant.createdAt(), tenant.lastLoginInfo(), tenant.creator(), tenant.developerKeys(), tenant.info(), tenant.tenantSecretStores(), tenant.archiveAccess());
+ this(tenant.name(), tenant.createdAt(), tenant.lastLoginInfo(), tenant.creator(), tenant.developerKeys(), tenant.info(), tenant.tenantSecretStores(), tenant.archiveAccess(), tenant.invalidateUserSessionsBefore());
}
@Override
public CloudTenant get() {
- return new CloudTenant(name, createdAt, lastLoginInfo, creator, developerKeys, info, tenantSecretStores, archiveAccess);
+ return new CloudTenant(name, createdAt, lastLoginInfo, creator, developerKeys, info, tenantSecretStores, archiveAccess, invalidateUserSessionsBefore);
}
public Cloud withDeveloperKey(PublicKey key, Principal principal) {
@@ -155,38 +157,42 @@ 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, createdAt, lastLoginInfo, creator, keys, info, tenantSecretStores, archiveAccess);
+ return new Cloud(name, createdAt, lastLoginInfo, creator, keys, info, tenantSecretStores, archiveAccess, invalidateUserSessionsBefore);
}
public Cloud withoutDeveloperKey(PublicKey key) {
BiMap<PublicKey, Principal> keys = HashBiMap.create(developerKeys);
keys.remove(key);
- return new Cloud(name, createdAt, lastLoginInfo, creator, keys, info, tenantSecretStores, archiveAccess);
+ return new Cloud(name, createdAt, lastLoginInfo, creator, keys, info, tenantSecretStores, archiveAccess, invalidateUserSessionsBefore);
}
public Cloud withInfo(TenantInfo newInfo) {
- return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, newInfo, tenantSecretStores, archiveAccess);
+ return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, newInfo, tenantSecretStores, archiveAccess, invalidateUserSessionsBefore);
}
@Override
public LockedTenant with(LastLoginInfo lastLoginInfo) {
- return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, tenantSecretStores, archiveAccess);
+ return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, tenantSecretStores, archiveAccess, invalidateUserSessionsBefore);
}
public Cloud withSecretStore(TenantSecretStore tenantSecretStore) {
ArrayList<TenantSecretStore> secretStores = new ArrayList<>(tenantSecretStores);
secretStores.add(tenantSecretStore);
- return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, secretStores, archiveAccess);
+ return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, secretStores, archiveAccess, invalidateUserSessionsBefore);
}
public Cloud withoutSecretStore(TenantSecretStore tenantSecretStore) {
ArrayList<TenantSecretStore> secretStores = new ArrayList<>(tenantSecretStores);
secretStores.remove(tenantSecretStore);
- return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, secretStores, archiveAccess);
+ return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, secretStores, archiveAccess, invalidateUserSessionsBefore);
}
public Cloud withArchiveAccess(ArchiveAccess archiveAccess) {
- return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, tenantSecretStores, archiveAccess);
+ return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, tenantSecretStores, archiveAccess, invalidateUserSessionsBefore);
+ }
+
+ public Cloud withInvalidateUserSessionsBefore(Instant invalidateUserSessionsBefore) {
+ return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, tenantSecretStores, archiveAccess, Optional.of(invalidateUserSessionsBefore));
}
}
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 e7cf0c34511..e91fbe8b1b7 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
@@ -81,6 +81,7 @@ public class TenantSerializer {
private static final String archiveAccessField = "archiveAccess";
private static final String awsArchiveAccessRoleField = "awsArchiveAccessRole";
private static final String gcpArchiveAccessMemberField = "gcpArchiveAccessMember";
+ private static final String invalidateUserSessionsBeforeField = "invalidateUserSessionsBefore";
private static final String awsIdField = "awsId";
private static final String roleField = "role";
@@ -123,6 +124,7 @@ public class TenantSerializer {
toSlime(tenant.info(), root);
toSlime(tenant.tenantSecretStores(), root);
toSlime(tenant.archiveAccess(), root);
+ tenant.invalidateUserSessionsBefore().ifPresent(instant -> root.setLong(invalidateUserSessionsBeforeField, instant.toEpochMilli()));
}
private void toSlime(ArchiveAccess archiveAccess, Cursor root) {
@@ -187,7 +189,8 @@ public class TenantSerializer {
TenantInfo info = tenantInfoFromSlime(tenantObject.field(tenantInfoField));
List<TenantSecretStore> tenantSecretStores = secretStoresFromSlime(tenantObject.field(secretStoresField));
ArchiveAccess archiveAccess = archiveAccessFromSlime(tenantObject);
- return new CloudTenant(name, createdAt, lastLoginInfo, creator, developerKeys, info, tenantSecretStores, archiveAccess);
+ Optional<Instant> invalidateUserSessionsBefore = SlimeUtils.optionalInstant(tenantObject.field(invalidateUserSessionsBeforeField));
+ return new CloudTenant(name, createdAt, lastLoginInfo, creator, developerKeys, info, tenantSecretStores, archiveAccess, invalidateUserSessionsBefore);
}
private DeletedTenant deletedTenantFrom(Inspector tenantObject) {
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDbTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDbTest.java
index 1a171341ee0..4c1344650f8 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDbTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDbTest.java
@@ -61,7 +61,8 @@ public class NotificationsDbTest {
List.of(TenantContacts.Audience.NOTIFICATIONS),
email)))),
List.of(),
- new ArchiveAccess());
+ new ArchiveAccess(),
+ Optional.empty());
private static final List<Notification> notifications = List.of(
notification(1001, Type.deployment, Level.error, NotificationSource.from(tenant), "tenant msg"),
notification(1101, Type.applicationPackage, Level.warning, NotificationSource.from(TenantAndApplicationId.from(tenant.value(), "app1")), "app msg"),
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotifierTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotifierTest.java
index 00d8c100ced..7c07192d633 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotifierTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotifierTest.java
@@ -41,7 +41,8 @@ public class NotifierTest {
List.of(TenantContacts.Audience.NOTIFICATIONS),
email)))),
List.of(),
- new ArchiveAccess());
+ new ArchiveAccess(),
+ Optional.empty());
MockCuratorDb curatorDb = new MockCuratorDb(SystemName.Public);
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 e29d4afabff..636620acf07 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
@@ -103,8 +103,8 @@ public class TenantSerializerTest {
otherPublicKey, new SimplePrincipal("jane")),
TenantInfo.empty(),
List.of(),
- new ArchiveAccess()
- );
+ new ArchiveAccess(),
+ Optional.empty());
CloudTenant serialized = (CloudTenant) serializer.tenantFrom(serializer.toSlime(tenant));
assertEquals(tenant.name(), serialized.name());
assertEquals(tenant.creator(), serialized.creator());
@@ -125,11 +125,12 @@ public class TenantSerializerTest {
new TenantSecretStore("ss1", "123", "role1"),
new TenantSecretStore("ss2", "124", "role2")
),
- new ArchiveAccess().withAWSRole("arn:aws:iam::123456789012:role/my-role")
- );
+ new ArchiveAccess().withAWSRole("arn:aws:iam::123456789012:role/my-role"),
+ Optional.of(Instant.ofEpochMilli(1234567)));
CloudTenant serialized = (CloudTenant) serializer.tenantFrom(serializer.toSlime(tenant));
assertEquals(tenant.info(), serialized.info());
assertEquals(tenant.tenantSecretStores(), serialized.tenantSecretStores());
+ assertEquals(tenant.invalidateUserSessionsBefore(), serialized.invalidateUserSessionsBefore());
}
@Test
@@ -174,8 +175,8 @@ public class TenantSerializerTest {
otherPublicKey, new SimplePrincipal("jane")),
TenantInfo.empty(),
List.of(),
- new ArchiveAccess().withAWSRole("arn:aws:iam::123456789012:role/my-role").withGCPMember("user:foo@example.com")
- );
+ new ArchiveAccess().withAWSRole("arn:aws:iam::123456789012:role/my-role").withGCPMember("user:foo@example.com"),
+ Optional.empty());
CloudTenant serialized = (CloudTenant) serializer.tenantFrom(serializer.toSlime(tenant));
assertEquals(serialized.archiveAccess().awsRole().get(), "arn:aws:iam::123456789012:role/my-role");
assertEquals(serialized.archiveAccess().gcpMember().get(), "user:foo@example.com");
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 9ff79213983..ec9be1f04c3 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
@@ -77,7 +77,8 @@ public class SignatureFilterTest {
ImmutableBiMap.of(),
TenantInfo.empty(),
List.of(),
- new ArchiveAccess()));
+ new ArchiveAccess(),
+ Optional.empty()));
tester.curator().writeApplication(new Application(appId, tester.clock().instant()));
}
@@ -123,7 +124,8 @@ public class SignatureFilterTest {
ImmutableBiMap.of(publicKey, () -> "user"),
TenantInfo.empty(),
List.of(),
- new ArchiveAccess()));
+ new ArchiveAccess(),
+ Optional.empty()));
verifySecurityContext(requestOf(signer.signed(request.copy(), Method.POST, () -> new ByteArrayInputStream(hiBytes)), hiBytes),
new SecurityContext(new SimplePrincipal("user"),
Set.of(Role.reader(id.tenant()),