Merge commit '94aeaa86500d376a1141c34692883b2540a21931' into sqlite
This commit is contained in:
36
build.gradle
36
build.gradle
@@ -1,36 +0,0 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id "com.diffplug.spotless" version "6.25.0"
|
||||
}
|
||||
|
||||
|
||||
group = 'de.srsoftware'
|
||||
version = '1.0.1'
|
||||
|
||||
jar.enabled = false
|
||||
build.enabled = false
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation platform('org.junit:junit-bom:5.10.0')
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
spotless {
|
||||
java {
|
||||
target '*/src/*/java/**/*.java'
|
||||
removeUnusedImports()
|
||||
importOrder()
|
||||
clangFormat('18.1.8').style('file:config/clang-format')
|
||||
licenseHeader '/* © SRSoftware $YEAR */' // or licenseHeaderFile
|
||||
}
|
||||
}
|
||||
|
||||
compileJava.dependsOn 'spotlessApply'
|
||||
50
build.gradle.kts
Normal file
50
build.gradle.kts
Normal file
@@ -0,0 +1,50 @@
|
||||
plugins {
|
||||
id("com.diffplug.spotless") version "latest.release"
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
|
||||
spotless {
|
||||
java {
|
||||
target("**/src/**/java/**/*.java")
|
||||
removeUnusedImports()
|
||||
importOrder()
|
||||
clangFormat("18.1.8").style("file:config/clang-format")
|
||||
licenseHeader("/* © SRSoftware 2024 */")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
subprojects {
|
||||
group = "de.srsoftware"
|
||||
version = "1.0-SNAPSHOT"
|
||||
|
||||
apply(plugin = "java")
|
||||
apply(plugin = "maven-publish")
|
||||
apply(plugin = "com.diffplug.spotless")
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
|
||||
|
||||
val implementation by configurations
|
||||
val compileOnly by configurations
|
||||
val testImplementation by configurations
|
||||
val testRuntimeOnly by configurations
|
||||
|
||||
|
||||
dependencies {
|
||||
testImplementation(platform("org.junit:junit-bom:5.10.0"))
|
||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||
}
|
||||
|
||||
tasks.withType<Test>() {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group = 'de.srsoftware'
|
||||
version = '1.0-SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation platform('org.junit:junit-bom:5.10.0')
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
implementation 'org.json:json:20240303'
|
||||
implementation project(':de.srsoftware.utils')
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.http;
|
||||
|
||||
import static de.srsoftware.utils.Optionals.nullable;
|
||||
import static java.lang.System.Logger.Level.*;
|
||||
|
||||
import com.sun.net.httpserver.Headers;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class Cookie implements Map.Entry<String, String> {
|
||||
static final System.Logger LOG = System.getLogger(SessionToken.class.getSimpleName());
|
||||
private final String key;
|
||||
private String value = null;
|
||||
|
||||
Cookie(String key, String value) {
|
||||
this.key = key;
|
||||
setValue(value);
|
||||
}
|
||||
|
||||
public <T extends Cookie> T addTo(Headers headers) {
|
||||
LOG.log(INFO, "sending cookie {0}={1}", key, value);
|
||||
headers.add("Set-Cookie", "%s=%s".formatted(key, value));
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
public <T extends Cookie> T addTo(HttpExchange ex) {
|
||||
return this.addTo(ex.getResponseHeaders());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
protected static List<String> of(HttpExchange ex) {
|
||||
return nullable(ex.getRequestHeaders().get("Cookie")).stream().flatMap(List::stream).flatMap(s -> Arrays.stream(s.split(";"))).map(String::trim).peek(cookie -> LOG.log(INFO, "received cookie {0}", cookie)).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setValue(String s) {
|
||||
var oldVal = value;
|
||||
value = s;
|
||||
return oldVal;
|
||||
}
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.http;
|
||||
|
||||
|
||||
import static de.srsoftware.utils.Optionals.nullable;
|
||||
import static java.lang.System.Logger.Level.*;
|
||||
import static java.net.HttpURLConnection.*;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import com.sun.net.httpserver.HttpsExchange;
|
||||
import de.srsoftware.utils.Error;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public abstract class PathHandler implements HttpHandler {
|
||||
public static final String AUTHORIZATION = "Authorization";
|
||||
public static final String CONTENT_TYPE = "Content-Type";
|
||||
public static final String DEFAULT_LANGUAGE = "en";
|
||||
public static final String DELETE = "DELETE";
|
||||
private static final String FORWARDED_HOST = "x-forwarded-host";
|
||||
public static final String GET = "GET";
|
||||
public static final String HOST = "host";
|
||||
public static final String JSON = "application/json";
|
||||
public static System.Logger LOG = System.getLogger(PathHandler.class.getSimpleName());
|
||||
public static final String POST = "POST";
|
||||
|
||||
private String[] paths;
|
||||
|
||||
public record BasicAuth(String userId, String pass) {
|
||||
}
|
||||
|
||||
public class Bond {
|
||||
Bond(String[] paths) {
|
||||
PathHandler.this.paths = paths;
|
||||
}
|
||||
public PathHandler on(HttpServer server) {
|
||||
for (var path : paths) server.createContext(path, PathHandler.this);
|
||||
return PathHandler.this;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean badRequest(HttpExchange ex, byte[] bytes) throws IOException {
|
||||
return sendContent(ex, HTTP_BAD_REQUEST, bytes);
|
||||
}
|
||||
|
||||
public static boolean badRequest(HttpExchange ex, Object o) throws IOException {
|
||||
return sendContent(ex, HTTP_BAD_REQUEST, o);
|
||||
}
|
||||
|
||||
public Bond bindPath(String... path) {
|
||||
return new Bond(path);
|
||||
}
|
||||
|
||||
public boolean doDelete(String path, HttpExchange ex) throws IOException {
|
||||
return notFound(ex);
|
||||
}
|
||||
|
||||
public boolean doGet(String path, HttpExchange ex) throws IOException {
|
||||
return notFound(ex);
|
||||
}
|
||||
|
||||
public boolean doPost(String path, HttpExchange ex) throws IOException {
|
||||
return notFound(ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(HttpExchange ex) throws IOException {
|
||||
String path = relativePath(ex);
|
||||
String method = ex.getRequestMethod();
|
||||
LOG.log(INFO, "{0} {1}", method, path);
|
||||
boolean ignored = switch (method) {
|
||||
case DELETE -> doDelete(path,ex);
|
||||
case GET -> doGet(path,ex);
|
||||
case POST -> doPost(path,ex);
|
||||
default -> false;
|
||||
};
|
||||
ex.getResponseBody().close();
|
||||
}
|
||||
|
||||
public String relativePath(HttpExchange ex) {
|
||||
var requestPath = ex.getRequestURI().toString();
|
||||
for (var path : paths){
|
||||
if (requestPath.startsWith(path)) {
|
||||
requestPath = requestPath.substring(path.length());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!requestPath.startsWith("/")) requestPath = "/" + requestPath;
|
||||
var pos = requestPath.indexOf("?");
|
||||
if (pos >= 0) requestPath = requestPath.substring(0, pos);
|
||||
return requestPath;
|
||||
}
|
||||
|
||||
/******* begin of static methods *************/
|
||||
|
||||
public static String body(HttpExchange ex) throws IOException {
|
||||
return new String(ex.getRequestBody().readAllBytes(), UTF_8);
|
||||
}
|
||||
|
||||
public static Optional<String> getAuthToken(HttpExchange ex) {
|
||||
return getHeader(ex, AUTHORIZATION);
|
||||
}
|
||||
|
||||
public static Optional<BasicAuth> getBasicAuth(HttpExchange ex) {
|
||||
return getAuthToken(ex)
|
||||
.filter(token -> token.startsWith("Basic ")) //
|
||||
.map(token -> token.substring(6))
|
||||
.map(Base64.getDecoder()::decode)
|
||||
.map(bytes -> new String(bytes, UTF_8))
|
||||
.map(token -> token.split(":", 2))
|
||||
.map(arr -> new BasicAuth(arr[0], arr[1]));
|
||||
}
|
||||
|
||||
public static Optional<String> getBearer(HttpExchange ex) {
|
||||
return getAuthToken(ex).filter(token -> token.startsWith("Bearer ")).map(token -> token.substring(7));
|
||||
}
|
||||
|
||||
public static Optional<String> getHeader(HttpExchange ex, String key) {
|
||||
return nullable(ex.getRequestHeaders().get(key)).map(List::stream).flatMap(Stream::findFirst);
|
||||
}
|
||||
|
||||
public static String hostname(HttpExchange ex) {
|
||||
var headers = ex.getRequestHeaders();
|
||||
var host = headers.getFirst(FORWARDED_HOST);
|
||||
if (host == null) host = headers.getFirst(HOST);
|
||||
var proto = nullable(headers.getFirst("X-forwarded-proto")).orElseGet(() -> ex instanceof HttpsExchange ? "https" : "http");
|
||||
return host == null ? null : proto + "://" + host;
|
||||
}
|
||||
|
||||
public static JSONObject json(HttpExchange ex) throws IOException {
|
||||
return new JSONObject(body(ex));
|
||||
}
|
||||
|
||||
public static String language(HttpExchange ex) {
|
||||
return getHeader(ex, "Accept-Language") //
|
||||
.map(s -> Arrays.stream(s.split(",")))
|
||||
.flatMap(Stream::findFirst)
|
||||
.orElse(DEFAULT_LANGUAGE);
|
||||
}
|
||||
|
||||
public static boolean notFound(HttpExchange ex) throws IOException {
|
||||
LOG.log(ERROR, "not implemented");
|
||||
return sendEmptyResponse(HTTP_NOT_FOUND, ex);
|
||||
}
|
||||
|
||||
public Map<String, String> queryParam(HttpExchange ex) {
|
||||
return Arrays
|
||||
.stream(ex.getRequestURI().getQuery().split("&")) //
|
||||
.map(s -> s.split("=", 2))
|
||||
.collect(Collectors.toMap(arr -> arr[0], arr -> arr[1]));
|
||||
}
|
||||
|
||||
public static boolean sendEmptyResponse(int statusCode, HttpExchange ex) throws IOException {
|
||||
ex.sendResponseHeaders(statusCode, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean sendRedirect(HttpExchange ex, String url) throws IOException {
|
||||
ex.getResponseHeaders().add("Location", url);
|
||||
return sendEmptyResponse(HTTP_MOVED_TEMP, ex);
|
||||
}
|
||||
|
||||
public static boolean sendContent(HttpExchange ex, int status, byte[] bytes) throws IOException {
|
||||
LOG.log(DEBUG, "sending {0} response…", status);
|
||||
ex.sendResponseHeaders(status, bytes.length);
|
||||
ex.getResponseBody().write(bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean sendContent(HttpExchange ex, int status, Object o) throws IOException {
|
||||
if (o instanceof List<?> list) o = new JSONArray(list);
|
||||
if (o instanceof Map<?, ?> map) o = new JSONObject(map);
|
||||
if (o instanceof Error<?> error) o = error.json();
|
||||
if (o instanceof JSONObject) ex.getResponseHeaders().add(CONTENT_TYPE, JSON);
|
||||
return sendContent(ex, status, o.toString().getBytes(UTF_8));
|
||||
}
|
||||
|
||||
|
||||
public static boolean sendContent(HttpExchange ex, byte[] bytes) throws IOException {
|
||||
return sendContent(ex, HTTP_OK, bytes);
|
||||
}
|
||||
|
||||
public static boolean sendContent(HttpExchange ex, Object o) throws IOException {
|
||||
return sendContent(ex, HTTP_OK, o);
|
||||
}
|
||||
|
||||
public static boolean serverError(HttpExchange ex, Object o) throws IOException {
|
||||
sendContent(ex, HTTP_INTERNAL_ERROR, o);
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String url(HttpExchange ex) {
|
||||
return hostname(ex) + ex.getRequestURI();
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.http;
|
||||
|
||||
|
||||
import com.sun.net.httpserver.Headers;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
public class SessionToken extends Cookie {
|
||||
private final String sessionId;
|
||||
private static final DateTimeFormatter FORMAT = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss O");
|
||||
|
||||
public SessionToken(String sessionId, Instant expiration, boolean trust) {
|
||||
super("sessionToken", sessionToken(sessionId, expiration, trust));
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
|
||||
private static String sessionToken(String sessionId, Instant expiration, boolean trust) {
|
||||
if (trust) return "%s; Path=/api; Expires=%s".formatted(sessionId, FORMAT.format(expiration.atZone(ZoneOffset.UTC)));
|
||||
return "%s; Path=/api".formatted(sessionId);
|
||||
}
|
||||
|
||||
public SessionToken(String sessionId) {
|
||||
super("sessionToken", sessionId + "; Path=/api");
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Cookie> T addTo(Headers headers) {
|
||||
headers.add("session", getValue());
|
||||
return super.addTo(headers);
|
||||
}
|
||||
|
||||
public static Optional<SessionToken> from(HttpExchange ex) {
|
||||
return Cookie.of(ex)
|
||||
.stream()
|
||||
.filter(cookie -> cookie.startsWith("sessionToken="))
|
||||
|
||||
.map(cookie -> cookie.split("=", 2)[1])
|
||||
.map(id -> new SessionToken(id))
|
||||
.findAny();
|
||||
}
|
||||
|
||||
public String sessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group = 'de.srsoftware'
|
||||
version = '1.0-SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation platform('org.junit:junit-bom:5.10.0')
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.logging;
|
||||
|
||||
import static de.srsoftware.logging.ConsoleColors.*;
|
||||
import static java.lang.System.Logger.Level.*;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.MessageFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class ColorLogger implements System.Logger {
|
||||
private final String name;
|
||||
private static int rootLevel = INFO.getSeverity();
|
||||
private static DateFormat TIME = new SimpleDateFormat("hh:mm:ss.SSS");
|
||||
private static DateFormat DATE = new SimpleDateFormat("yyyy-MM-dd");
|
||||
private static String lastDate = null;
|
||||
|
||||
public ColorLogger(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoggable(Level level) {
|
||||
return level.getSeverity() >= rootLevel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level level, ResourceBundle bundle, String msg, Throwable thrown) {
|
||||
if (isLoggable(level)) {
|
||||
System.out.println(colorize(msg, level.getSeverity()));
|
||||
thrown.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level level, ResourceBundle bundle, String format, Object... params) {
|
||||
if (isLoggable(level)) {
|
||||
System.out.println(colorize(MessageFormat.format(format, params), level.getSeverity()));
|
||||
}
|
||||
}
|
||||
|
||||
public ColorLogger setLogLevel(Level level) {
|
||||
rootLevel = level.getSeverity();
|
||||
return this;
|
||||
}
|
||||
|
||||
private static String colorize(String message, int severity) {
|
||||
var color = severity >= ERROR.getSeverity() ? RED : severity >= WARNING.getSeverity() ? YELLOW : severity >= INFO.getSeverity() ? WHITE_BRIGHT : WHITE;
|
||||
var date = new Date();
|
||||
var day = DATE.format(date);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (!day.equals(lastDate)) {
|
||||
lastDate = day;
|
||||
sb.append(WHITE).append(day).append("\n");
|
||||
}
|
||||
return sb.append(WHITE).append(TIME.format(date)).append(" ").append(color).append(message).append(RESET).toString();
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.logging;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ColorLoggerFinder extends System.LoggerFinder {
|
||||
private static final Map<String, ColorLogger> LOGGERS = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public System.Logger getLogger(String name, Module module) {
|
||||
return LOGGERS.computeIfAbsent(name, ColorLogger::new);
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.logging;
|
||||
|
||||
public class ConsoleColors {
|
||||
// Reset
|
||||
public static final String RESET = "\033[0m"; // Text Reset
|
||||
|
||||
// Regular Colors
|
||||
public static final String BLACK = "\033[0;30m"; // BLACK
|
||||
public static final String RED = "\033[0;31m"; // RED
|
||||
public static final String GREEN = "\033[0;32m"; // GREEN
|
||||
public static final String YELLOW = "\033[0;33m"; // YELLOW
|
||||
public static final String BLUE = "\033[0;34m"; // BLUE
|
||||
public static final String PURPLE = "\033[0;35m"; // PURPLE
|
||||
public static final String CYAN = "\033[0;36m"; // CYAN
|
||||
public static final String WHITE = "\033[0;37m"; // WHITE
|
||||
|
||||
// Bold
|
||||
public static final String BLACK_BOLD = "\033[1;30m"; // BLACK
|
||||
public static final String RED_BOLD = "\033[1;31m"; // RED
|
||||
public static final String GREEN_BOLD = "\033[1;32m"; // GREEN
|
||||
public static final String YELLOW_BOLD = "\033[1;33m"; // YELLOW
|
||||
public static final String BLUE_BOLD = "\033[1;34m"; // BLUE
|
||||
public static final String PURPLE_BOLD = "\033[1;35m"; // PURPLE
|
||||
public static final String CYAN_BOLD = "\033[1;36m"; // CYAN
|
||||
public static final String WHITE_BOLD = "\033[1;37m"; // WHITE
|
||||
|
||||
// Underline
|
||||
public static final String BLACK_UNDERLINED = "\033[4;30m"; // BLACK
|
||||
public static final String RED_UNDERLINED = "\033[4;31m"; // RED
|
||||
public static final String GREEN_UNDERLINED = "\033[4;32m"; // GREEN
|
||||
public static final String YELLOW_UNDERLINED = "\033[4;33m"; // YELLOW
|
||||
public static final String BLUE_UNDERLINED = "\033[4;34m"; // BLUE
|
||||
public static final String PURPLE_UNDERLINED = "\033[4;35m"; // PURPLE
|
||||
public static final String CYAN_UNDERLINED = "\033[4;36m"; // CYAN
|
||||
public static final String WHITE_UNDERLINED = "\033[4;37m"; // WHITE
|
||||
|
||||
// Background
|
||||
public static final String BLACK_BACKGROUND = "\033[40m"; // BLACK
|
||||
public static final String RED_BACKGROUND = "\033[41m"; // RED
|
||||
public static final String GREEN_BACKGROUND = "\033[42m"; // GREEN
|
||||
public static final String YELLOW_BACKGROUND = "\033[43m"; // YELLOW
|
||||
public static final String BLUE_BACKGROUND = "\033[44m"; // BLUE
|
||||
public static final String PURPLE_BACKGROUND = "\033[45m"; // PURPLE
|
||||
public static final String CYAN_BACKGROUND = "\033[46m"; // CYAN
|
||||
public static final String WHITE_BACKGROUND = "\033[47m"; // WHITE
|
||||
|
||||
// High Intensity
|
||||
public static final String BLACK_BRIGHT = "\033[0;90m"; // BLACK
|
||||
public static final String RED_BRIGHT = "\033[0;91m"; // RED
|
||||
public static final String GREEN_BRIGHT = "\033[0;92m"; // GREEN
|
||||
public static final String YELLOW_BRIGHT = "\033[0;93m"; // YELLOW
|
||||
public static final String BLUE_BRIGHT = "\033[0;94m"; // BLUE
|
||||
public static final String PURPLE_BRIGHT = "\033[0;95m"; // PURPLE
|
||||
public static final String CYAN_BRIGHT = "\033[0;96m"; // CYAN
|
||||
public static final String WHITE_BRIGHT = "\033[0;97m"; // WHITE
|
||||
|
||||
// Bold High Intensity
|
||||
public static final String BLACK_BOLD_BRIGHT = "\033[1;90m"; // BLACK
|
||||
public static final String RED_BOLD_BRIGHT = "\033[1;91m"; // RED
|
||||
public static final String GREEN_BOLD_BRIGHT = "\033[1;92m"; // GREEN
|
||||
public static final String YELLOW_BOLD_BRIGHT = "\033[1;93m"; // YELLOW
|
||||
public static final String BLUE_BOLD_BRIGHT = "\033[1;94m"; // BLUE
|
||||
public static final String PURPLE_BOLD_BRIGHT = "\033[1;95m"; // PURPLE
|
||||
public static final String CYAN_BOLD_BRIGHT = "\033[1;96m"; // CYAN
|
||||
public static final String WHITE_BOLD_BRIGHT = "\033[1;97m"; // WHITE
|
||||
|
||||
// High Intensity backgrounds
|
||||
public static final String BLACK_BACKGROUND_BRIGHT = "\033[0;100m"; // BLACK
|
||||
public static final String RED_BACKGROUND_BRIGHT = "\033[0;101m"; // RED
|
||||
public static final String GREEN_BACKGROUND_BRIGHT = "\033[0;102m"; // GREEN
|
||||
public static final String YELLOW_BACKGROUND_BRIGHT = "\033[0;103m"; // YELLOW
|
||||
public static final String BLUE_BACKGROUND_BRIGHT = "\033[0;104m"; // BLUE
|
||||
public static final String PURPLE_BACKGROUND_BRIGHT = "\033[0;105m"; // PURPLE
|
||||
public static final String CYAN_BACKGROUND_BRIGHT = "\033[0;106m"; // CYAN
|
||||
public static final String WHITE_BACKGROUND_BRIGHT = "\033[0;107m"; // WHITE
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
de.srsoftware.logging.ColorLoggerFinder
|
||||
@@ -1,24 +1,15 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group = 'de.srsoftware'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
description = 'SRSoftware OIDC: api'
|
||||
|
||||
dependencies {
|
||||
testImplementation platform('org.junit:junit-bom:5.10.0')
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
implementation project(':de.srsoftware.utils')
|
||||
implementation 'org.json:json:20240303'
|
||||
implementation 'org.bitbucket.b_c:jose4j:0.9.6'
|
||||
implementation 'com.sun.mail:jakarta.mail:2.0.1'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
implementation 'de.srsoftware:tools.optionals:1.0.0'
|
||||
implementation 'de.srsoftware:tools.util:1.0.2'
|
||||
implementation 'org.bitbucket.b_c:jose4j:0.9.6'
|
||||
implementation 'org.json:json:20240303'
|
||||
implementation 'com.sun.mail:jakarta.mail:2.0.1'
|
||||
}
|
||||
|
||||
task jarTests (type: Jar) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import static java.util.Optional.empty;
|
||||
import de.srsoftware.oidc.api.data.AccessToken;
|
||||
import de.srsoftware.oidc.api.data.Lock;
|
||||
import de.srsoftware.oidc.api.data.User;
|
||||
import de.srsoftware.utils.Result;
|
||||
import de.srsoftware.tools.Result;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package de.srsoftware.oidc.api.data;
|
||||
|
||||
|
||||
import static de.srsoftware.oidc.api.Constants.*;
|
||||
import static de.srsoftware.utils.Optionals.nullable;
|
||||
import static de.srsoftware.tools.Optionals.nullable;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package de.srsoftware.oidc.api;
|
||||
|
||||
import static de.srsoftware.oidc.api.Constants.OPENID;
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
import static java.time.temporal.ChronoUnit.SECONDS;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.oidc.api;
|
||||
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package de.srsoftware.oidc.api;
|
||||
|
||||
import static de.srsoftware.oidc.api.Constants.EXPIRATION;
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
import static org.jose4j.jws.AlgorithmIdentifiers.RSA_USING_SHA256;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package de.srsoftware.oidc.api;
|
||||
|
||||
import static de.srsoftware.oidc.api.Constants.*;
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import jakarta.mail.Authenticator;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.oidc.api;
|
||||
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import de.srsoftware.oidc.api.data.User;
|
||||
import de.srsoftware.utils.PasswordHasher;
|
||||
import de.srsoftware.utils.UuidHasher;
|
||||
import de.srsoftware.tools.PasswordHasher;
|
||||
import de.srsoftware.tools.UuidHasher;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
@@ -6,8 +6,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import de.srsoftware.oidc.api.data.Permission;
|
||||
import de.srsoftware.oidc.api.data.User;
|
||||
import de.srsoftware.utils.PasswordHasher;
|
||||
import de.srsoftware.utils.UuidHasher;
|
||||
import de.srsoftware.tools.PasswordHasher;
|
||||
import de.srsoftware.tools.UuidHasher;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.UUID;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group = 'de.srsoftware'
|
||||
version = '1.0-SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation platform('org.junit:junit-bom:5.10.0')
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
implementation 'org.xerial:sqlite-jdbc:3.46.0.0'
|
||||
implementation project(':de.srsoftware.http')
|
||||
implementation project(':de.srsoftware.logging')
|
||||
implementation project(':de.srsoftware.oidc.api')
|
||||
implementation project(':de.srsoftware.oidc.backend')
|
||||
implementation project(':de.srsoftware.oidc.datastore.encrypted')
|
||||
implementation project(':de.srsoftware.oidc.datastore.file')
|
||||
implementation project(':de.srsoftware.oidc.datastore.sqlite')
|
||||
implementation project(':de.srsoftware.oidc.web')
|
||||
implementation project(':de.srsoftware.utils')
|
||||
implementation 'org.json:json:20240303'
|
||||
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
task run(type: JavaExec) {
|
||||
group = "application"
|
||||
description = "Run the main class with JavaExecTask"
|
||||
classpath = sourceSets.main.runtimeClasspath
|
||||
mainClass = 'de.srsoftware.oidc.app.Application'
|
||||
args = ['--base','/home/srichter/workspace/LightOIDC/de.srsoftware.oidc.web/src/main/resources']
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
attributes "Main-Class": "de.srsoftware.oidc.app.Application"
|
||||
}
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
from {
|
||||
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
|
||||
}
|
||||
}
|
||||
16
de.srsoftware.oidc.app/build.gradle.kts
Normal file
16
de.srsoftware.oidc.app/build.gradle.kts
Normal file
@@ -0,0 +1,16 @@
|
||||
description = "SRSoftware OIDC: app"
|
||||
|
||||
dependencies{
|
||||
implementation("org.json:json:20240303")
|
||||
implementation("org.xerial:sqlite-jdbc:3.46.0.0")
|
||||
implementation("de.srsoftware:tools.http:1.0.0")
|
||||
implementation("de.srsoftware:tools.logging:1.0.0")
|
||||
implementation("de.srsoftware:tools.optionals:1.0.0")
|
||||
implementation("de.srsoftware:tools.util:1.0.2")
|
||||
implementation(project(":de.srsoftware.oidc.api"))
|
||||
implementation(project(":de.srsoftware.oidc.backend"))
|
||||
implementation(project(":de.srsoftware.oidc.datastore.encrypted"))
|
||||
implementation(project(":de.srsoftware.oidc.datastore.file"))
|
||||
implementation(project(":de.srsoftware.oidc.datastore.sqlite"))
|
||||
implementation(project(":de.srsoftware.oidc.web"))
|
||||
}
|
||||
@@ -4,18 +4,17 @@ package de.srsoftware.oidc.app;
|
||||
|
||||
import static de.srsoftware.oidc.api.Constants.*;
|
||||
import static de.srsoftware.oidc.api.data.Permission.*;
|
||||
import static de.srsoftware.utils.Optionals.emptyIfBlank;
|
||||
import static de.srsoftware.utils.Optionals.nullable;
|
||||
import static de.srsoftware.utils.Paths.configDir;
|
||||
import static de.srsoftware.utils.Paths.extension;
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
import static de.srsoftware.tools.Optionals.absentIfBlank;
|
||||
import static de.srsoftware.tools.Optionals.nullable;
|
||||
import static de.srsoftware.tools.Paths.configDir;
|
||||
import static de.srsoftware.tools.Paths.extension;
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
import static java.lang.System.Logger.Level.DEBUG;
|
||||
import static java.lang.System.Logger.Level.ERROR;
|
||||
import static java.lang.System.getenv;
|
||||
import static java.util.Optional.empty;
|
||||
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import de.srsoftware.logging.ColorLogger;
|
||||
import de.srsoftware.oidc.api.*;
|
||||
import de.srsoftware.oidc.api.data.User;
|
||||
import de.srsoftware.oidc.backend.*;
|
||||
@@ -28,7 +27,8 @@ import de.srsoftware.oidc.datastore.file.PlaintextKeyStore;
|
||||
import de.srsoftware.oidc.datastore.sqlite.*;
|
||||
import de.srsoftware.oidc.web.Forward;
|
||||
import de.srsoftware.oidc.web.StaticPages;
|
||||
import de.srsoftware.utils.UuidHasher;
|
||||
import de.srsoftware.tools.ColorLogger;
|
||||
import de.srsoftware.tools.UuidHasher;
|
||||
import java.io.File;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.file.Path;
|
||||
@@ -108,7 +108,7 @@ public class Application {
|
||||
|
||||
private static AuthorizationService setupAuthService(Configuration config, Path defaultFile, FileStoreProvider fileStoreProvider) throws SQLException {
|
||||
var authServiceLocation = new File(config.getOrDefault("auth_store", defaultFile));
|
||||
return switch (extension(authServiceLocation)){
|
||||
return switch (extension(authServiceLocation)) {
|
||||
case "db", "sqlite", "sqlite3" -> new SqliteAuthService(connectionProvider.get(authServiceLocation));
|
||||
default -> fileStoreProvider.get(authServiceLocation);
|
||||
};
|
||||
@@ -116,17 +116,17 @@ public class Application {
|
||||
|
||||
private static SessionService setupSessionService(Configuration config, Path defaultFile, FileStoreProvider fileStoreProvider) throws SQLException {
|
||||
var sessionStore = new File(config.getOrDefault("session_storage", defaultFile));
|
||||
return switch (extension(sessionStore)){
|
||||
return switch (extension(sessionStore)) {
|
||||
case "db", "sqlite", "sqlite3" -> new SqliteSessionService(connectionProvider.get(sessionStore));
|
||||
default -> fileStoreProvider.get(sessionStore);
|
||||
};
|
||||
}
|
||||
|
||||
private static MailConfig setupMailConfig(Configuration config, Optional<String> encryptionKey, Path defaultFile, FileStoreProvider fileStoreProvider) throws SQLException {
|
||||
var mailConfigLocation = new File(config.getOrDefault("mail_config_storage", defaultFile));
|
||||
var mailConfig = switch (extension(mailConfigLocation)){
|
||||
case "db", "sqlite", "sqlite3" -> new SqliteMailConfig(connectionProvider.get(mailConfigLocation));
|
||||
default -> fileStoreProvider.get(mailConfigLocation);
|
||||
var mailConfigLocation = new File(config.getOrDefault("mail_config_storage", defaultFile));
|
||||
var mailConfig = switch (extension(mailConfigLocation)) {
|
||||
case "db", "sqlite", "sqlite3" -> new SqliteMailConfig(connectionProvider.get(mailConfigLocation));
|
||||
default -> fileStoreProvider.get(mailConfigLocation);
|
||||
};
|
||||
|
||||
if (encryptionKey.isPresent()) {
|
||||
@@ -137,10 +137,10 @@ public class Application {
|
||||
}
|
||||
|
||||
private static UserService setupUserService(Configuration config, Optional<String> encryptionKey, Path defaultFile, FileStoreProvider fileStoreProvider, UuidHasher passHasher) throws SQLException {
|
||||
var userStorageLocation = new File(config.getOrDefault("user_storage", defaultFile));
|
||||
var userService = switch (extension(userStorageLocation).toLowerCase()){
|
||||
case "db", "sqlite", "sqlite3" -> new SqliteUserService(connectionProvider.get(userStorageLocation),passHasher);
|
||||
default -> fileStoreProvider.get(userStorageLocation);
|
||||
var userStorageLocation = new File(config.getOrDefault("user_storage", defaultFile));
|
||||
var userService = switch (extension(userStorageLocation).toLowerCase()) {
|
||||
case "db", "sqlite", "sqlite3" -> new SqliteUserService(connectionProvider.get(userStorageLocation), passHasher);
|
||||
default -> fileStoreProvider.get(userStorageLocation);
|
||||
};
|
||||
|
||||
if (encryptionKey.isPresent()) {
|
||||
@@ -152,7 +152,7 @@ public class Application {
|
||||
|
||||
private static KeyStorage setupKeyStore(Configuration config, Optional<String> encryptionKey, Path defaultConfigDir) throws SQLException {
|
||||
var keyStorageLocation = new File(config.getOrDefault("key_storage", defaultConfigDir.resolve("keys")));
|
||||
KeyStorage keyStore = null;
|
||||
KeyStorage keyStore = null;
|
||||
if ((keyStorageLocation.exists() && keyStorageLocation.isDirectory()) || !keyStorageLocation.getName().contains(".")) {
|
||||
keyStore = new PlaintextKeyStore(keyStorageLocation.toPath());
|
||||
} else { // SQLite
|
||||
@@ -171,26 +171,26 @@ public class Application {
|
||||
var tokens = new ArrayList<>(List.of(args));
|
||||
var map = new HashMap<String, Object>();
|
||||
|
||||
emptyIfBlank(getenv(BASE_PATH)).map(Path::of).ifPresent(path -> map.put(BASE_PATH, path));
|
||||
emptyIfBlank(getenv(CONFIG_PATH)).map(Path::of).ifPresent(path -> map.put(CONFIG_PATH, path));
|
||||
absentIfBlank(getenv(BASE_PATH)).map(Path::of).ifPresent(path -> map.put(BASE_PATH, path));
|
||||
absentIfBlank(getenv(CONFIG_PATH)).map(Path::of).ifPresent(path -> map.put(CONFIG_PATH, path));
|
||||
|
||||
// Command line arguments override environment
|
||||
while (!tokens.isEmpty()) {
|
||||
var token = tokens.remove(0);
|
||||
switch (token) {
|
||||
case "--base":
|
||||
if (tokens.isEmpty()) throw new IllegalArgumentException("--base option requires second argument!");
|
||||
map.put(BASE_PATH, Path.of(tokens.remove(0)));
|
||||
break;
|
||||
case "--config":
|
||||
if (tokens.isEmpty()) throw new IllegalArgumentException("--config option requires second argument!");
|
||||
map.put(CONFIG_PATH, Path.of(tokens.remove(0)));
|
||||
break;
|
||||
default:
|
||||
LOG.log(ERROR, "Unknown option: {0}", token);
|
||||
if (tokens.isEmpty()) throw new IllegalArgumentException("--base option requires second argument!");
|
||||
map.put(BASE_PATH, Path.of(tokens.remove(0)));
|
||||
break;
|
||||
case "--config":
|
||||
if (tokens.isEmpty()) throw new IllegalArgumentException("--config option requires second argument!");
|
||||
map.put(CONFIG_PATH, Path.of(tokens.remove(0)));
|
||||
break;
|
||||
default:
|
||||
LOG.log(ERROR, "Unknown option: {0}", token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group = 'de.srsoftware'
|
||||
version = '1.0-SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation platform('org.junit:junit-bom:5.10.0')
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
implementation project(':de.srsoftware.http')
|
||||
implementation project(':de.srsoftware.logging')
|
||||
implementation project(':de.srsoftware.oidc.api')
|
||||
implementation project(':de.srsoftware.utils')
|
||||
implementation 'org.json:json:20240303'
|
||||
implementation 'org.bitbucket.b_c:jose4j:0.9.6'
|
||||
implementation 'com.sun.mail:jakarta.mail:2.0.1'
|
||||
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
13
de.srsoftware.oidc.backend/build.gradle.kts
Normal file
13
de.srsoftware.oidc.backend/build.gradle.kts
Normal file
@@ -0,0 +1,13 @@
|
||||
description = "SRSoftware OIDC: backend"
|
||||
|
||||
dependencies{
|
||||
implementation("com.sun.mail:jakarta.mail:2.0.1")
|
||||
implementation("de.srsoftware:tools.http:1.0.0")
|
||||
implementation("de.srsoftware:tools.optionals:1.0.0")
|
||||
implementation("de.srsoftware:tools.util:1.0.2")
|
||||
implementation("org.bitbucket.b_c:jose4j:0.9.6")
|
||||
implementation("org.json:json:20240303")
|
||||
|
||||
implementation(project(":de.srsoftware.oidc.api"))
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ import de.srsoftware.oidc.api.data.AuthorizedScopes;
|
||||
import de.srsoftware.oidc.api.data.Client;
|
||||
import de.srsoftware.oidc.api.data.Session;
|
||||
import de.srsoftware.oidc.api.data.User;
|
||||
import de.srsoftware.utils.Error;
|
||||
import de.srsoftware.utils.Optionals;
|
||||
import de.srsoftware.tools.Error;
|
||||
import de.srsoftware.tools.Optionals;
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
package de.srsoftware.oidc.backend;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import de.srsoftware.http.PathHandler;
|
||||
import de.srsoftware.http.SessionToken;
|
||||
import de.srsoftware.oidc.api.SessionService;
|
||||
import de.srsoftware.oidc.api.data.Session;
|
||||
import de.srsoftware.tools.PathHandler;
|
||||
import de.srsoftware.tools.SessionToken;
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
package de.srsoftware.oidc.backend;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import de.srsoftware.http.PathHandler;
|
||||
import de.srsoftware.oidc.api.KeyStorage;
|
||||
import de.srsoftware.tools.PathHandler;
|
||||
import java.io.IOException;
|
||||
import org.jose4j.jwk.JsonWebKey;
|
||||
import org.jose4j.jwk.PublicJsonWebKey;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
package de.srsoftware.oidc.backend;
|
||||
|
||||
import static de.srsoftware.oidc.api.Constants.EXPIRATION;
|
||||
import static de.srsoftware.utils.Optionals.nullable;
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
import static de.srsoftware.tools.Optionals.nullable;
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
import static org.jose4j.jws.AlgorithmIdentifiers.RSA_USING_SHA256;
|
||||
|
||||
import de.srsoftware.oidc.api.KeyManager;
|
||||
|
||||
@@ -3,16 +3,16 @@ package de.srsoftware.oidc.backend;
|
||||
|
||||
import static de.srsoftware.oidc.api.Constants.*;
|
||||
import static de.srsoftware.oidc.api.Constants.ERROR;
|
||||
import static de.srsoftware.utils.Optionals.emptyIfBlank;
|
||||
import static de.srsoftware.tools.Optionals.absentIfBlank;
|
||||
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import de.srsoftware.http.PathHandler;
|
||||
import de.srsoftware.oidc.api.*;
|
||||
import de.srsoftware.oidc.api.data.AccessToken;
|
||||
import de.srsoftware.oidc.api.data.Client;
|
||||
import de.srsoftware.oidc.api.data.User;
|
||||
import de.srsoftware.tools.PathHandler;
|
||||
import java.io.IOException;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -68,7 +68,7 @@ public class TokenController extends PathHandler {
|
||||
private HashMap<String, String> tokenResponse(String errorCode, String description) throws IOException {
|
||||
var map = new HashMap<String, String>();
|
||||
map.put(ERROR, errorCode);
|
||||
emptyIfBlank(description).ifPresent(d -> map.put(ERROR_DESCRIPTION, d));
|
||||
absentIfBlank(description).ifPresent(d -> map.put(ERROR_DESCRIPTION, d));
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,19 +4,19 @@ package de.srsoftware.oidc.backend;
|
||||
import static de.srsoftware.oidc.api.Constants.*;
|
||||
import static de.srsoftware.oidc.api.data.Permission.MANAGE_USERS;
|
||||
import static de.srsoftware.oidc.api.data.User.*;
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
import static java.lang.System.Logger.Level.WARNING;
|
||||
import static java.net.HttpURLConnection.*;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import de.srsoftware.http.SessionToken;
|
||||
import de.srsoftware.oidc.api.*;
|
||||
import de.srsoftware.oidc.api.data.Permission;
|
||||
import de.srsoftware.oidc.api.data.Session;
|
||||
import de.srsoftware.oidc.api.data.User;
|
||||
import de.srsoftware.utils.Payload;
|
||||
import de.srsoftware.utils.Result;
|
||||
import de.srsoftware.tools.Payload;
|
||||
import de.srsoftware.tools.Result;
|
||||
import de.srsoftware.tools.SessionToken;
|
||||
import jakarta.mail.*;
|
||||
import jakarta.mail.internet.*;
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -3,7 +3,7 @@ package de.srsoftware.oidc.backend;
|
||||
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import de.srsoftware.http.PathHandler;
|
||||
import de.srsoftware.tools.PathHandler;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group = 'de.srsoftware'
|
||||
version = '1.0-SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation platform('org.junit:junit-bom:5.10.0')
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
testImplementation project(path: ':de.srsoftware.oidc.api', configuration: "testBundle")
|
||||
implementation project(':de.srsoftware.oidc.api')
|
||||
implementation 'com.sun.mail:jakarta.mail:2.0.1'
|
||||
implementation project(':de.srsoftware.utils')
|
||||
implementation 'com.sun.mail:jakarta.mail:2.0.1'
|
||||
implementation 'org.bitbucket.b_c:jose4j:0.9.6'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
11
de.srsoftware.oidc.datastore.encrypted/build.gradle.kts
Normal file
11
de.srsoftware.oidc.datastore.encrypted/build.gradle.kts
Normal file
@@ -0,0 +1,11 @@
|
||||
description = "SRSoftware OIDC: encrypted datastore module"
|
||||
|
||||
dependencies{
|
||||
implementation("com.sun.mail:jakarta.mail:2.0.1")
|
||||
implementation("de.srsoftware:tools.optionals:1.0.0")
|
||||
implementation("de.srsoftware:tools.util:1.0.2")
|
||||
|
||||
implementation(project(":de.srsoftware.oidc.api"))
|
||||
testImplementation(project(":de.srsoftware.oidc.api","testBundle"))
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ import static java.util.Optional.empty;
|
||||
import de.srsoftware.oidc.api.UserService;
|
||||
import de.srsoftware.oidc.api.data.AccessToken;
|
||||
import de.srsoftware.oidc.api.data.User;
|
||||
import de.srsoftware.utils.Error;
|
||||
import de.srsoftware.utils.PasswordHasher;
|
||||
import de.srsoftware.utils.Payload;
|
||||
import de.srsoftware.utils.Result;
|
||||
import de.srsoftware.tools.Error;
|
||||
import de.srsoftware.tools.PasswordHasher;
|
||||
import de.srsoftware.tools.Payload;
|
||||
import de.srsoftware.tools.Result;
|
||||
import java.util.*;
|
||||
|
||||
public class EncryptedUserService extends EncryptedConfig implements UserService {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/* © SRSoftware 2024 */
|
||||
import static de.srsoftware.utils.Optionals.nullable;
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
package de.srsoftware.oidc.datastore.encrypted; /* © SRSoftware 2024 */
|
||||
import static de.srsoftware.tools.Optionals.nullable;
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
|
||||
import de.srsoftware.oidc.api.ClientService;
|
||||
import de.srsoftware.oidc.api.ClientServiceTest;
|
||||
import de.srsoftware.oidc.api.data.Client;
|
||||
import de.srsoftware.oidc.datastore.encrypted.EncryptedClientService;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -1,8 +1,8 @@
|
||||
/* © SRSoftware 2024 */
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
package de.srsoftware.oidc.datastore.encrypted; /* © SRSoftware 2024 */
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import de.srsoftware.oidc.datastore.encrypted.EncryptedConfig;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class EncryptedConfigTest {
|
||||
@@ -1,9 +1,9 @@
|
||||
/* © SRSoftware 2024 */
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
package de.srsoftware.oidc.datastore.encrypted; /* © SRSoftware 2024 */
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
|
||||
import de.srsoftware.oidc.api.KeyStorage;
|
||||
import de.srsoftware.oidc.api.KeyStoreTest;
|
||||
import de.srsoftware.oidc.datastore.encrypted.EncryptedKeyStore;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
@@ -1,9 +1,9 @@
|
||||
/* © SRSoftware 2024 */
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
package de.srsoftware.oidc.datastore.encrypted; /* © SRSoftware 2024 */
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import de.srsoftware.oidc.api.MailConfig;
|
||||
import de.srsoftware.oidc.datastore.encrypted.EncryptedMailConfig;
|
||||
import jakarta.mail.Authenticator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
@@ -1,17 +1,17 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.oidc.datastore.encrypted; /* © SRSoftware 2024 */
|
||||
import static de.srsoftware.oidc.api.Constants.*;
|
||||
import static de.srsoftware.utils.Optionals.nullable;
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
import static de.srsoftware.tools.Optionals.nullable;
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
import static java.lang.System.Logger.Level.WARNING;
|
||||
|
||||
import de.srsoftware.oidc.api.*;
|
||||
import de.srsoftware.oidc.api.data.AccessToken;
|
||||
import de.srsoftware.oidc.api.data.User;
|
||||
import de.srsoftware.oidc.datastore.encrypted.EncryptedUserService;
|
||||
import de.srsoftware.utils.Error;
|
||||
import de.srsoftware.utils.PasswordHasher;
|
||||
import de.srsoftware.utils.Payload;
|
||||
import de.srsoftware.utils.Result;
|
||||
import de.srsoftware.tools.Error;
|
||||
import de.srsoftware.tools.PasswordHasher;
|
||||
import de.srsoftware.tools.Payload;
|
||||
import de.srsoftware.tools.Result;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -1,26 +0,0 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group = 'de.srsoftware'
|
||||
version = '1.0-SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation platform('org.junit:junit-bom:5.10.0')
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
testImplementation project(path: ':de.srsoftware.oidc.api', configuration: "testBundle")
|
||||
implementation project(':de.srsoftware.oidc.api')
|
||||
implementation project(':de.srsoftware.utils')
|
||||
implementation 'org.json:json:20240303'
|
||||
implementation 'org.bitbucket.b_c:jose4j:0.9.6'
|
||||
implementation 'com.sun.mail:jakarta.mail:2.0.1'
|
||||
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
13
de.srsoftware.oidc.datastore.file/build.gradle.kts
Normal file
13
de.srsoftware.oidc.datastore.file/build.gradle.kts
Normal file
@@ -0,0 +1,13 @@
|
||||
description = "SRSoftware OIDC: file datastore module"
|
||||
|
||||
dependencies{
|
||||
implementation("com.sun.mail:jakarta.mail:2.0.1")
|
||||
implementation("de.srsoftware:tools.optionals:1.0.0")
|
||||
implementation("de.srsoftware:tools.util:1.0.2")
|
||||
implementation("org.json:json:20240303")
|
||||
|
||||
implementation(project(":de.srsoftware.oidc.api"))
|
||||
implementation(project(":de.srsoftware.oidc.web"))
|
||||
testImplementation(project(":de.srsoftware.oidc.api","testBundle"))
|
||||
}
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
package de.srsoftware.oidc.datastore.file; /* © SRSoftware 2024 */
|
||||
import static de.srsoftware.oidc.api.Constants.*;
|
||||
import static de.srsoftware.oidc.api.data.User.*;
|
||||
import static de.srsoftware.utils.Optionals.nullable;
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
import static de.srsoftware.tools.Optionals.nullable;
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
import static java.lang.System.Logger.Level.*;
|
||||
import static java.time.temporal.ChronoUnit.SECONDS;
|
||||
import static java.util.Optional.empty;
|
||||
|
||||
import de.srsoftware.oidc.api.*;
|
||||
import de.srsoftware.oidc.api.data.*;
|
||||
import de.srsoftware.utils.Error;
|
||||
import de.srsoftware.utils.PasswordHasher;
|
||||
import de.srsoftware.utils.Payload;
|
||||
import de.srsoftware.utils.Result;
|
||||
import de.srsoftware.tools.Error;
|
||||
import de.srsoftware.tools.PasswordHasher;
|
||||
import de.srsoftware.tools.Payload;
|
||||
import de.srsoftware.tools.Result;
|
||||
import jakarta.mail.Authenticator;
|
||||
import jakarta.mail.PasswordAuthentication;
|
||||
import java.io.File;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.oidc.datastore.file;
|
||||
|
||||
import de.srsoftware.utils.UuidHasher;
|
||||
import de.srsoftware.tools.UuidHasher;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -3,8 +3,8 @@ package de.srsoftware.oidc.datastore.file;
|
||||
|
||||
import de.srsoftware.oidc.api.UserService;
|
||||
import de.srsoftware.oidc.api.UserServiceTest;
|
||||
import de.srsoftware.utils.PasswordHasher;
|
||||
import de.srsoftware.utils.UuidHasher;
|
||||
import de.srsoftware.tools.PasswordHasher;
|
||||
import de.srsoftware.tools.UuidHasher;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group = 'de.srsoftware'
|
||||
version = '1.0-SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation platform('org.junit:junit-bom:5.10.0')
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
testImplementation project(path: ':de.srsoftware.oidc.api', configuration: "testBundle")
|
||||
implementation project(':de.srsoftware.oidc.api')
|
||||
implementation project(':de.srsoftware.utils')
|
||||
implementation 'org.bitbucket.b_c:jose4j:0.9.6'
|
||||
implementation 'org.xerial:sqlite-jdbc:3.46.0.0'
|
||||
implementation 'com.sun.mail:jakarta.mail:2.0.1'
|
||||
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
15
de.srsoftware.oidc.datastore.sqlite/build.gradle.kts
Normal file
15
de.srsoftware.oidc.datastore.sqlite/build.gradle.kts
Normal file
@@ -0,0 +1,15 @@
|
||||
description = "SRSoftware OIDC: sqlite datastore module"
|
||||
|
||||
dependencies{
|
||||
implementation("com.sun.mail:jakarta.mail:2.0.1")
|
||||
implementation("de.srsoftware:tools.optionals:1.0.0")
|
||||
implementation("de.srsoftware:tools.util:1.0.2")
|
||||
implementation("org.json:json:20240303")
|
||||
implementation("org.bitbucket.b_c:jose4j:0.9.6")
|
||||
implementation("org.xerial:sqlite-jdbc:3.46.0.0")
|
||||
|
||||
implementation(project(":de.srsoftware.oidc.api"))
|
||||
implementation(project(":de.srsoftware.oidc.web"))
|
||||
testImplementation(project(":de.srsoftware.oidc.api","testBundle"))
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.oidc.datastore.sqlite;
|
||||
|
||||
import static de.srsoftware.utils.Optionals.nullable;
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
import static de.srsoftware.tools.Optionals.nullable;
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
|
||||
import de.srsoftware.oidc.api.AuthorizationService;
|
||||
import de.srsoftware.oidc.api.data.AuthResult;
|
||||
|
||||
@@ -7,6 +7,7 @@ import de.srsoftware.oidc.api.ClientService;
|
||||
import de.srsoftware.oidc.api.data.Client;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -16,22 +17,27 @@ public class SqliteClientService extends SqliteStore implements ClientService {
|
||||
private static final String SELECT_STORE_VERSION = "SELECT * FROM metainfo WHERE key = '" + STORE_VERSION + "'";
|
||||
private static final String SET_STORE_VERSION = "UPDATE metainfo SET value = ? WHERE key = '" + STORE_VERSION + "'";
|
||||
|
||||
private static final String CREATE_CLIENT_TABLE = "CREATE TABLE IF NOT EXISTS clients(id VARCHAR(255) NOT NULL PRIMARY KEY, name VARCHAR(255), secret VARCHAR(255), landing_page VARCHAR(255));";
|
||||
private static final String CREATE_REDIRECT_TABLE = "CREATE TABLE IF NOT EXISTS client_redirects(clientId VARCHAR(255), uri VARCHAR(255), PRIMARY KEY(clientId, uri));";
|
||||
private static final String SAVE_CLIENT = "INSERT INTO clients (id, name, secret, landing_page) VALUES (?,?,?,?) ON CONFLICT DO UPDATE SET name = ?, secret = ?, landing_page = ?;";
|
||||
private static final String SAVE_REDIRECT = "INSERT OR IGNORE INTO client_redirects(clientId, uri) VALUES (?, ?)";
|
||||
private static final String DROP_OTHER_REDIRECTS = "DELETE FROM client_redirects WHERE clientId = ? AND uri NOT IN";
|
||||
private static final String SELECT_CLIENT = "SELECT * FROM clients WHERE id = ?";
|
||||
private static final String SELECT_CLIENT_REDIRECTS = "SELECT uri FROM client_redirects WHERE clientId = ?";
|
||||
private static final String LIST_CLIENT_REDIRECTS = "SELECT * FROM client_redirects";
|
||||
private static final String LIST_CLIENTS = "SELECT * FROM clients";
|
||||
private static final String DELETE_CLIENT = "DELETE FROM clients WHERE id = ?";
|
||||
private static final String DELETE_CLIENT_REDIRECTS = "DELETE FROM client_redirects WHERE clientId = ?";
|
||||
private static final String ADD_FIELD_TOKEN_VALIDITY = "ALTER TABLE clients ADD COLUMN token_validity LONG";
|
||||
private static final String CREATE_CLIENT_TABLE = "CREATE TABLE IF NOT EXISTS clients(id VARCHAR(255) NOT NULL PRIMARY KEY, name VARCHAR(255), secret VARCHAR(255), landing_page VARCHAR(255));";
|
||||
private static final String CREATE_REDIRECT_TABLE = "CREATE TABLE IF NOT EXISTS client_redirects(clientId VARCHAR(255), uri VARCHAR(255), PRIMARY KEY(clientId, uri));";
|
||||
private static final String SAVE_CLIENT = "INSERT INTO clients (id, name, secret, landing_page, token_validity) VALUES (?,?,?,?,?) ON CONFLICT DO UPDATE SET name = ?, secret = ?, landing_page = ?, token_validity = ?;";
|
||||
private static final String SAVE_REDIRECT = "INSERT OR IGNORE INTO client_redirects(clientId, uri) VALUES (?, ?)";
|
||||
private static final String DROP_OTHER_REDIRECTS = "DELETE FROM client_redirects WHERE clientId = ? AND uri NOT IN";
|
||||
private static final String SELECT_CLIENT = "SELECT * FROM clients WHERE id = ?";
|
||||
private static final String SELECT_CLIENT_REDIRECTS = "SELECT uri FROM client_redirects WHERE clientId = ?";
|
||||
private static final String LIST_CLIENT_REDIRECTS = "SELECT * FROM client_redirects";
|
||||
private static final String LIST_CLIENTS = "SELECT * FROM clients";
|
||||
private static final String DELETE_CLIENT = "DELETE FROM clients WHERE id = ?";
|
||||
private static final String DELETE_CLIENT_REDIRECTS = "DELETE FROM client_redirects WHERE clientId = ?";
|
||||
|
||||
public SqliteClientService(Connection connection) throws SQLException {
|
||||
super(connection);
|
||||
}
|
||||
|
||||
private void addTokenValidity() throws SQLException {
|
||||
conn.prepareStatement(ADD_FIELD_TOKEN_VALIDITY).execute();
|
||||
}
|
||||
|
||||
private void createStoreTables() throws SQLException {
|
||||
conn.prepareStatement(CREATE_CLIENT_TABLE).execute();
|
||||
conn.prepareStatement(CREATE_REDIRECT_TABLE).execute();
|
||||
@@ -40,7 +46,7 @@ public class SqliteClientService extends SqliteStore implements ClientService {
|
||||
@Override
|
||||
protected void initTables() throws SQLException {
|
||||
var rs = conn.prepareStatement(SELECT_STORE_VERSION).executeQuery();
|
||||
int availableVersion = 1;
|
||||
int availableVersion = 2;
|
||||
int currentVersion;
|
||||
if (rs.next()) {
|
||||
currentVersion = rs.getInt("value");
|
||||
@@ -59,6 +65,9 @@ public class SqliteClientService extends SqliteStore implements ClientService {
|
||||
case 0:
|
||||
createStoreTables();
|
||||
break;
|
||||
case 1:
|
||||
addTokenValidity();
|
||||
break;
|
||||
}
|
||||
stmt.setInt(1, ++currentVersion);
|
||||
stmt.execute();
|
||||
@@ -86,10 +95,12 @@ public class SqliteClientService extends SqliteStore implements ClientService {
|
||||
stmt.setString(1, clientId);
|
||||
rs = stmt.executeQuery();
|
||||
if (rs.next()) {
|
||||
var name = rs.getString(NAME);
|
||||
var secret = rs.getString(SECRET);
|
||||
var landing = rs.getString(LANDING_PAGE);
|
||||
result = Optional.of(new Client(clientId, name, secret, uris).landingPage(landing));
|
||||
var name = rs.getString(NAME);
|
||||
var secret = rs.getString(SECRET);
|
||||
var landing = rs.getString(LANDING_PAGE);
|
||||
var tokenValidity = rs.getLong(TOKEN_VALIDITY);
|
||||
var client = new Client(clientId, name, secret, uris).landingPage(landing).tokenValidity(Duration.ofSeconds(tokenValidity));
|
||||
result = Optional.of(client);
|
||||
}
|
||||
rs.close();
|
||||
return result;
|
||||
@@ -115,11 +126,13 @@ public class SqliteClientService extends SqliteStore implements ClientService {
|
||||
rs = stmt.executeQuery();
|
||||
var result = new ArrayList<Client>();
|
||||
while (rs.next()) {
|
||||
var id = rs.getString("id");
|
||||
var name = rs.getString(NAME);
|
||||
var secret = rs.getString(SECRET);
|
||||
var landing = rs.getString(LANDING_PAGE);
|
||||
result.add(new Client(id, name, secret, redirects.get(id)).landingPage(landing));
|
||||
var id = rs.getString("id");
|
||||
var name = rs.getString(NAME);
|
||||
var secret = rs.getString(SECRET);
|
||||
var landing = rs.getString(LANDING_PAGE);
|
||||
var tokenValidity = rs.getLong(TOKEN_VALIDITY);
|
||||
var client = new Client(id, name, secret, redirects.get(id)).landingPage(landing).tokenValidity(Duration.ofSeconds(tokenValidity));
|
||||
result.add(client);
|
||||
}
|
||||
rs.close();
|
||||
return result;
|
||||
@@ -146,14 +159,17 @@ public class SqliteClientService extends SqliteStore implements ClientService {
|
||||
@Override
|
||||
public ClientService save(Client client) {
|
||||
try {
|
||||
var stmt = conn.prepareStatement(SAVE_CLIENT);
|
||||
var stmt = conn.prepareStatement(SAVE_CLIENT);
|
||||
var tokenValidity = client.tokenValidity().getSeconds();
|
||||
stmt.setString(1, client.id());
|
||||
stmt.setString(2, client.name());
|
||||
stmt.setString(3, client.secret());
|
||||
stmt.setString(4, client.landingPage());
|
||||
stmt.setString(5, client.name());
|
||||
stmt.setString(6, client.secret());
|
||||
stmt.setString(7, client.landingPage());
|
||||
stmt.setLong(5, tokenValidity);
|
||||
stmt.setString(6, client.name());
|
||||
stmt.setString(7, client.secret());
|
||||
stmt.setString(8, client.landingPage());
|
||||
stmt.setLong(9, tokenValidity);
|
||||
stmt.execute();
|
||||
stmt = conn.prepareStatement(SAVE_REDIRECT);
|
||||
stmt.setString(1, client.id());
|
||||
|
||||
@@ -70,114 +70,113 @@ public class SqliteMailConfig extends SqliteStore implements MailConfig {
|
||||
try {
|
||||
switch (currentVersion) {
|
||||
case 0:
|
||||
createStoreTables();
|
||||
break;
|
||||
createStoreTables();
|
||||
break;
|
||||
}
|
||||
stmt.setInt(1, ++currentVersion);
|
||||
stmt.execute();
|
||||
conn.commit();
|
||||
} catch (Exception e) {
|
||||
conn.rollback();
|
||||
LOG.log(System.Logger.Level.ERROR, "Failed to update at {} = {}", STORE_VERSION, currentVersion);
|
||||
break;
|
||||
}
|
||||
stmt.setInt(1, ++currentVersion);
|
||||
stmt.execute();
|
||||
conn.commit();
|
||||
}
|
||||
catch (Exception e) {
|
||||
conn.rollback();
|
||||
LOG.log(System.Logger.Level.ERROR, "Failed to update at {} = {}", STORE_VERSION, currentVersion);
|
||||
break;
|
||||
}
|
||||
conn.setAutoCommit(true);
|
||||
}
|
||||
conn.setAutoCommit(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String smtpHost() {
|
||||
return smtpHost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailConfig smtpHost(String newValue) {
|
||||
smtpHost = newValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int smtpPort() {
|
||||
return smtpPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailConfig smtpPort(int newValue) {
|
||||
smtpPort = newValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String senderAddress() {
|
||||
return senderAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailConfig senderAddress(String newValue) {
|
||||
senderAddress = newValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String senderPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailConfig senderPassword(String newValue) {
|
||||
password = newValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startTls() {
|
||||
return startTls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean smtpAuth() {
|
||||
return smtpAuth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailConfig startTls(boolean newValue) {
|
||||
startTls = newValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailConfig smtpAuth(boolean newValue) {
|
||||
smtpAuth = newValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator authenticator() {
|
||||
if (auth == null) {
|
||||
auth = new Authenticator() {
|
||||
// override the getPasswordAuthentication method
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(senderAddress(), senderPassword());
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public String smtpHost() {
|
||||
return smtpHost;
|
||||
}
|
||||
return auth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailConfig save() {
|
||||
try {
|
||||
var stmt = conn.prepareStatement(SAVE_MAILCONFIG);
|
||||
for (var entry : map().entrySet()) {
|
||||
stmt.setString(1, entry.getKey());
|
||||
stmt.setObject(2, entry.getValue());
|
||||
stmt.setObject(3, entry.getValue());
|
||||
stmt.execute();
|
||||
}
|
||||
@Override
|
||||
public MailConfig smtpHost(String newValue) {
|
||||
smtpHost = newValue;
|
||||
return this;
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int smtpPort() {
|
||||
return smtpPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailConfig smtpPort(int newValue) {
|
||||
smtpPort = newValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String senderAddress() {
|
||||
return senderAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailConfig senderAddress(String newValue) {
|
||||
senderAddress = newValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String senderPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailConfig senderPassword(String newValue) {
|
||||
password = newValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startTls() {
|
||||
return startTls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean smtpAuth() {
|
||||
return smtpAuth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailConfig startTls(boolean newValue) {
|
||||
startTls = newValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailConfig smtpAuth(boolean newValue) {
|
||||
smtpAuth = newValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator authenticator() {
|
||||
if (auth == null) {
|
||||
auth = new Authenticator() {
|
||||
// override the getPasswordAuthentication method
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(senderAddress(), senderPassword());
|
||||
}
|
||||
};
|
||||
}
|
||||
return auth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailConfig save() {
|
||||
try {
|
||||
var stmt = conn.prepareStatement(SAVE_MAILCONFIG);
|
||||
for (var entry : map().entrySet()) {
|
||||
stmt.setString(1, entry.getKey());
|
||||
stmt.setObject(2, entry.getValue());
|
||||
stmt.setObject(3, entry.getValue());
|
||||
stmt.execute();
|
||||
}
|
||||
return this;
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.oidc.datastore.sqlite;
|
||||
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
import static java.time.temporal.ChronoUnit.SECONDS;
|
||||
|
||||
import de.srsoftware.oidc.api.SessionService;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
package de.srsoftware.oidc.datastore.sqlite;
|
||||
|
||||
import static de.srsoftware.oidc.api.Constants.*;
|
||||
import static de.srsoftware.utils.Optionals.nullable;
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
import static de.srsoftware.tools.Optionals.nullable;
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
import static java.lang.System.Logger.Level.WARNING;
|
||||
import static java.util.Optional.empty;
|
||||
|
||||
@@ -11,10 +11,10 @@ import de.srsoftware.oidc.api.UserService;
|
||||
import de.srsoftware.oidc.api.data.AccessToken;
|
||||
import de.srsoftware.oidc.api.data.Permission;
|
||||
import de.srsoftware.oidc.api.data.User;
|
||||
import de.srsoftware.utils.Error;
|
||||
import de.srsoftware.utils.PasswordHasher;
|
||||
import de.srsoftware.utils.Payload;
|
||||
import de.srsoftware.utils.Result;
|
||||
import de.srsoftware.tools.Error;
|
||||
import de.srsoftware.tools.PasswordHasher;
|
||||
import de.srsoftware.tools.Payload;
|
||||
import de.srsoftware.tools.Result;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.oidc.datastore.sqlite;
|
||||
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
|
||||
import de.srsoftware.oidc.api.AuthServiceTest;
|
||||
import de.srsoftware.oidc.api.AuthorizationService;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.oidc.datastore.sqlite;
|
||||
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
|
||||
import de.srsoftware.oidc.api.ClientService;
|
||||
import de.srsoftware.oidc.api.ClientServiceTest;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.oidc.datastore.sqlite;
|
||||
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
|
||||
import de.srsoftware.oidc.api.KeyStorage;
|
||||
import de.srsoftware.oidc.api.KeyStoreTest;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.oidc.datastore.sqlite;
|
||||
|
||||
import static de.srsoftware.utils.Strings.uuid;
|
||||
import static de.srsoftware.tools.Strings.uuid;
|
||||
|
||||
import de.srsoftware.oidc.api.MailConfig;
|
||||
import de.srsoftware.oidc.api.MailConfigTest;
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group = 'de.srsoftware'
|
||||
version = '1.0-SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation platform('org.junit:junit-bom:5.10.0')
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
implementation project(':de.srsoftware.oidc.api')
|
||||
implementation project(':de.srsoftware.http')
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
8
de.srsoftware.oidc.web/build.gradle.kts
Normal file
8
de.srsoftware.oidc.web/build.gradle.kts
Normal file
@@ -0,0 +1,8 @@
|
||||
description = "SRSoftware OIDC: web module"
|
||||
|
||||
dependencies{
|
||||
implementation("de.srsoftware:tools.http:1.0.0")
|
||||
|
||||
implementation(project(":de.srsoftware.oidc.api"))
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ package de.srsoftware.oidc.web;
|
||||
import static java.lang.System.Logger.Level.INFO;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import de.srsoftware.http.PathHandler;
|
||||
import de.srsoftware.tools.PathHandler;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Forward extends PathHandler {
|
||||
|
||||
@@ -5,8 +5,8 @@ import static java.lang.System.Logger.Level.*;
|
||||
import static java.util.Optional.empty;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import de.srsoftware.http.PathHandler;
|
||||
import de.srsoftware.oidc.api.ResourceLoader;
|
||||
import de.srsoftware.tools.PathHandler;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group = 'de.srsoftware'
|
||||
version = '1.0-SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation platform('org.junit:junit-bom:5.10.0')
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
implementation 'org.json:json:20240303'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.utils;
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class Error<T> implements Result<T> {
|
||||
private final String cause;
|
||||
private Map<String, Object> metadata;
|
||||
|
||||
public Error(String cause) {
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
public String cause() {
|
||||
return cause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isError() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static <T> Error<T> message(String cause, Object... tokens) {
|
||||
var err = new Error<T>(cause);
|
||||
err.metadata = new HashMap<>();
|
||||
for (int i = 0; i < tokens.length - 1; i += 2) {
|
||||
err.metadata.put(tokens[i].toString(), tokens[i + 1]);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
public JSONObject json() {
|
||||
var json = new JSONObject(Map.of("error", cause));
|
||||
if (metadata != null) json.put("metadata", metadata);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.utils;
|
||||
import static java.util.Optional.empty;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class Optionals {
|
||||
public static <T> Optional<T> nullable(T val) {
|
||||
return Optional.ofNullable(val);
|
||||
}
|
||||
|
||||
public static Optional<String> emptyIfBlank(String text) {
|
||||
return text == null || text.isBlank() ? empty() : nullable(text.trim());
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.utils;
|
||||
|
||||
public interface PasswordHasher<T> {
|
||||
public String hash(String password, String salt);
|
||||
public String salt(String hashedPassword);
|
||||
|
||||
public default boolean matches(String plaintextPassword, String hashedPassword) {
|
||||
return hash(plaintextPassword, salt(hashedPassword)).equals(hashedPassword);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class Paths {
|
||||
public static Path configDir(String applicationName) {
|
||||
String home = System.getProperty("user.home");
|
||||
return Path.of(home, ".config", applicationName);
|
||||
}
|
||||
|
||||
public static Path configDir(Class clazz) {
|
||||
return configDir(clazz.getSimpleName());
|
||||
}
|
||||
|
||||
public static Path configDir(Object clazz) {
|
||||
return configDir(clazz.getClass());
|
||||
}
|
||||
|
||||
public static String extension(File file) {
|
||||
var parts = file.getName().split("\\.");
|
||||
return parts.length == 1 ? "" : parts[parts.length - 1];
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.utils;
|
||||
|
||||
|
||||
public class Payload<T> implements Result<T> {
|
||||
private final T object;
|
||||
|
||||
public Payload(T object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public static <T> Payload<T> of(T object) {
|
||||
return new Payload<>(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isError() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public T get() {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.utils;
|
||||
|
||||
public interface Result<T> {
|
||||
public boolean isError();
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.utils;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class Strings {
|
||||
public static String uuid() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.utils;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
|
||||
public class UuidHasher implements PasswordHasher<String> {
|
||||
private static final String SHA256 = "SHA-256";
|
||||
|
||||
private final MessageDigest digest;
|
||||
|
||||
public UuidHasher() throws NoSuchAlgorithmException {
|
||||
digest = MessageDigest.getInstance(SHA256);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String hash(String password, String uuid) {
|
||||
var salt = uuid;
|
||||
var saltedPass = "%s %s".formatted(salt, password);
|
||||
var bytes = digest.digest(saltedPass.getBytes(UTF_8));
|
||||
|
||||
return "%s@%s".formatted(hex(bytes), salt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String salt(String hashedPassword) {
|
||||
return hashedPassword.split("@", 2)[1];
|
||||
}
|
||||
|
||||
public static String hex(byte[] bytes) {
|
||||
StringBuilder sb = new StringBuilder(bytes.length * 2);
|
||||
for (byte b : bytes) sb.append(String.format("%02x", b));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
rootProject.name = 'LightOIDC'
|
||||
include 'de.srsoftware.http'
|
||||
include 'de.srsoftware.logging'
|
||||
include 'de.srsoftware.oidc.api'
|
||||
include 'de.srsoftware.oidc.app'
|
||||
include 'de.srsoftware.oidc.backend'
|
||||
include 'de.srsoftware.oidc.datastore.sqlite'
|
||||
include 'de.srsoftware.oidc.datastore.encrypted'
|
||||
include 'de.srsoftware.oidc.datastore.file'
|
||||
include 'de.srsoftware.oidc.web'
|
||||
include 'de.srsoftware.utils'
|
||||
|
||||
9
settings.gradle.kts
Normal file
9
settings.gradle.kts
Normal file
@@ -0,0 +1,9 @@
|
||||
rootProject.name = "LightOIDC"
|
||||
include("de.srsoftware.oidc.api")
|
||||
include("de.srsoftware.oidc.app")
|
||||
include("de.srsoftware.oidc.backend")
|
||||
include("de.srsoftware.oidc.datastore.encrypted")
|
||||
include("de.srsoftware.oidc.datastore.file")
|
||||
include("de.srsoftware.oidc.datastore.sqlite")
|
||||
include("de.srsoftware.oidc.web")
|
||||
|
||||
Reference in New Issue
Block a user