Browse Source

implemented client removal

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
sqlite
Stephan Richter 4 months ago
parent
commit
2158d62da1
  1. 9
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/Constants.java
  2. 9
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/PathHandler.java
  3. 37
      de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/Backend.java
  4. 46
      de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/FileStore.java
  5. 12
      de.srsoftware.oidc.web/src/main/resources/en/clients.html
  6. 23
      de.srsoftware.oidc.web/src/main/resources/en/clients.js
  7. 4
      de.srsoftware.oidc.web/src/main/resources/en/style.css

9
de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/Constants.java

@ -1,8 +1,9 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.api; package de.srsoftware.oidc.api;
public class Constants { public class Constants {
public static final String CLIENT_ID = "client_id"; public static final String CLIENT_ID = "client_id";
public static final String NAME = "name"; public static final String NAME = "name";
public static final String REDIRECT_URI = "redirect_uri"; public static final String REDIRECT_URI = "redirect_uri";
public static final String SECRET = "secret"; public static final String SECRET = "secret";
} }

9
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 abstract class PathHandler implements HttpHandler {
public static final String CONTENT_TYPE = "Content-Type"; public static final String CONTENT_TYPE = "Content-Type";
public static final String DELETE = "DELETE";
public static final String GET = "GET"; public static final String GET = "GET";
public static final String JSON = "application/json"; public static final String JSON = "application/json";
public static final String POST = "POST"; public static final String POST = "POST";
@ -37,9 +38,14 @@ public abstract class PathHandler implements HttpHandler {
return new Bond(path); return new Bond(path);
} }
public boolean doDelete(String path, HttpExchange ex) throws IOException {
return false;
}
public boolean doGet(String path, HttpExchange ex) throws IOException { public boolean doGet(String path, HttpExchange ex) throws IOException {
return false; return false;
} }
public boolean doPost(String path, HttpExchange ex) throws IOException { public boolean doPost(String path, HttpExchange ex) throws IOException {
return false; return false;
} }
@ -50,8 +56,9 @@ public abstract class PathHandler implements HttpHandler {
String method = ex.getRequestMethod(); String method = ex.getRequestMethod();
System.out.printf("%s %s\n", method, path); System.out.printf("%s %s\n", method, path);
boolean dummy = switch (method) { boolean dummy = switch (method) {
case POST -> doPost(path,ex); case DELETE -> doDelete(path,ex);
case GET -> doGet(path,ex); case GET -> doGet(path,ex);
case POST -> doPost(path,ex);
default -> false; default -> false;
}; };
ex.getResponseBody().close(); ex.getResponseBody().close();

37
de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/Backend.java

@ -1,9 +1,9 @@
/* © SRSoftware 2024 */ /* © SRSoftware 2024 */
package de.srsoftware.oidc.backend; 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.Permission.MANAGE_CLIENTS;
import static de.srsoftware.oidc.api.User.*; import static de.srsoftware.oidc.api.User.*;
import static de.srsoftware.oidc.api.Constants.*;
import static java.net.HttpURLConnection.*; import static java.net.HttpURLConnection.*;
import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpExchange;
@ -27,14 +27,15 @@ public class Backend extends PathHandler {
} }
private boolean addClient(HttpExchange ex, Session session) throws IOException { 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<String>(); var redirects = new HashSet<String>();
for (Object o : json.getJSONArray(REDIRECT_URI)){ for (Object o : json.getJSONArray(REDIRECT_URI)) {
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 client = new Client(json.getString(CLIENT_ID), json.getString(NAME), json.getString(SECRET), redirects);
clients.add(client); clients.add(client);
return sendContent(ex,client); return sendContent(ex, client);
} }
private boolean authorize(HttpExchange ex, Session session) throws IOException { private boolean authorize(HttpExchange ex, Session session) throws IOException {
@ -53,6 +54,14 @@ public class Backend extends PathHandler {
return sendContent(ex, json); 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 { private boolean doLogin(HttpExchange ex) throws IOException {
var body = json(ex); var body = json(ex);
@ -64,6 +73,22 @@ public class Backend extends PathHandler {
return sendEmptyResponse(HTTP_UNAUTHORIZED, ex); 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 @Override
public boolean doGet(String path, HttpExchange ex) throws IOException { public boolean doGet(String path, HttpExchange ex) throws IOException {
// pre-login paths // pre-login paths
@ -100,7 +125,7 @@ public class Backend extends PathHandler {
var session = optSession.get(); var session = optSession.get();
switch (path) { switch (path) {
case "/add/client": case "/add/client":
return addClient(ex,session); return addClient(ex, session);
case "/authorize": case "/authorize":
return authorize(ex, session); return authorize(ex, session);
case "/clients": case "/clients":

46
de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/FileStore.java

@ -1,6 +1,5 @@
/* © SRSoftware 2024 */ /* © SRSoftware 2024 */
package de.srsoftware.oidc.datastore.file; /* © 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 static de.srsoftware.oidc.api.User.*;
import de.srsoftware.oidc.api.*; import de.srsoftware.oidc.api.*;
@ -16,14 +15,14 @@ import java.util.*;
import org.json.JSONObject; import org.json.JSONObject;
public class FileStore implements ClientService, SessionService, UserService { public class FileStore implements ClientService, SessionService, UserService {
private static final String CLIENTS = "clients"; private static final String CLIENTS = "clients";
private static final String EXPIRATION = "expiration"; private static final String EXPIRATION = "expiration";
private static final String NAME = "name"; private static final String NAME = "name";
private static final String REDIRECT_URIS = "redirect_uris"; private static final String REDIRECT_URIS = "redirect_uris";
private static final String SECRET = "secret"; private static final String SECRET = "secret";
private static final String SESSIONS = "sessions"; private static final String SESSIONS = "sessions";
private static final String USERS = "users"; private static final String USERS = "users";
private static final String USER = "user"; private static final String USER = "user";
private final Path storageFile; private final Path storageFile;
private final JSONObject json; private final JSONObject json;
@ -200,35 +199,40 @@ public class FileStore implements ClientService, SessionService, UserService {
@Override @Override
public ClientService add(Client client) { 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(); save();
return this; return this;
} }
@Override @Override
public Optional<Client> getClient(String clientId) { public Optional<Client> getClient(String clientId) {
var clients = json.getJSONObject(CLIENTS);
if (clients.has(clientId)) return Optional.of(toClient(clientId,clients.getJSONObject(clientId)));
return Optional.empty(); return Optional.empty();
} }
private Client toClient(String clientId, JSONObject clientData) {
var redirectUris = new HashSet<String>();
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 @Override
public List<Client> listClients() { public List<Client> listClients() {
var clients = json.getJSONObject(CLIENTS); var clients = json.getJSONObject(CLIENTS);
var list = new ArrayList<Client>(); var list = new ArrayList<Client>();
for (var clientId : clients.keySet()){ for (var clientId : clients.keySet()) list.add(toClient(clientId,clients.getJSONObject(clientId)));
var clientData = clients.getJSONObject(clientId);
var redirectUris = new HashSet<String>();
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);
}
return list; return list;
} }
@Override @Override
public ClientService remove(Client client) { public FileStore remove(Client client) {
return null; var clients = json.getJSONObject(CLIENTS);
if (clients.has(client.id())) clients.remove(client.id());
return save();
} }
@Override @Override

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

@ -11,19 +11,25 @@
<nav> <nav>
<a id="clients" href="clients.html">Clients</a> <a id="clients" href="clients.html">Clients</a>
</nav> </nav>
<h1>Welcome!</h1> <h1>Clients</h1>
<h2>Clients</h2>
These are clients that are registered with LightOIDC: These are clients that are registered with LightOIDC:
<table> <table>
<tr> <tr>
<th>Client</th> <th>Client</th>
<th>ID</th>
<th>Redirect URLs</th>
<th>Actions</th> <th>Actions</th>
</tr> </tr>
<tr> <tr id="bottom">
<td></td>
<td></td>
<td></td>
<td> <td>
<button onclick="window.location.href='newclient.html';">Add new client…</button> <button onclick="window.location.href='newclient.html';">Add new client…</button>
</td> </td>
</tr> </tr>
</table> </table>
<span class="hidden" id="message">Really remove client "{}"?</span>
</body> </body>
</html> </html>

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

@ -1,11 +1,30 @@
async function handleClients(response){ async function handleClients(response){
if (response.status == UNAUTHORIZED) { if (response.status == UNAUTHORIZED) {
redirect('login.html?return_to='+encodeURI(window.location.href)) redirect('login.html?return_to='+encodeURI(window.location.href))
return; return;
} }
var clients = await response.json(); 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 = "<td>"+client.name+"</td>\n<td>"+id+"</td>\n<td>"+client.redirect_uris.join("<br/>")+'</td>\n<td><button onclick="remove(\''+id+'\')" type="button">remove '+client.name+'</button></td>';
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); fetch(api+"/clients",{method:'POST'}).then(handleClients);

4
de.srsoftware.oidc.web/src/main/resources/en/style.css

@ -15,3 +15,7 @@ fieldset th,
form th{ form th{
text-align: right; text-align: right;
} }
.hidden{
display: none;
}
Loading…
Cancel
Save