implemented client removal
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -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";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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":
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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);
|
||||||
@@ -14,4 +14,8 @@ a {
|
|||||||
fieldset th,
|
fieldset th,
|
||||||
form th{
|
form th{
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden{
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user