From e53beb984817bc78cda2156f8b209f292007dc70 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Thu, 3 Jul 2025 20:32:20 +0200 Subject: [PATCH] implemented oidc management --- frontend/src/App.svelte | 3 +- .../src/routes/user/ConnectedServices.svelte | 10 ++--- frontend/src/routes/user/EditService.svelte | 6 +-- frontend/src/routes/user/LoginServices.svelte | 40 +++++++++++++++---- translations/src/main/resources/de.json | 1 + .../srsoftware/umbrella/user/UserModule.java | 15 ++++++- 6 files changed, 56 insertions(+), 19 deletions(-) diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index 6b8ba88..09aea23 100644 --- a/frontend/src/App.svelte +++ b/frontend/src/App.svelte @@ -33,7 +33,8 @@ - + +

Page not found

diff --git a/frontend/src/routes/user/ConnectedServices.svelte b/frontend/src/routes/user/ConnectedServices.svelte index b585d68..8ee9e4a 100644 --- a/frontend/src/routes/user/ConnectedServices.svelte +++ b/frontend/src/routes/user/ConnectedServices.svelte @@ -11,10 +11,8 @@ let resp = await fetch(url,{credentials:'include'}); if (resp.ok){ const arr = await resp.json(); - for (let entry of arr){ - connections.push(entry) - console.log(entry); - } + while (connections.length) connections.pop(); + for (let entry of arr) connections.push(entry); } } @@ -22,13 +20,13 @@ async function unlink(connection){ const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/oidc/connected`; - const resp = fetch(url,{ + const resp = await fetch(url,{ method: 'DELETE', credentials: 'include', body: JSON.stringify(connection) }); if (resp.ok){ - alert('succeeded'); + loadConnections(); } else { alert('failed'); } diff --git a/frontend/src/routes/user/EditService.svelte b/frontend/src/routes/user/EditService.svelte index 008ef64..8704a5a 100644 --- a/frontend/src/routes/user/EditService.svelte +++ b/frontend/src/routes/user/EditService.svelte @@ -11,7 +11,7 @@ let disabled = $state(false); onMount(async () => { - const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/service/${serviceName}`; + const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/oidc/${serviceName}`; const resp = await fetch(url,{credentials:'include'}); if (resp.ok){ const json = await resp.json(); @@ -24,7 +24,7 @@ async function update(){ caption = t('user.data_sent'); - const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/service/${serviceName}`; + const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/oidc/${serviceName}`; const resp = await fetch(url,{ credentials: 'include', method: 'PATCH', @@ -42,7 +42,7 @@
{t('user.edit_service',serviceName)} - {#if service.name} + {#if service.name || !serviceName} diff --git a/frontend/src/routes/user/LoginServices.svelte b/frontend/src/routes/user/LoginServices.svelte index 283a6ea..62ccf25 100644 --- a/frontend/src/routes/user/LoginServices.svelte +++ b/frontend/src/routes/user/LoginServices.svelte @@ -8,22 +8,48 @@ let services = $state([]); - onMount(async () => { + async function loadButtons(){ const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/oidc/buttons`; const resp = await fetch(url,{credentials:'include'}); if (resp.ok){ const json = await resp.json(); + while (services.length) services.pop(); for (let service of json) services.push(service); } - }); + } + onMount(loadButtons); + + async function connect(service){ + const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/oidc/redirect/${service}`; + const resp = await fetch(url,{credentials:'include'}); + if (resp.ok){ + var json = await resp.json(); + if (json.authorization_endpoint) { + var endpoint = json.authorization_endpoint; + delete json.authorization_endpoint; + location.href = endpoint + '?' + new URLSearchParams(json); + } + } + } + + async function drop(service){ + const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/oidc/${service}`; + const resp = await fetch(url,{ + credentials: 'include', + method: 'DELETE' + }); + if (resp.ok) loadButtons(); + }
{t('user.login_services')} - - + {#if user.permissions.includes('MANAGE_LOGIN_SERVICES')} + + {/if} +
@@ -36,10 +62,10 @@ diff --git a/translations/src/main/resources/de.json b/translations/src/main/resources/de.json index f4cddde..ac6db24 100644 --- a/translations/src/main/resources/de.json +++ b/translations/src/main/resources/de.json @@ -59,6 +59,7 @@ "old_password": "altes Passwort", "password": "Passwort", "permissions": "Berechtigungen", + "processing_code": "Code wird verarbeitet…", "repeat_new_password": "Wiederholung", "saved": "gespeichert", "save_service": "Service speichern", 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 ad87a62..77cb116 100644 --- a/user/src/main/java/de/srsoftware/umbrella/user/UserModule.java +++ b/user/src/main/java/de/srsoftware/umbrella/user/UserModule.java @@ -91,10 +91,21 @@ public class UserModule extends PathHandler { var head = path.pop(); return switch (head){ case CONNECTED -> deleteServiceConnection(ex,user); - case null, default -> super.doGet(path,ex); + case null -> super.doGet(path,ex); + default -> deleteService(ex,user,head); }; } + private boolean deleteService(HttpExchange ex, UmbrellaUser user, String serviceName) throws IOException { + if (!(user instanceof DbUser dbUser && dbUser.permissions().contains(MANAGE_LOGIN_SERVICES))) return sendEmptyResponse(HTTP_UNAUTHORIZED,ex); + try { + logins.delete(serviceName); + return sendEmptyResponse(HTTP_OK,ex); + } catch (UmbrellaException e) { + return sendContent(ex,e.statusCode(),e.getMessage()); + } + } + private boolean deleteServiceConnection(HttpExchange ex, UmbrellaUser user) throws IOException { if (user == null) return sendContent(ex,HTTP_SERVER_ERROR,"Expected user object to be of type DbUser"); JSONObject json; @@ -110,7 +121,7 @@ public class UserModule extends PathHandler { try { logins.unlink(ForeignLogin.of(serviceId,foreignId,user.id())); - return sendEmptyResponse(OK,ex); + return sendEmptyResponse(HTTP_OK,ex); } catch (UmbrellaException e) { return send(ex,e); }
{service} - + {#if user.permissions.includes('MANAGE_LOGIN_SERVICES')} - - + + {/if}