Search in sources :

Example 1 with ClientAuthorization

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("");
}
Also used : Response(it.unibo.arces.wot.sepa.commons.response.Response) RegistrationResponse(it.unibo.arces.wot.sepa.commons.response.RegistrationResponse) ErrorResponse(it.unibo.arces.wot.sepa.commons.response.ErrorResponse) JWTResponse(it.unibo.arces.wot.sepa.commons.response.JWTResponse) ClientAuthorization(it.unibo.arces.wot.sepa.commons.security.ClientAuthorization) ApplicationIdentity(it.unibo.arces.wot.sepa.engine.dependability.authorization.identities.ApplicationIdentity) RegistrationResponse(it.unibo.arces.wot.sepa.commons.response.RegistrationResponse) JWTResponse(it.unibo.arces.wot.sepa.commons.response.JWTResponse)

Example 2 with ClientAuthorization

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);
}
Also used : ClientAuthorization(it.unibo.arces.wot.sepa.commons.security.ClientAuthorization) JsonObject(com.google.gson.JsonObject) JsonParseException(com.google.gson.JsonParseException) JsonSyntaxException(com.google.gson.JsonSyntaxException) SEPASecurityException(it.unibo.arces.wot.sepa.commons.exceptions.SEPASecurityException) SEPAProtocolException(it.unibo.arces.wot.sepa.commons.exceptions.SEPAProtocolException) SEPASparqlParsingException(it.unibo.arces.wot.sepa.commons.exceptions.SEPASparqlParsingException) JsonParser(com.google.gson.JsonParser)

Example 3 with ClientAuthorization

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);
}
Also used : ClientAuthorization(it.unibo.arces.wot.sepa.commons.security.ClientAuthorization) JWTClaimsSet(com.nimbusds.jwt.JWTClaimsSet) SEPASecurityException(it.unibo.arces.wot.sepa.commons.exceptions.SEPASecurityException) SignedJWT(com.nimbusds.jwt.SignedJWT) ParseException(java.text.ParseException) JOSEException(com.nimbusds.jose.JOSEException) SimpleDateFormat(java.text.SimpleDateFormat) Date(java.util.Date) Credentials(it.unibo.arces.wot.sepa.commons.security.Credentials)

Example 4 with ClientAuthorization

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();
    }
}
Also used : ScheduledRequest(it.unibo.arces.wot.sepa.engine.scheduling.ScheduledRequest) ClientAuthorization(it.unibo.arces.wot.sepa.commons.security.ClientAuthorization) SEPASecurityException(it.unibo.arces.wot.sepa.commons.exceptions.SEPASecurityException) InternalUQRequest(it.unibo.arces.wot.sepa.engine.scheduling.InternalUQRequest) ErrorResponse(it.unibo.arces.wot.sepa.commons.response.ErrorResponse)

Example 5 with ClientAuthorization

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);
}
Also used : ClientAuthorization(it.unibo.arces.wot.sepa.commons.security.ClientAuthorization) SEPASecurityException(it.unibo.arces.wot.sepa.commons.exceptions.SEPASecurityException) SignedJWT(com.nimbusds.jwt.SignedJWT) Date(java.util.Date) BadJOSEException(com.nimbusds.jose.proc.BadJOSEException) JWTClaimsSet(com.nimbusds.jwt.JWTClaimsSet) ParseException(java.text.ParseException) JOSEException(com.nimbusds.jose.JOSEException) BadJOSEException(com.nimbusds.jose.proc.BadJOSEException) SimpleDateFormat(java.text.SimpleDateFormat) Credentials(it.unibo.arces.wot.sepa.commons.security.Credentials)

Aggregations

ClientAuthorization (it.unibo.arces.wot.sepa.commons.security.ClientAuthorization)6 SEPASecurityException (it.unibo.arces.wot.sepa.commons.exceptions.SEPASecurityException)4 ErrorResponse (it.unibo.arces.wot.sepa.commons.response.ErrorResponse)3 JOSEException (com.nimbusds.jose.JOSEException)2 JWTClaimsSet (com.nimbusds.jwt.JWTClaimsSet)2 SignedJWT (com.nimbusds.jwt.SignedJWT)2 Credentials (it.unibo.arces.wot.sepa.commons.security.Credentials)2 ParseException (java.text.ParseException)2 SimpleDateFormat (java.text.SimpleDateFormat)2 Date (java.util.Date)2 JsonObject (com.google.gson.JsonObject)1 JsonParseException (com.google.gson.JsonParseException)1 JsonParser (com.google.gson.JsonParser)1 JsonSyntaxException (com.google.gson.JsonSyntaxException)1 BadJOSEException (com.nimbusds.jose.proc.BadJOSEException)1 SEPAProtocolException (it.unibo.arces.wot.sepa.commons.exceptions.SEPAProtocolException)1 SEPASparqlParsingException (it.unibo.arces.wot.sepa.commons.exceptions.SEPASparqlParsingException)1 JWTResponse (it.unibo.arces.wot.sepa.commons.response.JWTResponse)1 RegistrationResponse (it.unibo.arces.wot.sepa.commons.response.RegistrationResponse)1 Response (it.unibo.arces.wot.sepa.commons.response.Response)1