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 75b51fe..d2ce230 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 @@ -29,6 +29,7 @@ public class Constants { public static final String INVALID_REQUEST = "invalid_request"; public static final String INVALID_REQUEST_OBJECT = "invalid_request_object"; public static final String INVALID_SCOPE = "invalid_scope"; + public static final String LANDING_PAGE = "landing_page"; public static final String MAILCONFIG = "mail_config"; public static final String NAME = "name"; public static final String NONCE = "nonce"; 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 ac9ef24..ff87307 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 @@ -3,16 +3,21 @@ package de.srsoftware.oidc.api.data; import static de.srsoftware.oidc.api.Constants.*; +import static de.srsoftware.utils.Optionals.nullable; import java.util.*; public final class Client { private static System.Logger LOG = System.getLogger(Client.class.getSimpleName()); - private final String id, name, secret; + private final String id; + private String landingPage; + private final String name; + private final String secret; private final Set redirectUris; public Client(String id, String name, String secret, Set redirectUris) { this.id = id; + landingPage = null; this.name = name; this.secret = secret; this.redirectUris = redirectUris; @@ -22,8 +27,23 @@ public final class Client { return id; } + public String landingPage() { + return landingPage; + } + + public Client landingPage(String newVal) { + landingPage = newVal; + return this; + } + public Map map() { - return Map.of(CLIENT_ID, id, NAME, name, SECRET, secret, REDIRECT_URIS, redirectUris); + var map = new HashMap(); + map.put(CLIENT_ID, id); + map.put(NAME, name); + map.put(SECRET, secret); + nullable(redirectUris).ifPresent(uris -> map.put(REDIRECT_URIS, uris)); + nullable(landingPage).ifPresent(lp -> map.put(LANDING_PAGE, lp)); + return map; } @@ -57,6 +77,7 @@ public final class Client { public String toString() { return "Client[" + "id=" + id + ", " + + "landing_page=" + landingPage + ", " + "name=" + name + ", " + "secret=" + secret + ", " + "redirectUris=" + redirectUris + ']'; 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 8984b5a..7da9747 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 @@ -22,7 +22,8 @@ public abstract class ClientServiceTest { assertTrue(cs.listClients().isEmpty()); var clientId = uuid(); var clientSecret = uuid(); - var client = new Client(clientId, NAME, clientSecret, Set.of(URI)); + var landingPage = uuid(); + var client = new Client(clientId, NAME, clientSecret, Set.of(URI)).landingPage(landingPage); var list = cs.save(client).listClients(); assertEquals(1, list.size()); assertTrue(list.contains(client)); @@ -35,7 +36,8 @@ public abstract class ClientServiceTest { var cs = clientService(); var clientId = uuid(); var clientSecret = uuid(); - var client = new Client(clientId, NAME, clientSecret, Set.of(URI)); + var landingPage = uuid(); + var client = new Client(clientId, NAME, clientSecret, Set.of(URI)).landingPage(landingPage); var optClient = cs.save(client).getClient(clientId); assertTrue(optClient.isPresent()); assertEquals(client, optClient.get()); @@ -49,8 +51,10 @@ public abstract class ClientServiceTest { var clientId = uuid(); var clientSecret = uuid(); var clientSecret2 = uuid(); - var client1 = new Client(clientId, NAME, clientSecret, Set.of(URI)); - var client2 = new Client(clientId, "test", clientSecret2, Set.of(URI2)); + var landingPage1 = uuid(); + + var client1 = new Client(clientId, NAME, clientSecret, Set.of(URI)).landingPage(landingPage1); + var client2 = new Client(clientId, "test", clientSecret2, Set.of(URI2)); var optClient = cs.save(client1).getClient(clientId); assertTrue(optClient.isPresent()); 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 c5ccfc0..40103aa 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 @@ -161,7 +161,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(), Map.of("name", client.name(), "redirect_uris", client.redirectUris()))); + clients.listClients().forEach(client -> json.put(client.id(), client.map())); return sendContent(ex, json); } @@ -188,7 +188,8 @@ public class ClientController extends Controller { for (Object o : json.getJSONArray(REDIRECT_URIS)) { if (o instanceof String s) redirects.add(s); } - var client = new Client(json.getString(CLIENT_ID), json.getString(NAME), json.getString(SECRET), redirects); + 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); 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 db3f37b..f5f8f83 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 @@ -168,8 +168,8 @@ public class TokenController extends PathHandler { } private JwtClaims createIdTokenClaims(User user, Client client, String atHash) { - var optNonce = authorizations.consumeNonce(user.uuid(), client.id()); - JwtClaims claims = new JwtClaims(); + 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 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 d4c203a..df1cdb3 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 @@ -298,17 +298,20 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe @Override public ClientService save(Client client) { if (!json.has(CLIENTS)) json.put(CLIENTS, new JSONObject()); - json.getJSONObject(CLIENTS).put(client.id(), Map.of(NAME, client.name(), SECRET, client.secret(), REDIRECT_URIS, client.redirectUris())); + json.getJSONObject(CLIENTS).put(client.id(), client.map()); save(); return this; } private Client toClient(String clientId, JSONObject clientData) { var redirectUris = new HashSet(); - for (var o : clientData.getJSONArray(REDIRECT_URIS)) { - if (o instanceof String s) redirectUris.add(s); - } - return new Client(clientId, clientData.getString(NAME), clientData.getString(SECRET), redirectUris); + if (clientData.has(REDIRECT_URIS)) + for (var o : clientData.getJSONArray(REDIRECT_URIS)) { + if (o instanceof String s) redirectUris.add(s); + } + var client = new Client(clientId, clientData.getString(NAME), clientData.getString(SECRET), redirectUris); + if (clientData.has(LANDING_PAGE)) client.landingPage(clientData.getString(LANDING_PAGE)); + return client; } /*** AuthorizationService methods ***/ diff --git a/de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteClientService.java b/de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteClientService.java index 8d409ee..cf92fed 100644 --- a/de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteClientService.java +++ b/de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteClientService.java @@ -1,8 +1,7 @@ /* © SRSoftware 2024 */ package de.srsoftware.oidc.datastore.sqlite; -import static de.srsoftware.oidc.api.Constants.NAME; -import static de.srsoftware.oidc.api.Constants.SECRET; +import static de.srsoftware.oidc.api.Constants.*; import de.srsoftware.oidc.api.ClientService; import de.srsoftware.oidc.api.data.Client; @@ -17,9 +16,9 @@ public class SqliteClientService extends SqliteStore implements ClientService { private static final String SELECT_STORE_VERSION = "SELECT * FROM metainfo WHERE key = '" + STORE_VERSION + "'"; private static final String SET_STORE_VERSION = "UPDATE metainfo SET value = ? WHERE key = '" + STORE_VERSION + "'"; - private static final String CREATE_CLIENT_TABLE = "CREATE TABLE IF NOT EXISTS clients(id VARCHAR(255) NOT NULL PRIMARY KEY, name VARCHAR(255), secret VARCHAR(255));"; + private static final String CREATE_CLIENT_TABLE = "CREATE TABLE IF NOT EXISTS clients(id VARCHAR(255) NOT NULL PRIMARY KEY, name VARCHAR(255), secret VARCHAR(255), landing_page VARCHAR(255));"; private static final String CREATE_REDIRECT_TABLE = "CREATE TABLE IF NOT EXISTS client_redirects(clientId VARCHAR(255), uri VARCHAR(255), PRIMARY KEY(clientId, uri));"; - private static final String SAVE_CLIENT = "INSERT INTO clients (id, name, secret) VALUES (?,?,?) ON CONFLICT DO UPDATE SET name = ?, secret = ?;"; + private static final String SAVE_CLIENT = "INSERT INTO clients (id, name, secret, landing_page) VALUES (?,?,?,?) ON CONFLICT DO UPDATE SET name = ?, secret = ?, landing_page = ?;"; private static final String SAVE_REDIRECT = "INSERT OR IGNORE INTO client_redirects(clientId, uri) VALUES (?, ?)"; private static final String DROP_OTHER_REDIRECTS = "DELETE FROM client_redirects WHERE clientId = ? AND uri NOT IN"; private static final String SELECT_CLIENT = "SELECT * FROM clients WHERE id = ?"; @@ -87,9 +86,10 @@ public class SqliteClientService extends SqliteStore implements ClientService { stmt.setString(1, clientId); rs = stmt.executeQuery(); if (rs.next()) { - var name = rs.getString(NAME); - var secret = rs.getString(SECRET); - result = Optional.of(new Client(clientId, name, secret, uris)); + var name = rs.getString(NAME); + var secret = rs.getString(SECRET); + var landing = rs.getString(LANDING_PAGE); + result = Optional.of(new Client(clientId, name, secret, uris).landingPage(landing)); } rs.close(); return result; @@ -115,10 +115,11 @@ public class SqliteClientService extends SqliteStore implements ClientService { rs = stmt.executeQuery(); var result = new ArrayList(); while (rs.next()) { - var id = rs.getString("id"); - var name = rs.getString(NAME); - var secret = rs.getString(SECRET); - result.add(new Client(id, name, secret, redirects.get(id))); + var id = rs.getString("id"); + var name = rs.getString(NAME); + var secret = rs.getString(SECRET); + var landing = rs.getString(LANDING_PAGE); + result.add(new Client(id, name, secret, redirects.get(id)).landingPage(landing)); } rs.close(); return result; @@ -149,8 +150,10 @@ public class SqliteClientService extends SqliteStore implements ClientService { stmt.setString(1, client.id()); stmt.setString(2, client.name()); stmt.setString(3, client.secret()); - stmt.setString(4, client.name()); - stmt.setString(5, client.secret()); + stmt.setString(4, client.landingPage()); + stmt.setString(5, client.name()); + stmt.setString(6, client.secret()); + stmt.setString(7, client.landingPage()); stmt.execute(); stmt = conn.prepareStatement(SAVE_REDIRECT); stmt.setString(1, client.id()); diff --git a/de.srsoftware.oidc.web/src/main/resources/en/clients.html b/de.srsoftware.oidc.web/src/main/resources/en/clients.html index f31ca58..62dd211 100644 --- a/de.srsoftware.oidc.web/src/main/resources/en/clients.html +++ b/de.srsoftware.oidc.web/src/main/resources/en/clients.html @@ -19,9 +19,11 @@ Client ID Redirect URLs + Landing page Actions + 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 decfc45..58e90d0 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 @@ -15,14 +15,14 @@
Data - - - - + + + + @@ -33,6 +33,10 @@ + + + + diff --git a/de.srsoftware.oidc.web/src/main/resources/en/new_client.html b/de.srsoftware.oidc.web/src/main/resources/en/new_client.html index 7f1f1db..abe0305 100644 --- a/de.srsoftware.oidc.web/src/main/resources/en/new_client.html +++ b/de.srsoftware.oidc.web/src/main/resources/en/new_client.html @@ -17,21 +17,25 @@ Settings
ID
Name
ID
Secret
Landing page
- - + + - - + + - + - + + + + + 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 31df4ec..7fe0331 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,6 +15,7 @@ function handleClients(response){ row.innerHTML = ` +
client idClient Name
client nameClient ID
client secretClient Secret
redirect urlsRedirect URLs
Landing page
${client.name} ${id} ${client.redirect_uris.join("
")}
${link(client.landing_page)} @@ -24,6 +25,10 @@ function handleClients(response){ }); } +function link(url){ + return url ? ''+url.split('?')[0]+'': ""; +} + function handleRemove(response){ redirect("clients.html"); } 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 4cdeee2..8d1bc49 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 @@ -9,6 +9,7 @@ function handleLoadResponse(response){ get('client-name').value = json.name; 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:''; }); } } @@ -17,6 +18,7 @@ function handleUpdateResponse(response){ if (response.ok) { enable('button'); setText('button','saved.'); + redirect('clients.html'); } } @@ -32,7 +34,8 @@ function updateClient(){ client_id : getValue('client-id'), name : getValue('client-name'), secret : getValue('client-secret'), - redirect_uris : getValue('redirect-urls').split("\n") + redirect_uris : getValue('redirect-urls').split("\n"), + landing_page : getValue('landing-page') }; fetch(client_controller+'/update',{ method : 'POST', diff --git a/de.srsoftware.oidc.web/src/main/resources/en/scripts/new_client.js b/de.srsoftware.oidc.web/src/main/resources/en/scripts/new_client.js index 625e8e8..3cbb4d1 100644 --- a/de.srsoftware.oidc.web/src/main/resources/en/scripts/new_client.js +++ b/de.srsoftware.oidc.web/src/main/resources/en/scripts/new_client.js @@ -4,7 +4,8 @@ function addClient(){ client_id : getValue('client-id'), name : getValue('client-name'), secret : getValue('client-secret'), - redirect_uris : getValue('redirect-urls').split("\n") + redirect_uris : getValue('redirect-urls').split("\n"), + landing_page : getValue('landing-page') }; fetch(client_controller+'/add',{ method : 'POST',