Browse Source

implemented implicit flow, added user claim to id token

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
main
Stephan Richter 2 months ago
parent
commit
eec87f678d
  1. 5
      de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java
  2. 29
      de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/ClientController.java
  3. 3
      de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/TokenController.java
  4. 3
      de.srsoftware.oidc.web/src/main/resources/en/scripts/authorization.js

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

@ -79,8 +79,9 @@ public class Application { @@ -79,8 +79,9 @@ public class Application {
new WellKnownController().bindPath(WELL_KNOWN, "/realms/oidc" + WELL_KNOWN).on(server);
new UserController(mailConfig, sessionService, userService, staticPages).bindPath(API_USER).on(server);
var tokenControllerConfig = new TokenController.Configuration(10);
new TokenController(authService, clientService, keyManager, userService, tokenControllerConfig).bindPath(API_TOKEN).on(server);
new ClientController(authService, clientService, sessionService, userService).bindPath(API_CLIENT).on(server);
var tokenController = new TokenController(authService, clientService, keyManager, userService, tokenControllerConfig);
tokenController.bindPath(API_TOKEN).on(server);
new ClientController(authService, clientService, sessionService, userService, tokenController).bindPath(API_CLIENT).on(server);
new KeyStoreController(keyStore).bindPath(JWKS).on(server);
new EmailController(mailConfig, sessionService, userService).bindPath(API_EMAIL).on(server);
server.setExecutor(Executors.newCachedThreadPool());

29
de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/ClientController.java

@ -25,12 +25,14 @@ public class ClientController extends Controller { @@ -25,12 +25,14 @@ public class ClientController extends Controller {
private final AuthorizationService authorizations;
private final ClientService clients;
private final UserService users;
private final TokenController tokens;
public ClientController(AuthorizationService authorizationService, ClientService clientService, SessionService sessionService, UserService userService) {
public ClientController(AuthorizationService authorizationService, ClientService clientService, SessionService sessionService, UserService userService, TokenController tokenController) {
super(sessionService);
authorizations = authorizationService;
clients = clientService;
users = userService;
tokens = tokenController;
}
@ -50,15 +52,18 @@ public class ClientController extends Controller { @@ -50,15 +52,18 @@ public class ClientController extends Controller {
var scopes = toList(json, SCOPE);
if (!scopes.contains(OPENID)) return badRequest(ex, Error.message(ERROR_MISSING_PARAMETER, PARAM, "Scope: openid", STATE, state));
var responseTypes = toList(json, RESPONSE_TYPE);
var types = 0;
for (var responseType : responseTypes) {
switch (responseType) {
case CODE:
case ID_TOKEN:
types++;
break;
default:
return badRequest(ex, Error.message(ERROR_UNSUPPORTED_RESPONSE_TYPE, RESPONSE_TYPE, responseType, STATE, state));
}
}
if (!responseTypes.contains(CODE)) return badRequest(ex, Error.message(ERROR_MISSING_CODE_RESPONSE_TYPE, STATE, state));
if (types < 1) return badRequest(ex, Error.message(ERROR_MISSING_CODE_RESPONSE_TYPE, STATE, state));
var client = optClient.get();
var redirect = json.getString(REDIRECT_URI);
@ -74,16 +79,32 @@ public class ClientController extends Controller { @@ -74,16 +79,32 @@ public class ClientController extends Controller {
}
if (json.has(NONCE)) authorizations.nonce(user.uuid(), client.id(), json.getString(NONCE));
var authResult = authorizations.getAuthorization(user.uuid(), client.id(), scopes);
if (!authResult.unauthorizedScopes().isEmpty()) {
return sendContent(ex, Map.of("unauthorized_scopes", authResult.unauthorizedScopes(), "rp", client.name()));
}
var joinedAuthorizedScopes = Optionals.nullable(authResult.authorizedScopes()).map(AuthorizedScopes::scopes).map(list -> String.join(" ", list));
var result = new HashMap<String, String>();
var result = new HashMap<String, Object>();
joinedAuthorizedScopes.ifPresent(authorizedScopes -> result.put(SCOPE, authorizedScopes));
if (responseTypes.contains(ID_TOKEN)) {
var accessToken = users.accessToken(user);
var issuer = hostname(ex);
String jwToken = tokens.createJWT(client, user, accessToken, issuer);
ex.getResponseHeaders().add("Cache-Control", "no-store");
result.put(ACCESS_TOKEN, accessToken.id());
result.put(TOKEN_TYPE, BEARER);
result.put(EXPIRES_IN, 3600);
result.put(ID_TOKEN, jwToken);
} else if (responseTypes.contains(CODE)) {
result.put(CODE, authResult.authCode());
if (state != null) result.put(STATE, state);
}
return sendContent(ex, result);
}

3
de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/TokenController.java

@ -127,7 +127,7 @@ public class TokenController extends PathHandler { @@ -127,7 +127,7 @@ public class TokenController extends PathHandler {
return sendContent(ex, response);
}
private String createJWT(Client client, User user, AccessToken accessToken, String issuer) {
String createJWT(Client client, User user, AccessToken accessToken, String issuer) {
try {
PublicJsonWebKey key = keyManager.getKey();
var algo = key.getAlgorithm();
@ -181,6 +181,7 @@ public class TokenController extends PathHandler { @@ -181,6 +181,7 @@ public class TokenController extends PathHandler {
claims.setClaim(AT_HASH, atHash);
claims.setClaim(CLIENT_ID, client.id());
claims.setClaim(EMAIL, user.email()); // additional claims/attributes about the subject can be added
claims.setClaim(USER, user.username());
optNonce.ifPresent(nonce -> claims.setClaim(NONCE, nonce));
claims.setGeneratedJwtId(); // a unique identifier for the token

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

@ -35,8 +35,9 @@ function handleResponse(response){ @@ -35,8 +35,9 @@ function handleResponse(response){
return;
}
if (json.scope){
var separator = json.id_token ? '#' : '?';
var query = Object.keys(json).map(key => `${key}=${encodeURIComponent(json[key])}`).join('&');
var url = params.get('redirect_uri') + '?' + query.toString();
var url = params.get('redirect_uri') + separator + query.toString();
redirect(url);
return;
}

Loading…
Cancel
Save