From add4209a1fb5ae8c3b8539fdc1e94268c91f9577 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Wed, 17 Jul 2024 00:18:14 +0200 Subject: [PATCH] working on user login Signed-off-by: Stephan Richter --- .../de/srsoftware/oidc/api/PathHandler.java | 19 ++ .../build.gradle | 5 +- .../de/srsoftware/oidc/app}/Application.java | 12 +- .../build.gradle | 16 +- .../de/srsoftware/oidc/backend/Backend.java | 44 +++++ .../de/srsoftware/oidc/light/Constants.java | 20 -- .../de/srsoftware/oidc/light/LightOICD.java | 178 ------------------ .../de/srsoftware/oidc/light/Templates.java | 94 --------- .../src/main/resources/templates/head.snippet | 16 -- .../src/main/resources/templates/index.html | 5 - .../main/resources/templates/login.snippet | 16 -- .../src/main/resources/templates/messages.txt | 2 - .../main/resources/templates/scaffold.html | 6 - .../main/resources/templates/welcome.snippet | 1 - .../oidc/server/LanguageDirector.java | 27 --- .../java/de/srsoftware/oidc/web/Forward.java | 23 +++ .../de/srsoftware/oidc/web/StaticPages.java | 26 +-- .../src/main/resources/en/config.js | 1 + .../src/main/resources/en/index.html | 10 +- .../src/main/resources/en/lightoidc.js | 25 +++ .../src/main/resources/en/login.html | 24 +++ settings.gradle | 4 +- 22 files changed, 173 insertions(+), 401 deletions(-) rename {de.srsoftware.oidc.server => de.srsoftware.oidc.app}/build.gradle (81%) rename {de.srsoftware.oidc.server/src/main/java/de/srsoftware/oidc/server => de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app}/Application.java (52%) rename {de.srsoftware.oidc.light => de.srsoftware.oidc.backend}/build.gradle (51%) create mode 100644 de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/Backend.java delete mode 100644 de.srsoftware.oidc.light/src/main/java/de/srsoftware/oidc/light/Constants.java delete mode 100644 de.srsoftware.oidc.light/src/main/java/de/srsoftware/oidc/light/LightOICD.java delete mode 100644 de.srsoftware.oidc.light/src/main/java/de/srsoftware/oidc/light/Templates.java delete mode 100644 de.srsoftware.oidc.light/src/main/resources/templates/head.snippet delete mode 100644 de.srsoftware.oidc.light/src/main/resources/templates/index.html delete mode 100644 de.srsoftware.oidc.light/src/main/resources/templates/login.snippet delete mode 100644 de.srsoftware.oidc.light/src/main/resources/templates/messages.txt delete mode 100644 de.srsoftware.oidc.light/src/main/resources/templates/scaffold.html delete mode 100644 de.srsoftware.oidc.light/src/main/resources/templates/welcome.snippet delete mode 100644 de.srsoftware.oidc.server/src/main/java/de/srsoftware/oidc/server/LanguageDirector.java create mode 100644 de.srsoftware.oidc.web/src/main/java/de/srsoftware/oidc/web/Forward.java create mode 100644 de.srsoftware.oidc.web/src/main/resources/en/config.js create mode 100644 de.srsoftware.oidc.web/src/main/resources/en/lightoidc.js create mode 100644 de.srsoftware.oidc.web/src/main/resources/en/login.html diff --git a/de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/PathHandler.java b/de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/PathHandler.java index a58a38f..04db2d4 100644 --- a/de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/PathHandler.java +++ b/de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/PathHandler.java @@ -4,10 +4,16 @@ package de.srsoftware.oidc.api; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; public abstract class PathHandler implements HttpHandler { private String path; + public class Bond { Bond(String p) { path = p; @@ -28,4 +34,17 @@ public abstract class PathHandler implements HttpHandler { if (path.startsWith("/")) path = path.substring(1); return path; } + + public Optional getHeader(HttpExchange ex, String key) { + return Optional.ofNullable(ex.getRequestHeaders().get(key)).map(List::stream).map(Stream::findFirst).orElse(Optional.empty()); + } + + public Optional language(HttpExchange ex) { + return getHeader(ex, "Accept-Language").map(s -> Arrays.stream(s.split(","))).map(Stream::findFirst).orElse(Optional.empty()); + } + + public void emptyResponse(int statusCode, HttpExchange ex) throws IOException { + ex.sendResponseHeaders(statusCode, 0); + ex.getResponseBody().close(); + } } diff --git a/de.srsoftware.oidc.server/build.gradle b/de.srsoftware.oidc.app/build.gradle similarity index 81% rename from de.srsoftware.oidc.server/build.gradle rename to de.srsoftware.oidc.app/build.gradle index fe694de..994e69f 100644 --- a/de.srsoftware.oidc.server/build.gradle +++ b/de.srsoftware.oidc.app/build.gradle @@ -12,8 +12,9 @@ repositories { dependencies { testImplementation platform('org.junit:junit-bom:5.10.0') testImplementation 'org.junit.jupiter:junit-jupiter' - implementation project(':de.srsoftware.oidc.web') implementation project(':de.srsoftware.oidc.api') + implementation project(':de.srsoftware.oidc.backend') + implementation project(':de.srsoftware.oidc.web') } test { @@ -22,7 +23,7 @@ test { jar { manifest { - attributes "Main-Class": "de.srsoftware.oidc.server.Application" + attributes "Main-Class": "de.srsoftware.oidc.app.Application" } duplicatesStrategy = DuplicatesStrategy.EXCLUDE from { diff --git a/de.srsoftware.oidc.server/src/main/java/de/srsoftware/oidc/server/Application.java b/de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java similarity index 52% rename from de.srsoftware.oidc.server/src/main/java/de/srsoftware/oidc/server/Application.java rename to de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java index bd09a97..7695b51 100644 --- a/de.srsoftware.oidc.server/src/main/java/de/srsoftware/oidc/server/Application.java +++ b/de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java @@ -1,17 +1,23 @@ /* © SRSoftware 2024 */ -package de.srsoftware.oidc.server; +package de.srsoftware.oidc.app; import com.sun.net.httpserver.HttpServer; +import de.srsoftware.oidc.backend.Backend; +import de.srsoftware.oidc.web.Forward; import de.srsoftware.oidc.web.StaticPages; import java.net.InetSocketAddress; import java.util.concurrent.Executors; public class Application { + public static final String STATIC_PATH = "/web"; + public static final String INDEX = STATIC_PATH + "/index.html"; + public static void main(String[] args) throws Exception { HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0); - new StaticPages().bindPath("/static").on(server); - new LanguageDirector("/static").bindPath("/").on(server); + new StaticPages().bindPath(STATIC_PATH).on(server); + new Forward(INDEX).bindPath("/").on(server); + new Backend().bindPath("/api").on(server); server.setExecutor(Executors.newCachedThreadPool()); server.start(); } diff --git a/de.srsoftware.oidc.light/build.gradle b/de.srsoftware.oidc.backend/build.gradle similarity index 51% rename from de.srsoftware.oidc.light/build.gradle rename to de.srsoftware.oidc.backend/build.gradle index 49b0f29..f56e27a 100644 --- a/de.srsoftware.oidc.light/build.gradle +++ b/de.srsoftware.oidc.backend/build.gradle @@ -1,6 +1,5 @@ plugins { id 'java' - id 'war' } group = 'de.srsoftware' @@ -11,22 +10,11 @@ repositories { } dependencies { - compileOnly 'jakarta.servlet:jakarta.servlet-api:6.1.0' - implementation 'ch.qos.logback:logback-core:1.5.6' - implementation 'ch.qos.logback:logback-classic:1.5.6' - implementation 'org.slf4j:slf4j-api:2.0.13' - implementation project(':de.srsoftware.oidc.api') testImplementation platform('org.junit:junit-bom:5.10.0') testImplementation 'org.junit.jupiter:junit-jupiter' + implementation project(':de.srsoftware.oidc.api') } test { useJUnitPlatform() -} - -war { - archiveFileName = 'oidc.war' - webAppDirName = 'src/main/resources' -} - - +} \ No newline at end of file diff --git a/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/Backend.java b/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/Backend.java new file mode 100644 index 0000000..7bcf6a0 --- /dev/null +++ b/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/Backend.java @@ -0,0 +1,44 @@ +/* © SRSoftware 2024 */ +package de.srsoftware.oidc.backend; + +import static java.net.HttpURLConnection.HTTP_NOT_FOUND; +import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; + +import com.sun.net.httpserver.HttpExchange; +import de.srsoftware.oidc.api.PathHandler; +import java.io.IOException; +import java.util.Optional; + +public class Backend extends PathHandler { + @Override + public void handle(HttpExchange ex) throws IOException { + String path = relativePath(ex); + String method = ex.getRequestMethod(); + System.out.printf("%s %s…", method, path); + + if ("login".equals(path)) { + doLogin(ex); + return; + } + var token = getAuthToken(ex); + if (token.isEmpty()) { + emptyResponse(HTTP_UNAUTHORIZED, ex); + System.err.println("unauthorized"); + return; + } + System.err.println("not implemented"); + ex.sendResponseHeaders(HTTP_NOT_FOUND, 0); + ex.getResponseBody().close(); + } + + private void doLogin(HttpExchange ex) throws IOException { + Optional user = getHeader(ex, "login-username"); + Optional pass = getHeader(ex, "login-password"); + System.out.printf("%s : %s", user, pass); + emptyResponse(HTTP_UNAUTHORIZED, ex); + } + + private Optional getAuthToken(HttpExchange ex) { + return getHeader(ex, "Authorization"); + } +} diff --git a/de.srsoftware.oidc.light/src/main/java/de/srsoftware/oidc/light/Constants.java b/de.srsoftware.oidc.light/src/main/java/de/srsoftware/oidc/light/Constants.java deleted file mode 100644 index 734e4cb..0000000 --- a/de.srsoftware.oidc.light/src/main/java/de/srsoftware/oidc/light/Constants.java +++ /dev/null @@ -1,20 +0,0 @@ -/* © SRSoftware 2024 */ -package de.srsoftware.oidc.light; - -public class Constants { - public static final String BODY = "body"; - public static final String EMAIL = "email"; - public static final String ERR_PAGE_NOT_FOUND = "page_not_found"; - public static final String ERR_REDIRECT_FAILED = "redirect_failed"; - public static final String HEAD = "head"; - public static final String MESSAGES = "messages.txt"; - public static final String PAGE_LOGIN = "login"; - public static final String PAGE_START = "start"; - public static final String PAGE_WELCOME = "welcome"; - public static final String PASSWORD = "password"; - public static final String TARGET = "target"; - public static final String TITLE = "title"; - public static final String TITLE_LOGIN = "title_login"; - public static final String TITLE_WELCOME = "title_welcom"; - public static final String USER = "user"; -} diff --git a/de.srsoftware.oidc.light/src/main/java/de/srsoftware/oidc/light/LightOICD.java b/de.srsoftware.oidc.light/src/main/java/de/srsoftware/oidc/light/LightOICD.java deleted file mode 100644 index 3cad53e..0000000 --- a/de.srsoftware.oidc.light/src/main/java/de/srsoftware/oidc/light/LightOICD.java +++ /dev/null @@ -1,178 +0,0 @@ -/* © SRSoftware 2024 */ -package de.srsoftware.oidc.light; - -import static de.srsoftware.oidc.light.Constants.*; -import static de.srsoftware.oidc.light.Templates.braced; - -import de.srsoftware.oidc.api.User; -import jakarta.servlet.ServletException; -import jakarta.servlet.annotation.WebServlet; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.servlet.http.HttpSession; -import java.io.IOException; -import java.util.*; -import java.util.stream.Collectors; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@WebServlet("/web") -public class LightOICD extends HttpServlet { - private static final Logger LOG = LoggerFactory.getLogger(LightOICD.class); - private static final Templates templates; - - static { - try { - templates = Templates.singleton(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @Override - public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { - var path = relativePath(req); - var optUser = loadUser(req); - handleGet(path, optUser, req, resp).ifPresent(resp.getWriter()::println); - } - - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - var path = relativePath(req); - var optUser = loadUser(req); - handlePost(path, optUser, req, resp).ifPresent(resp.getWriter()::println); - } - - public List relativePath(HttpServletRequest req) { - var cp = req.getContextPath(); - var uri = req.getRequestURI(); - if (uri.startsWith(cp)) uri = uri.substring(cp.length()); // strip context path → relative path! - var path = Arrays.stream(uri.split("/")).skip(1).collect(Collectors.toList()); - if (path.isEmpty()) path.add(PAGE_START); - return path; - } - - private Optional handleGet(List path, Optional optUser, HttpServletRequest req, HttpServletResponse resp) { - String token = path.remove(0); - if (optUser.isPresent()) { - var user = optUser.get(); - switch (token) { - case PAGE_START: - return pageStart(user, req, resp); - case PAGE_WELCOME: - return pageWelcome(user, req, resp); - } - } - - switch (token) { - case PAGE_LOGIN: - return pageLogin(req, resp); - case PAGE_START: - case PAGE_WELCOME: - return redirect(resp, PAGE_LOGIN); - } - return templates.message(ERR_PAGE_NOT_FOUND); - } - - - private Optional handlePost(List path, Optional optUser, HttpServletRequest req, HttpServletResponse resp) { - String token = path.remove(0); - if (optUser.isPresent()) { - var user = optUser.get(); - switch (token) { - case PAGE_START: - return pageStart(user, req, resp); - } - } - - switch (token) { - case PAGE_LOGIN: - return postLogin(req, resp); - case PAGE_START: - return redirect(resp, PAGE_LOGIN); - } - return templates.message(ERR_PAGE_NOT_FOUND); - } - - private Optional loadUser(HttpServletRequest req) { - HttpSession session = req.getSession(); - if (session.getAttribute(USER) instanceof User user) return Optional.of(user); - return Optional.empty(); - } - - - private Optional pageLogin(HttpServletRequest req, HttpServletResponse resp) { - LOG.debug("pageLogin(…)"); - try { - var title = templates.message(TITLE_LOGIN).orElse(TITLE_LOGIN); - var head = templates.get("head.snippet", Map.of(TITLE, title)).get(); - var login = templates.get("login.snippet", Map.of(USER, "Darling", EMAIL, "", PASSWORD, "")).get(); - var page = templates.get("scaffold.html", Map.of(BODY, login, HEAD, head)).get(); - resp.setContentType("text/html"); - resp.getWriter().println(page); - return Optional.empty(); - } catch (Exception e) { - return Optional.of(e.getMessage()); - } - } - - private Optional pageStart(User user, HttpServletRequest req, HttpServletResponse resp) { - LOG.debug("pageStart(…)"); - return Optional.empty(); - } - - private Optional pageWelcome(User user, HttpServletRequest req, HttpServletResponse resp) { - LOG.debug("pageWelcome(…)"); - try { - var title = templates.message(TITLE_WELCOME).orElse(TITLE_WELCOME); - var head = templates.get("head.snippet", Map.of(TITLE, title)).get(); - var login = templates.get("welcome.snippet", Map.of(USER, "Darling", EMAIL, "", PASSWORD, "")).get(); - var page = templates.get("scaffold.html", Map.of(BODY, login, HEAD, head)).get(); - resp.setContentType("text/html"); - resp.getWriter().println(page); - return Optional.empty(); - } catch (Exception e) { - return Optional.of(e.getMessage()); - } - } - - private Optional postLogin(HttpServletRequest req, HttpServletResponse resp) { - LOG.debug("postLogin(…)"); - var email = req.getParameter(EMAIL); - if (braced(EMAIL).equals(email)) email = ""; - var pass = req.getParameter(PASSWORD); - var user = tryLogin(email, pass); - if (user.isPresent()) { - req.getSession().setAttribute(USER, user.get()); - return redirect(resp, PAGE_WELCOME); - } - try { - var title = templates.message(TITLE_LOGIN).orElse(TITLE_LOGIN); - var head = templates.get("head.snippet", Map.of(TITLE, title)).get(); - var login = templates.get("login.snippet", Map.of(USER, "Darling", EMAIL, email, PASSWORD, "")).get(); - var page = templates.get("scaffold.html", Map.of(BODY, login, HEAD, head)).get(); - resp.setContentType("text/html"); - resp.getWriter().println(page); - return Optional.empty(); - } catch (Exception e) { - return Optional.of(e.getMessage()); - } - } - - private Optional tryLogin(String email, String pass) { - if (email == null || pass == null) return Optional.empty(); - if (email.equals(pass)) return Optional.of(new User()); - return Optional.empty(); - } - - private Optional redirect(HttpServletResponse resp, String path) { - try { - resp.sendRedirect(path); - } catch (IOException e) { - return templates.message(ERR_REDIRECT_FAILED, Map.of(TARGET, path)); - } - return Optional.empty(); - } -} diff --git a/de.srsoftware.oidc.light/src/main/java/de/srsoftware/oidc/light/Templates.java b/de.srsoftware.oidc.light/src/main/java/de/srsoftware/oidc/light/Templates.java deleted file mode 100644 index 65bd1ce..0000000 --- a/de.srsoftware.oidc.light/src/main/java/de/srsoftware/oidc/light/Templates.java +++ /dev/null @@ -1,94 +0,0 @@ -/* © SRSoftware 2024 */ -package de.srsoftware.oidc.light; - -import static de.srsoftware.oidc.light.Constants.MESSAGES; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class Templates { - private static Templates singleton = null; - private static Logger LOG = LoggerFactory.getLogger(Templates.class); - private Path dir = searchTemplates(); - private Map messages = null; - - public Templates() throws FileNotFoundException { - } - - private static Path searchTemplates() throws FileNotFoundException { - return searchTemplates(new File(System.getProperty("user.dir"))).map(File::toPath).orElseThrow(() -> new FileNotFoundException("Missing template directory")); - } - - private static Optional searchTemplates(File dir) { - if (dir.isDirectory()) { - var children = dir.listFiles(); - for (File child : children) { - if (child.isDirectory()) { - if (child.getName().equals("templates")) return Optional.of(child); - var inner = searchTemplates(child); - if (inner.isPresent()) return inner; - } - } - } - return Optional.empty(); - } - - public static Templates singleton() throws IOException { - if (singleton == null) singleton = new Templates(); - return singleton; - } - - public Optional get(String path) { - return get(path, Map.of()); - } - - public Optional get(String path, Map replacements) { - var file = dir.resolve(path); - try { - return Optional.of(Files.readString(file)).map(s -> replaceKeys(s, replacements)); - } catch (IOException e) { - LOG.warn("Failed to read {}", path, e); - return Optional.empty(); - } - } - - private String replaceKeys(String text, Map replacements) { - for (Map.Entry replacement : replacements.entrySet()) text = text.replace(braced(replacement.getKey()), replacement.getValue()); - return text; - } - - public Optional message(String code) { - return message(code, Map.of()); - } - - public Optional message(String code, Map replacements) { - if (this.messages == null) { - get(MESSAGES).map(s -> s.split("\n")).ifPresent(this::setMessages); - } - return Optional.ofNullable(messages.get(code)).map(text -> replaceKeys(text, replacements)); - } - - private void setMessages(String[] lines) { - this.messages = new HashMap<>(); - for (String line : lines) { - var parts = line.split(" ", 2); - if (parts.length < 2) { - LOG.warn("Invalid format in {} file, skipped {}", MESSAGES, line); - continue; - } - messages.put(parts[0], parts[1]); - } - } - - public static String braced(String key) { - return String.join(key, "{", "}"); - } -} diff --git a/de.srsoftware.oidc.light/src/main/resources/templates/head.snippet b/de.srsoftware.oidc.light/src/main/resources/templates/head.snippet deleted file mode 100644 index ba8bce2..0000000 --- a/de.srsoftware.oidc.light/src/main/resources/templates/head.snippet +++ /dev/null @@ -1,16 +0,0 @@ - -{title} - \ No newline at end of file diff --git a/de.srsoftware.oidc.light/src/main/resources/templates/index.html b/de.srsoftware.oidc.light/src/main/resources/templates/index.html deleted file mode 100644 index 572deaf..0000000 --- a/de.srsoftware.oidc.light/src/main/resources/templates/index.html +++ /dev/null @@ -1,5 +0,0 @@ - - -Hallo {user}, dies ist die Index-Seite! - - \ No newline at end of file diff --git a/de.srsoftware.oidc.light/src/main/resources/templates/login.snippet b/de.srsoftware.oidc.light/src/main/resources/templates/login.snippet deleted file mode 100644 index 4af605e..0000000 --- a/de.srsoftware.oidc.light/src/main/resources/templates/login.snippet +++ /dev/null @@ -1,16 +0,0 @@ -

Login

- -
-
- Light OIDC Login - - - -
-
\ No newline at end of file diff --git a/de.srsoftware.oidc.light/src/main/resources/templates/messages.txt b/de.srsoftware.oidc.light/src/main/resources/templates/messages.txt deleted file mode 100644 index 4dfd798..0000000 --- a/de.srsoftware.oidc.light/src/main/resources/templates/messages.txt +++ /dev/null @@ -1,2 +0,0 @@ -title_login LightOIDC Login -title_welcome Willkommen bei LightOIDC! \ No newline at end of file diff --git a/de.srsoftware.oidc.light/src/main/resources/templates/scaffold.html b/de.srsoftware.oidc.light/src/main/resources/templates/scaffold.html deleted file mode 100644 index c18243a..0000000 --- a/de.srsoftware.oidc.light/src/main/resources/templates/scaffold.html +++ /dev/null @@ -1,6 +0,0 @@ - - -{head} - -{body} - \ No newline at end of file diff --git a/de.srsoftware.oidc.light/src/main/resources/templates/welcome.snippet b/de.srsoftware.oidc.light/src/main/resources/templates/welcome.snippet deleted file mode 100644 index 45c6c97..0000000 --- a/de.srsoftware.oidc.light/src/main/resources/templates/welcome.snippet +++ /dev/null @@ -1 +0,0 @@ -Willkommen! \ No newline at end of file diff --git a/de.srsoftware.oidc.server/src/main/java/de/srsoftware/oidc/server/LanguageDirector.java b/de.srsoftware.oidc.server/src/main/java/de/srsoftware/oidc/server/LanguageDirector.java deleted file mode 100644 index fae63c9..0000000 --- a/de.srsoftware.oidc.server/src/main/java/de/srsoftware/oidc/server/LanguageDirector.java +++ /dev/null @@ -1,27 +0,0 @@ -/* © SRSoftware 2024 */ -package de.srsoftware.oidc.server; - -import com.sun.net.httpserver.Headers; -import com.sun.net.httpserver.HttpExchange; -import de.srsoftware.oidc.api.PathHandler; -import java.io.IOException; -import java.util.Arrays; - -public class LanguageDirector extends PathHandler { - private static final String DEFAULT_LANG = "de"; - private final String path; - - public LanguageDirector(String pathTo) { - path = pathTo; - } - - @Override - public void handle(HttpExchange t) throws IOException { - Headers headers = t.getRequestHeaders(); - String lang = headers.get("Accept-Language").stream().flatMap(s -> Arrays.stream(s.split(","))).findFirst().orElse(DEFAULT_LANG); - - t.getResponseHeaders().add("Location", String.join(lang, "/static/", "/de/index.html")); - t.sendResponseHeaders(301, 0); - t.getResponseBody().close(); - } -} diff --git a/de.srsoftware.oidc.web/src/main/java/de/srsoftware/oidc/web/Forward.java b/de.srsoftware.oidc.web/src/main/java/de/srsoftware/oidc/web/Forward.java new file mode 100644 index 0000000..aa915ab --- /dev/null +++ b/de.srsoftware.oidc.web/src/main/java/de/srsoftware/oidc/web/Forward.java @@ -0,0 +1,23 @@ +/* © SRSoftware 2024 */ +package de.srsoftware.oidc.web; + +import com.sun.net.httpserver.HttpExchange; +import de.srsoftware.oidc.api.PathHandler; +import java.io.IOException; + +public class Forward extends PathHandler { + private final int CODE = 302; + private final String toPath; + + public Forward(String toPath) { + this.toPath = toPath; + } + + @Override + public void handle(HttpExchange ex) throws IOException { + System.out.printf("Forwarding (%d) %s to %s…\n", CODE, ex.getRequestURI(), toPath); + ex.getResponseHeaders().add("Location", toPath); + ex.sendResponseHeaders(CODE, 0); + ex.getResponseBody().close(); + } +} diff --git a/de.srsoftware.oidc.web/src/main/java/de/srsoftware/oidc/web/StaticPages.java b/de.srsoftware.oidc.web/src/main/java/de/srsoftware/oidc/web/StaticPages.java index 1a25358..d7616b9 100644 --- a/de.srsoftware.oidc.web/src/main/java/de/srsoftware/oidc/web/StaticPages.java +++ b/de.srsoftware.oidc.web/src/main/java/de/srsoftware/oidc/web/StaticPages.java @@ -9,40 +9,42 @@ import java.io.OutputStream; import java.util.Optional; public class StaticPages extends PathHandler { - private static final String DEFAULT_LANG = "en"; + private static final String DEFAULT_LANGUAGE = "en"; private ClassLoader loader; private record Response(String contentType, byte[] content) { } - private static final String INDEX = "de/index.html"; + private static final String INDEX = "en/index.html"; @Override public void handle(HttpExchange ex) throws IOException { - String path = relativePath(ex); + String path = relativePath(ex); + String lang = language(ex).orElse(DEFAULT_LANGUAGE); + String method = ex.getRequestMethod(); + if (path.isBlank()) path = INDEX; + System.out.printf("%s %s: ", method, ex.getRequestURI()); try { - var response = loadTemplate(path).orElseThrow(() -> new FileNotFoundException()); + System.out.printf("Loading %s for lagnuage %s…", path, lang); + var response = loadTemplate(lang, path).orElseThrow(() -> new FileNotFoundException()); ex.getResponseHeaders().add("Content-Type", response.contentType); ex.sendResponseHeaders(200, response.content.length); OutputStream os = ex.getResponseBody(); os.write(response.content); os.close(); + System.out.println("success."); } catch (FileNotFoundException fnf) { ex.sendResponseHeaders(404, 0); ex.getResponseBody().close(); + System.err.println("failed!"); } } - private Optional loadTemplate(String path) throws IOException { + private Optional loadTemplate(String language, String path) throws IOException { if (loader == null) loader = getClass().getClassLoader(); - var resource = loader.getResource(path); - if (resource == null) { - var parts = path.split("/"); - parts[0] = DEFAULT_LANG; - path = String.join("/", parts); - resource = loader.getResource(path); - } + var resource = loader.getResource(String.join("/", language, path)); + if (resource == null) resource = loader.getResource(String.join("/", DEFAULT_LANGUAGE, path)); if (resource == null) return Optional.empty(); var connection = resource.openConnection(); var contentType = connection.getContentType(); diff --git a/de.srsoftware.oidc.web/src/main/resources/en/config.js b/de.srsoftware.oidc.web/src/main/resources/en/config.js new file mode 100644 index 0000000..4b5e604 --- /dev/null +++ b/de.srsoftware.oidc.web/src/main/resources/en/config.js @@ -0,0 +1 @@ +var api = "/api"; \ No newline at end of file diff --git a/de.srsoftware.oidc.web/src/main/resources/en/index.html b/de.srsoftware.oidc.web/src/main/resources/en/index.html index 81a27f6..a410308 100644 --- a/de.srsoftware.oidc.web/src/main/resources/en/index.html +++ b/de.srsoftware.oidc.web/src/main/resources/en/index.html @@ -1,9 +1,13 @@ - {title} - + + - {body} +

Welcome!

\ No newline at end of file diff --git a/de.srsoftware.oidc.web/src/main/resources/en/lightoidc.js b/de.srsoftware.oidc.web/src/main/resources/en/lightoidc.js new file mode 100644 index 0000000..06efdec --- /dev/null +++ b/de.srsoftware.oidc.web/src/main/resources/en/lightoidc.js @@ -0,0 +1,25 @@ +const UNAUTHORIZED = 401; + +function handleCheckUser(response){ + console.log(window.location.href); + if (response.status == UNAUTHORIZED){ + window.location.href = "login.html"; + return; + } +} +function checkUser(){ + fetch(api+"/user") + .then(handleCheckUser) + .catch((err) => console.log(err)); +} +function submitForm(formId){ + var data = Object.fromEntries(new FormData(document.getElementById(formId))); + fetch(api+"/login",{ + headers: { + 'login-username': data.user, + 'login-password': data.pass, // TODO: send via body? + Accept: 'application/json', + 'Content-Type': 'application/json' + } + }); +} \ No newline at end of file diff --git a/de.srsoftware.oidc.web/src/main/resources/en/login.html b/de.srsoftware.oidc.web/src/main/resources/en/login.html new file mode 100644 index 0000000..8e98e4f --- /dev/null +++ b/de.srsoftware.oidc.web/src/main/resources/en/login.html @@ -0,0 +1,24 @@ + + + Light OIDC + + + + +

Login

+
+
+ User credentials + + + +
+
+ + \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 603cc4d..bbaa2a6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,6 @@ rootProject.name = 'LightOIDC' include 'de.srsoftware.oidc.api' -include 'de.srsoftware.oidc.light' -include 'de.srsoftware.oidc.server' +include 'de.srsoftware.oidc.app' include 'de.srsoftware.oidc.web' +include 'de.srsoftware.oidc.backend'