diff options
author | Bjørn Christian Seime <bjorncs@yahooinc.com> | 2023-07-31 15:22:54 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@yahooinc.com> | 2023-07-31 15:22:54 +0200 |
commit | a6d61ed6951906119f0579252e06eb57532f8458 (patch) | |
tree | 3e72060218628bc8e47f57e27634fa77a6b1bb77 /controller-server/src | |
parent | 5afe0b9399cbadf334b26157d1a6d10bf02a73d8 (diff) |
Accept both timestamp and duration for token expiration parameter
Diffstat (limited to 'controller-server/src')
3 files changed, 29 insertions, 16 deletions
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 4824ccc576a..6294fc59b5e 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 @@ -987,9 +987,7 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { private HttpResponse generateToken(String tenant, String tokenid, HttpRequest request) { - // 'expiration=PT0S' for no expiration, no 'expiration' for default TTL. - Duration expiration = Optional.ofNullable(request.getProperty("expiration")) - .map(Duration::parse).orElse(DataplaneTokenService.DEFAULT_TTL); + var expiration = resolveExpiration(request).orElse(null); DataplaneToken token = controller.dataplaneTokenService().generateToken( TenantName.from(tenant), TokenId.of(tokenid), expiration, request.getJDiscRequest().getUserPrincipal()); Slime slime = new Slime(); @@ -1001,6 +999,22 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { return new SlimeJsonResponse(slime); } + /** + * Specify 'expiration=none' for no expiration, no parameter or 'expiration=default' for default TTL. + * Use ISO-8601 format for timestamp or period, + * e.g 'expiration=PT1H' for 1 hour, 'expiration=2021-01-01T12:00:00Z' for a specific time. + */ + private Optional<Instant> resolveExpiration(HttpRequest r) { + var expirationParam = r.getProperty("expiration"); + var now = controller.clock().instant(); + if (expirationParam == null || expirationParam.equals("default")) + return Optional.of(now.plus(DataplaneTokenService.DEFAULT_TTL)); + if (expirationParam.equals("none")) return Optional.empty(); + return expirationParam.startsWith("P") + ? Optional.of(now.plus(Duration.parse(expirationParam))) + : Optional.of(Instant.parse(expirationParam)); + } + private HttpResponse deleteToken(String tenant, String tokenid, HttpRequest request) { String fingerprint = Optional.ofNullable(request.getProperty("fingerprint")).orElseThrow(() -> new IllegalArgumentException("Cannot delete token without fingerprint")); controller.dataplaneTokenService().deleteToken(TenantName.from(tenant), TokenId.of(tokenid), FingerPrint.of(fingerprint)); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/dataplanetoken/DataplaneTokenService.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/dataplanetoken/DataplaneTokenService.java index 32872a01bce..385200a1624 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/dataplanetoken/DataplaneTokenService.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/dataplanetoken/DataplaneTokenService.java @@ -54,12 +54,11 @@ public class DataplaneTokenService { * * @param tenantName name of the tenant to connect the token to * @param tokenId The user generated name/id of the token - * @param ttl The time to live of the token. Use {@link Duration#ZERO} for no TTL. + * @param expiration Token expiration * @param principal The principal making the request * @return a DataplaneToken containing the secret generated token */ - public DataplaneToken generateToken(TenantName tenantName, TokenId tokenId, Duration ttl, Principal principal) { - Optional<Instant> expiration = ttl.isZero() ? Optional.empty() : Optional.ofNullable(controller.clock().instant().plus(ttl)); + public DataplaneToken generateToken(TenantName tenantName, TokenId tokenId, Instant expiration, Principal principal) { TokenDomain tokenDomain = TokenDomain.of("Vespa Cloud tenant data plane:%s".formatted(tenantName.value())); Token token = TokenGenerator.generateToken(tokenDomain, TOKEN_PREFIX, TOKEN_BYTES); TokenCheckHash checkHash = TokenCheckHash.of(token, CHECK_HASH_BYTES); @@ -67,7 +66,7 @@ public class DataplaneTokenService { FingerPrint.of(token.fingerprint().toDelimitedHexString()), checkHash.toHexString(), controller.clock().instant(), - expiration, + Optional.ofNullable(expiration), principal.getName()); CuratorDb curator = controller.curator(); @@ -92,7 +91,7 @@ public class DataplaneTokenService { // Return the data plane token including the secret token. return new DataplaneToken(tokenId, FingerPrint.of(token.fingerprint().toDelimitedHexString()), - token.secretTokenString(), expiration); + token.secretTokenString(), Optional.ofNullable(expiration)); } } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/dataplanetoken/DataplaneTokenServiceTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/dataplanetoken/DataplaneTokenServiceTest.java index 9a8e43d1597..e148eac7365 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/dataplanetoken/DataplaneTokenServiceTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/dataplanetoken/DataplaneTokenServiceTest.java @@ -30,7 +30,7 @@ public class DataplaneTokenServiceTest { @Test void generates_and_persists_token() { - DataplaneToken dataplaneToken = dataplaneTokenService.generateToken(tenantName, tokenId, Duration.ofDays(100), principal); + DataplaneToken dataplaneToken = dataplaneTokenService.generateToken(tenantName, tokenId, tester.clock().instant().plus(Duration.ofDays(100)), principal); List<DataplaneTokenVersions> dataplaneTokenVersions = dataplaneTokenService.listTokens(tenantName); assertEquals(dataplaneToken.fingerPrint(), dataplaneTokenVersions.get(0).tokenVersions().get(0).fingerPrint()); assertEquals(dataplaneToken.expiration(), dataplaneTokenVersions.get(0).tokenVersions().get(0).expiration()); @@ -38,8 +38,8 @@ public class DataplaneTokenServiceTest { @Test void generating_new_token_appends() { - DataplaneToken dataplaneToken1 = dataplaneTokenService.generateToken(tenantName, tokenId, Duration.ofDays(1), principal); - DataplaneToken dataplaneToken2 = dataplaneTokenService.generateToken(tenantName, tokenId, Duration.ZERO, principal); + DataplaneToken dataplaneToken1 = dataplaneTokenService.generateToken(tenantName, tokenId, tester.clock().instant().plus(Duration.ofDays(1)), principal); + DataplaneToken dataplaneToken2 = dataplaneTokenService.generateToken(tenantName, tokenId, null, principal); assertNotEquals(dataplaneToken1.fingerPrint(), dataplaneToken2.fingerPrint()); List<DataplaneTokenVersions> dataplaneTokenVersions = dataplaneTokenService.listTokens(tenantName); @@ -54,8 +54,8 @@ public class DataplaneTokenServiceTest { @Test void delete_last_fingerprint_deletes_token() { - DataplaneToken dataplaneToken1 = dataplaneTokenService.generateToken(tenantName, tokenId, Duration.ZERO, principal); - DataplaneToken dataplaneToken2 = dataplaneTokenService.generateToken(tenantName, tokenId, Duration.ZERO, principal); + DataplaneToken dataplaneToken1 = dataplaneTokenService.generateToken(tenantName, tokenId, null, principal); + DataplaneToken dataplaneToken2 = dataplaneTokenService.generateToken(tenantName, tokenId, null, principal); dataplaneTokenService.deleteToken(tenantName, tokenId, dataplaneToken1.fingerPrint()); dataplaneTokenService.deleteToken(tenantName, tokenId, dataplaneToken2.fingerPrint()); assertEquals(List.of(), dataplaneTokenService.listTokens(tenantName)); @@ -63,8 +63,8 @@ public class DataplaneTokenServiceTest { @Test void deleting_nonexistent_fingerprint_throws() { - DataplaneToken dataplaneToken = dataplaneTokenService.generateToken(tenantName, tokenId, Duration.ZERO, principal); - DataplaneToken dataplaneToken2 = dataplaneTokenService.generateToken(tenantName, tokenId, Duration.ZERO, principal); + DataplaneToken dataplaneToken = dataplaneTokenService.generateToken(tenantName, tokenId, null, principal); + DataplaneToken dataplaneToken2 = dataplaneTokenService.generateToken(tenantName, tokenId, null, principal); dataplaneTokenService.deleteToken(tenantName, tokenId, dataplaneToken.fingerPrint()); // Token currently contains value of "dataplaneToken2" @@ -74,7 +74,7 @@ public class DataplaneTokenServiceTest { @Test void deleting_nonexistent_token_throws() { - DataplaneToken dataplaneToken = dataplaneTokenService.generateToken(tenantName, tokenId, Duration.ZERO, principal); + DataplaneToken dataplaneToken = dataplaneTokenService.generateToken(tenantName, tokenId, null, principal); dataplaneTokenService.deleteToken(tenantName, tokenId, dataplaneToken.fingerPrint()); // Token is created and deleted above, no longer exists |