re-implemented first part: authorization
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -12,18 +12,25 @@ public class Constants {
|
||||
public static final String CLIENT_ID = "client_id";
|
||||
public static final String CLIENT_SECRET = "client_secret";
|
||||
public static final String CODE = "code";
|
||||
public static final String ERROR = "error";
|
||||
public static final String CONFIG_PATH = "LIGHTOIDC_CONFIG_PATH";
|
||||
public static final String CONFIRMED = "confirmed";
|
||||
public static final String DAYS = "days";
|
||||
public static final String ERROR_DESCRIPTION = "error_description";
|
||||
public static final String EXPIRATION = "expiration";
|
||||
public static final String EXPIRES_IN = "expires_in";
|
||||
public static final String GRANT_TYPE = "grant_type";
|
||||
public static final String ID_TOKEN = "id_token";
|
||||
public static final String INVALID_REDIRECT_URI = "invalid_request_uri";
|
||||
public static final String INVALID_REQUEST = "invalid_request";
|
||||
public static final String INVALID_REQUEST_OBJECT = "invalid_request_object";
|
||||
public static final String INVALID_SCOPE = "invalid_scope";
|
||||
public static final String NAME = "name";
|
||||
public static final String NONCE = "nonce";
|
||||
public static final String OPENID = "openid";
|
||||
public static final String REDIRECT_URI = "redirect_uri";
|
||||
public static final String REDIRECT_URIS = "redirect_uris";
|
||||
public static final String REQUEST_NOT_SUPPORTED = "request_not_supported";
|
||||
public static final String RESPONSE_TYPE = "response_type";
|
||||
public static final String SCOPE = "scope";
|
||||
public static final String SECRET = "secret";
|
||||
|
||||
@@ -25,36 +25,45 @@ public class ClientController extends Controller {
|
||||
clients = clientService;
|
||||
}
|
||||
|
||||
private boolean authorizationError(HttpExchange ex, String errorCode, String description, String state) throws IOException {
|
||||
var map = new HashMap<String, String>();
|
||||
map.put(ERROR,errorCode);
|
||||
if (description != null) map.put(ERROR_DESCRIPTION,description);
|
||||
if (state != null) map.put(STATE,state);
|
||||
return badRequest(ex,map);
|
||||
}
|
||||
|
||||
private boolean authorize(HttpExchange ex, Session session) throws IOException {
|
||||
var user = session.user();
|
||||
var json = json(ex);
|
||||
for (String param : List.of(SCOPE, RESPONSE_TYPE, CLIENT_ID, REDIRECT_URI)) {
|
||||
if (!json.has(param)) return badRequest(ex, "Missing required parameter \"%s\"!".formatted(param));
|
||||
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);
|
||||
var clientId = json.getString(CLIENT_ID);
|
||||
var optClient = clients.getClient(clientId);
|
||||
if (optClient.isEmpty()) return authorizationError(ex,INVALID_REQUEST_OBJECT,"unknown client: %s".formatted(clientId),state);
|
||||
|
||||
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);
|
||||
}
|
||||
var scopes = toList(json, SCOPE);
|
||||
if (!scopes.contains(OPENID)) return badRequest(ex, "This is an OpenID Provider. You should request \"openid\" scope!");
|
||||
if (!scopes.contains(OPENID)) return authorizationError(ex,INVALID_SCOPE,"This is an OpenID Provider. You should request \"openid\" scope!",state);
|
||||
var responseTypes = toList(json, RESPONSE_TYPE);
|
||||
for (var responseType : responseTypes) {
|
||||
switch (responseType) {
|
||||
case ID_TOKEN:
|
||||
case TOKEN:
|
||||
return sendContent(ex, HTTP_NOT_IMPLEMENTED, "Response type \"%s\" currently not supported".formatted(responseType));
|
||||
return authorizationError(ex, REQUEST_NOT_SUPPORTED, "Response type \"%s\" currently not supported".formatted(responseType),state);
|
||||
case CODE:
|
||||
break;
|
||||
default:
|
||||
return badRequest(ex, "Unknown response type \"%s\"".formatted(responseType));
|
||||
return authorizationError(ex,INVALID_REQUEST_OBJECT,"Unknown response type \"%s\"".formatted(responseType),state);
|
||||
}
|
||||
}
|
||||
if (!responseTypes.contains(CODE)) return badRequest(ex, "Sorry, at the moment I can only handle \"%s\" response type".formatted(CODE));
|
||||
if ( !responseTypes.contains(CODE)) return authorizationError(ex, REQUEST_NOT_SUPPORTED, "Sorry, at the moment I can only handle \"%s\" response type".formatted(CODE),state);
|
||||
|
||||
var clientId = json.getString(CLIENT_ID);
|
||||
var optClient = clients.getClient(clientId);
|
||||
if (optClient.isEmpty()) return badRequest(ex, Map.of(CAUSE, "unknown client", CLIENT_ID, clientId));
|
||||
var client = optClient.get();
|
||||
var redirect = json.getString(REDIRECT_URI);
|
||||
if (!client.redirectUris().contains(redirect)) return badRequest(ex, Map.of(CAUSE, "unknown redirect uri", REDIRECT_URI, redirect));
|
||||
var state = json.has(STATE) ? json.getString(STATE) : null;
|
||||
if (!client.redirectUris().contains(redirect)) authorizationError(ex, INVALID_REDIRECT_URI, "unknown redirect uri: %s".formatted(redirect),state);
|
||||
|
||||
client.nonce(json.has(NONCE) ? json.getString(NONCE) : null);
|
||||
if (json.has(AUTHORZED)) {
|
||||
@@ -69,9 +78,9 @@ public class ClientController extends Controller {
|
||||
if (!authResult.unauthorizedScopes().isEmpty()) {
|
||||
return sendContent(ex, Map.of("unauthorized_scopes", authResult.unauthorizedScopes(), "rp", client.name()));
|
||||
}
|
||||
var authoriedScopes = authResult.authorizedScopes().stream().map(AuthorizedScope::scope).collect(Collectors.joining(" "));
|
||||
var authorizedScopes = authResult.authorizedScopes().stream().map(AuthorizedScope::scope).collect(Collectors.joining(" "));
|
||||
var result = new HashMap<String, String>();
|
||||
result.put(SCOPE, authoriedScopes);
|
||||
result.put(SCOPE, authorizedScopes);
|
||||
result.put(CODE, authResult.authCode());
|
||||
if (state != null) result.put(STATE, state);
|
||||
return sendContent(ex, result);
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Light OIDC</title>
|
||||
<script src="common.js"></script>
|
||||
<script src="user.js"></script>
|
||||
<script src="clients.js"></script>
|
||||
<script src="scripts/common.js"></script>
|
||||
<script src="scripts/user.js"></script>
|
||||
<script src="scripts/clients.js"></script>
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<a href="index.html">Übersicht</a>
|
||||
<a href="clients.html" class="MANAGE_CLIENTS">Clients</a>
|
||||
<a href="users.html" class="MANAGE_USERS">Benutzer</a>
|
||||
<a href="https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth" target="_blank">Spec</a>
|
||||
<a href="settings.html">Einstellungen</a>
|
||||
<a href="logout.html">Ausloggen</a>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Light OIDC</title>
|
||||
<script src="common.js"></script>
|
||||
<script src="user.js"></script>
|
||||
<script src="authorization.js"></script>
|
||||
<script src="scripts/common.js"></script>
|
||||
<script src="scripts/user.js"></script>
|
||||
<script src="scripts/authorization.js"></script>
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Light OIDC</title>
|
||||
<script src="common.js"></script>
|
||||
<script src="user.js"></script>
|
||||
<script src="clients.js"></script>
|
||||
<script src="scripts/common.js"></script>
|
||||
<script src="scripts/user.js"></script>
|
||||
<script src="scripts/clients.js"></script>
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Light OIDC</title>
|
||||
<script src="common.js"></script>
|
||||
<script src="user.js"></script>
|
||||
<script src="edit_client.js"></script>
|
||||
<script src="scripts/common.js"></script>
|
||||
<script src="scripts/user.js"></script>
|
||||
<script src="scripts/edit_client.js"></script>
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Light OIDC</title>
|
||||
<script src="common.js"></script>
|
||||
<script src="user.js"></script>
|
||||
<script src="scripts/common.js"></script>
|
||||
<script src="scripts/user.js"></script>
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Light OIDC</title>
|
||||
<script src="common.js"></script>
|
||||
<script src="login.js"></script>
|
||||
<script src="scripts/common.js"></script>
|
||||
<script src="scripts/login.js"></script>
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Light OIDC</title>
|
||||
<script src="common.js"></script>
|
||||
<script src="logout.js"></script>
|
||||
<script src="scripts/common.js"></script>
|
||||
<script src="scripts/logout.js"></script>
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<a href="index.html">Dashboard</a>
|
||||
<a href="clients.html" class="MANAGE_CLIENTS">Clients</a>
|
||||
<a href="users.html" class="MANAGE_USERS">Users</a>
|
||||
<a href="https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth" target="_blank">Spec</a>
|
||||
<a href="settings.html">Settings</a>
|
||||
<a href="logout.html">Logout</a>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Light OIDC</title>
|
||||
<script src="common.js"></script>
|
||||
<script src="user.js"></script>
|
||||
<script src="new_client.js"></script>
|
||||
<script src="scripts/common.js"></script>
|
||||
<script src="scripts/user.js"></script>
|
||||
<script src="scripts/new_client.js"></script>
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -39,14 +39,19 @@ async function handleResponse(response){
|
||||
}
|
||||
show('missing_scopes');
|
||||
} else {
|
||||
console.log(response);
|
||||
console.log("handleResponse(…) ← ",response);
|
||||
if (response.status == 401){
|
||||
login();
|
||||
return;
|
||||
}
|
||||
var text = await response.text();
|
||||
setText('error',"Error: <br/>"+text);
|
||||
var json = await response.json();
|
||||
setText('error',"Error: <br/>"+json.error_description);
|
||||
show('error');
|
||||
if (json.error != "invalid_request_uri"){
|
||||
var url = params.get('redirect_uri') + '?' + new URLSearchParams(json).toString();
|
||||
console.log('redirecting to '+url);
|
||||
redirect(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +61,7 @@ function grantAutorization(days){
|
||||
}
|
||||
|
||||
function denyAutorization(){
|
||||
redirect(params.get('redirect_uri')+"?error=access denied");
|
||||
redirect(params.get('redirect_uri')+"?error=consent_required");
|
||||
}
|
||||
|
||||
function backendAutorization(){
|
||||
@@ -2,9 +2,9 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Light OIDC</title>
|
||||
<script src="common.js"></script>
|
||||
<script src="user.js"></script>
|
||||
<script src="settings.js"></script>
|
||||
<script src="scripts/common.js"></script>
|
||||
<script src="scripts/user.js"></script>
|
||||
<script src="scripts/settings.js"></script>
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user