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;
}
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;
}
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);
}
}
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);
}
}
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);
}
}
Aggregations