You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

137 lines
4.9 KiB

/* © SRSoftware 2024 */
package de.srsoftware.oidc.backend;
import static de.srsoftware.oidc.api.Constants.*;
import static de.srsoftware.oidc.api.Permission.MANAGE_CLIENTS;
import static de.srsoftware.utils.Strings.uuid;
import static java.lang.System.Logger.Level.ERROR;
import static java.net.HttpURLConnection.*;
import com.sun.net.httpserver.HttpExchange;
import de.srsoftware.oidc.api.*;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import org.json.JSONObject;
public class ClientController extends Controller {
private static final System.Logger LOG = System.getLogger(ClientController.class.getSimpleName());
private final AuthorizationService authorizations;
private final ClientService clients;
public ClientController(AuthorizationService authorizationService, ClientService clientService, SessionService sessionService) {
super(sessionService);
authorizations = authorizationService;
clients = clientService;
}
private boolean authorize(HttpExchange ex, Session session) throws IOException {
var user = session.user();
var json = json(ex);
var scope = json.getString(SCOPE);
if (!Arrays.asList(scope.split(" ")).contains(OPENID)) return sendContent(ex, HTTP_BAD_REQUEST, Map.of(ERROR, "openid scope missing in request"));
var clientId = json.getString(CLIENT_ID);
var redirect = json.getString(REDIRECT_URI);
var optClient = clients.getClient(clientId);
if (optClient.isEmpty()) return badRequest(ex, Map.of(CAUSE, "unknown client", CLIENT_ID, clientId));
var client = optClient.get();
if (!client.redirectUris().contains(redirect)) return badRequest(ex, Map.of(CAUSE, "unknown redirect uri", REDIRECT_URI, redirect));
client.nonce(json.has(NONCE) ? json.getString(NONCE) : null);
if (!authorizations.isAuthorized(client, session.user())) {
if (json.has(DAYS)) {
var days = json.getInt(DAYS);
var expiration = Instant.now().plus(Duration.ofDays(days));
authorizations.authorize(client, user, expiration);
} else {
return sendContent(ex, Map.of(CONFIRMED, false, NAME, client.name()));
}
}
var state = json.getString(STATE);
var code = uuid();
authorizations.addCode(client, session.user(), code);
return sendContent(ex, Map.of(CONFIRMED, true, CODE, code, REDIRECT_URI, redirect, STATE, state));
}
private boolean deleteClient(HttpExchange ex, Session session) throws IOException {
if (!session.user().hasPermission(MANAGE_CLIENTS)) return badRequest(ex, "NOT ALLOWED");
var json = json(ex);
var id = json.getString(CLIENT_ID);
clients.getClient(id).ifPresent(clients::remove);
return sendEmptyResponse(HTTP_OK, ex);
}
@Override
public boolean doDelete(String path, HttpExchange ex) throws IOException {
var optSession = getSession(ex);
if (optSession.isEmpty()) return sendEmptyResponse(HTTP_UNAUTHORIZED, ex);
// post-login paths
var session = optSession.get();
switch (path) {
case "/":
return deleteClient(ex, session);
}
return notFound(ex);
}
@Override
public boolean doPost(String path, HttpExchange ex) throws IOException {
var optSession = getSession(ex);
if (optSession.isEmpty()) return sendEmptyResponse(HTTP_UNAUTHORIZED, ex);
// post-login paths
var session = optSession.get();
switch (path) {
case "/":
return load(ex, session);
case "/add", "/update":
return save(ex, session);
case "/authorize":
return authorize(ex, session);
case "/list":
return list(ex, session);
}
return notFound(ex);
}
private boolean list(HttpExchange ex, Session session) throws IOException {
var user = session.user();
if (!user.hasPermission(MANAGE_CLIENTS)) return sendEmptyResponse(HTTP_FORBIDDEN, ex);
var json = new JSONObject();
clients.listClients().forEach(client -> json.put(client.id(), Map.of("name", client.name(), "redirect_uris", client.redirectUris())));
return sendContent(ex, json);
}
private boolean load(HttpExchange ex, Session session) throws IOException {
if (!session.user().hasPermission(MANAGE_CLIENTS)) return sendEmptyResponse(HTTP_FORBIDDEN, ex);
var json = json(ex);
if (json.has(CLIENT_ID)) {
var clientID = json.getString(CLIENT_ID);
var client = clients.getClient(clientID).map(Client::map).map(JSONObject::new);
if (client.isPresent()) return sendContent(ex, client.get());
}
return sendEmptyResponse(HTTP_NOT_FOUND, ex);
}
private boolean save(HttpExchange ex, Session session) throws IOException {
if (!session.user().hasPermission(MANAGE_CLIENTS)) return badRequest(ex, "NOT ALLOWED");
var json = json(ex);
var redirects = new HashSet<String>();
for (Object o : json.getJSONArray(REDIRECT_URIS)) {
if (o instanceof String s) redirects.add(s);
}
var client = new Client(json.getString(CLIENT_ID), json.getString(NAME), json.getString(SECRET), redirects);
clients.save(client);
return sendContent(ex, client);
}
}