From 1a5a1373292906e806d0684641d9164ba621302e Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Sun, 20 Oct 2024 17:32:32 +0200 Subject: [PATCH 1/8] bugfix: deriving issuer from hostname Signed-off-by: Stephan Richter --- .../java/de/srsoftware/oidc/app/Application.java | 2 +- .../de/srsoftware/oidc/backend/TokenController.java | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java b/de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java index 0342348..a163862 100644 --- a/de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java +++ b/de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java @@ -78,7 +78,7 @@ public class Application { new Forward(INDEX).bindPath(ROOT).on(server); new WellKnownController().bindPath(WELL_KNOWN, "/realms/oidc" + WELL_KNOWN).on(server); new UserController(mailConfig, sessionService, userService, staticPages).bindPath(API_USER).on(server); - var tokenControllerConfig = new TokenController.Configuration("https://lightoidc.srsoftware.de", 10); // TODO configure or derive from hostname + var tokenControllerConfig = new TokenController.Configuration( 10); new TokenController(authService, clientService, keyManager, userService, tokenControllerConfig).bindPath(API_TOKEN).on(server); new ClientController(authService, clientService, sessionService, userService).bindPath(API_CLIENT).on(server); new KeyStoreController(keyStore).bindPath(JWKS).on(server); 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 f5f8f83..f9da058 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 @@ -27,7 +27,7 @@ import org.jose4j.lang.JoseException; import org.json.JSONObject; public class TokenController extends PathHandler { - public record Configuration(String issuer, int tokenExpirationMinutes) { + public record Configuration(int tokenExpirationMinutes) { } private final ClientService clients; private final AuthorizationService authorizations; @@ -115,7 +115,8 @@ public class TokenController extends PathHandler { var user = optUser.get(); var accessToken = users.accessToken(user); - String jwToken = createJWT(client, user, accessToken); + var issuer = "https://"+hostname(ex); + String jwToken = createJWT(client, user, accessToken, issuer); ex.getResponseHeaders().add("Cache-Control", "no-store"); JSONObject response = new JSONObject(); response.put(ACCESS_TOKEN, accessToken.id()); @@ -126,13 +127,13 @@ public class TokenController extends PathHandler { return sendContent(ex, response); } - private String createJWT(Client client, User user, AccessToken accessToken) { + private String createJWT(Client client, User user, AccessToken accessToken, String issuer) { try { PublicJsonWebKey key = keyManager.getKey(); var algo = key.getAlgorithm(); var atHash = this.atHash(algo, accessToken); key.setUse("sig"); - JwtClaims claims = createIdTokenClaims(user, client, atHash); + JwtClaims claims = createIdTokenClaims(user, client, atHash, issuer); // A JWT is a JWS and/or a JWE with JSON claims as the payload. // In this example it is a JWS so we create a JsonWebSignature object. @@ -167,12 +168,12 @@ public class TokenController extends PathHandler { } } - private JwtClaims createIdTokenClaims(User user, Client client, String atHash) { + private JwtClaims createIdTokenClaims(User user, Client client, String atHash, String issuer) { var optNonce = authorizations.consumeNonce(user.uuid(), client.id()); JwtClaims claims = new JwtClaims(); // required claims: - claims.setIssuer(config.issuer); // who creates the token and signs it + 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) From f5ceb77ea7ca0f14e10d9aed9fa528deedcb4952 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Sun, 20 Oct 2024 17:36:15 +0200 Subject: [PATCH 2/8] bugfix: removed duplicate protocol Signed-off-by: Stephan Richter --- .../src/main/java/de/srsoftware/oidc/app/Application.java | 2 +- .../java/de/srsoftware/oidc/backend/TokenController.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java b/de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java index a163862..9917a41 100644 --- a/de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java +++ b/de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java @@ -78,7 +78,7 @@ public class Application { new Forward(INDEX).bindPath(ROOT).on(server); new WellKnownController().bindPath(WELL_KNOWN, "/realms/oidc" + WELL_KNOWN).on(server); new UserController(mailConfig, sessionService, userService, staticPages).bindPath(API_USER).on(server); - var tokenControllerConfig = new TokenController.Configuration( 10); + var tokenControllerConfig = new TokenController.Configuration(10); new TokenController(authService, clientService, keyManager, userService, tokenControllerConfig).bindPath(API_TOKEN).on(server); new ClientController(authService, clientService, sessionService, userService).bindPath(API_CLIENT).on(server); new KeyStoreController(keyStore).bindPath(JWKS).on(server); 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 f9da058..46d0c32 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 @@ -115,7 +115,7 @@ public class TokenController extends PathHandler { var user = optUser.get(); var accessToken = users.accessToken(user); - var issuer = "https://"+hostname(ex); + var issuer = hostname(ex); String jwToken = createJWT(client, user, accessToken, issuer); ex.getResponseHeaders().add("Cache-Control", "no-store"); JSONObject response = new JSONObject(); @@ -173,8 +173,8 @@ public class TokenController extends PathHandler { JwtClaims claims = new JwtClaims(); // required claims: - claims.setIssuer(issuer); // who creates the token and signs it - claims.setSubject(user.uuid()); // the subject/principal is whom the token is about + 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.setIssuedAtToNow(); From bc3f016e1e84aa3d0984f119ca08c76d18263523 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Sun, 20 Oct 2024 17:46:01 +0200 Subject: [PATCH 3/8] improving authorization script Signed-off-by: Stephan Richter --- .../src/main/resources/en/scripts/authorization.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/de.srsoftware.oidc.web/src/main/resources/en/scripts/authorization.js b/de.srsoftware.oidc.web/src/main/resources/en/scripts/authorization.js index d88c4b9..e565373 100644 --- a/de.srsoftware.oidc.web/src/main/resources/en/scripts/authorization.js +++ b/de.srsoftware.oidc.web/src/main/resources/en/scripts/authorization.js @@ -84,4 +84,7 @@ function backendAutorization(){ }).then(handleResponse); } -backendAutorization(); +document.addEventListener("logged_in", function(event) { // wait until page loaded + backendAutorization(); +}); + From a10be0980876efb6ef5253a4cea92889901786b5 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Sun, 20 Oct 2024 19:37:29 +0200 Subject: [PATCH 4/8] added translation Signed-off-by: Stephan Richter --- .../main/resources/de/reset_password.template.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 de.srsoftware.oidc.web/src/main/resources/de/reset_password.template.txt diff --git a/de.srsoftware.oidc.web/src/main/resources/de/reset_password.template.txt b/de.srsoftware.oidc.web/src/main/resources/de/reset_password.template.txt new file mode 100644 index 0000000..2b77005 --- /dev/null +++ b/de.srsoftware.oidc.web/src/main/resources/de/reset_password.template.txt @@ -0,0 +1,12 @@ +Link zum Zurückseten des Passworts für {service} +Liebe(r) {displayname}, + +Jemand – wahrscheinlich du – beauftragte das Passwort für {service} zurückzusetzen. + +Falls du das warst öffne bitte den folgenden Link in deinem Browser: + +{link} + +Falls du das Zurücksetzen *nicht angefragt hast* (oder versehentlich), kannst du diese Mail einfach ignorieren. + +Beste Grüße, dein OIDC-Admin. \ No newline at end of file From db07cf1301a8d2d7a065d6f603bf80bd38462d6e Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Sun, 20 Oct 2024 19:48:25 +0200 Subject: [PATCH 5/8] sorting lists Signed-off-by: Stephan Richter --- .../main/java/de/srsoftware/oidc/backend/ClientController.java | 2 +- .../main/java/de/srsoftware/oidc/backend/UserController.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) 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..cac913c 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 @@ -182,7 +182,7 @@ public class ClientController extends Controller { if (optUser.isEmpty()) return invalidSessionUser(ex); if (!optUser.get().hasPermission(MANAGE_CLIENTS)) return sendEmptyResponse(HTTP_FORBIDDEN, ex); var json = new JSONObject(); - clients.listClients().forEach(client -> json.put(client.id(), client.map())); + clients.listClients().stream().sorted(Comparator.comparing(Client::name)).forEach(client -> json.put(client.id(), client.map())); return sendContent(ex, json); } diff --git a/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/UserController.java b/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/UserController.java index 52e945a..ea94c00 100644 --- a/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/UserController.java +++ b/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/UserController.java @@ -21,6 +21,7 @@ import jakarta.mail.*; import jakarta.mail.internet.*; import java.io.IOException; import java.time.Duration; +import java.util.Comparator; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -186,7 +187,7 @@ public class UserController extends Controller { private boolean list(HttpExchange ex, User user) throws IOException { if (!user.hasPermission(MANAGE_USERS)) return sendEmptyResponse(HTTP_FORBIDDEN, ex); var json = new JSONObject(); - users.list().forEach(u -> json.put(u.uuid(), u.map(false))); + users.list().stream().sorted(Comparator.comparing(User::username)).forEach(u -> json.put(u.uuid(), u.map(false))); return sendContent(ex, json); } From 8711b3e491becfcd557b204856b0f427ea6b14b4 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Sun, 20 Oct 2024 20:06:35 +0200 Subject: [PATCH 6/8] sorting lists Signed-off-by: Stephan Richter --- .../oidc/backend/ClientController.java | 2 +- .../oidc/backend/UserController.java | 2 +- .../src/main/resources/en/scripts/clients.js | 12 ++++++----- .../src/main/resources/en/scripts/users.js | 21 +++++++++++-------- 4 files changed, 21 insertions(+), 16 deletions(-) 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 cac913c..ae0ef54 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 @@ -182,7 +182,7 @@ public class ClientController extends Controller { if (optUser.isEmpty()) return invalidSessionUser(ex); if (!optUser.get().hasPermission(MANAGE_CLIENTS)) return sendEmptyResponse(HTTP_FORBIDDEN, ex); var json = new JSONObject(); - clients.listClients().stream().sorted(Comparator.comparing(Client::name)).forEach(client -> json.put(client.id(), client.map())); + clients.listClients().forEach(client -> json.put(client.id(), client.map())); return sendContent(ex, json); } diff --git a/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/UserController.java b/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/UserController.java index ea94c00..f915fe8 100644 --- a/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/UserController.java +++ b/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/UserController.java @@ -187,7 +187,7 @@ public class UserController extends Controller { private boolean list(HttpExchange ex, User user) throws IOException { if (!user.hasPermission(MANAGE_USERS)) return sendEmptyResponse(HTTP_FORBIDDEN, ex); var json = new JSONObject(); - users.list().stream().sorted(Comparator.comparing(User::username)).forEach(u -> json.put(u.uuid(), u.map(false))); + users.list().forEach(u -> json.put(u.uuid(), u.map(false))); return sendContent(ex, json); } diff --git a/de.srsoftware.oidc.web/src/main/resources/en/scripts/clients.js b/de.srsoftware.oidc.web/src/main/resources/en/scripts/clients.js index 23a000a..c0af9d6 100644 --- a/de.srsoftware.oidc.web/src/main/resources/en/scripts/clients.js +++ b/de.srsoftware.oidc.web/src/main/resources/en/scripts/clients.js @@ -8,17 +8,19 @@ function handleClients(response){ return; } var clients = response.json().then(clients => { + var arr = []; + for (let id in clients) arr.push(clients[id]); + arr.sort((a,b) => a.name < b.name ? -1 : 1); var bottom = document.getElementById('bottom'); - for (let id in clients){ + for (let client of arr){ var row = document.createElement("tr"); - var client = clients[id]; row.innerHTML = `${client.name} - ${id} + ${client.id} ${client.redirect_uris.join("
")} ${link(client.landing_page)} - - + + `; bottom.parentNode.insertBefore(row,bottom); } diff --git a/de.srsoftware.oidc.web/src/main/resources/en/scripts/users.js b/de.srsoftware.oidc.web/src/main/resources/en/scripts/users.js index 08a2670..b384050 100644 --- a/de.srsoftware.oidc.web/src/main/resources/en/scripts/users.js +++ b/de.srsoftware.oidc.web/src/main/resources/en/scripts/users.js @@ -39,10 +39,13 @@ function handleUsers(response){ return; } response.json().then(users => { + var arr = []; + for (let id in users) arr.push(users[id]); + arr.sort((a,b) => a.username < b.username ? -1 : 1); var bottom = document.getElementById('bottom'); - for (let id in users){ + for (var u of arr){ var row = document.createElement("tr"); - var u = users[id]; + //var u = users[id]; var manage = { clients : u.permissions.includes('MANAGE_CLIENTS'), perms : u.permissions.includes('MANAGE_PERMISSIONS'), @@ -52,16 +55,16 @@ function handleUsers(response){ row.innerHTML = `${u.username} ${u.realname} ${u.email} - ${id} + ${u.uuid} - - - - + + + + - - + + `; bottom.parentNode.insertBefore(row,bottom); if (user.permissions.includes('MANAGE_PERMISSIONS')) showAll('permissions'); From f60cdf75c99ddb179c87cd9190903a37257b5700 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Sun, 20 Oct 2024 20:27:53 +0200 Subject: [PATCH 7/8] extended translation Signed-off-by: Stephan Richter --- .../src/main/resources/de/authorization.html | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 de.srsoftware.oidc.web/src/main/resources/de/authorization.html diff --git a/de.srsoftware.oidc.web/src/main/resources/de/authorization.html b/de.srsoftware.oidc.web/src/main/resources/de/authorization.html new file mode 100644 index 0000000..0533750 --- /dev/null +++ b/de.srsoftware.oidc.web/src/main/resources/de/authorization.html @@ -0,0 +1,42 @@ + + + + Light OIDC + + + + + + + + + + + + +
+ Fehlender Rückgabe-Typ: code +
+ + + + \ No newline at end of file From 41466943eb5bd93fa948c486ca7253b33767c835 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Sun, 20 Oct 2024 20:32:36 +0200 Subject: [PATCH 8/8] bugfix Signed-off-by: Stephan Richter --- .../src/main/resources/en/scripts/clients.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/de.srsoftware.oidc.web/src/main/resources/en/scripts/clients.js b/de.srsoftware.oidc.web/src/main/resources/en/scripts/clients.js index c0af9d6..1739337 100644 --- a/de.srsoftware.oidc.web/src/main/resources/en/scripts/clients.js +++ b/de.srsoftware.oidc.web/src/main/resources/en/scripts/clients.js @@ -15,12 +15,12 @@ function handleClients(response){ for (let client of arr){ var row = document.createElement("tr"); row.innerHTML = `${client.name} - ${client.id} + ${client.client_id} ${client.redirect_uris.join("
")} ${link(client.landing_page)} - - + + `; bottom.parentNode.insertBefore(row,bottom); }