use of it.unibo.arces.wot.sepa.commons.security.ClientAuthorization in project SEPA by arces-wot.
the class SecurityManager method securityCheck.
public void securityCheck(String identity) throws SEPASecurityException {
logger.info("*** Security check ***");
// Add identity
addAuthorizedIdentity(new ApplicationIdentity(identity));
// Register
Response response = register(identity);
if (response.getClass().equals(RegistrationResponse.class)) {
RegistrationResponse ret = (RegistrationResponse) response;
String basicAuth = ret.getClientId() + ":" + ret.getClientSecret();
// Get token
String encodedCredentials = Base64.getEncoder().encodeToString(basicAuth.getBytes());
logger.debug("Authorization Basic " + encodedCredentials);
response = getToken(encodedCredentials);
if (response.getClass().equals(JWTResponse.class)) {
logger.debug("Access token: " + ((JWTResponse) response).getAccessToken());
// Validate token
ClientAuthorization authRet = validateToken(((JWTResponse) response).getAccessToken());
if (authRet.isAuthorized()) {
removeCredentials(new ApplicationIdentity(ret.getClientId()));
removeJwt(ret.getClientId());
logger.info("*** PASSED ***");
} else {
logger.error(authRet.getError());
logger.info("*** FAILED ***");
}
} else {
logger.debug(response.toString());
logger.info("*** FAILED ***");
}
} else {
logger.debug(response.toString());
logger.info("*** FAILED ***");
// Remove identity
removeAuthorizedIdentity(identity);
}
System.out.println("");
}
use of it.unibo.arces.wot.sepa.commons.security.ClientAuthorization in project SEPA by arces-wot.
the class Gate method authorize.
/**
* <pre>
* Specific to SPARQL 1.1 SE Subscribe request:
* 1. Check if the request contains an "authorization" member.
* 2. Check if the request contains an "authorization" member that start with "Bearer"
* 3. Check if the value of the "authorization" member is a JWT object ==> VALIDATE TOKEN
*
* Token validation:
* 4. Check if the JWT object is signed
* 5. Check if the signature of the JWT object is valid. This is to be checked with AS public signature verification key
* 6. Check the contents of the JWT object
* 7. Check if the value of "iss" is https://wot.arces.unibo.it:8443/oauth/token
* 8. Check if the value of "aud" contains https://wot.arces.unibo.it:8443/sparql
* 9. Accept the request as well as "sub" as the originator of the request and process it as usual
*
* Respond with 401 if not
*
* According to RFC6749, the error member can assume the following values: invalid_request, invalid_client, invalid_grant, unauthorized_client, unsupported_grant_type, invalid_scope.
*
* invalid_request
* The request is missing a required parameter, includes an
* unsupported parameter value (other than grant type),
* repeats a parameter, includes multiple credentials,
* utilizes more than one mechanism for authenticating the
* client, or is otherwise malformed.
*
* invalid_client
* Client authentication failed (e.g., unknown client, no
* client authentication included, or unsupported
* authentication method). The authorization server MAY
* return an HTTP 401 (Unauthorized) status code to indicate
* which HTTP authentication schemes are supported. If the
* client attempted to authenticate via the "Authorization"
* request header field, the authorization server MUST
* respond with an HTTP 401 (Unauthorized) status code and
* include the "WWW-Authenticate" response header field
* matching the authentication scheme used by the client.
*
* invalid_grant
* The provided authorization grant (e.g., authorization
* code, resource owner credentials) or refresh token is
* invalid, expired, revoked, does not match the redirection
* URI used in the authorization request, or was issued to
* another client.
*
* unauthorized_client
* The authenticated client is not authorized to use this
* authorization grant type.
*
* unsupported_grant_type
* The authorization grant type is not supported by the
* authorization server.
*
* </pre>
* @throws SEPASecurityException
*/
protected final ClientAuthorization authorize(String message) throws SEPASecurityException {
if (!authorizationRequired)
return new ClientAuthorization();
JsonObject request;
try {
request = new JsonParser().parse(message).getAsJsonObject();
} catch (Exception e) {
logger.error(e.getMessage());
return new ClientAuthorization("invalid_request", "Failed to parse JSON message: " + message);
}
String bearer = null;
JsonObject subUnsub = null;
if (request.has("subscribe"))
subUnsub = request.get("subscribe").getAsJsonObject();
else if (request.has("unsubscribe"))
subUnsub = request.get("unsubscribe").getAsJsonObject();
if (subUnsub == null) {
logger.error("Neither subscribe or unsuscribe found");
return new ClientAuthorization("invalid_request", "Neither subscribe or unsuscribe found");
}
if (!subUnsub.has("authorization")) {
logger.error("authorization member is missing");
return new ClientAuthorization("invalid_request", "authorization member is missing");
}
try {
bearer = subUnsub.get("authorization").getAsString();
} catch (Exception e) {
logger.error("Authorization member is not a string");
return new ClientAuthorization("invalid_request", "authorization member is not a string");
}
if (!bearer.toUpperCase().startsWith("BEARER ")) {
logger.error("Authorization value MUST be of type Bearer");
return new ClientAuthorization("unsupported_grant_type", "Authorization value MUST be of type Bearer");
}
String jwt = bearer.substring(7);
if (jwt == null) {
logger.error("Token is null");
return new ClientAuthorization("invalid_request", "Token is null");
}
if (jwt.equals("")) {
logger.error("Token is empty");
return new ClientAuthorization("invalid_request", "Token is empty");
}
// Token validation
return Dependability.validateToken(jwt);
}
use of it.unibo.arces.wot.sepa.commons.security.ClientAuthorization in project SEPA by arces-wot.
the class KeyCloakSecurityManager method validateToken.
/**
* Requesting Party Token
*
* If you want to validate these tokens without a call to the remote introspection endpoint, you can decode the RPT and query for its validity locally.
* Once you decode the token, you can also use the permissions within the token to enforce authorization decisions.
*
* This is essentially what the policy enforcers do. Be sure to:
* 1) Validate the signature of the RPT (based on the realm’s public key)
* 2) Query for token validity based on its exp, iat, and aud claims
*
* The claim "preferred_username" is used to identify the user
*/
@Override
public synchronized ClientAuthorization validateToken(String accessToken) {
logger.log(Level.getLevel("oauth"), "VALIDATE TOKEN");
// Parse token
SignedJWT signedJWT = null;
try {
signedJWT = SignedJWT.parse(accessToken);
} catch (ParseException e) {
logger.log(Level.getLevel("oauth"), e.getMessage());
return new ClientAuthorization("invalid_request", "ParseException: " + e.getMessage());
}
// Verify token
try {
if (!signedJWT.verify(verifier)) {
logger.log(Level.getLevel("oauth"), "Signed JWT not verified");
return new ClientAuthorization("invalid_grant", "Signed JWT not verified");
}
} catch (JOSEException e) {
logger.log(Level.getLevel("oauth"), e.getMessage());
return new ClientAuthorization("invalid_grant", "JOSEException: " + e.getMessage());
}
String uid;
// Process token (validate)
JWTClaimsSet claimsSet = null;
try {
claimsSet = signedJWT.getJWTClaimsSet();
logger.log(Level.getLevel("oauth"), claimsSet);
// Get client credentials for accessing the SPARQL endpoint
uid = claimsSet.getStringClaim("username");
if (uid == null) {
logger.log(Level.getLevel("oauth"), "<username> claim is null. Look for <preferred_username>");
uid = claimsSet.getStringClaim("preferred_username");
if (uid == null) {
logger.log(Level.getLevel("oauth"), "USER ID not found...");
return new ClientAuthorization("invalid_grant", "Username claim not found");
}
}
logger.log(Level.getLevel("oauth"), "Subject: " + claimsSet.getSubject());
logger.log(Level.getLevel("oauth"), "Issuer: " + claimsSet.getIssuer());
logger.log(Level.getLevel("oauth"), "Username: " + uid);
} catch (ParseException e) {
logger.error(e.getMessage());
return new ClientAuthorization("invalid_grant", "ParseException. " + e.getMessage());
}
// Check token expiration (an "invalid_grant" error is raised if the token is
// expired)
Date now = new Date();
long nowUnixSeconds = (now.getTime() / 1000) * 1000;
Date expiring = claimsSet.getExpirationTime();
Date notBefore = claimsSet.getNotBeforeTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
if (expiring.getTime() - nowUnixSeconds < 0) {
logger.log(Level.getLevel("oauth"), "Token is expired: " + sdf.format(claimsSet.getExpirationTime()) + " < " + sdf.format(new Date(nowUnixSeconds)));
return new ClientAuthorization("invalid_grant", "Token issued at " + sdf.format(claimsSet.getIssueTime()) + " is expired: " + sdf.format(claimsSet.getExpirationTime()) + " < " + sdf.format(now));
}
if (notBefore != null && nowUnixSeconds < notBefore.getTime()) {
logger.log(Level.getLevel("oauth"), "Token can not be used before: " + claimsSet.getNotBeforeTime());
return new ClientAuthorization("invalid_grant", "Token can not be used before: " + claimsSet.getNotBeforeTime());
}
Credentials cred = null;
try {
cred = getEndpointCredentials(uid);
logger.log(Level.getLevel("oauth"), "Endpoint credentials: " + cred);
} catch (SEPASecurityException e) {
logger.log(Level.getLevel("oauth"), "Failed to retrieve credentials (" + uid + ")");
return new ClientAuthorization("invalid_grant", "Failed to get credentials (" + uid + ")");
}
return new ClientAuthorization(cred);
}
use of it.unibo.arces.wot.sepa.commons.security.ClientAuthorization in project SEPA by arces-wot.
the class SPARQL11Handler method handle.
@Override
public void handle(HttpRequest request, HttpAsyncExchange httpExchange, HttpContext context) throws HttpException, IOException {
logger.log(Level.getLevel("http"), "@handle " + request + " " + context);
// CORS
if (!corsHandling(httpExchange))
return;
// Authorize
ClientAuthorization oauth = null;
try {
oauth = authorize(httpExchange.getRequest());
} catch (SEPASecurityException e1) {
HttpUtilities.sendFailureResponse(httpExchange, new ErrorResponse(HttpStatus.SC_UNAUTHORIZED, "oauth_exception", e1.getMessage()));
jmx.authorizingFailed();
return;
}
if (!oauth.isAuthorized()) {
logger.log(Level.getLevel("oauth"), "*** NOT AUTHORIZED *** " + oauth.getDescription());
HttpUtilities.sendFailureResponse(httpExchange, new ErrorResponse(HttpStatus.SC_UNAUTHORIZED, oauth.getError(), oauth.getDescription()));
jmx.authorizingFailed();
return;
}
InternalUQRequest sepaRequest = null;
try {
// Parsing SPARQL 1.1 request and attach a token
sepaRequest = parse(httpExchange, oauth);
} catch (SPARQL11ProtocolException e) {
logger.log(Level.getLevel("http"), "Parsing failed: " + httpExchange.getRequest());
HttpUtilities.sendFailureResponse(httpExchange, new ErrorResponse(e.getCode(), "SPARQL11ProtocolException", "Parsing failed: " + e.getMessage()));
jmx.parsingFailed();
return;
}
// Schedule request
Timings.log(sepaRequest);
ScheduledRequest req = scheduler.schedule(sepaRequest, new SPARQL11ResponseHandler(httpExchange, jmx));
if (req == null) {
logger.error("Out of tokens");
HttpUtilities.sendFailureResponse(httpExchange, new ErrorResponse(429, "too_many_requests", "Too many pending requests"));
jmx.outOfTokens();
}
}
use of it.unibo.arces.wot.sepa.commons.security.ClientAuthorization in project SEPA by arces-wot.
the class SecurityManager method validateToken.
/**
* Operation when receiving a request at a protected endpoint
*
* <pre>
* Specific to HTTP request:
* 1. Check if the request contains an Authorization header.
* 2. Check if the request contains an Authorization: Bearer-header with non-null/empty contents
* 3. Check if the value of the Authorization: Bearer-header is a JWT object
*
* Token validation:
* 4. Check if the JWT object is signed
* 5. Check if the signature of the JWT object is valid. This is to be checked with AS public signature verification key
* 6. Check the contents of the JWT object
* 7. Check if the value of "iss" is https://wot.arces.unibo.it:8443/oauth/token
* 8. Check if the value of "aud" contains https://wot.arces.unibo.it:8443/sparql
* 9. Accept the request as well as "sub" as the originator of the request and process it as usual
*
* Respond with 401 if not
*
* According to RFC6749, the error member can assume the following values: invalid_request, invalid_client, invalid_grant, unauthorized_client, unsupported_grant_type, invalid_scope.
*
* invalid_request
* The request is missing a required parameter, includes an
* unsupported parameter value (other than grant type),
* repeats a parameter, includes multiple credentials,
* utilizes more than one mechanism for authenticating the
* client, or is otherwise malformed.
*
* invalid_client
* Client authentication failed (e.g., unknown client, no
* client authentication included, or unsupported
* authentication method). The authorization server MAY
* return an HTTP 401 (Unauthorized) status code to indicate
* which HTTP authentication schemes are supported. If the
* client attempted to authenticate via the "Authorization"
* request header field, the authorization server MUST
* respond with an HTTP 401 (Unauthorized) status code and
* include the "WWW-Authenticate" response header field
* matching the authentication scheme used by the client.
*
* invalid_grant
* The provided authorization grant (e.g., authorization
* code, resource owner credentials) or refresh token is
* invalid, expired, revoked, does not match the redirection
* URI used in the authorization request, or was issued to
* another client.
*
* unauthorized_client
* The authenticated client is not authorized to use this
* authorization grant type.
*
* unsupported_grant_type
* The authorization grant type is not supported by the
* authorization server.
*
* </pre>
*
* @param accessToken the JWT token to be validate according to points 4-6
*/
public synchronized ClientAuthorization validateToken(String accessToken) {
logger.debug("VALIDATE TOKEN");
// Parse token
SignedJWT signedJWT = null;
try {
signedJWT = SignedJWT.parse(accessToken);
} catch (ParseException e) {
logger.error(e.getMessage());
return new ClientAuthorization("invalid_request", "ParseException: " + e.getMessage());
}
// Verify token
try {
if (!signedJWT.verify(verifier)) {
logger.error("Signed JWT not verified");
return new ClientAuthorization("invalid_grant", "Signed JWT not verified");
}
} catch (JOSEException e) {
logger.error(e.getMessage());
return new ClientAuthorization("invalid_grant", "JOSEException: " + e.getMessage());
}
// Process token (validate)
JWTClaimsSet claimsSet = null;
try {
claimsSet = jwtProcessor.process(accessToken, new SEPASecurityContext());
} catch (ParseException e) {
logger.error(e.getMessage());
return new ClientAuthorization("invalid_grant", "ParseException. " + e.getMessage());
} catch (BadJOSEException e) {
logger.error(e.getMessage());
return new ClientAuthorization("invalid_grant", "BadJOSEException. " + e.getMessage());
} catch (JOSEException e) {
logger.error(e.getMessage());
return new ClientAuthorization("invalid_grant", "JOSEException. " + e.getMessage());
}
// Check token expiration (an "invalid_grant" error is raised if the token is expired)
Date now = new Date();
long nowUnixSeconds = (now.getTime() / 1000) * 1000;
Date expiring = claimsSet.getExpirationTime();
Date notBefore = claimsSet.getNotBeforeTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
if (expiring.getTime() - nowUnixSeconds < 0) {
logger.warn("Token is expired: " + sdf.format(claimsSet.getExpirationTime()) + " < " + sdf.format(new Date(nowUnixSeconds)));
return new ClientAuthorization("invalid_grant", "Token issued at " + sdf.format(claimsSet.getIssueTime()) + " is expired: " + sdf.format(claimsSet.getExpirationTime()) + " < " + sdf.format(now));
}
if (notBefore != null && nowUnixSeconds < notBefore.getTime()) {
logger.warn("Token can not be used before: " + claimsSet.getNotBeforeTime());
return new ClientAuthorization("invalid_grant", "Token can not be used before: " + claimsSet.getNotBeforeTime());
}
// Get client credentials for accessing the SPARQL endpoint
String id = claimsSet.getSubject();
logger.debug("Get credentials for uid: " + id);
Credentials cred = null;
try {
cred = getEndpointCredentials(id);
logger.trace(cred);
} catch (SEPASecurityException e) {
logger.error("Failed to retrieve credentials (" + id + ")");
return new ClientAuthorization("invalid_grant", "Failed to get credentials (" + id + ")");
}
return new ClientAuthorization(cred);
}
Aggregations