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_ID = "client_id";
|
||||||
public static final String CLIENT_SECRET = "client_secret";
|
public static final String CLIENT_SECRET = "client_secret";
|
||||||
public static final String CODE = "code";
|
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 CONFIG_PATH = "LIGHTOIDC_CONFIG_PATH";
|
||||||
public static final String CONFIRMED = "confirmed";
|
public static final String CONFIRMED = "confirmed";
|
||||||
public static final String DAYS = "days";
|
public static final String DAYS = "days";
|
||||||
|
public static final String ERROR_DESCRIPTION = "error_description";
|
||||||
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";
|
||||||
public static final String ID_TOKEN = "id_token";
|
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 NAME = "name";
|
||||||
public static final String NONCE = "nonce";
|
public static final String NONCE = "nonce";
|
||||||
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";
|
||||||
public static final String REDIRECT_URIS = "redirect_uris";
|
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 RESPONSE_TYPE = "response_type";
|
||||||
public static final String SCOPE = "scope";
|
public static final String SCOPE = "scope";
|
||||||
public static final String SECRET = "secret";
|
public static final String SECRET = "secret";
|
||||||
|
|||||||
@@ -25,36 +25,45 @@ public class ClientController extends Controller {
|
|||||||
clients = clientService;
|
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 {
|
private boolean authorize(HttpExchange ex, Session session) throws IOException {
|
||||||
var user = session.user();
|
var user = session.user();
|
||||||
var json = json(ex);
|
var json = json(ex);
|
||||||
for (String param : List.of(SCOPE, RESPONSE_TYPE, CLIENT_ID, REDIRECT_URI)) {
|
var state = json.has(STATE) ? json.getString(STATE) : null;
|
||||||
if (!json.has(param)) return badRequest(ex, "Missing required parameter \"%s\"!".formatted(param));
|
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);
|
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);
|
var responseTypes = toList(json, RESPONSE_TYPE);
|
||||||
for (var responseType : responseTypes) {
|
for (var responseType : responseTypes) {
|
||||||
switch (responseType) {
|
switch (responseType) {
|
||||||
case ID_TOKEN:
|
case ID_TOKEN:
|
||||||
case 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:
|
case CODE:
|
||||||
break;
|
break;
|
||||||
default:
|
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 client = optClient.get();
|
||||||
var redirect = json.getString(REDIRECT_URI);
|
var redirect = json.getString(REDIRECT_URI);
|
||||||
if (!client.redirectUris().contains(redirect)) return badRequest(ex, Map.of(CAUSE, "unknown redirect uri", REDIRECT_URI, redirect));
|
if (!client.redirectUris().contains(redirect)) authorizationError(ex, INVALID_REDIRECT_URI, "unknown redirect uri: %s".formatted(redirect),state);
|
||||||
var state = json.has(STATE) ? json.getString(STATE) : null;
|
|
||||||
|
|
||||||
client.nonce(json.has(NONCE) ? json.getString(NONCE) : null);
|
client.nonce(json.has(NONCE) ? json.getString(NONCE) : null);
|
||||||
if (json.has(AUTHORZED)) {
|
if (json.has(AUTHORZED)) {
|
||||||
@@ -69,9 +78,9 @@ public class ClientController extends Controller {
|
|||||||
if (!authResult.unauthorizedScopes().isEmpty()) {
|
if (!authResult.unauthorizedScopes().isEmpty()) {
|
||||||
return sendContent(ex, Map.of("unauthorized_scopes", authResult.unauthorizedScopes(), "rp", client.name()));
|
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>();
|
var result = new HashMap<String, String>();
|
||||||
result.put(SCOPE, authoriedScopes);
|
result.put(SCOPE, authorizedScopes);
|
||||||
result.put(CODE, authResult.authCode());
|
result.put(CODE, authResult.authCode());
|
||||||
if (state != null) result.put(STATE, state);
|
if (state != null) result.put(STATE, state);
|
||||||
return sendContent(ex, result);
|
return sendContent(ex, result);
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Light OIDC</title>
|
<title>Light OIDC</title>
|
||||||
<script src="common.js"></script>
|
<script src="scripts/common.js"></script>
|
||||||
<script src="user.js"></script>
|
<script src="scripts/user.js"></script>
|
||||||
<script src="clients.js"></script>
|
<script src="scripts/clients.js"></script>
|
||||||
<link rel="stylesheet" href="style.css" />
|
<link rel="stylesheet" href="style.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<a href="index.html">Übersicht</a>
|
<a href="index.html">Übersicht</a>
|
||||||
<a href="clients.html" class="MANAGE_CLIENTS">Clients</a>
|
<a href="clients.html" class="MANAGE_CLIENTS">Clients</a>
|
||||||
<a href="users.html" class="MANAGE_USERS">Benutzer</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="settings.html">Einstellungen</a>
|
||||||
<a href="logout.html">Ausloggen</a>
|
<a href="logout.html">Ausloggen</a>
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Light OIDC</title>
|
<title>Light OIDC</title>
|
||||||
<script src="common.js"></script>
|
<script src="scripts/common.js"></script>
|
||||||
<script src="user.js"></script>
|
<script src="scripts/user.js"></script>
|
||||||
<script src="authorization.js"></script>
|
<script src="scripts/authorization.js"></script>
|
||||||
<link rel="stylesheet" href="style.css" />
|
<link rel="stylesheet" href="style.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Light OIDC</title>
|
<title>Light OIDC</title>
|
||||||
<script src="common.js"></script>
|
<script src="scripts/common.js"></script>
|
||||||
<script src="user.js"></script>
|
<script src="scripts/user.js"></script>
|
||||||
<script src="clients.js"></script>
|
<script src="scripts/clients.js"></script>
|
||||||
<link rel="stylesheet" href="style.css" />
|
<link rel="stylesheet" href="style.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Light OIDC</title>
|
<title>Light OIDC</title>
|
||||||
<script src="common.js"></script>
|
<script src="scripts/common.js"></script>
|
||||||
<script src="user.js"></script>
|
<script src="scripts/user.js"></script>
|
||||||
<script src="edit_client.js"></script>
|
<script src="scripts/edit_client.js"></script>
|
||||||
<link rel="stylesheet" href="style.css" />
|
<link rel="stylesheet" href="style.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Light OIDC</title>
|
<title>Light OIDC</title>
|
||||||
<script src="common.js"></script>
|
<script src="scripts/common.js"></script>
|
||||||
<script src="user.js"></script>
|
<script src="scripts/user.js"></script>
|
||||||
<link rel="stylesheet" href="style.css" />
|
<link rel="stylesheet" href="style.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Light OIDC</title>
|
<title>Light OIDC</title>
|
||||||
<script src="common.js"></script>
|
<script src="scripts/common.js"></script>
|
||||||
<script src="login.js"></script>
|
<script src="scripts/login.js"></script>
|
||||||
<link rel="stylesheet" href="style.css" />
|
<link rel="stylesheet" href="style.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Light OIDC</title>
|
<title>Light OIDC</title>
|
||||||
<script src="common.js"></script>
|
<script src="scripts/common.js"></script>
|
||||||
<script src="logout.js"></script>
|
<script src="scripts/logout.js"></script>
|
||||||
<link rel="stylesheet" href="style.css" />
|
<link rel="stylesheet" href="style.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<a href="index.html">Dashboard</a>
|
<a href="index.html">Dashboard</a>
|
||||||
<a href="clients.html" class="MANAGE_CLIENTS">Clients</a>
|
<a href="clients.html" class="MANAGE_CLIENTS">Clients</a>
|
||||||
<a href="users.html" class="MANAGE_USERS">Users</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="settings.html">Settings</a>
|
||||||
<a href="logout.html">Logout</a>
|
<a href="logout.html">Logout</a>
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Light OIDC</title>
|
<title>Light OIDC</title>
|
||||||
<script src="common.js"></script>
|
<script src="scripts/common.js"></script>
|
||||||
<script src="user.js"></script>
|
<script src="scripts/user.js"></script>
|
||||||
<script src="new_client.js"></script>
|
<script src="scripts/new_client.js"></script>
|
||||||
<link rel="stylesheet" href="style.css" />
|
<link rel="stylesheet" href="style.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -39,14 +39,19 @@ async function handleResponse(response){
|
|||||||
}
|
}
|
||||||
show('missing_scopes');
|
show('missing_scopes');
|
||||||
} else {
|
} else {
|
||||||
console.log(response);
|
console.log("handleResponse(…) ← ",response);
|
||||||
if (response.status == 401){
|
if (response.status == 401){
|
||||||
login();
|
login();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var text = await response.text();
|
var json = await response.json();
|
||||||
setText('error',"Error: <br/>"+text);
|
setText('error',"Error: <br/>"+json.error_description);
|
||||||
show('error');
|
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(){
|
function denyAutorization(){
|
||||||
redirect(params.get('redirect_uri')+"?error=access denied");
|
redirect(params.get('redirect_uri')+"?error=consent_required");
|
||||||
}
|
}
|
||||||
|
|
||||||
function backendAutorization(){
|
function backendAutorization(){
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Light OIDC</title>
|
<title>Light OIDC</title>
|
||||||
<script src="common.js"></script>
|
<script src="scripts/common.js"></script>
|
||||||
<script src="user.js"></script>
|
<script src="scripts/user.js"></script>
|
||||||
<script src="settings.js"></script>
|
<script src="scripts/settings.js"></script>
|
||||||
<link rel="stylesheet" href="style.css" />
|
<link rel="stylesheet" href="style.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
Reference in New Issue
Block a user