From 38081894ef77b61baaa7a05b209eecec0de1141b Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Thu, 3 Jul 2025 00:31:32 +0200 Subject: [PATCH] working on login service management --- frontend/src/App.svelte | 2 + frontend/src/routes/user/EditService.svelte | 79 +++++++++++++++++++ frontend/src/routes/user/LoginServices.svelte | 3 +- translations/src/main/resources/de.json | 9 ++- .../srsoftware/umbrella/user/UserModule.java | 33 +++++++- .../umbrella/user/model/LoginService.java | 7 +- 6 files changed, 127 insertions(+), 6 deletions(-) create mode 100644 frontend/src/routes/user/EditService.svelte diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index eb732ab..d08d9bd 100644 --- a/frontend/src/App.svelte +++ b/frontend/src/App.svelte @@ -3,6 +3,7 @@ import { loadTranslation } from './translations.svelte.js'; import { user } from './user.svelte.js'; import { Router, Route } from 'svelte-tiny-router'; + import EditService from "./routes/user/EditService.svelte"; import Footer from "./Components/Footer.svelte"; import Login from "./Components/Login.svelte"; import Menu from "./Components/Menu.svelte"; @@ -31,6 +32,7 @@ +

Page not found

diff --git a/frontend/src/routes/user/EditService.svelte b/frontend/src/routes/user/EditService.svelte new file mode 100644 index 0000000..008ef64 --- /dev/null +++ b/frontend/src/routes/user/EditService.svelte @@ -0,0 +1,79 @@ + + +
+ {t('user.edit_service',serviceName)} + {#if service.name} + + + + + + + + + + + + + + + + + + + +
{t('user.name')} + +
{t('user.client_id')} + +
{t('user.client_secret')} + +
{t('user.base_url')} + +
+ + + {:else} + {message} + {/if} +
\ No newline at end of file diff --git a/frontend/src/routes/user/LoginServices.svelte b/frontend/src/routes/user/LoginServices.svelte index 1bdb397..c62c96f 100644 --- a/frontend/src/routes/user/LoginServices.svelte +++ b/frontend/src/routes/user/LoginServices.svelte @@ -16,6 +16,7 @@ for (let service of json) services.push(service); } }); +
@@ -34,7 +35,7 @@ {#if user.permissions.includes('MANAGE_LOGIN_SERVICES')} - + {/if} diff --git a/translations/src/main/resources/de.json b/translations/src/main/resources/de.json index b292145..698e6a8 100644 --- a/translations/src/main/resources/de.json +++ b/translations/src/main/resources/de.json @@ -18,12 +18,16 @@ "tutorial": "Tutorial" }, "status" : { - "403": "Zugriff verweigert" + "403": "Zugriff verweigert", + "501": "Nicht implementiert" }, "user" : { "actions": "Aktionen", "abort": "abbrechen", "add_login_service": "Login-Service anlegen", + "base_url": "Basis-URL", + "client_id": "Client-ID", + "client_secret": "Client-Geheimnis", "connect_service": "mit Service verbinden", "CREATE_USERS": "NUTZER ANLEGEN", "data_sent": "Daten übermittelt", @@ -32,6 +36,7 @@ "edit": "Bearbeiten", "editing": "Nutzer {0} bearbeiten", "edit_password": "Passwort ändern", + "edit_service": "Login-Service \"{0}\" bearbeiten", "email": "E-Mail", "failed": "fehlgeschlagen", "id": "Id", @@ -42,6 +47,7 @@ "LIST_USERS": "NUTZER AUFLISTEN", "loading_data": "Daten werden geladen…", "login": "Login", + "login_services": "Login-Services", "MANAGE_LOGIN_SERVICES": "LOGIN-SERVICES VERWALTEN", "mismatch": "ungleich", "must_not_be_empty": "darf nicht leer sein", @@ -52,6 +58,7 @@ "permissions": "Berechtigungen", "repeat_new_password": "Wiederholung", "saved": "gespeichert", + "save_service": "Service speichern", "save_user": "Nutzer speichern", "service": "Service", "theme": "Design", diff --git a/user/src/main/java/de/srsoftware/umbrella/user/UserModule.java b/user/src/main/java/de/srsoftware/umbrella/user/UserModule.java index ef8e142..7a3ef4c 100644 --- a/user/src/main/java/de/srsoftware/umbrella/user/UserModule.java +++ b/user/src/main/java/de/srsoftware/umbrella/user/UserModule.java @@ -6,6 +6,7 @@ import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Paths.LIST; import static de.srsoftware.umbrella.core.Paths.LOGOUT; import static de.srsoftware.umbrella.core.ResponseCode.*; +import static de.srsoftware.umbrella.core.ResponseCode.HTTP_NOT_IMPLEMENTED; import static de.srsoftware.umbrella.core.ResponseCode.HTTP_SERVER_ERROR; import static de.srsoftware.umbrella.user.Constants.*; import static de.srsoftware.umbrella.user.Paths.*; @@ -14,12 +15,14 @@ import static de.srsoftware.umbrella.user.model.DbUser.PERMISSION; import static de.srsoftware.umbrella.user.model.DbUser.PERMISSION.*; import static java.lang.System.Logger.Level.WARNING; import static java.net.HttpURLConnection.*; +import static java.text.MessageFormat.format; import static java.time.temporal.ChronoUnit.DAYS; import com.sun.net.httpserver.HttpExchange; import de.srsoftware.tools.Path; import de.srsoftware.tools.PathHandler; import de.srsoftware.tools.SessionToken; +import de.srsoftware.umbrella.core.ResponseCode; import de.srsoftware.umbrella.core.UmbrellaException; import de.srsoftware.umbrella.user.api.LoginServiceDb; import de.srsoftware.umbrella.user.api.UserDb; @@ -121,6 +124,7 @@ public class UserModule extends PathHandler { try { if (head == null || head.isBlank()) return sendContent(ex, HTTP_UNPROCESSABLE,"User id missing!"); if (PASSWORD.equals(head)) return patchPassword(ex,requestingUser); + if (SERVICE.equals(head)) return patchService(ex,path.pop(),requestingUser); userId = Long.parseLong(head); } catch (NumberFormatException e) { return sendContent(ex, HTTP_UNPROCESSABLE,"Invalid user id: "+head); @@ -174,10 +178,22 @@ public class UserModule extends PathHandler { return switch (head){ case BUTTONS -> getOidcButtons(ex); case LIST -> getServiceList(ex,user); - case null, default -> super.doGet(path,ex); + case null -> super.doGet(path,ex); + default -> getService(ex,user,head); }; } + private boolean getService(HttpExchange ex, UmbrellaUser user, String serviceId) throws IOException { + if (!(user instanceof DbUser dbUser && dbUser.permissions().contains(MANAGE_LOGIN_SERVICES))) return sendEmptyResponse(HTTP_FORBIDDEN,ex); + try { + return sendContent(ex,logins.loadLoginService(serviceId).toMap()); + } catch (UmbrellaException e) { + return sendContent(ex,e.statusCode(),e.getMessage()); + } catch (IOException e) { + return sendContent(ex,HTTP_SERVER_ERROR,e.getMessage()); + } + } + private boolean getOidcButtons(HttpExchange ex) throws IOException { try { var services = logins.listLoginServices().stream().map(LoginService::name); @@ -268,6 +284,21 @@ public class UserModule extends PathHandler { } } + private boolean patchService(HttpExchange ex, String serviceName, UmbrellaUser requestingUser) throws IOException { + if (!(requestingUser instanceof DbUser user && user.permissions().contains(MANAGE_LOGIN_SERVICES))) return sendEmptyResponse(HTTP_FORBIDDEN,ex); + try { + var json = json(ex); + if (!json.has(NAME) || !(json.get(NAME) instanceof String name) || name.isBlank()) return sendContent(ex,HTTP_UNPROCESSABLE,format(ERROR_MISSING_FIELD,NAME)); + if (!json.has(URL) || !(json.get(URL) instanceof String url) || url.isBlank()) return sendContent(ex,HTTP_UNPROCESSABLE,format(ERROR_MISSING_FIELD,URL)); + if (!json.has(CLIENT_ID) || !(json.get(CLIENT_ID) instanceof String clientId) || clientId.isBlank()) return sendContent(ex,HTTP_UNPROCESSABLE,format(ERROR_MISSING_FIELD,CLIENT_ID)); + if (!json.has(CLIENT_SECRET) || !(json.get(CLIENT_SECRET) instanceof String secret) || secret.isBlank()) return sendContent(ex,HTTP_UNPROCESSABLE,format(ERROR_MISSING_FIELD,CLIENT_SECRET)); + var service = logins.save(new LoginService(name,url,clientId,secret, DEFAULT_FIELD)); + return sendContent(ex,service.toMap()); + } catch (UmbrellaException e) { + return sendContent(ex,e.statusCode(),e.getMessage()); + } + } + private boolean postLogin(HttpExchange ex) throws IOException { var json = json(ex); if (!(json.has(USERNAME) && json.get(USERNAME) instanceof String username)) return sendContent(ex, HTTP_UNPROCESSABLE,"Username missing"); diff --git a/user/src/main/java/de/srsoftware/umbrella/user/model/LoginService.java b/user/src/main/java/de/srsoftware/umbrella/user/model/LoginService.java index c5b39c2..eb1900b 100644 --- a/user/src/main/java/de/srsoftware/umbrella/user/model/LoginService.java +++ b/user/src/main/java/de/srsoftware/umbrella/user/model/LoginService.java @@ -5,6 +5,7 @@ package de.srsoftware.umbrella.user.model; import static de.srsoftware.tools.Strings.base64; import static de.srsoftware.umbrella.core.Constants.NAME; import static de.srsoftware.umbrella.core.Constants.URL; +import static de.srsoftware.umbrella.user.Constants.*; import static java.nio.charset.StandardCharsets.UTF_8; import de.srsoftware.tools.Mappable; @@ -18,9 +19,9 @@ public record LoginService(String name, String url, String clientId, String clie var map = new HashMap(); map.put(NAME,name); map.put(URL,url); - map.put("clientId",clientId); - map.put("clientSecret",clientSecret); - map.put("userInfoField",userInfoField); + map.put(CLIENT_ID,clientId); + map.put(CLIENT_SECRET,clientSecret); + map.put(USER_INFO_FIELD,userInfoField); return map; }