refactored classes and modules, fixed decoding bug

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
2024-08-05 00:27:09 +02:00
parent 49929adaa3
commit d01289c068
31 changed files with 82 additions and 56 deletions

View File

@@ -0,0 +1,16 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.api;
import de.srsoftware.oidc.api.data.AuthResult;
import de.srsoftware.oidc.api.data.Authorization;
import de.srsoftware.oidc.api.data.Client;
import de.srsoftware.oidc.api.data.User;
import java.time.Instant;
import java.util.Collection;
import java.util.Optional;
public interface AuthorizationService {
AuthorizationService authorize(User user, Client client, Collection<String> scopes, Instant expiration);
Optional<Authorization> consumeAuthorization(String authCode);
AuthResult getAuthorization(User user, Client client, Collection<String> scopes);
}

View File

@@ -1,12 +0,0 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.api;
import java.time.Instant;
import java.util.Collection;
import java.util.Optional;
public interface ClaimAuthorizationService {
ClaimAuthorizationService authorize(User user, Client client, Collection<String> scopes, Instant expiration);
Optional<Authorization> consumeAuthorization(String authCode);
AuthResult getAuthorization(User user, Client client, Collection<String> scopes);
}

View File

@@ -1,6 +1,7 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.api;
import de.srsoftware.oidc.api.data.Client;
import java.util.List;
import java.util.Optional;

View File

@@ -6,7 +6,6 @@ public class Constants {
public static final String ACCESS_TOKEN = "access_token";
public static final String APP_NAME = "LightOIDC";
public static final String AUTH_CODE = "authorization_code";
public static final String AUTHORIZATION = "Authorization";
public static final String AUTHORZED = "authorized";
public static final String BEARER = "Bearer";
public static final String CAUSE = "cause";

View File

@@ -1,174 +0,0 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.api;
import static de.srsoftware.oidc.api.Constants.AUTHORIZATION;
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 java.io.IOException;
import java.util.*;
import java.util.stream.Stream;
import org.json.JSONObject;
public abstract class PathHandler implements HttpHandler {
public static final String CONTENT_TYPE = "Content-Type";
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 HttpServer on(HttpServer server) {
for (var path : paths) server.createContext(path, PathHandler.this);
return server;
}
}
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);
return host == null ? null : "https://" + host;
}
public static JSONObject json(HttpExchange ex) throws IOException {
return new JSONObject(body(ex));
}
public static Optional<String> language(HttpExchange ex) {
return getHeader(ex, "Accept-Language").map(s -> Arrays.stream(s.split(","))).flatMap(Stream::findFirst);
}
public static boolean notFound(HttpExchange ex) throws IOException {
LOG.log(ERROR, "not implemented");
return sendEmptyResponse(HTTP_NOT_FOUND, ex);
}
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 Map map) o = new JSONObject(map);
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);
}
}

View File

@@ -1,6 +1,8 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.api;
import de.srsoftware.oidc.api.data.Session;
import de.srsoftware.oidc.api.data.User;
import java.time.Duration;
import java.util.Optional;

View File

@@ -1,6 +1,7 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.api;
import de.srsoftware.oidc.api.data.User;
import java.util.List;
import java.util.Optional;

View File

@@ -1,5 +1,5 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.api;
package de.srsoftware.oidc.api.data;
import java.util.Set;

View File

@@ -1,5 +1,5 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.api;
package de.srsoftware.oidc.api.data;
public record Authorization(String clientId, String userId, AuthorizedScopes scopes) {
}

View File

@@ -1,5 +1,5 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.api;
package de.srsoftware.oidc.api.data;
import java.time.Instant;
import java.util.Set;

View File

@@ -1,5 +1,5 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.api;
package de.srsoftware.oidc.api.data;
import static de.srsoftware.oidc.api.Constants.*;

View File

@@ -1,4 +1,4 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.api;
package de.srsoftware.oidc.api.data;
public enum Permission { MANAGE_CLIENTS }

View File

@@ -1,5 +1,5 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.api;
package de.srsoftware.oidc.api.data;
import java.time.Instant;

View File

@@ -1,5 +1,5 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.api;
package de.srsoftware.oidc.api.data;
import java.util.*;