Search in sources :

Example 6 with OIDCException

use of it.spid.cie.oidc.exception.OIDCException in project spid-cie-oidc-java by italia.

the class RelyingPartyHandler method getAuthorizeURL.

/**
 * Build the "authorize url": the URL a RelyingParty have to send to an OpenID
 * Provider to start a SPID authorization flow
 *
 * @param spidProvider
 * @param trustAnchor
 * @param redirectUri
 * @param scope
 * @param profile
 * @param prompt
 * @return
 * @throws OIDCException
 */
public String getAuthorizeURL(String spidProvider, String trustAnchor, String redirectUri, String scope, String profile, String prompt) throws OIDCException {
    // TODO: CIE could reuse this flow?
    if (Validator.isNullOrEmpty(profile)) {
        profile = OIDCProfile.SPID.getValue();
    }
    TrustChain tc = getSPIDProvider(spidProvider, trustAnchor);
    if (tc == null) {
        throw new OIDCException("TrustChain is unavailable");
    }
    JSONObject providerMetadata;
    try {
        providerMetadata = new JSONObject(tc.getMetadata());
        if (providerMetadata.isEmpty()) {
            throw new OIDCException("Provider metadata is empty");
        }
    } catch (Exception e) {
        throw e;
    }
    FederationEntity entityConf = persistence.fetchFederationEntity(OIDCConstants.OPENID_RELYING_PARTY);
    if (entityConf == null || !entityConf.isActive()) {
        throw new OIDCException("Missing configuration");
    }
    JSONObject entityMetadata;
    JWKSet entityJWKSet;
    try {
        entityMetadata = entityConf.getMetadataValue(OIDCConstants.OPENID_RELYING_PARTY);
        if (entityMetadata.isEmpty()) {
            throw new OIDCException("Entity metadata is empty");
        }
        entityJWKSet = JWTHelper.getJWKSetFromJSON(entityConf.getJwks());
        if (entityJWKSet.getKeys().isEmpty()) {
            throw new OIDCException("Entity with invalid or empty jwks");
        }
    } catch (OIDCException e) {
        throw e;
    }
    JWKSet providerJWKSet = JWTHelper.getMetadataJWKSet(providerMetadata);
    String authzEndpoint = providerMetadata.getString("authorization_endpoint");
    JSONArray entityRedirectUris = entityMetadata.getJSONArray("redirect_uris");
    if (entityRedirectUris.isEmpty()) {
        throw new OIDCException("Entity has no redirect_uris");
    }
    if (!Validator.isNullOrEmpty(redirectUri)) {
        if (!JSONUtil.contains(entityRedirectUris, redirectUri)) {
            logger.warn("Requested for unknown redirect uri '{}'. Reverted to default '{}'", redirectUri, entityRedirectUris.getString(0));
            redirectUri = entityRedirectUris.getString(0);
        }
    } else {
        redirectUri = entityRedirectUris.getString(0);
    }
    if (Validator.isNullOrEmpty(scope)) {
        scope = OIDCConstants.SCOPE_OPENID;
    }
    if (Validator.isNullOrEmpty(profile)) {
        profile = options.getAcrValue(OIDCProfile.SPID);
    }
    if (Validator.isNullOrEmpty(prompt)) {
        prompt = "consent login";
    }
    String responseType = entityMetadata.getJSONArray("response_types").getString(0);
    String nonce = UUID.randomUUID().toString();
    String state = UUID.randomUUID().toString();
    String clientId = entityMetadata.getString("client_id");
    long issuedAt = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);
    String[] aud = new String[] { tc.getSubject(), authzEndpoint };
    JSONObject claims = getRequestedClaims(profile);
    JSONObject pkce = PKCEHelper.getPKCE();
    String acr = options.getAcrValue(OIDCProfile.SPID);
    JSONObject authzData = new JSONObject().put("scope", scope).put("redirect_uri", redirectUri).put("response_type", responseType).put("nonce", nonce).put("state", state).put("client_id", clientId).put("endpoint", authzEndpoint).put("acr_values", acr).put("iat", issuedAt).put("aud", JSONUtil.asJSONArray(aud)).put("claims", claims).put("prompt", prompt).put("code_verifier", pkce.getString("code_verifier")).put("code_challenge", pkce.getString("code_challenge")).put("code_challenge_method", pkce.getString("code_challenge_method"));
    AuthnRequest authzEntry = new AuthnRequest().setClientId(clientId).setState(state).setEndpoint(authzEndpoint).setProvider(tc.getSubject()).setProviderId(tc.getSubject()).setData(authzData.toString()).setProviderJwks(providerJWKSet.toString()).setProviderConfiguration(providerMetadata.toString());
    authzEntry = persistence.storeOIDCAuthnRequest(authzEntry);
    authzData.remove("code_verifier");
    authzData.put("iss", entityMetadata.getString("client_id"));
    authzData.put("sub", entityMetadata.getString("client_id"));
    String requestObj = jwtHelper.createJWS(authzData, entityJWKSet);
    authzData.put("request", requestObj);
    String url = buildURL(authzEndpoint, authzData);
    logger.info("Starting Authn request to {}", url);
    return url;
}
Also used : FederationEntity(it.spid.cie.oidc.model.FederationEntity) TrustChain(it.spid.cie.oidc.model.TrustChain) JSONObject(org.json.JSONObject) AuthnRequest(it.spid.cie.oidc.model.AuthnRequest) OIDCException(it.spid.cie.oidc.exception.OIDCException) JWKSet(com.nimbusds.jose.jwk.JWKSet) JSONArray(org.json.JSONArray) SchemaException(it.spid.cie.oidc.exception.SchemaException) OIDCException(it.spid.cie.oidc.exception.OIDCException) RelyingPartyException(it.spid.cie.oidc.exception.RelyingPartyException) TrustChainException(it.spid.cie.oidc.exception.TrustChainException)

Example 7 with OIDCException

use of it.spid.cie.oidc.exception.OIDCException in project spid-cie-oidc-java by italia.

the class RelyingPartyHandler method doGetUserInfo.

protected JSONObject doGetUserInfo(String state, String code) throws OIDCException {
    if (Validator.isNullOrEmpty(code) || Validator.isNullOrEmpty(state)) {
        throw new SchemaException.Validation("Authn response object validation failed");
    }
    List<AuthnRequest> authnRequests = persistence.findAuthnRequests(state);
    if (authnRequests.isEmpty()) {
        throw new RelyingPartyException.Generic("No AuthnRequest");
    }
    AuthnRequest authnRequest = ListUtil.getLast(authnRequests);
    AuthnToken authnToken = new AuthnToken().setAuthnRequestId(authnRequest.getStorageId()).setCode(code);
    authnToken = persistence.storeOIDCAuthnToken(authnToken);
    // Get clientId configuration. In this situation "clientId" refers this
    // RelyingParty
    FederationEntity entityConf = persistence.fetchFederationEntity(authnRequest.getClientId(), true);
    if (entityConf == null) {
        throw new RelyingPartyException.Generic("RelyingParty %s not found", authnRequest.getClientId());
    } else if (!Objects.equals(options.getClientId(), authnRequest.getClientId())) {
        throw new RelyingPartyException.Generic("Invalid RelyingParty %s", authnRequest.getClientId());
    }
    JSONObject authnData = new JSONObject(authnRequest.getData());
    JSONObject providerConfiguration = new JSONObject(authnRequest.getProviderConfiguration());
    JSONObject jsonTokenResponse = oauth2Helper.performAccessTokenRequest(authnData.optString("redirect_uri"), state, code, authnRequest.getProviderId(), entityConf, providerConfiguration.optString("token_endpoint"), authnData.optString("code_verifier"));
    TokenResponse tokenResponse = TokenResponse.of(jsonTokenResponse);
    if (logger.isDebugEnabled()) {
        logger.debug("TokenResponse=" + tokenResponse.toString());
    }
    JWKSet providerJwks = JWTHelper.getJWKSetFromJSON(providerConfiguration.optJSONObject("jwks"));
    try {
        jwtHelper.verifyJWS(tokenResponse.getAccessToken(), providerJwks);
    } catch (Exception e) {
        throw new RelyingPartyException.Authentication("Authentication token validation error.");
    }
    try {
        jwtHelper.verifyJWS(tokenResponse.getIdToken(), providerJwks);
    } catch (Exception e) {
        throw new RelyingPartyException.Authentication("ID token validation error.");
    }
    // Update AuthenticationToken
    authnToken.setAccessToken(tokenResponse.getAccessToken());
    authnToken.setIdToken(tokenResponse.getIdToken());
    authnToken.setTokenType(tokenResponse.getTokenType());
    authnToken.setScope(jsonTokenResponse.optString("scope"));
    authnToken.setExpiresIn(tokenResponse.getExpiresIn());
    authnToken = persistence.storeOIDCAuthnToken(authnToken);
    JWKSet entityJwks = JWTHelper.getJWKSetFromJSON(entityConf.getJwks());
    JSONObject userInfo = oidcHelper.getUserInfo(state, tokenResponse.getAccessToken(), providerConfiguration, true, entityJwks);
    // TODO: userKey from options
    authnToken.setUserKey(userInfo.optString("https://attributes.spid.gov.it/email"));
    authnToken = persistence.storeOIDCAuthnToken(authnToken);
    return userInfo;
}
Also used : SchemaException(it.spid.cie.oidc.exception.SchemaException) OIDCException(it.spid.cie.oidc.exception.OIDCException) RelyingPartyException(it.spid.cie.oidc.exception.RelyingPartyException) TrustChainException(it.spid.cie.oidc.exception.TrustChainException) FederationEntity(it.spid.cie.oidc.model.FederationEntity) AuthnRequest(it.spid.cie.oidc.model.AuthnRequest) JSONObject(org.json.JSONObject) TokenResponse(it.spid.cie.oidc.schemas.TokenResponse) AuthnToken(it.spid.cie.oidc.model.AuthnToken) JWKSet(com.nimbusds.jose.jwk.JWKSet) RelyingPartyException(it.spid.cie.oidc.exception.RelyingPartyException)

Example 8 with OIDCException

use of it.spid.cie.oidc.exception.OIDCException in project spid-cie-oidc-java by italia.

the class EntityHelper method doHttpGet.

/**
 * @param url
 * @return
 * @throws OIDCException
 */
private static String doHttpGet(String url) throws OIDCException {
    try {
        HttpRequest request = HttpRequest.newBuilder().uri(new URI(url)).GET().build();
        HttpResponse<String> response = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.NORMAL).build().send(request, BodyHandlers.ofString());
        if (logger.isDebugEnabled()) {
            logger.debug(url + " --> " + response.statusCode());
        }
        if (response.statusCode() != 200) {
            throw new EntityException.Generic(url + " gets " + response.statusCode());
        }
        return response.body();
    } catch (EntityException e) {
        throw e;
    } catch (Exception e) {
        throw new EntityException.Generic(e);
    }
}
Also used : HttpRequest(java.net.http.HttpRequest) EntityException(it.spid.cie.oidc.exception.EntityException) URI(java.net.URI) EntityException(it.spid.cie.oidc.exception.EntityException) OIDCException(it.spid.cie.oidc.exception.OIDCException)

Example 9 with OIDCException

use of it.spid.cie.oidc.exception.OIDCException in project spid-cie-oidc-java by italia.

the class JWTHelper method getJWKSetFromJSON.

/**
 * Get the JSON Web Key (JWK) set from the provided JSON string
 *
 * @param value a string representation of a JSONArray (array of keys) or of a
 * JSONObject (complete jwks element)
 * @return
 * @throws OIDCException
 */
public static JWKSet getJWKSetFromJSON(String value) throws OIDCException {
    try {
        value = GetterUtil.getString(value, "{}").trim();
        JSONObject jwks;
        if (value.startsWith("[")) {
            jwks = new JSONObject().put("keys", new JSONArray(value));
        } else {
            jwks = new JSONObject(value);
        }
        return JWKSet.parse(jwks.toMap());
    } catch (Exception e) {
        throw new JWTException.Parse(e);
    }
}
Also used : JSONObject(org.json.JSONObject) JWTException(it.spid.cie.oidc.exception.JWTException) JSONArray(org.json.JSONArray) JOSEException(com.nimbusds.jose.JOSEException) JWTException(it.spid.cie.oidc.exception.JWTException) OIDCException(it.spid.cie.oidc.exception.OIDCException) ParseException(java.text.ParseException)

Example 10 with OIDCException

use of it.spid.cie.oidc.exception.OIDCException in project spid-cie-oidc-java by italia.

the class JWTHelper method getJWKSetFromJWT.

/**
 * Get the JSON Web Key (JWK) set from the "payload" part of the provided JWT Token,
 * or null if not present
 *
 * @param jwt the base64 encoded JWT Token
 * @return
 * @throws OIDCException
 */
public static JWKSet getJWKSetFromJWT(String jwt) throws OIDCException {
    try {
        JSONObject token = fastParse(jwt);
        JSONObject payload = token.getJSONObject("payload");
        return getJWKSet(payload);
    } catch (Exception e) {
        throw new JWTException.Parse(e);
    }
}
Also used : JSONObject(org.json.JSONObject) JWTException(it.spid.cie.oidc.exception.JWTException) JOSEException(com.nimbusds.jose.JOSEException) JWTException(it.spid.cie.oidc.exception.JWTException) OIDCException(it.spid.cie.oidc.exception.OIDCException) ParseException(java.text.ParseException)

Aggregations

OIDCException (it.spid.cie.oidc.exception.OIDCException)16 JSONObject (org.json.JSONObject)9 JWKSet (com.nimbusds.jose.jwk.JWKSet)7 JWTException (it.spid.cie.oidc.exception.JWTException)7 TrustChainException (it.spid.cie.oidc.exception.TrustChainException)6 JOSEException (com.nimbusds.jose.JOSEException)5 ParseException (java.text.ParseException)5 URI (java.net.URI)4 HttpRequest (java.net.http.HttpRequest)4 JWK (com.nimbusds.jose.jwk.JWK)3 EntityException (it.spid.cie.oidc.exception.EntityException)3 FederationEntity (it.spid.cie.oidc.model.FederationEntity)3 JSONArray (org.json.JSONArray)3 JWSAlgorithm (com.nimbusds.jose.JWSAlgorithm)2 RelyingPartyException (it.spid.cie.oidc.exception.RelyingPartyException)2 SchemaException (it.spid.cie.oidc.exception.SchemaException)2 TrustChainBuilderException (it.spid.cie.oidc.exception.TrustChainBuilderException)2 AuthnRequest (it.spid.cie.oidc.model.AuthnRequest)2 HashMap (java.util.HashMap)2 EncryptionMethod (com.nimbusds.jose.EncryptionMethod)1