refactored classes and modules, fixed decoding bug
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.oidc.api;
|
||||
package de.srsoftware.oidc.api.data;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
@@ -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;
|
||||
@@ -1,5 +1,5 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.oidc.api;
|
||||
package de.srsoftware.oidc.api.data;
|
||||
|
||||
|
||||
import static de.srsoftware.oidc.api.Constants.*;
|
||||
@@ -1,4 +1,4 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.oidc.api;
|
||||
package de.srsoftware.oidc.api.data;
|
||||
|
||||
public enum Permission { MANAGE_CLIENTS }
|
||||
@@ -1,5 +1,5 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.oidc.api;
|
||||
package de.srsoftware.oidc.api.data;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.oidc.api;
|
||||
package de.srsoftware.oidc.api.data;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
Reference in New Issue
Block a user