Search in sources :

Example 51 with PreEnvironment

use of net.openid.conformance.condition.PreEnvironment in project conformance-suite by openid-certification.

the class ValidateJARMExpRecommendations method evaluate.

@Override
@PreEnvironment(required = { "jarm_response" })
public Environment evaluate(Environment env) {
    Instant now = Instant.now();
    Long exp = env.getLong("jarm_response", "claims.exp");
    if (exp == null) {
        throw error("'exp' claim missing from JARM response");
    }
    // exp recommended to be less than 10 minutes - added after JARM ID1:
    // https://bitbucket.org/openid/fapi/commits/8ac0bc6059cfcfdb6c155efa2d992a1eb86e8b6c -
    final int allowableLifeTimeMinutes = 10;
    if (now.plusMillis(timeSkewMillis).plusSeconds(allowableLifeTimeMinutes * 60).isBefore(Instant.ofEpochSecond(exp))) {
        throw error("JARM 'exp' time is further in the future than the recommended " + allowableLifeTimeMinutes + " minutes", args("expiration", new Date(exp * 1000L), "now", now));
    }
    // not mentioned by spec, but for the sake of sanity check the response has a lifetime of at least 10 seconds
    // or it's likely to fall in various real world situations
    // We don't use 'timeSkewMillis' here, as that would allow a zero expiry to pass
    final int minimumLifeTimeSeconds = 10;
    if (now.plusSeconds(minimumLifeTimeSeconds).isAfter(Instant.ofEpochSecond(exp))) {
        throw error("JARM 'exp' time appears to be less than " + minimumLifeTimeSeconds + " seconds", args("expiration", new Date(exp * 1000L), "now", now));
    }
    logSuccess("JARM response 'exp' is less than " + allowableLifeTimeMinutes + " minutes", args("expiration", new Date(exp * 1000L), "now", now));
    return env;
}
Also used : Instant(java.time.Instant) Date(java.util.Date) PreEnvironment(net.openid.conformance.condition.PreEnvironment)

Example 52 with PreEnvironment

use of net.openid.conformance.condition.PreEnvironment in project conformance-suite by openid-certification.

the class ValidateJARMResponse method evaluate.

@Override
@PreEnvironment(required = { "jarm_response", "server", "client" })
public Environment evaluate(Environment env) {
    // to check the audience
    String clientId = env.getString("client", "client_id");
    // to validate the issuer
    String issuer = env.getString("server", "issuer");
    // to check timestamps
    Instant now = Instant.now();
    // check all our testable values
    if (Strings.isNullOrEmpty(clientId) || Strings.isNullOrEmpty(issuer)) {
        throw error("Couldn't find values to test response against");
    }
    JsonElement iss = env.getElementFromObject("jarm_response", "claims.iss");
    if (iss == null) {
        throw error("Missing issuer");
    }
    if (!issuer.equals(env.getString("jarm_response", "claims.iss"))) {
        throw error("Issuer mismatch", args("expected", issuer, "actual", env.getString("jarm_response", "claims.iss")));
    }
    JsonElement aud = env.getElementFromObject("jarm_response", "claims.aud");
    if (aud == null) {
        throw error("Missing audience");
    }
    if (aud.isJsonArray()) {
        if (!aud.getAsJsonArray().contains(new JsonPrimitive(clientId))) {
            throw error("Audience not found", args("expected", clientId, "actual", aud));
        }
    } else {
        if (!clientId.equals(OIDFJSON.getString(aud))) {
            throw error("Audience mismatch", args("expected", clientId, "actual", aud));
        }
    }
    Long exp = env.getLong("jarm_response", "claims.exp");
    if (exp == null) {
        throw error("Missing expiration");
    } else {
        if (now.minusMillis(timeSkewMillis).isAfter(Instant.ofEpochSecond(exp))) {
            throw error("Token expired", args("expiration", new Date(exp * 1000L), "now", now));
        }
    }
    // iat and nbf are not required to be present, but should be valid if they are
    // https://bitbucket.org/openid/fapi/issues/269/jarm-response-contents-clarifications
    Long iat = env.getLong("jarm_response", "claims.iat");
    if (iat != null) {
        if (now.plusMillis(timeSkewMillis).isBefore(Instant.ofEpochSecond(iat))) {
            throw error("Token issued in the future", args("issued-at", new Date(iat * 1000L), "now", now));
        }
    }
    Long nbf = env.getLong("jarm_response", "claims.nbf");
    if (nbf != null) {
        if (now.plusMillis(timeSkewMillis).isBefore(Instant.ofEpochSecond(nbf))) {
            // this is just something to log, it doesn't make the token invalid
            log("Token has future not-before", args("not-before", new Date(nbf * 1000L), "now", now));
        }
    }
    logSuccess("JARM response standard JWT claims are valid");
    return env;
}
Also used : JsonPrimitive(com.google.gson.JsonPrimitive) JsonElement(com.google.gson.JsonElement) Instant(java.time.Instant) Date(java.util.Date) PreEnvironment(net.openid.conformance.condition.PreEnvironment)

Example 53 with PreEnvironment

use of net.openid.conformance.condition.PreEnvironment in project conformance-suite by openid-certification.

the class ValidateLogoutTokenClaims method evaluate.

@Override
@PreEnvironment(required = { "logout_token", "server", "client" })
public Environment evaluate(Environment env) {
    // to check the audience
    String clientId = env.getString("client", "client_id");
    // to validate the issuer
    String issuer = env.getString("server", "issuer");
    // to check timestamps
    Instant now = Instant.now();
    if (Strings.isNullOrEmpty(clientId) || Strings.isNullOrEmpty(issuer)) {
        throw error("Couldn't find values to test token against");
    }
    // checks are in order listed in https://openid.net/specs/openid-connect-backchannel-1_0.html#LogoutToken
    // iss
    // REQUIRED. Issuer Identifier, as specified in Section 2 of [OpenID.Core].
    String logoutTokenIss = env.getString("logout_token", "claims.iss");
    if (logoutTokenIss == null) {
        throw error("'iss' claim missing");
    }
    if (!issuer.equals(logoutTokenIss)) {
        throw error("Issuer mismatch", args("expected", issuer, "actual", logoutTokenIss));
    }
    // sub
    // OPTIONAL. Subject Identifier, as specified in Section 2 of [OpenID.Core].
    // checked in CheckIdTokenSubMatchesLogoutToken & CheckLogoutTokenHasSubOrSid
    // aud
    // REQUIRED. Audience(s), as specified in Section 2 of [OpenID.Core].
    JsonElement aud = env.getElementFromObject("logout_token", "claims.aud");
    if (aud == null) {
        throw error("'aud' claim missing");
    }
    if (aud.isJsonArray()) {
        if (!aud.getAsJsonArray().contains(new JsonPrimitive(clientId))) {
            throw error("'aud' array does not contain our client id", args("expected", clientId, "actual", aud));
        }
    } else {
        if (!clientId.equals(OIDFJSON.getString(aud))) {
            throw error("'aud' is not our client id", args("expected", clientId, "actual", aud));
        }
    }
    // iat
    // REQUIRED. Issued at time, as specified in Section 2 of [OpenID.Core].
    Long iat = env.getLong("logout_token", "claims.iat");
    if (iat == null) {
        throw error("'iat' claim missing");
    } else {
        if (now.plusMillis(timeSkewMillis).isBefore(Instant.ofEpochSecond(iat))) {
            throw error("Token 'iat' in the future", args("issued-at", new Date(iat * 1000L), "now", now));
        }
    }
    // jti
    // REQUIRED. Unique identifier for the token, as specified in Section 9 of [OpenID.Core].
    String jti = env.getString("logout_token", "claims.jti");
    if (jti == null) {
        throw error("jti missing");
    }
    // events
    // REQUIRED. Claim whose value is a JSON object containing the member name http://schemas.openid.net/event/backchannel-logout. This declares that the JWT is a Logout Token. The corresponding member value MUST be a JSON object and SHOULD be the empty JSON object {}.
    JsonElement events = env.getElementFromObject("logout_token", "claims.events");
    if (events == null) {
        throw error("'events' claim missing");
    }
    if (!events.isJsonObject()) {
        throw error("'events' claim is not a json object");
    }
    JsonObject eventsObj = events.getAsJsonObject();
    if (eventsObj.size() != 1) {
        throw error("'events' object does not contain exactly 1 entry", eventsObj);
    }
    JsonElement eventsValueElement = eventsObj.get("http://schemas.openid.net/event/backchannel-logout");
    if (eventsValueElement == null) {
        throw error("http://schemas.openid.net/event/backchannel-logout entry is missing from 'events' claim", eventsObj);
    }
    if (!eventsValueElement.isJsonObject()) {
        throw error("http://schemas.openid.net/event/backchannel-logout is not a json object");
    }
    JsonObject eventsValue = (JsonObject) eventsValueElement;
    if (eventsValue.size() != 0) {
        throw error("http://schemas.openid.net/event/backchannel-logout is not an empty object", eventsObj);
    }
    // sid
    // OPTIONAL. Session ID - String identifier for a Session. This represents a Session of a User Agent or device for a logged-in End-User at an RP. Different sid values are used to identify distinct sessions at an OP. The sid value need only be unique in the context of a particular issuer. Its contents are opaque to the RP. Its syntax is the same as an OAuth 2.0 Client Identifier.
    // Checked in CheckIdTokenSidMatchesLogoutToken & CheckLogoutTokenHasSubOrSid
    // nonce checked in CheckLogoutTokenNoNonce
    logSuccess("logout token iss, aud, iat, jti and events claims passed validation checks");
    return env;
}
Also used : JsonPrimitive(com.google.gson.JsonPrimitive) JsonElement(com.google.gson.JsonElement) Instant(java.time.Instant) JsonObject(com.google.gson.JsonObject) Date(java.util.Date) PreEnvironment(net.openid.conformance.condition.PreEnvironment)

Example 54 with PreEnvironment

use of net.openid.conformance.condition.PreEnvironment in project conformance-suite by openid-certification.

the class ValidateMTLSCertificatesAsX509 method evaluate.

@Override
@PreEnvironment(required = "mutual_tls_authentication")
public Environment evaluate(Environment env) {
    String certString = env.getString("mutual_tls_authentication", "cert");
    String keyString = env.getString("mutual_tls_authentication", "key");
    String caString = env.getString("mutual_tls_authentication", "ca");
    if (Strings.isNullOrEmpty(certString) || Strings.isNullOrEmpty(keyString)) {
        throw error("Couldn't find TLS client certificate or key for MTLS");
    }
    CertificateFactory certFactory = null;
    try {
        certFactory = CertificateFactory.getInstance("X.509", "BC");
    } catch (CertificateException | NoSuchProviderException | IllegalArgumentException e) {
        throw error("Couldn't get CertificateFactory", e);
    }
    X509Certificate certificate = generateCertificateFromMTLSCert(certString, certFactory);
    validateMTLSKey(certString, keyString, certificate);
    if (!Strings.isNullOrEmpty(caString)) {
        validateMTLSCa(env, certFactory, caString);
    }
    logSuccess("Mutual TLS authentication cert validated as X.509");
    return env;
}
Also used : CertificateException(java.security.cert.CertificateException) NoSuchProviderException(java.security.NoSuchProviderException) CertificateFactory(java.security.cert.CertificateFactory) X509Certificate(java.security.cert.X509Certificate) PreEnvironment(net.openid.conformance.condition.PreEnvironment)

Example 55 with PreEnvironment

use of net.openid.conformance.condition.PreEnvironment in project conformance-suite by openid-certification.

the class ValidateResourceResponseSignature method evaluate.

@Override
@PreEnvironment(required = { "endpoint_response_jwt", "org_server_jwks" })
public Environment evaluate(Environment env) {
    String idToken = env.getString("endpoint_response_jwt", "value");
    // to validate the signature
    JsonObject serverJwks = env.getObject("org_server_jwks");
    verifyJwsSignature(idToken, serverJwks, "endpoint_response_jwt", true, "organization");
    return env;
}
Also used : JsonObject(com.google.gson.JsonObject) PreEnvironment(net.openid.conformance.condition.PreEnvironment)

Aggregations

PreEnvironment (net.openid.conformance.condition.PreEnvironment)591 JsonObject (com.google.gson.JsonObject)469 PostEnvironment (net.openid.conformance.condition.PostEnvironment)379 JsonElement (com.google.gson.JsonElement)143 JsonArray (com.google.gson.JsonArray)74 Instant (java.time.Instant)40 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)29 IOException (java.io.IOException)25 CertificateException (java.security.cert.CertificateException)24 ParseException (java.text.ParseException)24 KeyManagementException (java.security.KeyManagementException)20 KeyStoreException (java.security.KeyStoreException)20 UnrecoverableKeyException (java.security.UnrecoverableKeyException)20 InvalidKeySpecException (java.security.spec.InvalidKeySpecException)20 RestClientException (org.springframework.web.client.RestClientException)20 RestTemplate (org.springframework.web.client.RestTemplate)20 JsonPrimitive (com.google.gson.JsonPrimitive)18 Date (java.util.Date)17 JWK (com.nimbusds.jose.jwk.JWK)13 JOSEException (com.nimbusds.jose.JOSEException)11