Browse Source

working on authorization flow

sqlite
Stephan Richter 4 months ago
parent
commit
a277be5091
  1. 6
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/Client.java
  2. 3
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/Constants.java
  3. 10
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/PathHandler.java
  4. 4
      de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java
  5. 38
      de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/Backend.java
  6. 4
      de.srsoftware.oidc.web/src/main/java/de/srsoftware/oidc/web/Forward.java
  7. 2
      de.srsoftware.oidc.web/src/main/resources/en/authorization.html
  8. 12
      de.srsoftware.oidc.web/src/main/resources/en/authorization.js
  9. 2
      de.srsoftware.oidc.web/src/main/resources/en/user.js

6
de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/Client.java

@ -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();
}
} }

3
de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/Constants.java

@ -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";
} }

10
de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/PathHandler.java

@ -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);
}
} }

4
de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java

@ -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);

38
de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/Backend.java

@ -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);
} }
} }

4
de.srsoftware.oidc.web/src/main/java/de/srsoftware/oidc/web/Forward.java

@ -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;
} }
} }

2
de.srsoftware.oidc.web/src/main/resources/en/authorization.html

@ -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>

12
de.srsoftware.oidc.web/src/main/resources/en/authorization.js

@ -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);

2
de.srsoftware.oidc.web/src/main/resources/en/user.js

@ -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){

Loading…
Cancel
Save