From 2158d62da163e740f974cb75e8024b6b174f84df Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Mon, 22 Jul 2024 20:55:35 +0200 Subject: [PATCH] implemented client removal Signed-off-by: Stephan Richter --- .../de/srsoftware/oidc/api/Constants.java | 9 ++-- .../de/srsoftware/oidc/api/PathHandler.java | 9 +++- .../de/srsoftware/oidc/backend/Backend.java | 37 ++++++++++++--- .../oidc/datastore/file/FileStore.java | 46 ++++++++++--------- .../src/main/resources/en/clients.html | 12 +++-- .../src/main/resources/en/clients.js | 23 +++++++++- .../src/main/resources/en/style.css | 4 ++ 7 files changed, 103 insertions(+), 37 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 43e7b30..ef8d022 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 @@ -1,8 +1,9 @@ +/* © SRSoftware 2024 */ package de.srsoftware.oidc.api; public class Constants { - public static final String CLIENT_ID = "client_id"; - public static final String NAME = "name"; - public static final String REDIRECT_URI = "redirect_uri"; - public static final String SECRET = "secret"; + public static final String CLIENT_ID = "client_id"; + public static final String NAME = "name"; + public static final String REDIRECT_URI = "redirect_uri"; + public static final String SECRET = "secret"; } diff --git a/de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/PathHandler.java b/de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/PathHandler.java index 8e2b06a..42e0b1c 100644 --- a/de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/PathHandler.java +++ b/de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/PathHandler.java @@ -17,6 +17,7 @@ import org.json.JSONObject; public abstract class PathHandler implements HttpHandler { public static final String CONTENT_TYPE = "Content-Type"; + public static final String DELETE = "DELETE"; public static final String GET = "GET"; public static final String JSON = "application/json"; public static final String POST = "POST"; @@ -37,9 +38,14 @@ public abstract class PathHandler implements HttpHandler { return new Bond(path); } + public boolean doDelete(String path, HttpExchange ex) throws IOException { + return false; + } + public boolean doGet(String path, HttpExchange ex) throws IOException { return false; } + public boolean doPost(String path, HttpExchange ex) throws IOException { return false; } @@ -50,8 +56,9 @@ public abstract class PathHandler implements HttpHandler { String method = ex.getRequestMethod(); System.out.printf("%s %s\n", method, path); boolean dummy = switch (method) { - case POST -> doPost(path,ex); + case DELETE -> doDelete(path,ex); case GET -> doGet(path,ex); + case POST -> doPost(path,ex); default -> false; }; ex.getResponseBody().close(); diff --git a/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/Backend.java b/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/Backend.java index 1cb95b7..8780d10 100644 --- a/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/Backend.java +++ b/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/Backend.java @@ -1,9 +1,9 @@ /* © SRSoftware 2024 */ package de.srsoftware.oidc.backend; +import static de.srsoftware.oidc.api.Constants.*; import static de.srsoftware.oidc.api.Permission.MANAGE_CLIENTS; import static de.srsoftware.oidc.api.User.*; -import static de.srsoftware.oidc.api.Constants.*; import static java.net.HttpURLConnection.*; import com.sun.net.httpserver.HttpExchange; @@ -27,14 +27,15 @@ public class Backend extends PathHandler { } private boolean addClient(HttpExchange ex, Session session) throws IOException { - var json = json(ex); + if (!session.user().hasPermission(MANAGE_CLIENTS)) return sendError(ex, "NOT ALLOWED"); + var json = json(ex); var redirects = new HashSet(); - for (Object o : json.getJSONArray(REDIRECT_URI)){ + for (Object o : json.getJSONArray(REDIRECT_URI)) { if (o instanceof String s) redirects.add(s); } - var client = new Client(json.getString(CLIENT_ID),json.getString(NAME),json.getString(SECRET),redirects); + var client = new Client(json.getString(CLIENT_ID), json.getString(NAME), json.getString(SECRET), redirects); clients.add(client); - return sendContent(ex,client); + return sendContent(ex, client); } private boolean authorize(HttpExchange ex, Session session) throws IOException { @@ -53,6 +54,14 @@ public class Backend extends PathHandler { return sendContent(ex, json); } + private boolean deleteClient(HttpExchange ex, Session session) throws IOException { + if (!session.user().hasPermission(MANAGE_CLIENTS)) return sendError(ex, "NOT ALLOWED"); + var json = json(ex); + var id = json.getString(CLIENT_ID); + clients.getClient(id).ifPresent(clients::remove); + return sendEmptyResponse(HTTP_OK,ex); + } + private boolean doLogin(HttpExchange ex) throws IOException { var body = json(ex); @@ -64,6 +73,22 @@ public class Backend extends PathHandler { return sendEmptyResponse(HTTP_UNAUTHORIZED, ex); } + @Override + public boolean doDelete(String path, HttpExchange ex) throws IOException { + var optSession = getSession(ex); + if (optSession.isEmpty()) return sendEmptyResponse(HTTP_UNAUTHORIZED, ex); + + // post-login paths + var session = optSession.get(); + switch (path) { + case "/client": + return deleteClient(ex, session); + } + + System.err.println("not implemented"); + return sendEmptyResponse(HTTP_NOT_FOUND, ex); + } + @Override public boolean doGet(String path, HttpExchange ex) throws IOException { // pre-login paths @@ -100,7 +125,7 @@ public class Backend extends PathHandler { var session = optSession.get(); switch (path) { case "/add/client": - return addClient(ex,session); + return addClient(ex, session); case "/authorize": return authorize(ex, session); case "/clients": 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 043ce34..c0b2cd0 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 @@ -1,6 +1,5 @@ /* © SRSoftware 2024 */ package de.srsoftware.oidc.datastore.file; /* © SRSoftware 2024 */ -import static de.srsoftware.oidc.api.Constants.CLIENT_ID; import static de.srsoftware.oidc.api.User.*; import de.srsoftware.oidc.api.*; @@ -16,14 +15,14 @@ import java.util.*; import org.json.JSONObject; public class FileStore implements ClientService, SessionService, UserService { - private static final String CLIENTS = "clients"; - private static final String EXPIRATION = "expiration"; - private static final String NAME = "name"; + private static final String CLIENTS = "clients"; + private static final String EXPIRATION = "expiration"; + private static final String NAME = "name"; private static final String REDIRECT_URIS = "redirect_uris"; - private static final String SECRET = "secret"; - private static final String SESSIONS = "sessions"; - private static final String USERS = "users"; - private static final String USER = "user"; + private static final String SECRET = "secret"; + private static final String SESSIONS = "sessions"; + private static final String USERS = "users"; + private static final String USER = "user"; private final Path storageFile; private final JSONObject json; @@ -200,35 +199,40 @@ public class FileStore implements ClientService, SessionService, UserService { @Override public ClientService add(Client client) { - json.getJSONObject(CLIENTS).put(client.id(), Map.of(NAME,client.name(),SECRET,client.secret(),REDIRECT_URIS,client.redirectUris())); + json.getJSONObject(CLIENTS).put(client.id(), Map.of(NAME, client.name(), SECRET, client.secret(), REDIRECT_URIS, client.redirectUris())); save(); return this; } @Override public Optional getClient(String clientId) { + var clients = json.getJSONObject(CLIENTS); + if (clients.has(clientId)) return Optional.of(toClient(clientId,clients.getJSONObject(clientId))); return Optional.empty(); } + 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); + + } + @Override public List listClients() { var clients = json.getJSONObject(CLIENTS); - var list = new ArrayList(); - for (var clientId : clients.keySet()){ - var clientData = clients.getJSONObject(clientId); - var redirectUris = new HashSet(); - 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); - list.add(client); - } + var list = new ArrayList(); + for (var clientId : clients.keySet()) list.add(toClient(clientId,clients.getJSONObject(clientId))); return list; } @Override - public ClientService remove(Client client) { - return null; + public FileStore remove(Client client) { + var clients = json.getJSONObject(CLIENTS); + if (clients.has(client.id())) clients.remove(client.id()); + return save(); } @Override 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 e4cefba..3b08473 100644 --- a/de.srsoftware.oidc.web/src/main/resources/en/clients.html +++ b/de.srsoftware.oidc.web/src/main/resources/en/clients.html @@ -11,19 +11,25 @@ -

Welcome!

-

Clients

+

Clients

+ These are clients that are registered with LightOIDC: + + - + + + +
ClientIDRedirect URLs Actions
+ \ No newline at end of file diff --git a/de.srsoftware.oidc.web/src/main/resources/en/clients.js b/de.srsoftware.oidc.web/src/main/resources/en/clients.js index 7f6cbf0..2f4108f 100644 --- a/de.srsoftware.oidc.web/src/main/resources/en/clients.js +++ b/de.srsoftware.oidc.web/src/main/resources/en/clients.js @@ -1,11 +1,30 @@ - async function handleClients(response){ if (response.status == UNAUTHORIZED) { redirect('login.html?return_to='+encodeURI(window.location.href)) return; } var clients = await response.json(); - get() + var bottom = document.getElementById('bottom'); + for (let id in clients){ + var row = document.createElement("tr"); + var client = clients[id]; + row.innerHTML = ""+client.name+"\n"+id+"\n"+client.redirect_uris.join("
")+'\n'; + bottom.parentNode.insertBefore(row,bottom); + } +} + +function handleRemove(response){ + redirect("clients.html"); +} + +function remove(clientId){ + var message = document.getElementById('message').innerHTML; + if (confirm(message.replace("{}",clientId))) { + fetch(api+"/client",{ + method: 'DELETE', + body : JSON.stringify({ client_id : clientId }) + }).then(handleRemove); + } } fetch(api+"/clients",{method:'POST'}).then(handleClients); \ No newline at end of file diff --git a/de.srsoftware.oidc.web/src/main/resources/en/style.css b/de.srsoftware.oidc.web/src/main/resources/en/style.css index 22fc340..c54667c 100644 --- a/de.srsoftware.oidc.web/src/main/resources/en/style.css +++ b/de.srsoftware.oidc.web/src/main/resources/en/style.css @@ -14,4 +14,8 @@ a { fieldset th, form th{ text-align: right; +} + +.hidden{ + display: none; } \ No newline at end of file