Browse Source

added landing page to client properties

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
sqlite
Stephan Richter 2 months ago
parent
commit
2250a78e91
  1. 1
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/Constants.java
  2. 25
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/data/Client.java
  3. 12
      de.srsoftware.oidc.api/src/test/java/de/srsoftware/oidc/api/ClientServiceTest.java
  4. 5
      de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/ClientController.java
  5. 4
      de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/TokenController.java
  6. 13
      de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/FileStore.java
  7. 29
      de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteClientService.java
  8. 2
      de.srsoftware.oidc.web/src/main/resources/en/clients.html
  9. 12
      de.srsoftware.oidc.web/src/main/resources/en/edit_client.html
  10. 16
      de.srsoftware.oidc.web/src/main/resources/en/new_client.html
  11. 5
      de.srsoftware.oidc.web/src/main/resources/en/scripts/clients.js
  12. 5
      de.srsoftware.oidc.web/src/main/resources/en/scripts/edit_client.js
  13. 3
      de.srsoftware.oidc.web/src/main/resources/en/scripts/new_client.js

1
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 = "invalid_request";
public static final String INVALID_REQUEST_OBJECT = "invalid_request_object"; public static final String INVALID_REQUEST_OBJECT = "invalid_request_object";
public static final String INVALID_SCOPE = "invalid_scope"; 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 MAILCONFIG = "mail_config";
public static final String NAME = "name"; public static final String NAME = "name";
public static final String NONCE = "nonce"; public static final String NONCE = "nonce";

25
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.oidc.api.Constants.*;
import static de.srsoftware.utils.Optionals.nullable;
import java.util.*; import java.util.*;
public final class Client { public final class Client {
private static System.Logger LOG = System.getLogger(Client.class.getSimpleName()); 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<String> redirectUris; private final Set<String> redirectUris;
public Client(String id, String name, String secret, Set<String> redirectUris) { public Client(String id, String name, String secret, Set<String> redirectUris) {
this.id = id; this.id = id;
landingPage = null;
this.name = name; this.name = name;
this.secret = secret; this.secret = secret;
this.redirectUris = redirectUris; this.redirectUris = redirectUris;
@ -22,8 +27,23 @@ public final class Client {
return id; return id;
} }
public String landingPage() {
return landingPage;
}
public Client landingPage(String newVal) {
landingPage = newVal;
return this;
}
public Map<String, Object> map() { public Map<String, Object> map() {
return Map.of(CLIENT_ID, id, NAME, name, SECRET, secret, REDIRECT_URIS, redirectUris); var map = new HashMap<String, Object>();
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() { public String toString() {
return "Client[" return "Client["
+ "id=" + id + ", " + "id=" + id + ", "
+ "landing_page=" + landingPage + ", "
+ "name=" + name + ", " + "name=" + name + ", "
+ "secret=" + secret + ", " + "secret=" + secret + ", "
+ "redirectUris=" + redirectUris + ']'; + "redirectUris=" + redirectUris + ']';

12
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()); assertTrue(cs.listClients().isEmpty());
var clientId = uuid(); var clientId = uuid();
var clientSecret = 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(); var list = cs.save(client).listClients();
assertEquals(1, list.size()); assertEquals(1, list.size());
assertTrue(list.contains(client)); assertTrue(list.contains(client));
@ -35,7 +36,8 @@ public abstract class ClientServiceTest {
var cs = clientService(); var cs = clientService();
var clientId = uuid(); var clientId = uuid();
var clientSecret = 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); var optClient = cs.save(client).getClient(clientId);
assertTrue(optClient.isPresent()); assertTrue(optClient.isPresent());
assertEquals(client, optClient.get()); assertEquals(client, optClient.get());
@ -49,8 +51,10 @@ public abstract class ClientServiceTest {
var clientId = uuid(); var clientId = uuid();
var clientSecret = uuid(); var clientSecret = uuid();
var clientSecret2 = uuid(); var clientSecret2 = uuid();
var client1 = new Client(clientId, NAME, clientSecret, Set.of(URI)); var landingPage1 = uuid();
var client2 = new Client(clientId, "test", clientSecret2, Set.of(URI2));
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); var optClient = cs.save(client1).getClient(clientId);
assertTrue(optClient.isPresent()); assertTrue(optClient.isPresent());

5
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.isEmpty()) return invalidSessionUser(ex);
if (!optUser.get().hasPermission(MANAGE_CLIENTS)) return sendEmptyResponse(HTTP_FORBIDDEN, ex); if (!optUser.get().hasPermission(MANAGE_CLIENTS)) return sendEmptyResponse(HTTP_FORBIDDEN, ex);
var json = new JSONObject(); 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); return sendContent(ex, json);
} }
@ -188,7 +188,8 @@ public class ClientController extends Controller {
for (Object o : json.getJSONArray(REDIRECT_URIS)) { for (Object o : json.getJSONArray(REDIRECT_URIS)) {
if (o instanceof String s) redirects.add(s); 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); clients.save(client);
return sendContent(ex, client); return sendContent(ex, client);
} }

4
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) { private JwtClaims createIdTokenClaims(User user, Client client, String atHash) {
var optNonce = authorizations.consumeNonce(user.uuid(), client.id()); var optNonce = authorizations.consumeNonce(user.uuid(), client.id());
JwtClaims claims = new JwtClaims(); JwtClaims claims = new JwtClaims();
// required claims: // required claims:
claims.setIssuer(config.issuer); // who creates the token and signs it claims.setIssuer(config.issuer); // who creates the token and signs it

13
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 @Override
public ClientService save(Client client) { public ClientService save(Client client) {
if (!json.has(CLIENTS)) json.put(CLIENTS, new JSONObject()); 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(); save();
return this; return this;
} }
private Client toClient(String clientId, JSONObject clientData) { private Client toClient(String clientId, JSONObject clientData) {
var redirectUris = new HashSet<String>(); var redirectUris = new HashSet<String>();
for (var o : clientData.getJSONArray(REDIRECT_URIS)) { if (clientData.has(REDIRECT_URIS))
if (o instanceof String s) redirectUris.add(s); 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); }
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 ***/ /*** AuthorizationService methods ***/

29
de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteClientService.java

@ -1,8 +1,7 @@
/* © SRSoftware 2024 */ /* © SRSoftware 2024 */
package de.srsoftware.oidc.datastore.sqlite; package de.srsoftware.oidc.datastore.sqlite;
import static de.srsoftware.oidc.api.Constants.NAME; import static de.srsoftware.oidc.api.Constants.*;
import static de.srsoftware.oidc.api.Constants.SECRET;
import de.srsoftware.oidc.api.ClientService; import de.srsoftware.oidc.api.ClientService;
import de.srsoftware.oidc.api.data.Client; 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 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 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 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 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 DROP_OTHER_REDIRECTS = "DELETE FROM client_redirects WHERE clientId = ? AND uri NOT IN";
private static final String SELECT_CLIENT = "SELECT * FROM clients WHERE id = ?"; 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); stmt.setString(1, clientId);
rs = stmt.executeQuery(); rs = stmt.executeQuery();
if (rs.next()) { if (rs.next()) {
var name = rs.getString(NAME); var name = rs.getString(NAME);
var secret = rs.getString(SECRET); var secret = rs.getString(SECRET);
result = Optional.of(new Client(clientId, name, secret, uris)); var landing = rs.getString(LANDING_PAGE);
result = Optional.of(new Client(clientId, name, secret, uris).landingPage(landing));
} }
rs.close(); rs.close();
return result; return result;
@ -115,10 +115,11 @@ public class SqliteClientService extends SqliteStore implements ClientService {
rs = stmt.executeQuery(); rs = stmt.executeQuery();
var result = new ArrayList<Client>(); var result = new ArrayList<Client>();
while (rs.next()) { while (rs.next()) {
var id = rs.getString("id"); var id = rs.getString("id");
var name = rs.getString(NAME); var name = rs.getString(NAME);
var secret = rs.getString(SECRET); var secret = rs.getString(SECRET);
result.add(new Client(id, name, secret, redirects.get(id))); var landing = rs.getString(LANDING_PAGE);
result.add(new Client(id, name, secret, redirects.get(id)).landingPage(landing));
} }
rs.close(); rs.close();
return result; return result;
@ -149,8 +150,10 @@ public class SqliteClientService extends SqliteStore implements ClientService {
stmt.setString(1, client.id()); stmt.setString(1, client.id());
stmt.setString(2, client.name()); stmt.setString(2, client.name());
stmt.setString(3, client.secret()); stmt.setString(3, client.secret());
stmt.setString(4, client.name()); stmt.setString(4, client.landingPage());
stmt.setString(5, client.secret()); stmt.setString(5, client.name());
stmt.setString(6, client.secret());
stmt.setString(7, client.landingPage());
stmt.execute(); stmt.execute();
stmt = conn.prepareStatement(SAVE_REDIRECT); stmt = conn.prepareStatement(SAVE_REDIRECT);
stmt.setString(1, client.id()); stmt.setString(1, client.id());

2
de.srsoftware.oidc.web/src/main/resources/en/clients.html

@ -19,9 +19,11 @@
<th>Client</th> <th>Client</th>
<th>ID</th> <th>ID</th>
<th>Redirect URLs</th> <th>Redirect URLs</th>
<th>Landing page</th>
<th>Actions</th> <th>Actions</th>
</tr> </tr>
<tr id="bottom"> <tr id="bottom">
<td></td>
<td></td> <td></td>
<td></td> <td></td>
<td> <td>

12
de.srsoftware.oidc.web/src/main/resources/en/edit_client.html

@ -15,14 +15,14 @@
<fieldset class="wide"> <fieldset class="wide">
<legend>Data</legend> <legend>Data</legend>
<table> <table>
<tr>
<th>ID</th>
<td><input type="text" disabled="true" id="client-id" /></td>
</tr>
<tr> <tr>
<th>Name</th> <th>Name</th>
<td><input type="text" id="client-name" /></td> <td><input type="text" id="client-name" /></td>
</tr> </tr>
<tr>
<th>ID</th>
<td><input type="text" disabled="true" id="client-id" /></td>
</tr>
<tr> <tr>
<th>Secret</th> <th>Secret</th>
<td><input type="text" id="client-secret" /></td> <td><input type="text" id="client-secret" /></td>
@ -33,6 +33,10 @@
<textarea id="redirect-urls"></textarea> <textarea id="redirect-urls"></textarea>
</td> </td>
</tr> </tr>
<tr>
<th>Landing page</th>
<td><input type="text" id="landing-page" /></td>
</tr>
<tr> <tr>
<td></td> <td></td>
<td><button type="button" id="button" onclick="updateClient();">Update</button></td> <td><button type="button" id="button" onclick="updateClient();">Update</button></td>

16
de.srsoftware.oidc.web/src/main/resources/en/new_client.html

@ -17,21 +17,25 @@
<legend>Settings</legend> <legend>Settings</legend>
<table> <table>
<tr> <tr>
<th>client id</th> <th>Client Name</th>
<td><input type="text" size="50" id="client-id"></td> <td><input type="text" size="50" id="client-name"></td>
</tr> </tr>
<tr> <tr>
<th>client name</th> <th>Client ID</th>
<td><input type="text" size="50" id="client-name"></td> <td><input type="text" size="50" id="client-id"></td>
</tr> </tr>
<tr> <tr>
<th>client secret</th> <th>Client Secret</th>
<td><input type="text" size="50" id="client-secret"></td> <td><input type="text" size="50" id="client-secret"></td>
</tr> </tr>
<tr> <tr>
<th>redirect urls</th> <th>Redirect URLs</th>
<td><textarea cols="50" rows="5" id="redirect-urls"></textarea></td> <td><textarea cols="50" rows="5" id="redirect-urls"></textarea></td>
</tr> </tr>
<tr>
<th>Landing page</th>
<td><input type="text" size="50" id="landing-page" /></td>
</tr>
<tr> <tr>
<td></td> <td></td>
<td><button id="button" type="button" onclick="addClient()">Add client</button></td> <td><button id="button" type="button" onclick="addClient()">Add client</button></td>

5
de.srsoftware.oidc.web/src/main/resources/en/scripts/clients.js

@ -15,6 +15,7 @@ function handleClients(response){
row.innerHTML = `<td>${client.name}</td> row.innerHTML = `<td>${client.name}</td>
<td>${id}</td> <td>${id}</td>
<td>${client.redirect_uris.join("<br/>")}</td> <td>${client.redirect_uris.join("<br/>")}</td>
<td>${link(client.landing_page)}</td>
<td> <td>
<button type="button" onclick="edit('${id}')">Edit</button> <button type="button" onclick="edit('${id}')">Edit</button>
<button class="danger" onclick="remove('${id}')" type="button">Remove</button> <button class="danger" onclick="remove('${id}')" type="button">Remove</button>
@ -24,6 +25,10 @@ function handleClients(response){
}); });
} }
function link(url){
return url ? '<a href="'+url+'">'+url.split('?')[0]+'</a>': "";
}
function handleRemove(response){ function handleRemove(response){
redirect("clients.html"); redirect("clients.html");
} }

5
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-name').value = json.name;
get('client-secret').value = json.secret; get('client-secret').value = json.secret;
get('redirect-urls').value = json.redirect_uris.join("\n"); 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) { if (response.ok) {
enable('button'); enable('button');
setText('button','saved.'); setText('button','saved.');
redirect('clients.html');
} }
} }
@ -32,7 +34,8 @@ function updateClient(){
client_id : getValue('client-id'), client_id : getValue('client-id'),
name : getValue('client-name'), name : getValue('client-name'),
secret : getValue('client-secret'), 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',{ fetch(client_controller+'/update',{
method : 'POST', method : 'POST',

3
de.srsoftware.oidc.web/src/main/resources/en/scripts/new_client.js

@ -4,7 +4,8 @@ function addClient(){
client_id : getValue('client-id'), client_id : getValue('client-id'),
name : getValue('client-name'), name : getValue('client-name'),
secret : getValue('client-secret'), 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',{ fetch(client_controller+'/add',{
method : 'POST', method : 'POST',

Loading…
Cancel
Save