From 41c3ffa351ee0b097448e38364791938e7761b4d Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Thu, 3 Jul 2025 15:26:42 +0200 Subject: [PATCH] re-implemented login via OIDC --- core/build.gradle.kts | 2 + .../srsoftware/umbrella/core/Constants.java | 5 + .../umbrella/core/ResponseCode.java | 1 + .../de/srsoftware/umbrella/core/Util.java | 88 ++++++++++ frontend/src/App.svelte | 6 +- .../src/routes/user/ConnectedServices.svelte | 2 +- frontend/src/routes/user/OidcCallback.svelte | 33 ++++ translations/src/main/resources/de.json | 1 + user/build.gradle.kts | 1 + .../srsoftware/umbrella/user/UserModule.java | 151 +++++++++++++----- .../umbrella/user/model/ForeignLogin.java | 5 +- 11 files changed, 250 insertions(+), 45 deletions(-) create mode 100644 core/src/main/java/de/srsoftware/umbrella/core/Util.java create mode 100644 frontend/src/routes/user/OidcCallback.svelte diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 6bfd15b..c3dcd1f 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -10,6 +10,8 @@ repositories { } dependencies { + implementation("de.srsoftware:tools.mime:1.1.2") + implementation("org.json:json:20240303") testImplementation(platform("org.junit:junit-bom:5.10.0")) testImplementation("org.junit.jupiter:junit-jupiter") implementation("org.xerial:sqlite-jdbc:3.49.0.0") diff --git a/core/src/main/java/de/srsoftware/umbrella/core/Constants.java b/core/src/main/java/de/srsoftware/umbrella/core/Constants.java index eff8fbe..da71c2e 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/Constants.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/Constants.java @@ -8,7 +8,9 @@ public class Constants { public static final String ADDRESS = "address"; public static final String ATTACHMENTS = "attachments"; + public static final String AUTHORIZATION = "Authorization"; public static final String BODY = "body"; + public static final String CONTENT_TYPE = "Content-Type"; public static final String DATA = "data"; public static final String DATE = "date"; public static final String DEFAULT_LANGUAGE = "en"; @@ -23,6 +25,8 @@ public class Constants { public static final String ERROR_READ_TABLE = "Failed to read {0} from {1} table"; public static final String EXPIRATION = "expiration"; + public static final String GET = "GET"; + public static final String ID = "id"; public static final String KEY = "key"; public static final String LANGUAGE = "language"; @@ -33,6 +37,7 @@ public class Constants { public static final String NUMBER = "number"; public static final String OPTIONAL = "optional"; public static final String PASSWORD = "password"; + public static final String POST = "POST"; public static final String RECEIVERS = "receivers"; public static final String REDIRECT = "redirect"; diff --git a/core/src/main/java/de/srsoftware/umbrella/core/ResponseCode.java b/core/src/main/java/de/srsoftware/umbrella/core/ResponseCode.java index ee16ebd..a23a460 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/ResponseCode.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/ResponseCode.java @@ -3,6 +3,7 @@ package de.srsoftware.umbrella.core; public class ResponseCode { public static final int HTTP_UNPROCESSABLE = 422; + public static final int HTTP_FAILED_DEPENDENCY = 424; public static final int HTTP_SERVER_ERROR = 500; public static final int HTTP_NOT_IMPLEMENTED = 501; } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/Util.java b/core/src/main/java/de/srsoftware/umbrella/core/Util.java new file mode 100644 index 0000000..3733503 --- /dev/null +++ b/core/src/main/java/de/srsoftware/umbrella/core/Util.java @@ -0,0 +1,88 @@ +/* © SRSoftware 2025 */ +package de.srsoftware.umbrella.core; + +import static de.srsoftware.tools.MimeType.MIME_FORM_URL; +import static de.srsoftware.tools.MimeType.MIME_JSON; +import static de.srsoftware.umbrella.core.Constants.*; +import static java.lang.System.Logger.Level.*; +import static java.lang.System.Logger.Level.WARNING; +import static java.nio.charset.StandardCharsets.UTF_8; + +import de.srsoftware.tools.Query; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URL; +import java.util.Map; +import org.json.JSONObject; + +public class Util { + public static final System.Logger LOG = System.getLogger("Util"); + private Util(){} + + public static HttpURLConnection open(URL url) throws IOException { + var conn = (HttpURLConnection) url.openConnection(); + conn.setRequestProperty("Accept","*/*"); + conn.setRequestProperty("Host",url.getHost()); + conn.setRequestProperty("User-Agent","Umbrella/0.1"); + return conn; + } + + public static Object request(String location, Map data, String postMime, String auth) throws UmbrellaException { + URL url; + try { + url = new URI(location).toURL(); + } catch (Exception e) { + LOG.log(WARNING,"{0} is not a valid url",location,e); + throw new UmbrellaException(500,"{0} is not a valid url",location).causedBy(e); + } + return request(url,data,postMime,auth); + } + + public static Object request(URL target, Map data, String postMime, String auth) throws UmbrellaException { + String query = null; + if (data != null) { + query = switch (postMime){ + case MIME_FORM_URL -> Query.encode(data).orElse(null); + case null, default -> { + postMime = MIME_JSON; + yield new JSONObject(data).toString(); + } + }; + } + var method = query == null ? GET : POST; + try { + LOG.log(DEBUG,"sending {0} request ({1}) to {2}",method,postMime == null ? "empty" : postMime,target); + LOG.log(TRACE,"postData = {0}",query); + var conn = open(target); + conn.setRequestMethod(method); + conn.setRequestProperty(CONTENT_TYPE, postMime); + if (auth != null) conn.setRequestProperty(AUTHORIZATION,auth); + if (query != null) { + conn.setDoOutput(true); + var out = conn.getOutputStream(); + out.write(query.getBytes(UTF_8)); + out.flush(); + out.close(); + } + var bos = new ByteArrayOutputStream(); + if (conn.getResponseCode() == 200) { + var is = conn.getInputStream(); + is.transferTo(bos); + is.close(); + var content = bos.toString(UTF_8); + if (content.startsWith("{")) return new JSONObject(content); + return content; + } else { + var is = conn.getErrorStream(); + is.transferTo(bos); + is.close(); + throw new UmbrellaException(500,bos.toString(UTF_8)); + } + } catch (Exception e) { + LOG.log(WARNING,"Request to {0} failed: {1}",target,e.getMessage()); + throw new UmbrellaException(500,"Request to {0} failed!",target).causedBy(e); + } + } +} diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index 05c90f5..6b8ba88 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 Callback from "./routes/user/OidcCallback.svelte"; import EditService from "./routes/user/EditService.svelte"; import Footer from "./Components/Footer.svelte"; import Login from "./Components/Login.svelte"; @@ -26,9 +27,9 @@ {#if translations_ready } + {#if user.name } - @@ -36,10 +37,11 @@

Page not found

- {:else} + {/if} +