Merge commit '41466943eb5bd93fa948c486ca7253b33767c835' into sqlite
This commit is contained in:
@@ -81,7 +81,7 @@ public class Application {
|
|||||||
new Forward(INDEX).bindPath(ROOT).on(server);
|
new Forward(INDEX).bindPath(ROOT).on(server);
|
||||||
new WellKnownController().bindPath(WELL_KNOWN, "/realms/oidc" + WELL_KNOWN).on(server);
|
new WellKnownController().bindPath(WELL_KNOWN, "/realms/oidc" + WELL_KNOWN).on(server);
|
||||||
new UserController(mailConfig, sessionService, userService, staticPages).bindPath(API_USER).on(server);
|
new UserController(mailConfig, sessionService, userService, staticPages).bindPath(API_USER).on(server);
|
||||||
var tokenControllerConfig = new TokenController.Configuration("https://lightoidc.srsoftware.de", 10); // TODO configure or derive from hostname
|
var tokenControllerConfig = new TokenController.Configuration(10);
|
||||||
new TokenController(authService, clientService, keyManager, userService, tokenControllerConfig).bindPath(API_TOKEN).on(server);
|
new TokenController(authService, clientService, keyManager, userService, tokenControllerConfig).bindPath(API_TOKEN).on(server);
|
||||||
new ClientController(authService, clientService, sessionService, userService).bindPath(API_CLIENT).on(server);
|
new ClientController(authService, clientService, sessionService, userService).bindPath(API_CLIENT).on(server);
|
||||||
new KeyStoreController(keyStore).bindPath(JWKS).on(server);
|
new KeyStoreController(keyStore).bindPath(JWKS).on(server);
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import org.jose4j.lang.JoseException;
|
|||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
public class TokenController extends PathHandler {
|
public class TokenController extends PathHandler {
|
||||||
public record Configuration(String issuer, int tokenExpirationMinutes) {
|
public record Configuration(int tokenExpirationMinutes) {
|
||||||
}
|
}
|
||||||
private final ClientService clients;
|
private final ClientService clients;
|
||||||
private final AuthorizationService authorizations;
|
private final AuthorizationService authorizations;
|
||||||
@@ -115,7 +115,8 @@ public class TokenController extends PathHandler {
|
|||||||
var user = optUser.get();
|
var user = optUser.get();
|
||||||
|
|
||||||
var accessToken = users.accessToken(user);
|
var accessToken = users.accessToken(user);
|
||||||
String jwToken = createJWT(client, user, accessToken);
|
var issuer = hostname(ex);
|
||||||
|
String jwToken = createJWT(client, user, accessToken, issuer);
|
||||||
ex.getResponseHeaders().add("Cache-Control", "no-store");
|
ex.getResponseHeaders().add("Cache-Control", "no-store");
|
||||||
JSONObject response = new JSONObject();
|
JSONObject response = new JSONObject();
|
||||||
response.put(ACCESS_TOKEN, accessToken.id());
|
response.put(ACCESS_TOKEN, accessToken.id());
|
||||||
@@ -126,13 +127,13 @@ public class TokenController extends PathHandler {
|
|||||||
return sendContent(ex, response);
|
return sendContent(ex, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createJWT(Client client, User user, AccessToken accessToken) {
|
private String createJWT(Client client, User user, AccessToken accessToken, String issuer) {
|
||||||
try {
|
try {
|
||||||
PublicJsonWebKey key = keyManager.getKey();
|
PublicJsonWebKey key = keyManager.getKey();
|
||||||
var algo = key.getAlgorithm();
|
var algo = key.getAlgorithm();
|
||||||
var atHash = this.atHash(algo, accessToken);
|
var atHash = this.atHash(algo, accessToken);
|
||||||
key.setUse("sig");
|
key.setUse("sig");
|
||||||
JwtClaims claims = createIdTokenClaims(user, client, atHash);
|
JwtClaims claims = createIdTokenClaims(user, client, atHash, issuer);
|
||||||
|
|
||||||
// A JWT is a JWS and/or a JWE with JSON claims as the payload.
|
// A JWT is a JWS and/or a JWE with JSON claims as the payload.
|
||||||
// In this example it is a JWS so we create a JsonWebSignature object.
|
// In this example it is a JWS so we create a JsonWebSignature object.
|
||||||
@@ -167,13 +168,13 @@ public class TokenController extends PathHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private JwtClaims createIdTokenClaims(User user, Client client, String atHash) {
|
private JwtClaims createIdTokenClaims(User user, Client client, String atHash, String issuer) {
|
||||||
var optNonce = authorizations.consumeNonce(user.uuid(), client.id());
|
var optNonce = authorizations.consumeNonce(user.uuid(), client.id());
|
||||||
JwtClaims claims = new JwtClaims();
|
JwtClaims claims = new JwtClaims();
|
||||||
|
|
||||||
// required claims:
|
// required claims:
|
||||||
claims.setIssuer(config.issuer); // who creates the token and signs it
|
claims.setIssuer(issuer); // who creates the token and signs it
|
||||||
claims.setSubject(user.uuid()); // the subject/principal is whom the token is about
|
claims.setSubject(user.uuid()); // the subject/principal is whom the token is about
|
||||||
claims.setAudience(client.id());
|
claims.setAudience(client.id());
|
||||||
claims.setExpirationTimeMinutesInTheFuture(config.tokenExpirationMinutes); // time when the token will expire (10 minutes from now)
|
claims.setExpirationTimeMinutesInTheFuture(config.tokenExpirationMinutes); // time when the token will expire (10 minutes from now)
|
||||||
claims.setIssuedAtToNow();
|
claims.setIssuedAtToNow();
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import jakarta.mail.*;
|
|||||||
import jakarta.mail.internet.*;
|
import jakarta.mail.internet.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Light OIDC</title>
|
||||||
|
<script src="scripts/common.js"></script>
|
||||||
|
<script src="scripts/user.js"></script>
|
||||||
|
<script src="scripts/authorization.js"></script>
|
||||||
|
<link rel="stylesheet" href="style.css" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav></nav>
|
||||||
|
<div id="content" style="display: none">
|
||||||
|
Eine vertrauende Seite, <span id="rp">unknown</span>, hat Zugriff auf die folgenden Informationen erfragt:
|
||||||
|
<ul id="scopes">
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
Stimmen Sie zu, diese Informationen mit <span id="rp2">unknown</span> zu teilen?
|
||||||
|
<button type="button" onclick="grantAutorization(1)">Ja - für einen Tag</button>
|
||||||
|
<button type="button" onclick="grantAutorization(7)">Ja - für eine Woche</button>
|
||||||
|
<button type="button" onclick="grantAutorization(30)">Ja - für einen Monat</button>
|
||||||
|
<button type="button" onclick="grantAutorization(365)">Ja - für ein Jahr</button>
|
||||||
|
<button type="button" onclick="denyAutorization()">No</button>
|
||||||
|
</div>
|
||||||
|
<div id="error_missing_parameter" class="error" style="display: none">
|
||||||
|
Request enthält den benötigten Parameter "<span id="parameter"></span>" nicht!
|
||||||
|
</div>
|
||||||
|
<div id="error_unknown_client" class="error" style="display: none">
|
||||||
|
Client "<span id="client_id"></span>" ist dem Backend nicht bekannt!
|
||||||
|
</div>
|
||||||
|
<div id="error_unsupported_response_type" class="error" style="display: none">
|
||||||
|
Rückgabe-Typ "<span id="response_type"></span>" wird nicht unterstützt!
|
||||||
|
</div>
|
||||||
|
<div id="error_missing_code" class="error">
|
||||||
|
Fehlender Rückgabe-Typ: code
|
||||||
|
</div>
|
||||||
|
<div id="error_invalid_redirect" class="error" style="display: none">
|
||||||
|
Ungültige Umleitung: <span id="redirect_uri"></span>
|
||||||
|
</div>
|
||||||
|
<div id="missing_scopes" class="error" style="display: none">Authorisierungs-Quelle lieferte weder eine Liste von <em>nicht-autorisierten Scopes</em> noch eine Liste von <em>authorisierten Scopes</em>! Das ist ein Server-Fehler.</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
Link zum Zurückseten des Passworts für {service}
|
||||||
|
Liebe(r) {displayname},
|
||||||
|
|
||||||
|
Jemand – wahrscheinlich du – beauftragte das Passwort für {service} zurückzusetzen.
|
||||||
|
|
||||||
|
Falls du das warst öffne bitte den folgenden Link in deinem Browser:
|
||||||
|
|
||||||
|
{link}
|
||||||
|
|
||||||
|
Falls du das Zurücksetzen *nicht angefragt hast* (oder versehentlich), kannst du diese Mail einfach ignorieren.
|
||||||
|
|
||||||
|
Beste Grüße, dein OIDC-Admin.
|
||||||
@@ -84,4 +84,7 @@ function backendAutorization(){
|
|||||||
}).then(handleResponse);
|
}).then(handleResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
backendAutorization();
|
document.addEventListener("logged_in", function(event) { // wait until page loaded
|
||||||
|
backendAutorization();
|
||||||
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -8,17 +8,19 @@ function handleClients(response){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var clients = response.json().then(clients => {
|
var clients = response.json().then(clients => {
|
||||||
|
var arr = [];
|
||||||
|
for (let id in clients) arr.push(clients[id]);
|
||||||
|
arr.sort((a,b) => a.name < b.name ? -1 : 1);
|
||||||
var bottom = document.getElementById('bottom');
|
var bottom = document.getElementById('bottom');
|
||||||
for (let id in clients){
|
for (let client of arr){
|
||||||
var row = document.createElement("tr");
|
var row = document.createElement("tr");
|
||||||
var client = clients[id];
|
|
||||||
row.innerHTML = `<td>${client.name}</td>
|
row.innerHTML = `<td>${client.name}</td>
|
||||||
<td>${id}</td>
|
<td>${client.client_id}</td>
|
||||||
<td>${client.redirect_uris.join("<br/>")}</td>
|
<td>${client.redirect_uris.join("<br/>")}</td>
|
||||||
<td>${link(client.landing_page)}</td>
|
<td>${link(client.landing_page)}</td>
|
||||||
<td>
|
<td>
|
||||||
<button type="button" onclick="edit('${id}')">Edit</button>
|
<button type="button" onclick="edit('${client.client_id}')">Edit</button>
|
||||||
<button class="danger" onclick="remove('${id}')" type="button">Remove</button>
|
<button class="danger" onclick="remove('${client.client_id}')" type="button">Remove</button>
|
||||||
</td>`;
|
</td>`;
|
||||||
bottom.parentNode.insertBefore(row,bottom);
|
bottom.parentNode.insertBefore(row,bottom);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,13 @@ function handleUsers(response){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
response.json().then(users => {
|
response.json().then(users => {
|
||||||
|
var arr = [];
|
||||||
|
for (let id in users) arr.push(users[id]);
|
||||||
|
arr.sort((a,b) => a.username < b.username ? -1 : 1);
|
||||||
var bottom = document.getElementById('bottom');
|
var bottom = document.getElementById('bottom');
|
||||||
for (let id in users){
|
for (var u of arr){
|
||||||
var row = document.createElement("tr");
|
var row = document.createElement("tr");
|
||||||
var u = users[id];
|
//var u = users[id];
|
||||||
var manage = {
|
var manage = {
|
||||||
clients : u.permissions.includes('MANAGE_CLIENTS'),
|
clients : u.permissions.includes('MANAGE_CLIENTS'),
|
||||||
perms : u.permissions.includes('MANAGE_PERMISSIONS'),
|
perms : u.permissions.includes('MANAGE_PERMISSIONS'),
|
||||||
@@ -52,16 +55,16 @@ function handleUsers(response){
|
|||||||
row.innerHTML = `<td>${u.username}</td>
|
row.innerHTML = `<td>${u.username}</td>
|
||||||
<td>${u.realname}</td>
|
<td>${u.realname}</td>
|
||||||
<td>${u.email}</td>
|
<td>${u.email}</td>
|
||||||
<td>${id}</td>
|
<td>${u.uuid}</td>
|
||||||
<td style="display: none" class="permissions">
|
<td style="display: none" class="permissions">
|
||||||
<button onclick="editPermission('${id}','MANAGE_CLIENTS',${manage.clients})">${manage.clients ?'-':'+'} <span>Manage</span> Clients</button>
|
<button onclick="editPermission('${u.uuid}','MANAGE_CLIENTS',${manage.clients})">${manage.clients ?'-':'+'} <span>Manage</span> Clients</button>
|
||||||
<button onclick="editPermission('${id}','MANAGE_PERMISSIONS',${manage.perms})">${manage.perms ?'-':'+'} <span>Manage</span> Permissions</button>
|
<button onclick="editPermission('${u.uuid}','MANAGE_PERMISSIONS',${manage.perms})">${manage.perms ?'-':'+'} <span>Manage</span> Permissions</button>
|
||||||
<button onclick="editPermission('${id}','MANAGE_SMTP',${manage.smtp})">${manage.smtp ?'-':'+'} <span>Manage</span> SMTP</button>
|
<button onclick="editPermission('${u.uuid}','MANAGE_SMTP',${manage.smtp})">${manage.smtp ?'-':'+'} <span>Manage</span> SMTP</button>
|
||||||
<button onclick="editPermission('${id}','MANAGE_USERS',${manage.users})">${manage.users ?'-':'+'} <span>Manage</span> Users</button>
|
<button onclick="editPermission('${u.uuid}','MANAGE_USERS',${manage.users})">${manage.users ?'-':'+'} <span>Manage</span> Users</button>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button type="button" onclick="reset_password('${id}')" id="reset-${id}">Reset password</button>
|
<button type="button" onclick="reset_password('${u.uuid}')" id="reset-${u.uuid}">Reset password</button>
|
||||||
<button id="remove-${u.uuid}" class="danger" onclick="remove('${id}','${u.realname}')" type="button">Remove</button>
|
<button id="remove-${u.uuid}" class="danger" onclick="remove('${u.uuid}','${u.realname}')" type="button">Remove</button>
|
||||||
</td>`;
|
</td>`;
|
||||||
bottom.parentNode.insertBefore(row,bottom);
|
bottom.parentNode.insertBefore(row,bottom);
|
||||||
if (user.permissions.includes('MANAGE_PERMISSIONS')) showAll('permissions');
|
if (user.permissions.includes('MANAGE_PERMISSIONS')) showAll('permissions');
|
||||||
|
|||||||
Reference in New Issue
Block a user