improving path handling, working on authorization flow
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
/* © SRSoftware 2024 */
|
/* © SRSoftware 2024 */
|
||||||
package de.srsoftware.oidc.api;
|
package de.srsoftware.oidc.api;
|
||||||
|
|
||||||
|
import static java.net.HttpURLConnection.HTTP_OK;
|
||||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
|
||||||
import com.sun.net.httpserver.HttpExchange;
|
import com.sun.net.httpserver.HttpExchange;
|
||||||
@@ -15,30 +16,58 @@ import org.json.JSONObject;
|
|||||||
|
|
||||||
public abstract class PathHandler implements HttpHandler {
|
public abstract class PathHandler implements HttpHandler {
|
||||||
public static final String CONTENT_TYPE = "Content-Type";
|
public static final String CONTENT_TYPE = "Content-Type";
|
||||||
|
public static final String GET = "GET";
|
||||||
public static final String JSON = "application/json";
|
public static final String JSON = "application/json";
|
||||||
public static final String POST = "POST";
|
public static final String POST = "POST";
|
||||||
|
|
||||||
private String path;
|
private String[] paths;
|
||||||
|
|
||||||
public class Bond {
|
public class Bond {
|
||||||
Bond(String p) {
|
Bond(String[] paths) {
|
||||||
path = p;
|
PathHandler.this.paths = paths;
|
||||||
}
|
}
|
||||||
public HttpServer on(HttpServer server) {
|
public HttpServer on(HttpServer server) {
|
||||||
server.createContext(path, PathHandler.this);
|
for (var path : paths) server.createContext(path, PathHandler.this);
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bond bindPath(String path) {
|
public Bond bindPath(String... path) {
|
||||||
return new Bond(path);
|
return new Bond(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean doGet(String path, HttpExchange ex) throws IOException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public boolean doPost(String path, HttpExchange ex) throws IOException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(HttpExchange ex) throws IOException {
|
||||||
|
String path = relativePath(ex);
|
||||||
|
String method = ex.getRequestMethod();
|
||||||
|
System.out.printf("%s %s\n", method, path);
|
||||||
|
boolean dummy = switch (method) {
|
||||||
|
case POST -> doPost(path,ex);
|
||||||
|
case GET -> doGet(path,ex);
|
||||||
|
default -> false;
|
||||||
|
};
|
||||||
|
ex.getResponseBody().close();
|
||||||
|
}
|
||||||
|
|
||||||
public String relativePath(HttpExchange ex) {
|
public String relativePath(HttpExchange ex) {
|
||||||
var path = ex.getRequestURI().toString();
|
var requestPath = ex.getRequestURI().toString();
|
||||||
if (path.startsWith(this.path)) path = path.substring(this.path.length());
|
for (var path : paths){
|
||||||
if (path.startsWith("/")) path = path.substring(1);
|
if (requestPath.startsWith(path)) {
|
||||||
return 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 *************/
|
/******* begin of static methods *************/
|
||||||
@@ -55,6 +84,10 @@ public abstract class PathHandler implements HttpHandler {
|
|||||||
return Optional.ofNullable(ex.getRequestHeaders().get(key)).map(List::stream).map(Stream::findFirst).orElse(Optional.empty());
|
return Optional.ofNullable(ex.getRequestHeaders().get(key)).map(List::stream).map(Stream::findFirst).orElse(Optional.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isPost(String method) {
|
||||||
|
return POST.equals(method);
|
||||||
|
}
|
||||||
|
|
||||||
public static JSONObject json(HttpExchange ex) throws IOException {
|
public static JSONObject json(HttpExchange ex) throws IOException {
|
||||||
return new JSONObject(body(ex));
|
return new JSONObject(body(ex));
|
||||||
}
|
}
|
||||||
@@ -63,8 +96,23 @@ public abstract class PathHandler implements HttpHandler {
|
|||||||
return getHeader(ex, "Accept-Language").map(s -> Arrays.stream(s.split(","))).map(Stream::findFirst).orElse(Optional.empty());
|
return getHeader(ex, "Accept-Language").map(s -> Arrays.stream(s.split(","))).map(Stream::findFirst).orElse(Optional.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sendEmptyResponse(int statusCode, HttpExchange ex) throws IOException {
|
|
||||||
|
public static String prefix(HttpExchange ex) {
|
||||||
|
return "http://%s".formatted(ex.getRequestHeaders().getFirst("Host"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean sendEmptyResponse(int statusCode, HttpExchange ex) throws IOException {
|
||||||
ex.sendResponseHeaders(statusCode, 0);
|
ex.sendResponseHeaders(statusCode, 0);
|
||||||
ex.getResponseBody().close();
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean sendContent(HttpExchange ex, byte[] bytes) throws IOException {
|
||||||
|
ex.sendResponseHeaders(HTTP_OK, bytes.length);
|
||||||
|
ex.getResponseBody().write(bytes);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean sendContent(HttpExchange ex, Object o) throws IOException {
|
||||||
|
return sendContent(ex, o.toString().getBytes(UTF_8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,11 @@ import java.util.*;
|
|||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
public class Application {
|
public class Application {
|
||||||
|
public static final String BACKEND = "/api";
|
||||||
|
private static final String FAVICON = "/favicon.ico";
|
||||||
|
public static final String ROOT = "/";
|
||||||
public static final String STATIC_PATH = "/web";
|
public static final String STATIC_PATH = "/web";
|
||||||
|
private static final String WELL_KNOWN = "/.well-known";
|
||||||
public static final String FIRST_USER = "admin";
|
public static final String FIRST_USER = "admin";
|
||||||
public static final String FIRST_USER_PASS = "admin";
|
public static final String FIRST_USER_PASS = "admin";
|
||||||
public static final String FIRST_UUID = UUID.randomUUID().toString();
|
public static final String FIRST_UUID = UUID.randomUUID().toString();
|
||||||
@@ -36,9 +40,9 @@ public class Application {
|
|||||||
UserService userService = fileStore;
|
UserService userService = fileStore;
|
||||||
SessionService sessionService = fileStore;
|
SessionService sessionService = fileStore;
|
||||||
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
|
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
|
||||||
new StaticPages(basePath).bindPath(STATIC_PATH).on(server);
|
new StaticPages(basePath).bindPath(STATIC_PATH, FAVICON).on(server);
|
||||||
new Forward(INDEX).bindPath("/").on(server);
|
new Forward(INDEX).bindPath(ROOT).on(server);
|
||||||
new Backend(sessionService, userService).bindPath("/api").on(server);
|
new Backend(sessionService, userService).bindPath(BACKEND, WELL_KNOWN).on(server);
|
||||||
server.setExecutor(Executors.newCachedThreadPool());
|
server.setExecutor(Executors.newCachedThreadPool());
|
||||||
server.start();
|
server.start();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import java.util.Optional;
|
|||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
public class Backend extends PathHandler {
|
public class Backend extends PathHandler {
|
||||||
|
private static final String CLIENT_ID = "client_id";
|
||||||
|
private static final String REDIRECT_URI = "redirect_uri";
|
||||||
private final SessionService sessions;
|
private final SessionService sessions;
|
||||||
private final UserService users;
|
private final UserService users;
|
||||||
|
|
||||||
@@ -23,57 +25,81 @@ public class Backend extends PathHandler {
|
|||||||
users = userService;
|
users = userService;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doLogin(HttpExchange ex) throws IOException {
|
private boolean authorize(HttpExchange ex, Session session) throws IOException {
|
||||||
|
var json = json(ex);
|
||||||
|
var clientId = json.getString(CLIENT_ID);
|
||||||
|
var redirect = json.getString(REDIRECT_URI);
|
||||||
|
System.out.println(json);
|
||||||
|
return sendEmptyResponse(HTTP_NOT_FOUND,ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean doLogin(HttpExchange ex) throws IOException {
|
||||||
var body = json(ex);
|
var body = json(ex);
|
||||||
|
|
||||||
var username = body.has(USERNAME) ? body.getString(USERNAME) : null;
|
var username = body.has(USERNAME) ? body.getString(USERNAME) : null;
|
||||||
var password = body.has(PASSWORD) ? body.getString(PASSWORD) : null;
|
var password = body.has(PASSWORD) ? body.getString(PASSWORD) : null;
|
||||||
|
|
||||||
Optional<User> user = users.load(username, password);
|
Optional<User> user = users.load(username, password);
|
||||||
if (user.isPresent()) {
|
if (user.isPresent()) return sendUserAndCookie(ex, sessions.createSession(user.get()));
|
||||||
var session = sessions.createSession(user.get());
|
return sendEmptyResponse(HTTP_UNAUTHORIZED, ex);
|
||||||
sendUserAndCookie(ex, session);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sendEmptyResponse(HTTP_UNAUTHORIZED, ex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(HttpExchange ex) throws IOException {
|
public boolean doGet(String path, HttpExchange ex) throws IOException {
|
||||||
String path = relativePath(ex);
|
System.out.printf("GET %s…\n", path);
|
||||||
String method = ex.getRequestMethod();
|
|
||||||
System.out.printf("%s %s…", method, path);
|
|
||||||
|
|
||||||
var session = getSession(ex);
|
|
||||||
if ("login".equals(path) && POST.equals(method)) {
|
|
||||||
doLogin(ex); // TODO: prevent brute force
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (session.isEmpty()) {
|
|
||||||
sendEmptyResponse(HTTP_UNAUTHORIZED, ex);
|
|
||||||
System.err.println("unauthorized");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (path) {
|
switch (path) {
|
||||||
case "user":
|
case "/openid-configuration":
|
||||||
sendUserAndCookie(ex, session.get());
|
return openidConfig(ex);
|
||||||
return;
|
}
|
||||||
|
return sendEmptyResponse(HTTP_NOT_FOUND, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean doPost(String path, HttpExchange ex) throws IOException {
|
||||||
|
System.out.printf("POST %s…\n", path);
|
||||||
|
|
||||||
|
// pre-login paths
|
||||||
|
switch (path) {
|
||||||
|
case "/login":
|
||||||
|
return doLogin(ex);
|
||||||
|
}
|
||||||
|
var optSession = getSession(ex);
|
||||||
|
if (optSession.isEmpty()) return sendEmptyResponse(HTTP_UNAUTHORIZED, ex);
|
||||||
|
|
||||||
|
// post-login paths
|
||||||
|
var session = optSession.get();
|
||||||
|
switch (path) {
|
||||||
|
case "/authorize":
|
||||||
|
return authorize(ex,session);
|
||||||
|
case "/user":
|
||||||
|
return sendUserAndCookie(ex, session);
|
||||||
}
|
}
|
||||||
System.err.println("not implemented");
|
System.err.println("not implemented");
|
||||||
sendEmptyResponse(HTTP_NOT_FOUND, ex);
|
return sendEmptyResponse(HTTP_NOT_FOUND, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<Session> getSession(HttpExchange ex) {
|
private Optional<Session> getSession(HttpExchange ex) {
|
||||||
return SessionToken.from(ex).map(SessionToken::sessionId).flatMap(sessions::retrieve);
|
return SessionToken.from(ex).map(SessionToken::sessionId).flatMap(sessions::retrieve);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendUserAndCookie(HttpExchange ex, Session session) throws IOException {
|
private boolean openidConfig(HttpExchange ex) throws IOException {
|
||||||
|
var uri = ex.getRequestURI().toString();
|
||||||
|
JSONObject json = new JSONObject();
|
||||||
|
|
||||||
|
json.put("authorization_endpoint", prefix(ex) + "/web/authorization.html");
|
||||||
|
return sendContent(ex, json);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean sendUserAndCookie(HttpExchange ex, Session session) throws IOException {
|
||||||
var bytes = new JSONObject(session.user().map(false)).toString().getBytes(UTF_8);
|
var bytes = new JSONObject(session.user().map(false)).toString().getBytes(UTF_8);
|
||||||
var headers = ex.getResponseHeaders();
|
var headers = ex.getResponseHeaders();
|
||||||
|
|
||||||
headers.add(CONTENT_TYPE, JSON);
|
headers.add(CONTENT_TYPE, JSON);
|
||||||
new SessionToken(session.id()).addTo(headers);
|
new SessionToken(session.id()).addTo(headers);
|
||||||
ex.sendResponseHeaders(200, bytes.length);
|
ex.sendResponseHeaders(200, bytes.length);
|
||||||
ex.getResponseBody().write(bytes);
|
var out = ex.getResponseBody();
|
||||||
|
out.write(bytes);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ public class Forward extends PathHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(HttpExchange ex) throws IOException {
|
public boolean doGet(String path, HttpExchange ex) throws IOException {
|
||||||
System.out.printf("Forwarding (%d) %s to %s…\n", CODE, ex.getRequestURI(), toPath);
|
System.out.printf("Forwarding (%d) %s to %s…\n", CODE, path, toPath);
|
||||||
ex.getResponseHeaders().add("Location", toPath);
|
ex.getResponseHeaders().add("Location", toPath);
|
||||||
ex.sendResponseHeaders(CODE, 0);
|
ex.sendResponseHeaders(CODE, 0);
|
||||||
ex.getResponseBody().close();
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
/* © SRSoftware 2024 */
|
/* © SRSoftware 2024 */
|
||||||
package de.srsoftware.oidc.web;
|
package de.srsoftware.oidc.web;
|
||||||
|
|
||||||
|
import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
|
||||||
|
|
||||||
import com.sun.net.httpserver.HttpExchange;
|
import com.sun.net.httpserver.HttpExchange;
|
||||||
import de.srsoftware.oidc.api.PathHandler;
|
import de.srsoftware.oidc.api.PathHandler;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@@ -14,6 +15,7 @@ import java.util.Optional;
|
|||||||
|
|
||||||
public class StaticPages extends PathHandler {
|
public class StaticPages extends PathHandler {
|
||||||
private static final String DEFAULT_LANGUAGE = "en";
|
private static final String DEFAULT_LANGUAGE = "en";
|
||||||
|
private static final String FAVICON = "favicon.ico";
|
||||||
private final Optional<Path> base;
|
private final Optional<Path> base;
|
||||||
private ClassLoader loader;
|
private ClassLoader loader;
|
||||||
|
|
||||||
@@ -27,27 +29,22 @@ public class StaticPages extends PathHandler {
|
|||||||
private static final String INDEX = "en/index.html";
|
private static final String INDEX = "en/index.html";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(HttpExchange ex) throws IOException {
|
public boolean doGet(String relativePath, HttpExchange ex) throws IOException {
|
||||||
String relativePath = relativePath(ex);
|
|
||||||
String lang = language(ex).orElse(DEFAULT_LANGUAGE);
|
String lang = language(ex).orElse(DEFAULT_LANGUAGE);
|
||||||
String method = ex.getRequestMethod();
|
if (relativePath.startsWith("/")) relativePath = relativePath.substring(1);
|
||||||
|
if (relativePath.isBlank()) {
|
||||||
if (relativePath.isBlank()) relativePath = INDEX;
|
relativePath = ex.getRequestURI().toString().endsWith(FAVICON) ? FAVICON : INDEX;
|
||||||
System.out.printf("%s %s: ", method, ex.getRequestURI());
|
}
|
||||||
try {
|
try {
|
||||||
System.out.printf("Loading %s for lagnuage %s…", relativePath, lang);
|
System.out.printf("Loading %s for language %s…", relativePath, lang);
|
||||||
Response response = loadFile(lang, relativePath).orElseThrow(() -> new FileNotFoundException());
|
Response response = loadFile(lang, relativePath).orElseThrow(() -> new FileNotFoundException());
|
||||||
|
|
||||||
ex.getResponseHeaders().add(CONTENT_TYPE, response.contentType);
|
ex.getResponseHeaders().add(CONTENT_TYPE, response.contentType);
|
||||||
ex.sendResponseHeaders(200, response.content.length);
|
|
||||||
OutputStream os = ex.getResponseBody();
|
|
||||||
os.write(response.content);
|
|
||||||
os.close();
|
|
||||||
System.out.println("success.");
|
System.out.println("success.");
|
||||||
|
return sendContent(ex, response.content);
|
||||||
} catch (FileNotFoundException fnf) {
|
} catch (FileNotFoundException fnf) {
|
||||||
ex.sendResponseHeaders(404, 0);
|
|
||||||
ex.getResponseBody().close();
|
|
||||||
System.err.println("failed!");
|
System.err.println("failed!");
|
||||||
|
return sendEmptyResponse(HTTP_NOT_FOUND, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Light OIDC</title>
|
||||||
|
<script src="config.js"></script>
|
||||||
|
<script src="user.js"></script>
|
||||||
|
<script src="authorization.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Authorization!</h1>
|
||||||
|
Not implemented, yet!
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
var params = new URLSearchParams(window.location.search)
|
||||||
|
var json = Object.fromEntries(params);
|
||||||
|
|
||||||
|
fetch(api+"/authorize",{
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(json),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
BIN
de.srsoftware.oidc.web/src/main/resources/en/favicon.ico
Normal file
BIN
de.srsoftware.oidc.web/src/main/resources/en/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -1,10 +1,24 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
<title>Light OIDC</title>
|
<title>Light OIDC</title>
|
||||||
<script src="config.js"></script>
|
<script src="config.js"></script>
|
||||||
<script src="index.js"></script>
|
<script src="user.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Welcome!</h1>
|
<h1>Welcome!</h1>
|
||||||
|
<h2>Connected sites</h2>
|
||||||
|
These are sites that are connected with your account:
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Site</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<button onclick="window.location.href='newclient.html';">Add new site…</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
const UNAUTHORIZED = 401;
|
|
||||||
|
|
||||||
function handleUser(response){
|
|
||||||
console.log(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch(api+"/user").then(handleUser);
|
|
||||||
@@ -1,25 +1,24 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
<title>Light OIDC</title>
|
<title>Light OIDC</title>
|
||||||
<script src="config.js"></script>
|
<script src="config.js"></script>
|
||||||
<script src="index.js"></script>
|
<script src="login.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Login</h1>
|
<h1>Login</h1>
|
||||||
<form id="login">
|
<fieldset id="login">
|
||||||
<fieldset>
|
|
||||||
<legend>User credentials</legend>
|
<legend>User credentials</legend>
|
||||||
<label>
|
<label>
|
||||||
Username
|
Username
|
||||||
<input type="text" name="username" />
|
<input type="text" id="username" />
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Password
|
Password
|
||||||
<input type="password" name="password" />
|
<input type="password" id="password" />
|
||||||
</label>
|
</label>
|
||||||
<button type="button" onClick="tryLogin()">Login</button>
|
<button type="button" onClick="tryLogin()">Login</button>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
|
||||||
<div id="error"></div>
|
<div id="error"></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
33
de.srsoftware.oidc.web/src/main/resources/en/login.js
Normal file
33
de.srsoftware.oidc.web/src/main/resources/en/login.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
async function handleLogin(response){
|
||||||
|
if (response.ok){
|
||||||
|
var body = await response.json();
|
||||||
|
|
||||||
|
setTimeout(doRedirect,100);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function doRedirect(){
|
||||||
|
let params = new URL(document.location.toString()).searchParams;
|
||||||
|
let redirect = params.get("return_to") || 'index.html';
|
||||||
|
window.location.href = redirect,true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tryLogin(){
|
||||||
|
document.getElementById("error").innerHTML = "";
|
||||||
|
var username = document.getElementById('username').value;
|
||||||
|
var password = document.getElementById('password').value;
|
||||||
|
fetch(api+"/login",{
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
username : username,
|
||||||
|
password : password
|
||||||
|
})
|
||||||
|
}).then(handleLogin);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
28
de.srsoftware.oidc.web/src/main/resources/en/newclient.html
Normal file
28
de.srsoftware.oidc.web/src/main/resources/en/newclient.html
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Light OIDC</title>
|
||||||
|
<script src="config.js"></script>
|
||||||
|
<script src="user.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Add new client</h1>
|
||||||
|
<fieldset>
|
||||||
|
<legend>Settings</legend>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>client name</th>
|
||||||
|
<td><input type="text" size="50" id="client-name"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>client secret</th>
|
||||||
|
<td><input type="text" size="50" id="client-secret"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>redirect urls</th>
|
||||||
|
<td><textarea cols="50" rows="5" id="redirect-urls"></textarea></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</fieldset>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
12
de.srsoftware.oidc.web/src/main/resources/en/user.js
Normal file
12
de.srsoftware.oidc.web/src/main/resources/en/user.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
const UNAUTHORIZED = 401;
|
||||||
|
|
||||||
|
async function handleUser(response){
|
||||||
|
if (response.status == UNAUTHORIZED) {
|
||||||
|
window.location.href = 'login.html?return_to='+encodeURI(window.location.href);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var user = await response.json();
|
||||||
|
// TODO: load navigation
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(api+"/user",{method:'POST'}).then(handleUser);
|
||||||
Reference in New Issue
Block a user