working on authorization flow
This commit is contained in:
@@ -5,9 +5,15 @@ import static de.srsoftware.oidc.api.Constants.*;
|
|||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public record Client(String id, String name, String secret, Set<String> redirectUris) {
|
public record Client(String id, String name, String secret, Set<String> redirectUris) {
|
||||||
public Map<String, Object> map() {
|
public Map<String, Object> map() {
|
||||||
return Map.of(CLIENT_ID, id, NAME, name, SECRET, secret, REDIRECT_URIS, redirectUris);
|
return Map.of(CLIENT_ID, id, NAME, name, SECRET, secret, REDIRECT_URIS, redirectUris);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String generateCode() {
|
||||||
|
System.err.printf("%s.generateCode() not implemented!", getClass().getSimpleName());
|
||||||
|
return UUID.randomUUID().toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,12 @@
|
|||||||
package de.srsoftware.oidc.api;
|
package de.srsoftware.oidc.api;
|
||||||
|
|
||||||
public class Constants {
|
public class Constants {
|
||||||
|
public
|
||||||
|
static final String CODE = "code";
|
||||||
public static final String CLIENT_ID = "client_id";
|
public static final String CLIENT_ID = "client_id";
|
||||||
public static final String NAME = "name";
|
public static final String NAME = "name";
|
||||||
public static final String REDIRECT_URI = "redirect_uri";
|
public static final String REDIRECT_URI = "redirect_uri";
|
||||||
public static final String REDIRECT_URIS = "redirect_uris";
|
public static final String REDIRECT_URIS = "redirect_uris";
|
||||||
public static final String SECRET = "secret";
|
public static final String SECRET = "secret";
|
||||||
|
public static final String STATE = "state";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
/* © SRSoftware 2024 */
|
/* © SRSoftware 2024 */
|
||||||
package de.srsoftware.oidc.api;
|
package de.srsoftware.oidc.api;
|
||||||
|
|
||||||
import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
|
import static java.net.HttpURLConnection.*;
|
||||||
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;
|
||||||
@@ -11,6 +10,7 @@ import com.sun.net.httpserver.HttpServer;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
@@ -120,6 +120,7 @@ public abstract class PathHandler implements HttpHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean sendContent(HttpExchange ex, Object o) throws IOException {
|
public static boolean sendContent(HttpExchange ex, Object o) throws IOException {
|
||||||
|
if (o instanceof Map map) o = new JSONObject(map);
|
||||||
if (o instanceof JSONObject) ex.getResponseHeaders().add(CONTENT_TYPE, JSON);
|
if (o instanceof JSONObject) ex.getResponseHeaders().add(CONTENT_TYPE, JSON);
|
||||||
return sendContent(ex, HTTP_OK, o.toString().getBytes(UTF_8));
|
return sendContent(ex, HTTP_OK, o.toString().getBytes(UTF_8));
|
||||||
}
|
}
|
||||||
@@ -131,4 +132,9 @@ public abstract class PathHandler implements HttpHandler {
|
|||||||
public static boolean sendError(HttpExchange ex, Object o) throws IOException {
|
public static boolean sendError(HttpExchange ex, Object o) throws IOException {
|
||||||
return sendContent(ex, HTTP_BAD_REQUEST, o.toString().getBytes(UTF_8));
|
return sendContent(ex, HTTP_BAD_REQUEST, o.toString().getBytes(UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean sendRedirect(HttpExchange ex, String url) throws IOException {
|
||||||
|
ex.getResponseHeaders().add("Location", url);
|
||||||
|
return sendEmptyResponse(HTTP_MOVED_TEMP, ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,11 +49,11 @@ public class Application {
|
|||||||
var tokens = new ArrayList<>(List.of(args));
|
var tokens = new ArrayList<>(List.of(args));
|
||||||
var map = new HashMap<String, Object>();
|
var map = new HashMap<String, Object>();
|
||||||
while (!tokens.isEmpty()) {
|
while (!tokens.isEmpty()) {
|
||||||
var token = tokens.removeFirst();
|
var token = tokens.remove(0);
|
||||||
switch (token) {
|
switch (token) {
|
||||||
case "--base":
|
case "--base":
|
||||||
if (tokens.isEmpty()) throw new IllegalArgumentException("--path option requires second argument!");
|
if (tokens.isEmpty()) throw new IllegalArgumentException("--path option requires second argument!");
|
||||||
map.put(BASE_PATH, Path.of(tokens.removeFirst()));
|
map.put(BASE_PATH, Path.of(tokens.remove(0)));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
System.err.printf("Unknown option: %s\n", token);
|
System.err.printf("Unknown option: %s\n", token);
|
||||||
|
|||||||
@@ -39,11 +39,16 @@ public class Backend extends PathHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean authorize(HttpExchange ex, Session session) throws IOException {
|
private boolean authorize(HttpExchange ex, Session session) throws IOException {
|
||||||
var json = json(ex);
|
var json = json(ex);
|
||||||
var clientId = json.getString(CLIENT_ID);
|
var clientId = json.getString(CLIENT_ID);
|
||||||
|
var optClient = clients.getClient(clientId);
|
||||||
|
if (optClient.isEmpty()) return sendEmptyResponse(HTTP_NOT_FOUND, ex);
|
||||||
|
var client = optClient.get();
|
||||||
var redirect = json.getString(REDIRECT_URI);
|
var redirect = json.getString(REDIRECT_URI);
|
||||||
System.out.println(json);
|
if (!client.redirectUris().contains(redirect)) return sendEmptyResponse(HTTP_BAD_REQUEST, ex);
|
||||||
return sendEmptyResponse(HTTP_NOT_FOUND, ex);
|
var state = json.getString(STATE);
|
||||||
|
var code = client.generateCode();
|
||||||
|
return sendContent(ex, Map.of(CODE,code,REDIRECT_URI,redirect,STATE,state));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean clients(HttpExchange ex, Session session) throws IOException {
|
private boolean clients(HttpExchange ex, Session session) throws IOException {
|
||||||
@@ -117,6 +122,8 @@ public class Backend extends PathHandler {
|
|||||||
switch (path) {
|
switch (path) {
|
||||||
case "/login":
|
case "/login":
|
||||||
return doLogin(ex);
|
return doLogin(ex);
|
||||||
|
case "/token":
|
||||||
|
return provideToken(ex);
|
||||||
}
|
}
|
||||||
var optSession = getSession(ex);
|
var optSession = getSession(ex);
|
||||||
if (optSession.isEmpty()) return sendEmptyResponse(HTTP_UNAUTHORIZED, ex);
|
if (optSession.isEmpty()) return sendEmptyResponse(HTTP_UNAUTHORIZED, ex);
|
||||||
@@ -164,17 +171,23 @@ public class Backend extends PathHandler {
|
|||||||
return sendEmptyResponse(HTTP_OK, ex);
|
return sendEmptyResponse(HTTP_OK, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean openidConfig(HttpExchange ex) throws IOException {
|
private boolean provideToken(HttpExchange ex) throws IOException {
|
||||||
JSONObject json = new JSONObject();
|
System.err.printf("%s.provideToken(ex) not implemented!\n",getClass().getSimpleName());
|
||||||
|
var json = json(ex);
|
||||||
json.put("authorization_endpoint", hostname(ex) + "/web/authorization.html");
|
System.err.println(json);
|
||||||
return sendContent(ex, json);
|
return sendEmptyResponse(HTTP_NOT_FOUND,ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean openidConfig(HttpExchange ex) throws IOException {
|
||||||
|
return sendContent(ex, Map.of(
|
||||||
|
"token_endpoint",hostname(ex)+"/api/token",
|
||||||
|
"authorization_endpoint", hostname(ex) + "/web/authorization.html")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean sendUserAndCookie(HttpExchange ex, Session session) throws IOException {
|
private boolean sendUserAndCookie(HttpExchange ex, Session session) throws IOException {
|
||||||
new SessionToken(session.id()).addTo(ex);
|
new SessionToken(session.id()).addTo(ex);
|
||||||
return sendContent(ex, new JSONObject(session.user().map(false)));
|
return sendContent(ex, session.user().map(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean updatePassword(HttpExchange ex, Session session) throws IOException {
|
private boolean updatePassword(HttpExchange ex, Session session) throws IOException {
|
||||||
@@ -193,7 +206,7 @@ public class Backend extends PathHandler {
|
|||||||
return sendError(ex, "password mismatch");
|
return sendError(ex, "password mismatch");
|
||||||
}
|
}
|
||||||
users.updatePassword(user, newPass1);
|
users.updatePassword(user, newPass1);
|
||||||
return sendContent(ex, new JSONObject(user.map(false)));
|
return sendContent(ex, user.map(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean updateUser(HttpExchange ex, Session session) throws IOException {
|
private boolean updateUser(HttpExchange ex, Session session) throws IOException {
|
||||||
@@ -206,7 +219,6 @@ public class Backend extends PathHandler {
|
|||||||
user.username(json.getString(USERNAME));
|
user.username(json.getString(USERNAME));
|
||||||
user.email(json.getString(EMAIL));
|
user.email(json.getString(EMAIL));
|
||||||
users.save(user);
|
users.save(user);
|
||||||
JSONObject response = new JSONObject(user.map(false));
|
return sendContent(ex, user.map(false));
|
||||||
return sendContent(ex, response);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ public class Forward extends PathHandler {
|
|||||||
@Override
|
@Override
|
||||||
public boolean doGet(String path, HttpExchange ex) throws IOException {
|
public boolean doGet(String path, HttpExchange ex) throws IOException {
|
||||||
System.out.printf("Forwarding (%d) %s to %s…\n", CODE, path, toPath);
|
System.out.printf("Forwarding (%d) %s to %s…\n", CODE, path, toPath);
|
||||||
ex.getResponseHeaders().add("Location", toPath);
|
return sendRedirect(ex,toPath);
|
||||||
ex.sendResponseHeaders(CODE, 0);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,10 @@
|
|||||||
<script src="common.js"></script>
|
<script src="common.js"></script>
|
||||||
<script src="user.js"></script>
|
<script src="user.js"></script>
|
||||||
<script src="authorization.js"></script>
|
<script src="authorization.js"></script>
|
||||||
|
<link rel="stylesheet" href="style.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<nav></nav>
|
||||||
<h1>Authorization!</h1>
|
<h1>Authorization!</h1>
|
||||||
Not implemented, yet!
|
Not implemented, yet!
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
var params = new URLSearchParams(window.location.search)
|
var params = new URLSearchParams(window.location.search)
|
||||||
var json = Object.fromEntries(params);
|
var json = Object.fromEntries(params);
|
||||||
|
|
||||||
|
async function handleResponse(response){
|
||||||
|
if (response.ok){
|
||||||
|
var json = await response.json();
|
||||||
|
console.log(json);
|
||||||
|
redirect(json.redirect_uri+'?code='+json.code+'&state='+json.state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fetch(api+"/authorize",{
|
fetch(api+"/authorize",{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(json),
|
body: JSON.stringify(json),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
})
|
}).then(handleResponse);
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
var user = null;
|
var user = null;
|
||||||
async function handleUser(response){
|
async function handleUser(response){
|
||||||
if (response.status == UNAUTHORIZED) {
|
if (response.status == UNAUTHORIZED) {
|
||||||
redirect('login.html?return_to='+encodeURI(window.location.href));
|
redirect('login.html?return_to='+encodeURIComponent(window.location.href));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (response.ok){
|
if (response.ok){
|
||||||
|
|||||||
Reference in New Issue
Block a user