From 6ae33ac0fca9851742e00f0e62689691301f8951 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Thu, 31 Oct 2024 23:49:49 +0100 Subject: [PATCH] =?UTF-8?q?G=C3=BCltigkeitsdauer=20von=20Tokens=20editierb?= =?UTF-8?q?ar=20gemacht?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stephan Richter --- .../de/srsoftware/oidc/api/Constants.java | 1 + .../de/srsoftware/oidc/api/data/Client.java | 48 +++++++++++++------ .../oidc/api/ClientServiceTest.java | 5 +- .../oidc/backend/ClientController.java | 4 +- .../oidc/backend/TokenController.java | 2 +- .../encrypted/EncryptedClientService.java | 4 +- .../oidc/datastore/file/FileStore.java | 2 + .../src/main/resources/de/edit_client.html | 8 ++++ .../src/main/resources/en/edit_client.html | 9 ++++ .../main/resources/en/scripts/edit_client.js | 22 ++++++++- .../src/main/resources/en/todo.html | 2 + 11 files changed, 86 insertions(+), 21 deletions(-) diff --git a/de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/Constants.java b/de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/Constants.java index 743a75c..a94e8d0 100644 --- a/de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/Constants.java +++ b/de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/Constants.java @@ -64,6 +64,7 @@ public class Constants { public static final String START_TLS = "start_tls"; public static final String TOKEN = "token"; public static final String TOKEN_TYPE = "token_type"; + public static final String TOKEN_VALIDITY = "token_validity"; public static final String TRUST = "trust"; public static final String UNAUTHORIZED_CLIENT = "unauthorized_client"; public static final String USER = "user"; diff --git a/de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/data/Client.java b/de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/data/Client.java index 7b240de..db09475 100644 --- a/de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/data/Client.java +++ b/de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/data/Client.java @@ -5,6 +5,7 @@ package de.srsoftware.oidc.api.data; import static de.srsoftware.oidc.api.Constants.*; import static de.srsoftware.utils.Optionals.nullable; +import java.time.Duration; import java.util.*; public final class Client { @@ -14,15 +15,36 @@ public final class Client { private final String name; private final String secret; private final Set redirectUris; + private Duration tokenValidity; public Client(String id, String name, String secret, Set redirectUris) { - this.id = id; - landingPage = null; - this.name = name; - this.secret = secret; - this.redirectUris = redirectUris; + this.id = id; + landingPage = null; + this.name = name; + this.secret = secret; + this.redirectUris = redirectUris; + this.tokenValidity = Duration.ofMinutes(10); } + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || obj.getClass() != this.getClass()) return false; + var that = (Client)obj; + return Objects.equals(this.id, that.id) // + && Objects.equals(this.name, that.name) // + && Objects.equals(this.secret, that.secret) // + && Objects.equals(this.redirectUris, that.redirectUris) // + && Objects.equals(landingPage, that.landingPage) // + && Objects.equals(tokenValidity, that.tokenValidity); + } + + @Override + public int hashCode() { + return Objects.hash(id, name, secret, redirectUris); + } + + public String id() { return id; } @@ -53,6 +75,7 @@ public final class Client { map.put(NAME, name); nullable(redirectUris).ifPresent(uris -> map.put(REDIRECT_URIS, uris)); nullable(landingPage).ifPresent(lp -> map.put(LANDING_PAGE, lp)); + nullable(tokenValidity).ifPresent(tv -> map.put(TOKEN_VALIDITY, tv.toMinutes())); return map; } @@ -65,17 +88,14 @@ public final class Client { return redirectUris; } - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (obj == null || obj.getClass() != this.getClass()) return false; - var that = (Client)obj; - return Objects.equals(this.id, that.id) && Objects.equals(this.name, that.name) && Objects.equals(this.secret, that.secret) && Objects.equals(this.redirectUris, that.redirectUris); + + public Duration tokenValidity() { + return tokenValidity; } - @Override - public int hashCode() { - return Objects.hash(id, name, secret, redirectUris); + public Client tokenValidity(Duration newValue) { + this.tokenValidity = newValue; + return this; } @Override diff --git a/de.srsoftware.oidc.api/src/test/java/de/srsoftware/oidc/api/ClientServiceTest.java b/de.srsoftware.oidc.api/src/test/java/de/srsoftware/oidc/api/ClientServiceTest.java index 7da9747..b1ef86c 100644 --- a/de.srsoftware.oidc.api/src/test/java/de/srsoftware/oidc/api/ClientServiceTest.java +++ b/de.srsoftware.oidc.api/src/test/java/de/srsoftware/oidc/api/ClientServiceTest.java @@ -6,6 +6,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import de.srsoftware.oidc.api.data.Client; +import java.time.Duration; import java.util.Set; import org.junit.jupiter.api.Test; @@ -23,7 +24,7 @@ public abstract class ClientServiceTest { var clientId = uuid(); var clientSecret = uuid(); var landingPage = uuid(); - var client = new Client(clientId, NAME, clientSecret, Set.of(URI)).landingPage(landingPage); + var client = new Client(clientId, NAME, clientSecret, Set.of(URI)); var list = cs.save(client).listClients(); assertEquals(1, list.size()); assertTrue(list.contains(client)); @@ -37,7 +38,7 @@ public abstract class ClientServiceTest { var clientId = uuid(); var clientSecret = uuid(); var landingPage = uuid(); - var client = new Client(clientId, NAME, clientSecret, Set.of(URI)).landingPage(landingPage); + var client = new Client(clientId, NAME, clientSecret, Set.of(URI)).landingPage(landingPage).tokenValidity(Duration.ofMinutes(23)); var optClient = cs.save(client).getClient(clientId); assertTrue(optClient.isPresent()); assertEquals(client, optClient.get()); diff --git a/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/ClientController.java b/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/ClientController.java index ae0ef54..3642060 100644 --- a/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/ClientController.java +++ b/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/ClientController.java @@ -14,6 +14,7 @@ import de.srsoftware.oidc.api.data.User; import de.srsoftware.utils.Error; import de.srsoftware.utils.Optionals; import java.io.IOException; +import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.*; @@ -210,7 +211,8 @@ public class ClientController extends Controller { if (o instanceof String s) redirects.add(s); } var landingPage = json.has(LANDING_PAGE) ? json.getString(LANDING_PAGE) : null; - var client = new Client(json.getString(CLIENT_ID), json.getString(NAME), json.getString(SECRET), redirects).landingPage(landingPage); + var token_duration = Duration.ofMinutes(json.has(TOKEN_VALIDITY) ? json.getLong(TOKEN_VALIDITY) : 10); + var client = new Client(json.getString(CLIENT_ID), json.getString(NAME), json.getString(SECRET), redirects).landingPage(landingPage).tokenValidity(token_duration); clients.save(client); return sendContent(ex, client); } diff --git a/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/TokenController.java b/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/TokenController.java index 46d0c32..9b8b649 100644 --- a/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/TokenController.java +++ b/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/TokenController.java @@ -176,7 +176,7 @@ public class TokenController extends PathHandler { claims.setIssuer(issuer); // who creates the token and signs it claims.setSubject(user.uuid()); // the subject/principal is whom the token is about claims.setAudience(client.id()); - claims.setExpirationTimeMinutesInTheFuture(config.tokenExpirationMinutes); // time when the token will expire (10 minutes from now) + claims.setExpirationTimeMinutesInTheFuture(client.tokenValidity().toMinutes()); // time when the token will expire (10 minutes from now) claims.setIssuedAtToNow(); claims.setClaim(AT_HASH, atHash); claims.setClaim(CLIENT_ID, client.id()); diff --git a/de.srsoftware.oidc.datastore.encrypted/src/main/java/de/srsoftware/oidc/datastore/encrypted/EncryptedClientService.java b/de.srsoftware.oidc.datastore.encrypted/src/main/java/de/srsoftware/oidc/datastore/encrypted/EncryptedClientService.java index 05a1884..ca9ffe0 100644 --- a/de.srsoftware.oidc.datastore.encrypted/src/main/java/de/srsoftware/oidc/datastore/encrypted/EncryptedClientService.java +++ b/de.srsoftware.oidc.datastore.encrypted/src/main/java/de/srsoftware/oidc/datastore/encrypted/EncryptedClientService.java @@ -19,12 +19,12 @@ public class EncryptedClientService extends EncryptedConfig implements ClientSer public Client decrypt(Client client) { var decryptedUrls = client.redirectUris().stream().map(this::decrypt).collect(Collectors.toSet()); - return new Client(decrypt(client.id()), decrypt(client.name()), decrypt(client.secret()), decryptedUrls).landingPage(decrypt(client.landingPage())); + return new Client(decrypt(client.id()), decrypt(client.name()), decrypt(client.secret()), decryptedUrls).landingPage(decrypt(client.landingPage())).tokenValidity(client.tokenValidity()); } public Client encrypt(Client client) { var encryptedUrls = client.redirectUris().stream().map(this::encrypt).collect(Collectors.toSet()); - return new Client(encrypt(client.id()), encrypt(client.name()), encrypt(client.secret()), encryptedUrls).landingPage(encrypt(client.landingPage())); + return new Client(encrypt(client.id()), encrypt(client.name()), encrypt(client.secret()), encryptedUrls).landingPage(encrypt(client.landingPage())).tokenValidity(client.tokenValidity()); } @Override diff --git a/de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/FileStore.java b/de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/FileStore.java index 1348ef9..c475a20 100644 --- a/de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/FileStore.java +++ b/de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/FileStore.java @@ -21,6 +21,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.*; @@ -329,6 +330,7 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe } var client = new Client(clientId, clientData.getString(NAME), clientData.getString(SECRET), redirectUris); if (clientData.has(LANDING_PAGE)) client.landingPage(clientData.getString(LANDING_PAGE)); + if (clientData.has(TOKEN_VALIDITY)) client.tokenValidity(Duration.ofMinutes(clientData.getLong(TOKEN_VALIDITY))); return client; } diff --git a/de.srsoftware.oidc.web/src/main/resources/de/edit_client.html b/de.srsoftware.oidc.web/src/main/resources/de/edit_client.html index eb3eff3..05ca8ee 100644 --- a/de.srsoftware.oidc.web/src/main/resources/de/edit_client.html +++ b/de.srsoftware.oidc.web/src/main/resources/de/edit_client.html @@ -37,6 +37,14 @@ Ziel-Seite + + Gültigkeitsdauer von Access-Tokens + + +
+ Tage, Stunden, Minuten + + diff --git a/de.srsoftware.oidc.web/src/main/resources/en/edit_client.html b/de.srsoftware.oidc.web/src/main/resources/en/edit_client.html index 07675b5..ebe176a 100644 --- a/de.srsoftware.oidc.web/src/main/resources/en/edit_client.html +++ b/de.srsoftware.oidc.web/src/main/resources/en/edit_client.html @@ -37,10 +37,19 @@ Landing page + + Token validity duration + + +
+ days, hours, minutes + + +
diff --git a/de.srsoftware.oidc.web/src/main/resources/en/scripts/edit_client.js b/de.srsoftware.oidc.web/src/main/resources/en/scripts/edit_client.js index c8e04ff..78d1aed 100644 --- a/de.srsoftware.oidc.web/src/main/resources/en/scripts/edit_client.js +++ b/de.srsoftware.oidc.web/src/main/resources/en/scripts/edit_client.js @@ -1,5 +1,22 @@ var params = new URLSearchParams(window.location.search); var id = params.get('id'); +var token_validity = 10; + +function displayDuration(){ + var mins = token_validity; + hrs = Math.floor(mins/60); + mins-=60*hrs; + days = Math.floor(hrs/24); + hrs-=24*days; + setText('days',days); + setText('hours',hrs); + setText('minutes',mins); +} + +function durationUpdate(){ + token_validity = getValue('token_validity'); + displayDuration(); +} function handleAutoDiscover(response){ if (response.ok){ @@ -19,6 +36,8 @@ function handleLoadResponse(response){ get('client-secret').value = json.secret; get('redirect-urls').value = json.redirect_uris.join("\n"); get('landing-page').value = json.landing_page?json.landing_page:''; + token_validity = json.token_validity?json.token_validity:10; + displayDuration(); }); } } @@ -44,7 +63,8 @@ function updateClient(){ name : getValue('client-name'), secret : getValue('client-secret'), redirect_uris : getValue('redirect-urls').split("\n"), - landing_page : getValue('landing-page') + landing_page : getValue('landing-page'), + token_validity : getValue('token_validity') }; fetch(client_controller+'/update',{ method : 'POST', diff --git a/de.srsoftware.oidc.web/src/main/resources/en/todo.html b/de.srsoftware.oidc.web/src/main/resources/en/todo.html index 51782d2..7d5aa4b 100644 --- a/de.srsoftware.oidc.web/src/main/resources/en/todo.html +++ b/de.srsoftware.oidc.web/src/main/resources/en/todo.html @@ -16,6 +16,8 @@
  • implement token refresh
  • Configuration im Frontend
  • TOTP authentifizierung
  • +
  • Gültigkeitsdauer von Tokens pro Client konfigurierbar machen
  • +
  • Besserer Hinweis beim Zurücksetzen von Passworten, wenn das neue Passwort zu einfach ist