revised TokenController.provideToken
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
/* © SRSoftware 2024 */
|
||||||
|
package de.srsoftware.oidc.api;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public record AuthResult(AuthorizedScopes authorizedScopes, Set<String> unauthorizedScopes, String authCode) {
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/* © SRSoftware 2024 */
|
||||||
|
package de.srsoftware.oidc.api;
|
||||||
|
|
||||||
|
public record Authorization(String clientId, String userId, AuthorizedScopes scopes) {
|
||||||
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
/* © SRSoftware 2024 */
|
|
||||||
package de.srsoftware.oidc.api;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
|
|
||||||
public record AuthorizedScope(String scope, Instant expiration) {
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/* © SRSoftware 2024 */
|
||||||
|
package de.srsoftware.oidc.api;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public record AuthorizedScopes(Set<String> scopes, Instant expiration) {
|
||||||
|
}
|
||||||
@@ -3,12 +3,10 @@ package de.srsoftware.oidc.api;
|
|||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public interface ClaimAuthorizationService {
|
public interface ClaimAuthorizationService {
|
||||||
public record AuthResult(List<AuthorizedScope> authorizedScopes, Set<String> unauthorizedScopes, String authCode) {
|
|
||||||
}
|
|
||||||
AuthResult getAuthorization(User user, Client client, Collection<String> scopes);
|
|
||||||
ClaimAuthorizationService authorize(User user, Client client, Collection<String> scopes, Instant expiration);
|
ClaimAuthorizationService authorize(User user, Client client, Collection<String> scopes, Instant expiration);
|
||||||
|
Optional<Authorization> consumeAuthorization(String authCode);
|
||||||
|
AuthResult getAuthorization(User user, Client client, Collection<String> scopes);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/* © SRSoftware 2024 */
|
/* © SRSoftware 2024 */
|
||||||
package de.srsoftware.oidc.api;
|
package de.srsoftware.oidc.api;
|
||||||
|
|
||||||
|
|
||||||
public class Constants {
|
public class Constants {
|
||||||
public static final String ACCESS_TOKEN = "access_token";
|
public static final String ACCESS_TOKEN = "access_token";
|
||||||
public static final String APP_NAME = "LightOIDC";
|
public static final String APP_NAME = "LightOIDC";
|
||||||
@@ -21,6 +22,8 @@ public class Constants {
|
|||||||
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_CLIENT = "invalid_client";
|
||||||
|
public static final String INVALID_GRANT = "invalid_grant";
|
||||||
public static final String INVALID_REDIRECT_URI = "invalid_request_uri";
|
public static final String INVALID_REDIRECT_URI = "invalid_request_uri";
|
||||||
public static final String INVALID_REQUEST = "invalid_request";
|
public static final String INVALID_REQUEST = "invalid_request";
|
||||||
public static final String INVALID_REQUEST_OBJECT = "invalid_request_object";
|
public static final String INVALID_REQUEST_OBJECT = "invalid_request_object";
|
||||||
@@ -37,4 +40,5 @@ public class Constants {
|
|||||||
public static final String STATE = "state";
|
public static final String STATE = "state";
|
||||||
public static final String TOKEN = "token";
|
public static final String TOKEN = "token";
|
||||||
public static final String TOKEN_TYPE = "token_type";
|
public static final String TOKEN_TYPE = "token_type";
|
||||||
|
public static final String UNAUTHORIZED_CLIENT = "unauthorized_client";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,7 @@ import com.sun.net.httpserver.HttpExchange;
|
|||||||
import com.sun.net.httpserver.HttpHandler;
|
import com.sun.net.httpserver.HttpHandler;
|
||||||
import com.sun.net.httpserver.HttpServer;
|
import com.sun.net.httpserver.HttpServer;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
@@ -30,6 +27,9 @@ public abstract class PathHandler implements HttpHandler {
|
|||||||
|
|
||||||
private String[] paths;
|
private String[] paths;
|
||||||
|
|
||||||
|
public record BasicAuth(String userId, String pass) {
|
||||||
|
}
|
||||||
|
|
||||||
public class Bond {
|
public class Bond {
|
||||||
Bond(String[] paths) {
|
Bond(String[] paths) {
|
||||||
PathHandler.this.paths = paths;
|
PathHandler.this.paths = paths;
|
||||||
@@ -102,6 +102,16 @@ public abstract class PathHandler implements HttpHandler {
|
|||||||
return getHeader(ex, AUTHORIZATION);
|
return getHeader(ex, AUTHORIZATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Optional<BasicAuth> getBasicAuth(HttpExchange ex) {
|
||||||
|
return getAuthToken(ex)
|
||||||
|
.filter(token -> token.startsWith("Basic ")) //
|
||||||
|
.map(token -> token.substring(6))
|
||||||
|
.map(Base64.getDecoder()::decode)
|
||||||
|
.map(bytes -> new String(bytes, UTF_8))
|
||||||
|
.map(token -> token.split(":", 2))
|
||||||
|
.map(arr -> new BasicAuth(arr[0], arr[1]));
|
||||||
|
}
|
||||||
|
|
||||||
public static Optional<String> getBearer(HttpExchange ex) {
|
public static Optional<String> getBearer(HttpExchange ex) {
|
||||||
return getAuthToken(ex).filter(token -> token.startsWith("Bearer ")).map(token -> token.substring(7));
|
return getAuthToken(ex).filter(token -> token.startsWith("Bearer ")).map(token -> token.substring(7));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,15 +3,16 @@ 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.Permission.MANAGE_CLIENTS;
|
import static de.srsoftware.oidc.api.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;
|
||||||
import de.srsoftware.oidc.api.*;
|
import de.srsoftware.oidc.api.*;
|
||||||
|
import de.srsoftware.utils.Optionals;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
public class ClientController extends Controller {
|
public class ClientController extends Controller {
|
||||||
@@ -28,8 +29,8 @@ public class ClientController extends Controller {
|
|||||||
private boolean authorizationError(HttpExchange ex, String errorCode, String description, String state) throws IOException {
|
private boolean authorizationError(HttpExchange ex, String errorCode, String description, String state) throws IOException {
|
||||||
var map = new HashMap<String, String>();
|
var map = new HashMap<String, String>();
|
||||||
map.put(ERROR, errorCode);
|
map.put(ERROR, errorCode);
|
||||||
if (description != null) map.put(ERROR_DESCRIPTION,description);
|
emptyIfBlank(description).ifPresent(d -> map.put(ERROR_DESCRIPTION, d));
|
||||||
if (state != null) map.put(STATE,state);
|
emptyIfBlank(state).ifPresent(s -> map.put(STATE, s));
|
||||||
return badRequest(ex, map);
|
return badRequest(ex, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +67,7 @@ public class ClientController extends Controller {
|
|||||||
if (!client.redirectUris().contains(redirect)) authorizationError(ex, INVALID_REDIRECT_URI, "unknown redirect uri: %s".formatted(redirect), state);
|
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);
|
client.nonce(json.has(NONCE) ? json.getString(NONCE) : null);
|
||||||
if (json.has(AUTHORZED)) {
|
if (json.has(AUTHORZED)) { // user did consent
|
||||||
var authorized = json.getJSONObject(AUTHORZED);
|
var authorized = json.getJSONObject(AUTHORZED);
|
||||||
var days = authorized.getInt("days");
|
var days = authorized.getInt("days");
|
||||||
var list = new ArrayList<String>();
|
var list = new ArrayList<String>();
|
||||||
@@ -78,9 +79,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 authorizedScopes = authResult.authorizedScopes().stream().map(AuthorizedScope::scope).collect(Collectors.joining(" "));
|
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, String>();
|
||||||
result.put(SCOPE, authorizedScopes);
|
joinedAuthorizedScopes.ifPresent(authorizedScopes -> 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,18 +2,23 @@
|
|||||||
package de.srsoftware.oidc.backend;
|
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.Constants.ERROR;
|
||||||
|
import static de.srsoftware.utils.Optionals.emptyIfBlank;
|
||||||
import static java.lang.System.Logger.Level.*;
|
import static java.lang.System.Logger.Level.*;
|
||||||
import static java.net.HttpURLConnection.HTTP_NOT_IMPLEMENTED;
|
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
|
||||||
|
|
||||||
import com.sun.net.httpserver.HttpExchange;
|
import com.sun.net.httpserver.HttpExchange;
|
||||||
import de.srsoftware.oidc.api.*;
|
import de.srsoftware.oidc.api.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.jose4j.jwk.PublicJsonWebKey;
|
import org.jose4j.jwk.PublicJsonWebKey;
|
||||||
import org.jose4j.jws.JsonWebSignature;
|
import org.jose4j.jws.JsonWebSignature;
|
||||||
import org.jose4j.jwt.JwtClaims;
|
import org.jose4j.jwt.JwtClaims;
|
||||||
import org.jose4j.lang.JoseException;
|
import org.jose4j.lang.JoseException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
public class TokenController extends PathHandler {
|
public class TokenController extends PathHandler {
|
||||||
public record Configuration(String issuer, int tokenExpirationMinutes) {
|
public record Configuration(String issuer, int tokenExpirationMinutes) {
|
||||||
@@ -46,36 +51,54 @@ public class TokenController extends PathHandler {
|
|||||||
return notFound(ex);
|
return notFound(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private HashMap<String, String> tokenResponse(String errorCode, String description) throws IOException {
|
||||||
|
var map = new HashMap<String, String>();
|
||||||
|
map.put(ERROR, errorCode);
|
||||||
|
emptyIfBlank(description).ifPresent(d -> map.put(ERROR_DESCRIPTION, d));
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean provideToken(HttpExchange ex) throws IOException {
|
private boolean provideToken(HttpExchange ex) throws IOException {
|
||||||
var map = deserialize(body(ex));
|
var map = deserialize(body(ex));
|
||||||
// TODO: check data, → https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint
|
|
||||||
return sendEmptyResponse(HTTP_NOT_IMPLEMENTED, ex);
|
|
||||||
/*
|
|
||||||
var grantType = map.get(GRANT_TYPE);
|
|
||||||
if (!AUTH_CODE.equals(grantType)) return sendContent(ex, HTTP_BAD_REQUEST, Map.of(ERROR, "unknown grant type", GRANT_TYPE, grantType));
|
|
||||||
|
|
||||||
var code = map.get(CODE);
|
var grantType = map.get(GRANT_TYPE);
|
||||||
var optAuthorization = authorizations.forCode(code);
|
// verify grant type
|
||||||
if (optAuthorization.isEmpty()) return sendContent(ex, HTTP_BAD_REQUEST, Map.of(ERROR, "invalid auth code", CODE, code));
|
if (!AUTH_CODE.equals(grantType)) return badRequest(ex, tokenResponse(INVALID_GRANT, "unknown grant type \"%s\"".formatted(grantType)));
|
||||||
|
|
||||||
|
var basicAuth = getBasicAuth(ex).orElse(null);
|
||||||
|
|
||||||
|
var clientId = basicAuth != null ? basicAuth.userId() : map.get(CLIENT_ID);
|
||||||
|
var optClient = clients.getClient(clientId);
|
||||||
|
if (optClient.isEmpty()) return badRequest(ex, tokenResponse(INVALID_CLIENT, "unknown client \"%s\"".formatted(clientId)));
|
||||||
|
|
||||||
|
var client = optClient.get();
|
||||||
|
if (client.secret() != null) { // for confidential clients:
|
||||||
|
// authenticate client by matching secret
|
||||||
|
String clientSecret = basicAuth != null ? basicAuth.pass() : map.get(CLIENT_SECRET);
|
||||||
|
if (clientSecret == null) return sendContent(ex, HTTP_UNAUTHORIZED, tokenResponse(INVALID_CLIENT, "client not authenticated"));
|
||||||
|
if (!client.secret().equals(clientSecret)) return sendContent(ex, HTTP_UNAUTHORIZED, tokenResponse(INVALID_CLIENT, "client not authenticated"));
|
||||||
|
}
|
||||||
|
|
||||||
|
var authCode = map.get(CODE);
|
||||||
|
|
||||||
|
// verify that code is not re-used
|
||||||
|
var optAuthorization = authorizations.consumeAuthorization(authCode);
|
||||||
|
if (optAuthorization.isEmpty()) return badRequest(ex, tokenResponse(INVALID_GRANT, "invalid auth code: \"%s\"".formatted(authCode)));
|
||||||
var authorization = optAuthorization.get();
|
var authorization = optAuthorization.get();
|
||||||
|
|
||||||
var clientId = map.get(CLIENT_ID);
|
// verify authorization code was issued to the authenticated client
|
||||||
if (!authorization.clientId().equals(clientId)) return sendContent(ex, HTTP_BAD_REQUEST, Map.of(ERROR, "invalid client id", CLIENT_ID, clientId));
|
if (!authorization.clientId().equals(clientId)) return badRequest(ex, tokenResponse(UNAUTHORIZED_CLIENT, null));
|
||||||
var optClient = clients.getClient(clientId);
|
|
||||||
if (optClient.isEmpty()) return sendContent(ex, HTTP_BAD_REQUEST, Map.of(ERROR, "unknown client", CLIENT_ID, clientId));
|
|
||||||
var client = optClient.get();
|
|
||||||
|
|
||||||
var user = users.load(authorization.userId());
|
|
||||||
if (user.isEmpty()) return sendContent(ex, 500, Map.of(ERROR, "User not found"));
|
|
||||||
|
|
||||||
|
// verify redirect URI
|
||||||
var uri = URLDecoder.decode(map.get(REDIRECT_URI), StandardCharsets.UTF_8);
|
var uri = URLDecoder.decode(map.get(REDIRECT_URI), StandardCharsets.UTF_8);
|
||||||
if (!client.redirectUris().contains(uri)) sendContent(ex, HTTP_BAD_REQUEST, Map.of(ERROR, "unknown redirect uri", REDIRECT_URI, uri));
|
if (!client.redirectUris().contains(uri)) return badRequest(ex, tokenResponse(INVALID_REQUEST, "unknown redirect uri: \"%s\"".formatted(uri)));
|
||||||
|
|
||||||
|
// verify user is valid
|
||||||
|
var user = users.load(authorization.userId());
|
||||||
|
if (user.isEmpty()) return badRequest(ex, tokenResponse(INVALID_REQUEST, "unknown user"));
|
||||||
|
|
||||||
|
if (!authorization.scopes().scopes().contains(OPENID)) return badRequest(ex, tokenResponse(INVALID_REQUEST, "Token invalid for OpenID scope"));
|
||||||
|
|
||||||
if (client.secret() != null) {
|
|
||||||
String clientSecret = nullable(ex.getRequestHeaders().get(AUTHORIZATION)).map(list -> list.get(0)).filter(s -> s.startsWith("Basic ")).map(s -> s.substring(6)).map(s -> Base64.getDecoder().decode(s)).map(bytes -> new String(bytes, StandardCharsets.UTF_8)).filter(s -> s.startsWith("%s:".formatted(client.id()))).map(s -> s.substring(client.id().length() + 1).trim()).orElseGet(() -> map.get(CLIENT_SECRET));
|
|
||||||
if (clientSecret == null) return sendContent(ex, HTTP_BAD_REQUEST, Map.of(ERROR, "client secret missing"));
|
|
||||||
if (!client.secret().equals(clientSecret)) return sendContent(ex, HTTP_BAD_REQUEST, Map.of(ERROR, "client secret mismatch"));
|
|
||||||
}
|
|
||||||
String jwToken = createJWT(client, user.get());
|
String jwToken = createJWT(client, user.get());
|
||||||
ex.getResponseHeaders().add("Cache-Control", "no-store");
|
ex.getResponseHeaders().add("Cache-Control", "no-store");
|
||||||
JSONObject response = new JSONObject();
|
JSONObject response = new JSONObject();
|
||||||
@@ -83,8 +106,8 @@ public class TokenController extends PathHandler {
|
|||||||
response.put(TOKEN_TYPE, BEARER);
|
response.put(TOKEN_TYPE, BEARER);
|
||||||
response.put(EXPIRES_IN, 3600);
|
response.put(EXPIRES_IN, 3600);
|
||||||
response.put(ID_TOKEN, jwToken);
|
response.put(ID_TOKEN, jwToken);
|
||||||
LOG.log(DEBUG, jwToken);
|
|
||||||
return sendContent(ex, response);*/
|
return sendContent(ex, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createJWT(Client client, User user) {
|
private String createJWT(Client client, User user) {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class FileStore implements ClaimAuthorizationService, ClientService, Sess
|
|||||||
private Duration sessionDuration = Duration.of(10, ChronoUnit.MINUTES);
|
private Duration sessionDuration = Duration.of(10, ChronoUnit.MINUTES);
|
||||||
private Map<String, Client> clients = new HashMap<>();
|
private Map<String, Client> clients = new HashMap<>();
|
||||||
private Map<String, User> accessTokens = new HashMap<>();
|
private Map<String, User> accessTokens = new HashMap<>();
|
||||||
private Map<String, String> authCodes = new HashMap<>();
|
private Map<String, Authorization> authCodes = new HashMap<>();
|
||||||
|
|
||||||
public FileStore(File storage, PasswordHasher<String> passwordHasher) throws IOException {
|
public FileStore(File storage, PasswordHasher<String> passwordHasher) throws IOException {
|
||||||
this.storageFile = storage.toPath();
|
this.storageFile = storage.toPath();
|
||||||
@@ -266,6 +266,11 @@ public class FileStore implements ClaimAuthorizationService, ClientService, Sess
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*** ClaimAuthorizationService methods ***/
|
/*** ClaimAuthorizationService methods ***/
|
||||||
|
private String authCode(User user, Client client, Authorization authorization) {
|
||||||
|
var code = uuid();
|
||||||
|
authCodes.put(code, authorization);
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClaimAuthorizationService authorize(User user, Client client, Collection<String> scopes, Instant expiration) {
|
public ClaimAuthorizationService authorize(User user, Client client, Collection<String> scopes, Instant expiration) {
|
||||||
@@ -280,8 +285,10 @@ public class FileStore implements ClaimAuthorizationService, ClientService, Sess
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AuthResult unauthorized(Collection<String> scopes) {
|
|
||||||
return new AuthResult(List.of(), new HashSet<>(scopes), null);
|
@Override
|
||||||
|
public Optional<Authorization> consumeAuthorization(String authCode) {
|
||||||
|
return nullable(authCodes.remove(authCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -292,24 +299,26 @@ public class FileStore implements ClaimAuthorizationService, ClientService, Sess
|
|||||||
var clientScopes = userAuthorizations.has(client.id()) ? userAuthorizations.getJSONObject(client.id()) : null;
|
var clientScopes = userAuthorizations.has(client.id()) ? userAuthorizations.getJSONObject(client.id()) : null;
|
||||||
if (clientScopes == null) return unauthorized(scopes);
|
if (clientScopes == null) return unauthorized(scopes);
|
||||||
var now = Instant.now();
|
var now = Instant.now();
|
||||||
var authorizedScopes = new ArrayList<AuthorizedScope>();
|
var authorizedScopes = new HashSet<String>();
|
||||||
var unauthorizedScopes = new HashSet<String>();
|
var unauthorizedScopes = new HashSet<String>();
|
||||||
|
Instant earliestExpiration = null;
|
||||||
for (var scope : scopes) {
|
for (var scope : scopes) {
|
||||||
if (clientScopes.has(scope)) {
|
if (clientScopes.has(scope)) {
|
||||||
var expiration = Instant.ofEpochSecond(clientScopes.getLong(scope));
|
var expiration = Instant.ofEpochSecond(clientScopes.getLong(scope));
|
||||||
if (expiration.isAfter(now)) {
|
if (expiration.isAfter(now)) {
|
||||||
authorizedScopes.add(new AuthorizedScope(scope, expiration));
|
authorizedScopes.add(scope);
|
||||||
|
if (earliestExpiration == null || expiration.isBefore(earliestExpiration)) earliestExpiration = expiration;
|
||||||
} else {
|
} else {
|
||||||
unauthorizedScopes.add(scope);
|
unauthorizedScopes.add(scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new AuthResult(authorizedScopes, unauthorizedScopes, authCode(user, client));
|
|
||||||
|
var authorization = new Authorization(client.id(), user.uuid(), new AuthorizedScopes(authorizedScopes, earliestExpiration));
|
||||||
|
return new AuthResult(authorization.scopes(), unauthorizedScopes, authCode(user, client, authorization));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String authCode(User user, Client client) {
|
private AuthResult unauthorized(Collection<String> scopes) {
|
||||||
var code = uuid();
|
return new AuthResult(null, new HashSet<>(scopes), null);
|
||||||
authCodes.put(user.uuid() + "@" + client.id(), code);
|
|
||||||
return code;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user