implemented forwarding errors to UI
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -21,9 +21,14 @@ public class Constants {
|
|||||||
public static final String DAYS = "days";
|
public static final String DAYS = "days";
|
||||||
public static final String ENCRYPTION_KEY = "encryption_key";
|
public static final String ENCRYPTION_KEY = "encryption_key";
|
||||||
public static final String ERROR_DESCRIPTION = "error_description";
|
public static final String ERROR_DESCRIPTION = "error_description";
|
||||||
|
public static final String ERROR_INVALID_REDIRECT = "error_invalid_redirect";
|
||||||
public static final String ERROR_LOCKED = "error_locked";
|
public static final String ERROR_LOCKED = "error_locked";
|
||||||
public static final String ERROR_LOGIN_FAILED = "error_login_failed";
|
public static final String ERROR_LOGIN_FAILED = "error_login_failed";
|
||||||
|
public static final String ERROR_MISSING_PARAMETER = "error_missing_parameter";
|
||||||
|
public static final String ERROR_MISSONG_CODE_RESPONSE_TYPE = "error_missing_code";
|
||||||
public static final String ERROR_NO_USERNAME = "error_no_username";
|
public static final String ERROR_NO_USERNAME = "error_no_username";
|
||||||
|
public static final String ERROR_UNKNOWN_CLIENT = "error_unknown_client";
|
||||||
|
public static final String ERROR_UNSUPPORTED_RESPONSE_TYPE = "error_unsupported_response_type";
|
||||||
public static final String EXPIRATION = "expiration";
|
public static final String EXPIRATION = "expiration";
|
||||||
public static final String EXPIRES_IN = "expires_in";
|
public static final String EXPIRES_IN = "expires_in";
|
||||||
public static final String GRANT_TYPE = "grant_type";
|
public static final String GRANT_TYPE = "grant_type";
|
||||||
@@ -38,6 +43,7 @@ public class Constants {
|
|||||||
public static final String MAILCONFIG = "mail_config";
|
public static final String MAILCONFIG = "mail_config";
|
||||||
public static final String NAME = "name";
|
public static final String NAME = "name";
|
||||||
public static final String NONCE = "nonce";
|
public static final String NONCE = "nonce";
|
||||||
|
public static final String PARAM = "parameter";
|
||||||
public static final String PERMISSION = "permission";
|
public static final String PERMISSION = "permission";
|
||||||
public static final String OPENID = "openid";
|
public static final String OPENID = "openid";
|
||||||
public static final String REDIRECT_URI = "redirect_uri";
|
public static final String REDIRECT_URI = "redirect_uri";
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package de.srsoftware.oidc.backend;
|
|||||||
|
|
||||||
import static de.srsoftware.oidc.api.Constants.*;
|
import static de.srsoftware.oidc.api.Constants.*;
|
||||||
import static de.srsoftware.oidc.api.data.Permission.MANAGE_CLIENTS;
|
import static de.srsoftware.oidc.api.data.Permission.MANAGE_CLIENTS;
|
||||||
import static de.srsoftware.utils.Optionals.emptyIfBlank;
|
|
||||||
import static java.net.HttpURLConnection.*;
|
import static java.net.HttpURLConnection.*;
|
||||||
|
|
||||||
import com.sun.net.httpserver.HttpExchange;
|
import com.sun.net.httpserver.HttpExchange;
|
||||||
@@ -12,6 +11,7 @@ import de.srsoftware.oidc.api.data.AuthorizedScopes;
|
|||||||
import de.srsoftware.oidc.api.data.Client;
|
import de.srsoftware.oidc.api.data.Client;
|
||||||
import de.srsoftware.oidc.api.data.Session;
|
import de.srsoftware.oidc.api.data.Session;
|
||||||
import de.srsoftware.oidc.api.data.User;
|
import de.srsoftware.oidc.api.data.User;
|
||||||
|
import de.srsoftware.utils.Error;
|
||||||
import de.srsoftware.utils.Optionals;
|
import de.srsoftware.utils.Optionals;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
@@ -32,13 +32,6 @@ public class ClientController extends Controller {
|
|||||||
users = userService;
|
users = userService;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean authorizationError(HttpExchange ex, String errorCode, String description, String state) throws IOException {
|
|
||||||
var map = new HashMap<String, String>();
|
|
||||||
map.put(ERROR, errorCode);
|
|
||||||
emptyIfBlank(description).ifPresent(d -> map.put(ERROR_DESCRIPTION, d));
|
|
||||||
emptyIfBlank(state).ifPresent(s -> map.put(STATE, s));
|
|
||||||
return badRequest(ex, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean authorize(HttpExchange ex, Session session) throws IOException {
|
private boolean authorize(HttpExchange ex, Session session) throws IOException {
|
||||||
var optUser = users.load(session.userId());
|
var optUser = users.load(session.userId());
|
||||||
@@ -46,34 +39,30 @@ public class ClientController extends Controller {
|
|||||||
var user = optUser.get();
|
var user = optUser.get();
|
||||||
var json = json(ex);
|
var json = json(ex);
|
||||||
var state = json.has(STATE) ? json.getString(STATE) : null;
|
var state = json.has(STATE) ? json.getString(STATE) : null;
|
||||||
if (!json.has(CLIENT_ID)) return authorizationError(ex, INVALID_REQUEST, "Missing required parameter \"%s\"!".formatted(CLIENT_ID), state);
|
if (!json.has(CLIENT_ID)) return badRequest(ex, Error.message(ERROR_MISSING_PARAMETER, PARAM, CLIENT_ID, STATE, state));
|
||||||
var clientId = json.getString(CLIENT_ID);
|
var clientId = json.getString(CLIENT_ID);
|
||||||
var optClient = clients.getClient(clientId);
|
var optClient = clients.getClient(clientId);
|
||||||
if (optClient.isEmpty()) return authorizationError(ex, INVALID_REQUEST_OBJECT, "unknown client: %s".formatted(clientId), state);
|
if (optClient.isEmpty()) return badRequest(ex, Error.message(ERROR_UNKNOWN_CLIENT, CLIENT_ID, clientId, STATE, state));
|
||||||
|
|
||||||
for (String param : List.of(SCOPE, RESPONSE_TYPE, REDIRECT_URI)) {
|
for (String param : List.of(SCOPE, RESPONSE_TYPE, REDIRECT_URI)) {
|
||||||
if (!json.has(param)) return authorizationError(ex, INVALID_REQUEST, "Missing required parameter \"%s\"!".formatted(param), state);
|
if (!json.has(param)) return badRequest(ex, Error.message(ERROR_MISSING_PARAMETER, PARAM, param, STATE, state));
|
||||||
}
|
}
|
||||||
var scopes = toList(json, SCOPE);
|
var scopes = toList(json, SCOPE);
|
||||||
if (!scopes.contains(OPENID)) return authorizationError(ex, INVALID_SCOPE, "This is an OpenID Provider. You should request \"openid\" scope!", state);
|
if (!scopes.contains(OPENID)) return badRequest(ex, Error.message(ERROR_MISSING_PARAMETER, PARAM, "Scope: openid", STATE, state));
|
||||||
var responseTypes = toList(json, RESPONSE_TYPE);
|
var responseTypes = toList(json, RESPONSE_TYPE);
|
||||||
for (var responseType : responseTypes) {
|
for (var responseType : responseTypes) {
|
||||||
switch (responseType) {
|
switch (responseType) {
|
||||||
case ID_TOKEN:
|
|
||||||
case TOKEN:
|
|
||||||
return authorizationError(ex, REQUEST_NOT_SUPPORTED, "Response type \"%s\" currently not supported".formatted(responseType), state);
|
|
||||||
case CODE:
|
case CODE:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return authorizationError(ex, INVALID_REQUEST_OBJECT, "Unknown response type \"%s\"".formatted(responseType), state);
|
return badRequest(ex, Error.message(ERROR_UNSUPPORTED_RESPONSE_TYPE, RESPONSE_TYPE, responseType, STATE, state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!responseTypes.contains(CODE)) return authorizationError(ex, REQUEST_NOT_SUPPORTED, "Sorry, at the moment I can only handle \"%s\" response type".formatted(CODE), state);
|
if (!responseTypes.contains(CODE)) return badRequest(ex, Error.message(ERROR_MISSONG_CODE_RESPONSE_TYPE, STATE, state));
|
||||||
|
|
||||||
var client = optClient.get();
|
var client = optClient.get();
|
||||||
var redirect = json.getString(REDIRECT_URI);
|
var redirect = json.getString(REDIRECT_URI);
|
||||||
if (!client.redirectUris().contains(redirect)) authorizationError(ex, INVALID_REDIRECT_URI, "unknown redirect uri: %s".formatted(redirect), state);
|
|
||||||
|
|
||||||
|
if (!client.redirectUris().contains(redirect)) return badRequest(ex, Error.message(ERROR_INVALID_REDIRECT, REDIRECT_URI, redirect, STATE, state));
|
||||||
|
|
||||||
if (json.has(AUTHORZED)) { // user did consent
|
if (json.has(AUTHORZED)) { // user did consent
|
||||||
var authorized = json.getJSONObject(AUTHORZED);
|
var authorized = json.getJSONObject(AUTHORZED);
|
||||||
|
|||||||
@@ -22,7 +22,21 @@
|
|||||||
<button type="button" onclick="grantAutorization(365)">Yes - for 1 year</button>
|
<button type="button" onclick="grantAutorization(365)">Yes - for 1 year</button>
|
||||||
<button type="button" onclick="denyAutorization()">No</button>
|
<button type="button" onclick="denyAutorization()">No</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="error" class="error" style="display: none"></div>
|
<div id="error_missing_parameter" class="error">
|
||||||
|
Request does not contain required parameter "<span id="parameter"></span>"!
|
||||||
|
</div>
|
||||||
|
<div id="error_unknown_client" class="error">
|
||||||
|
Client "<span id="client_id"></span>" unknown to backend!
|
||||||
|
</div>
|
||||||
|
<div id="error_unsupported_response_type" class="error">
|
||||||
|
Response type "<span id="response_type"></span>" not supported!
|
||||||
|
</div>
|
||||||
|
<div id="error_missing_code" class="error">
|
||||||
|
Missing response type: code
|
||||||
|
</div>
|
||||||
|
<div id="error_invalid_redirect" class="error">
|
||||||
|
invalid redirect: <span id="redirect_uri"></span>
|
||||||
|
</div>
|
||||||
<div id="missing_scopes" class="error" style="display: none">Authorization resource contained neither list of <em>unauthorized scopes</em> nor list of <em>authorized scopes</em>! This is a server problem.</div>
|
<div id="missing_scopes" class="error" style="display: none">Authorization resource contained neither list of <em>unauthorized scopes</em> nor list of <em>authorized scopes</em>! This is a server problem.</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -18,6 +18,7 @@ function showScope(response,scope){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleResponse(response){
|
function handleResponse(response){
|
||||||
|
hideAll('error');
|
||||||
if (response.ok){
|
if (response.ok){
|
||||||
response.json().then(json => {
|
response.json().then(json => {
|
||||||
if (json.rp) {
|
if (json.rp) {
|
||||||
@@ -43,19 +44,23 @@ function handleResponse(response){
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log("handleResponse(…) ← ",response);
|
console.log("handleResponse(…) ← ",response);
|
||||||
if (response.status == 401){
|
if (response.status == 401){ // unauthorized
|
||||||
login();
|
login();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
response.json().then(json => {
|
response.json().then(json => {
|
||||||
setText('error',"Error: <br/>"+json.error_description);
|
console.log("handleResponse → error",json);
|
||||||
show('error');
|
if (json.error) show(json.error);
|
||||||
|
if (json.metadata.client_id) setText('client_id',json.metadata.client_id);
|
||||||
|
if (json.metadata.parameter) setText('parameter',json.metadata.parameter);
|
||||||
|
if (json.metadata.redirect_uri) setText('redirect_uri',json.metadata.redirect_uri);
|
||||||
|
if (json.metadata.response_type)setText('response_type',json.metadata.response_type)
|
||||||
});
|
});
|
||||||
if (json.error != "invalid_request_uri"){
|
/*if (json.error != "invalid_request_uri"){
|
||||||
var url = params.get('redirect_uri') + '?' + new URLSearchParams(json).toString();
|
var url = params.get('redirect_uri') + '?' + new URLSearchParams(json).toString();
|
||||||
console.log('redirecting to '+url);
|
console.log('redirecting to '+url);
|
||||||
redirect(url);
|
redirect(url);
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user