diff --git a/README.md b/README.md index 15b6528..ea0e00d 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ Sample projects using the library can be executed as docker or docker-compose. S ### SpringBoot Relying Party example -A simple [SpringBoot](examples/relying-party-spring-boot) web application using the starter-kit to implement a Relying Party. +A simple [SpringBoot](examples/relying-party-spring-boot) web application using the starter-kit to implement a Relying Party, as well to perform the complete onboarding and login/logout test within the CIE Federation. This application is for demo purpose only, please don't use it in production or critical environment. diff --git a/coverage/pom.xml b/coverage/pom.xml index 2b50038..baffef7 100644 --- a/coverage/pom.xml +++ b/coverage/pom.xml @@ -5,7 +5,7 @@ it.spid.cie.oidc starter-kit-parent - 0.4.1-SNAPSHOT + 1.0.0-SNAPSHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 1104bbf..f9614e3 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -5,7 +5,7 @@ it.spid.cie.oidc starter-kit-parent - 0.4.1-SNAPSHOT + 1.0.0-SNAPSHOT ../pom.xml diff --git a/examples/relying-party-spring-boot/README.md b/examples/relying-party-spring-boot/README.md index d3355ff..5b5e350 100644 --- a/examples/relying-party-spring-boot/README.md +++ b/examples/relying-party-spring-boot/README.md @@ -15,7 +15,7 @@ Run the provider [federation](https://github.com/italia/spid-cie-oidc-django) - the project should run on [http://127.0.0.1:8000](http://127.0.0.1:8000), keep it running -Clone this repository and install all the lement inside the MavenLocal registry +Clone this repository and install all the elements inside the MavenLocal registry ``` git clone https://github.com/italia/spid-cie-oidc-java @@ -39,9 +39,10 @@ this will start the relying party server on [http://127.0.0.1:8080](http://127.0 Do the on-boarding process - generate the relying party jwks - go [here](http://127.0.0.1:8080/) to auto-generate it - - jwks are exposed on the page and inside application log - - create the file `${user.home}/oidc-rp-jwk.json` with the jwks - - use "reload" link to proceed with next step + - federation jwks and core jwks are exposed on the page and inside application log + - create the file `${user.home}/oidc-rp-jwk.json` with the federation jwks + - create the file `${user.home}/oidc-rp-core-jwk.json` with the core jwks + - - use "reload" link to proceed with next step - show on-boarding datas - go [here](http://127.0.0.1:8080/) to see it - register the relying party [here](http://127.0.0.1:8000/admin/spid_cie_oidc_authority/federationdescendant/add) @@ -76,10 +77,32 @@ A docker image containing this example can be built a run: - visit `http://relying-party.org:8080/` Some hints: -- we are using [federation](https://github.com/italia/spid-cie-oidc-django) v1.2.0 +- we are using [federation](https://github.com/italia/spid-cie-oidc-django) v1.4.0 - docker images currently sets a proxy of the exposed ports on the localhost interface, so you could use previous chapter instructions replacing `127.0.0.1` with the right hostname -- docker image mounts the folder `./docker/data-java` as `/data` inside spring-boot container to externalize `jwk` and `trust-marks` configuration +- docker image mounts the folder `./docker/data-java` as `/data` inside spring-boot container to externalize federation and core `jwks` and `trust-marks` configuration [Docker Compose in action on YouTube](https://www.youtube.com/watch?v=U2Ec0No2EKg) + +**To be onboarded into CIE Federation**: +- use always appropriate and valid TLS Certificates +- use IP from Italian networks for server [CIE Federation servers uses geoblocking] +- as contact use the same institutional email address as stated into the administrative part [do not use PEC] +- when copy the federation public key please follow this pattern: + - ``` + { + "keys": [ + { + "alg": "RS256", + "kid": "....", + "kty": "RSA", + "n": ".....", + "e": "AQAB", + "use": "sig" + } + ] + } + ``` +- when onboarded, please retrieve the Trust Mark form TA fetch endpoint like this example for preproduction: `https://preprod.oidc.registry.servizicie.interno.gov.it/fetch?sub={your_client_id}` +- remember to (put `[` `]` around the Trust Mark when writing the appropriate file \ No newline at end of file diff --git a/examples/relying-party-spring-boot/docker/Dockerfile-cie.django b/examples/relying-party-spring-boot/docker/Dockerfile-cie.django index be228d9..d498711 100644 --- a/examples/relying-party-spring-boot/docker/Dockerfile-cie.django +++ b/examples/relying-party-spring-boot/docker/Dockerfile-cie.django @@ -2,7 +2,7 @@ FROM python:3.11-slim RUN apt update && apt -y install git -RUN git clone --depth=1 --branch v1.2.0 https://github.com/italia/spid-cie-oidc-django && \ +RUN git clone --depth=1 --branch v1.4.0 https://github.com/italia/spid-cie-oidc-django && \ cd spid-cie-oidc-django && \ pip install --upgrade pip && \ pip install -e . && \ diff --git a/examples/relying-party-spring-boot/docker/Dockerfile.django b/examples/relying-party-spring-boot/docker/Dockerfile.django index 09e619a..ecfa49b 100644 --- a/examples/relying-party-spring-boot/docker/Dockerfile.django +++ b/examples/relying-party-spring-boot/docker/Dockerfile.django @@ -2,7 +2,7 @@ FROM python:3.11-slim RUN apt update && apt -y install git -RUN git clone --depth=1 --branch v1.2.0 https://github.com/italia/spid-cie-oidc-django && \ +RUN git clone --depth=1 --branch v1.4.0 https://github.com/italia/spid-cie-oidc-django && \ cd spid-cie-oidc-django && \ pip install --upgrade pip && \ pip install -e . && \ diff --git a/examples/relying-party-spring-boot/docker/Dockerfile.java-rp b/examples/relying-party-spring-boot/docker/Dockerfile.java-rp index 6d00da8..ba171c4 100644 --- a/examples/relying-party-spring-boot/docker/Dockerfile.java-rp +++ b/examples/relying-party-spring-boot/docker/Dockerfile.java-rp @@ -13,7 +13,8 @@ VOLUME ["/data"] ENV OIDC_HOSTS_TRUST_ANCHOR="trust-anchor.org" ENV OIDC_HOSTS_CIE_PROVIDER="cie-provider.org" ENV OIDC_HOSTS_RELYING_PARTY="relying-party.org" -ENV OIDC_RELYING_PARTY_JWK_FILE_PATH="/data/oidc-rp-jwk.json" +ENV OIDC_RELYING_PARTY_JWK_FED_FILE_PATH="/data/oidc-rp-jwk.json" +ENV OIDC_RELYING_PARTY_CORE_JWK_CORE_FILE_PATH="/data/oidc-rp-core-jwk.json" ENV OIDC_RELYING_PARTY_TRUST_MARKS_FILE_PATH="/data/oidc-rp-trust-marks.json" ENV SPRING_H2_CONSOLE_SETTINGS_WEB_ALLOW_OTHERS="true" diff --git a/examples/relying-party-spring-boot/pom.xml b/examples/relying-party-spring-boot/pom.xml index 82d3126..7fbb1ff 100644 --- a/examples/relying-party-spring-boot/pom.xml +++ b/examples/relying-party-spring-boot/pom.xml @@ -5,7 +5,7 @@ it.spid.cie.oidc it.spid.cie.oidc.examples - 0.4.1-SNAPSHOT + 1.0.0-SNAPSHOT it.spid.cie.oidc.relying.party.spring-boot-sample diff --git a/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/RelyingPartyWrapper.java b/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/RelyingPartyWrapper.java index c7a94a4..af03f0f 100644 --- a/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/RelyingPartyWrapper.java +++ b/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/RelyingPartyWrapper.java @@ -48,10 +48,10 @@ public JSONObject getUserInfo(String state, String code) } public String getUserKey(JSONObject userInfo) { - String userKey = userInfo.optString("email"); + String userKey = userInfo.optString("sub"); if (Validator.isNullOrEmpty(userKey)) { - userKey = userInfo.optString("email", ""); + userKey = userInfo.optString("sub", ""); } return userKey; @@ -83,11 +83,12 @@ public void reloadHandler() throws OIDCException { @PostConstruct private void postConstruct() throws OIDCException { - String jwk = readFile(oidcConfig.getRelyingParty().getJwkFilePath()); + String jwkFed = readFile(oidcConfig.getRelyingParty().getJwkFedFilePath()); + String jwkCore = readFile(oidcConfig.getRelyingParty().getJwkCoreFilePath()); String trustMarks = readFile( oidcConfig.getRelyingParty().getTrustMarksFilePath()); - logger.info("final jwk: " + jwk); + logger.info("final jwkFed: " + jwkFed); logger.info("final trust_marks: " + trustMarks); RelyingPartyOptions options = new RelyingPartyOptions() @@ -110,7 +111,8 @@ private void postConstruct() throws OIDCException { .setLogoUri(oidcConfig.getRelyingParty().getLogoUri()) .setPolicyUri(oidcConfig.getRelyingParty().getPolicyUri()) .setFederationContacts(oidcConfig.getRelyingParty().getFederationContacts()) - .setJWK(jwk) + .setJWKFed(jwkFed) + .setJWKCore(jwkCore) .setTrustMarks(trustMarks); relyingPartyHandler = new RelyingPartyHandler(options, persistenceImpl); diff --git a/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/config/OidcConfig.java b/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/config/OidcConfig.java index fa4a864..3d2f070 100644 --- a/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/config/OidcConfig.java +++ b/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/config/OidcConfig.java @@ -208,10 +208,12 @@ public Set getRedirectUris() { // return jwk; // } - public String getJwkFilePath() { - return jwkFilePath; + public String getJwkFedFilePath() { + return jwkFedFilePath; + } + public String getJwkCoreFilePath() { + return jwkCoreFilePath; } - // public String getTrustMarks() { // return trustMarks; // } @@ -271,10 +273,13 @@ public void setFederationContacts(Set federationContacts) { // this.jwk = jwk; // } - public void setJwkFilePath(String jwkFilePath) { - this.jwkFilePath = jwkFilePath; + public void setJwkFedFilePath(String jwkFedFilePath) { + this.jwkFedFilePath = jwkFedFilePath; } + public void setJwkCoreFilePath(String jwkCoreFilePath) { + this.jwkCoreFilePath = jwkCoreFilePath; + } // public void setTrustMarks(String trustMarks) { // this.trustMarks = trustMarks; // } @@ -305,7 +310,8 @@ public JSONObject toJSON() { json.put("clientId", clientId); json.put("redirectUris", redirectUris); //json.put("jwk", jwk); - json.put("jwkFilePath", jwkFilePath); + json.put("jwkFilePath", jwkFedFilePath); + json.put("jwkCoreFilePath", jwkCoreFilePath); //json.put("trustMarks", trustMarks); json.put("trustMarksFilePath", trustMarksFilePath); @@ -319,7 +325,8 @@ public JSONObject toJSON() { private String clientId; private Set redirectUris = new HashSet<>(); //private String jwk; - private String jwkFilePath; + private String jwkFedFilePath; + private String jwkCoreFilePath; //private String trustMarks; private String trustMarksFilePath; diff --git a/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/controller/EntityStatementController.java b/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/controller/EntityStatementController.java index 00e1e78..1f0dc2d 100644 --- a/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/controller/EntityStatementController.java +++ b/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/controller/EntityStatementController.java @@ -70,7 +70,7 @@ public ResponseEntity resolveEntityStatement( .body(response.toString()); } else { JWTHelper jws = new JWTHelper(new RelyingPartyOptions()); - return new ResponseEntity<>(jws.createJWS(response, JWTHelper.getJWKSetFromJSON(entityConfiguration.getJwks())), HttpStatus.OK); + return new ResponseEntity<>(jws.createJWS(response, JWTHelper.getJWKSetFromJSON(entityConfiguration.getJwksFed())), HttpStatus.OK); } } } \ No newline at end of file diff --git a/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/controller/HomeController.java b/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/controller/HomeController.java index e88fb80..9bf2694 100644 --- a/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/controller/HomeController.java +++ b/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/controller/HomeController.java @@ -2,6 +2,8 @@ import javax.servlet.http.HttpServletRequest; +import org.json.JSONArray; +import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @@ -29,8 +31,13 @@ public ModelAndView home(HttpServletRequest request) mav.addObject("trustAnchorHost", oidcConfig.getHosts().getTrustAnchor()); if (wellKnow.hasOnlyJwks()) { - mav.addObject("mineJwks", wellKnow.getValue()); - mav.addObject("configFile", oidcConfig.getRelyingParty().getJwkFilePath()); + JSONArray json = new JSONArray(wellKnow.getValue()); + + mav.addObject("fedJwks", json.get(0).toString()); + mav.addObject("coreJwks", json.get(1).toString()); + + mav.addObject("configFile", oidcConfig.getRelyingParty().getJwkFedFilePath()); + mav.addObject("configCoreFile", oidcConfig.getRelyingParty().getJwkCoreFilePath()); } if (wellKnow.isIntermediate()) { diff --git a/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/controller/WellKnownController.java b/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/controller/WellKnownController.java index b8904cf..e3e5b13 100644 --- a/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/controller/WellKnownController.java +++ b/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/controller/WellKnownController.java @@ -37,7 +37,7 @@ public ResponseEntity wellKnownFederation( if (wellKnown.getStep() == WellKnownData.STEP_ONLY_JWKS) { logger.info( "Generated jwk. Please add it into 'application.yaml' or save as '" + - oidcConfig.getRelyingParty().getJwkFilePath() + "'.\n" + + oidcConfig.getRelyingParty().getJwkFedFilePath() + "'.\n" + wellKnown.getValue()); String body = new JSONObject() diff --git a/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/persistence/model/FederationEntityModel.java b/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/persistence/model/FederationEntityModel.java index 4c8c40d..112e654 100644 --- a/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/persistence/model/FederationEntityModel.java +++ b/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/persistence/model/FederationEntityModel.java @@ -9,6 +9,7 @@ import javax.persistence.Id; import javax.persistence.Table; +import com.nimbusds.jose.jwk.KeyUse; import it.spid.cie.oidc.model.FederationEntity; import it.spid.cie.oidc.util.GetterUtil; import it.spid.cie.oidc.util.Validator; @@ -30,7 +31,8 @@ public static FederationEntityModel of(FederationEntity source) { target.setActive(source.isActive()); target.setAuthorityHints(source.getAuthorityHints()); target.setConstraints(source.getConstraints()); - target.setJwks(source.getJwks()); + target.setJwksFed(source.getJwksFed()); + target.setJwksCore(source.getJwksCore()); target.setTrustMarks(source.getTrustMarks()); target.setTrustMarkIssuers(source.gettrustMarkIssuers()); target.setMetadata(source.getMetadata()); @@ -71,8 +73,12 @@ public String getAuthorityHints() { return authorityHints; } - public String getJwks() { - return jwks; + public String getJwksFed() { + return jwksFed; + } + + public String getJwksCore() { + return jwksCore; } public String getTrustMarks() { @@ -126,10 +132,12 @@ public void setAuthorityHints(String authorityHints) { this.authorityHints = authorityHints; } - public void setJwks(String jwks) { - this.jwks = jwks; + public void setJwksFed(String jwksFed) { + this.jwksFed = jwksFed; + } + public void setJwksCore(String jwksCore) { + this.jwksCore = jwksCore; } - public void setTrustMarks(String trustMarks) { this.trustMarks = trustMarks; } @@ -167,7 +175,8 @@ public FederationEntity toFederationEntity() { target.setActive(isActive()); target.setAuthorityHints(getAuthorityHints()); target.setConstraints(getConstraints()); - target.setJwks(getJwks()); + target.setJwksFed(getJwksFed()); + target.setJwksCore(getJwksCore()); target.setTrustMarks(getTrustMarks()); target.settrustMarkIssuers(getTrustMarkIssuers()); target.setMetadata(getMetadata()); @@ -213,8 +222,10 @@ private String getStorageId() { private String authorityHints; @Column(nullable = false, length = 2000) - private String jwks; + private String jwksFed; + @Column(nullable = false, length = 2000) + private String jwksCore; @Column(name = "trust_marks", nullable = false, length = 2000) private String trustMarks; diff --git a/examples/relying-party-spring-boot/src/main/resources/application.yml b/examples/relying-party-spring-boot/src/main/resources/application.yml index a54c927..e1ebee0 100644 --- a/examples/relying-party-spring-boot/src/main/resources/application.yml +++ b/examples/relying-party-spring-boot/src/main/resources/application.yml @@ -63,7 +63,7 @@ oidc: token-endpoint-auth-method: "private_key_jwt" id-token-signed-response-alg: "RS256" userinfo-signed-response-alg: "RS256" - userinfo-encrypted-response-alg: "RSA-OAEP" + userinfo-encrypted-response-alg: "RSA-OAEP-256" userinfo-encrypted-response-enc: "A128CBC-HS256" federation-resolve-endpoint: "http://${oidc.hosts.relying-party}:8080/resolve" @@ -77,5 +77,6 @@ oidc: client-id: "http://${oidc.hosts.relying-party}:8080/oidc/rp/" redirect-uris: - "http://${oidc.hosts.relying-party}:8080/oidc/rp/callback" - jwk-file-path: ${user.home}/oidc-rp-jwk.json + jwk-fed-file-path: ${user.home}/oidc-rp-jwk.json + jwk-core-file-path: ${user.home}/oidc-rp-core-jwk.json trust-marks-file-path: ${user.home}/oidc-rp-trust-marks.json diff --git a/examples/relying-party-spring-boot/src/main/resources/sql/schema.sql b/examples/relying-party-spring-boot/src/main/resources/sql/schema.sql index 97d86a8..47d943c 100644 --- a/examples/relying-party-spring-boot/src/main/resources/sql/schema.sql +++ b/examples/relying-party-spring-boot/src/main/resources/sql/schema.sql @@ -38,7 +38,8 @@ CREATE TABLE IF NOT EXISTS federation_entity_configuration ( default_exp INTEGER NOT NULL, default_signature_alg VARCHAR(16) NOT NULL, authority_hints VARCHAR NOT NULL, - jwks VARCHAR NOT NULL, + jwks_fed VARCHAR NOT NULL, + jwks_core VARCHAR NOT NULL, trust_marks VARCHAR NOT NULL, trust_mark_issuers VARCHAR NOT NULL, metadata VARCHAR NOT NULL, diff --git a/examples/relying-party-spring-boot/src/main/resources/templates/home.html b/examples/relying-party-spring-boot/src/main/resources/templates/home.html index 1ed9268..c88e0ca 100644 --- a/examples/relying-party-spring-boot/src/main/resources/templates/home.html +++ b/examples/relying-party-spring-boot/src/main/resources/templates/home.html @@ -2,14 +2,27 @@ OIDC Relying Party SpringBoot Example +

OIDC Relying Party SpringBoot Example

-

Before continue, put generated jwk into ''

+

Before continue, put generated Federation jwk into ''

-

+				
+			

+

the Core Sig and Enc jwks into ''

+

+

 			

then make the app reload it.

diff --git a/examples/relying-party-spring-boot/src/main/resources/templates/landing.html b/examples/relying-party-spring-boot/src/main/resources/templates/landing.html index 3a03f82..e4ba31b 100644 --- a/examples/relying-party-spring-boot/src/main/resources/templates/landing.html +++ b/examples/relying-party-spring-boot/src/main/resources/templates/landing.html @@ -36,7 +36,7 @@ diff --git a/pom.xml b/pom.xml index e80f3e5..b4d4122 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ it.spid.cie.oidc starter-kit-parent pom - 0.4.1-SNAPSHOT + 1.0.0-SNAPSHOT 11 diff --git a/starter-kit/pom.xml b/starter-kit/pom.xml index 8352d40..e377173 100644 --- a/starter-kit/pom.xml +++ b/starter-kit/pom.xml @@ -5,7 +5,7 @@ it.spid.cie.oidc starter-kit-parent - 0.4.1-SNAPSHOT + 1.0.0-SNAPSHOT ../pom.xml diff --git a/starter-kit/src/main/java/it/spid/cie/oidc/config/RelyingPartyOptions.java b/starter-kit/src/main/java/it/spid/cie/oidc/config/RelyingPartyOptions.java index 87b09d5..6d07880 100644 --- a/starter-kit/src/main/java/it/spid/cie/oidc/config/RelyingPartyOptions.java +++ b/starter-kit/src/main/java/it/spid/cie/oidc/config/RelyingPartyOptions.java @@ -52,7 +52,8 @@ public class RelyingPartyOptions extends GlobalOptions { private Set contacts = new HashSet<>(); private String clientId; private Set redirectUris = new HashSet<>(); - private String jwk; + private String jwkFed; + private String jwkCore; private String trustMarks; private String loginURL = "/oidc/rp/landing"; @@ -177,8 +178,12 @@ public Set getRedirectUris() { return Collections.unmodifiableSet(redirectUris); } - public String getJwk() { - return jwk; + public String getJwkFed() { + return jwkFed; + } + + public String getJwkCore() { + return jwkCore; } public String getTrustMarks() { @@ -379,14 +384,20 @@ public RelyingPartyOptions setDefaultTrustAnchor(String defaultTrustAnchor) { return this; } - public RelyingPartyOptions setJWK(String jwk) { + public RelyingPartyOptions setJWKFed(String jwk) { if (!Validator.isNullOrEmpty(jwk)) { - this.jwk = jwk; + this.jwkFed = jwk; } return this; } + public RelyingPartyOptions setJWKCore(String jwk) { + if (!Validator.isNullOrEmpty(jwk)) { + this.jwkCore = jwk; + } + return this; + } public RelyingPartyOptions setRedirectUris(Collection redirectUris) { if (redirectUris != null && !redirectUris.isEmpty()) { this.redirectUris.clear(); diff --git a/starter-kit/src/main/java/it/spid/cie/oidc/handler/RelyingPartyHandler.java b/starter-kit/src/main/java/it/spid/cie/oidc/handler/RelyingPartyHandler.java index f8122bb..8d37744 100644 --- a/starter-kit/src/main/java/it/spid/cie/oidc/handler/RelyingPartyHandler.java +++ b/starter-kit/src/main/java/it/spid/cie/oidc/handler/RelyingPartyHandler.java @@ -1,6 +1,8 @@ package it.spid.cie.oidc.handler; +import com.nimbusds.jose.JWEAlgorithm; import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.KeyUse; import com.nimbusds.jose.jwk.RSAKey; @@ -9,12 +11,7 @@ import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.time.ZoneOffset; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; +import java.util.*; import org.json.JSONArray; import org.json.JSONObject; @@ -135,7 +132,7 @@ public String getAuthorizeURL( throw new OIDCException("Entity metadata is empty"); } - entityJWKSet = JWTHelper.getJWKSetFromJSON(entityConf.getJwks()); + entityJWKSet = JWTHelper.getJWKSetFromJSON(entityConf.getJwksCoreByUse(KeyUse.SIGNATURE)); if (entityJWKSet.getKeys().isEmpty()) { throw new OIDCException("Entity with invalid or empty jwks"); @@ -218,7 +215,7 @@ public String getAuthorizeURL( authzData.remove("code_verifier"); authzData.put("iss", entityMetadata.getString("client_id")); - authzData.put("sub", entityMetadata.getString("client_id")); + //authzData.put("sub", entityMetadata.getString("client_id")); String requestObj = jwtHelper.createJWS(authzData, entityJWKSet); @@ -437,7 +434,7 @@ else if (!Objects.equals(options.getClientId(), authnRequest.getClientId())) { authnToken = persistence.storeOIDCAuthnToken(authnToken); - JWKSet entityJwks = JWTHelper.getJWKSetFromJSON(entityConf.getJwks()); + JWKSet entityJwks = JWTHelper.getJWKSetFromJSON(entityConf.getJwksCoreByUse(KeyUse.ENCRYPTION)); JSONObject userInfo = oidcHelper.getUserInfo( state, tokenResponse.getAccessToken(), providerConfiguration, true, @@ -496,7 +493,7 @@ protected String doPerformLogout( FederationEntity entityConf = persistence.fetchFederationEntity( authnRequest.getClientId(), true); - JWTHelper.getJWKSetFromJSON(entityConf.getJwks()); + JWTHelper.getJWKSetFromJSON(entityConf.getJwksFed()); authnToken.setRevoked(LocalDateTime.now()); @@ -742,7 +739,8 @@ private JSONObject getRequestedClaims(OIDCProfile profile) { private String getSubjectFromWellKnownURL(String url) { int x = url.indexOf(OIDCConstants.OIDC_FEDERATION_WELLKNOWN_URL); - + if(!this.options.getClientId().endsWith("/")) + x--; if (x > 0) { return url.substring(0, x); } @@ -805,7 +803,7 @@ private String getUserKeyFromUserInfo(JSONObject userInfo) { private WellKnownData getWellKnownData(FederationEntity entity, boolean jsonMode) throws OIDCException { - JWKSet jwkSet = JWTHelper.getJWKSetFromJSON(entity.getJwks()); + JWKSet jwkSet = JWTHelper.getJWKSetFromJSON(entity.getJwksFed()); JSONObject metadataJson = new JSONObject(entity.getMetadata()); @@ -836,37 +834,56 @@ private WellKnownData prepareOnboardingData(String sub, boolean jsonMode) // TODO: JWSAlgorithm via default? - String confJwk = options.getJwk(); + String confJwkFed = options.getJwkFed(); + String confJwkCore = options.getJwkCore(); // If not JSON Web Key is configured I have to create a new one - if (Validator.isNullOrEmpty(confJwk)) { + if (Validator.isNullOrEmpty(confJwkFed) || Validator.isNullOrEmpty(confJwkCore)) { // TODO: Type has to be defined by configuration? - RSAKey jwk = JWTHelper.createRSAKey(JWSAlgorithm.RS256, KeyUse.SIGNATURE); + RSAKey jwkFed = JWTHelper.createRSAKey(JWSAlgorithm.RS256, KeyUse.SIGNATURE); + RSAKey jwkCoreSig = JWTHelper.createRSAKey(JWSAlgorithm.RS256, KeyUse.SIGNATURE); + RSAKey jwkCoreEnc = JWTHelper.createRSAEncKey(JWEAlgorithm.RSA_OAEP_256, KeyUse.ENCRYPTION); + + JSONObject jsonFed = new JSONObject(jwkFed.toString()); + + JWKSet jwkCoreSet = new JWKSet(Arrays.asList(jwkCoreSig, jwkCoreEnc)); - JSONObject json = new JSONObject(jwk.toString()); + JSONArray json = new JSONArray() + .put(jsonFed) + .put(jwkCoreSet.toJSONObject(false)); return WellKnownData.of(WellKnownData.STEP_ONLY_JWKS, json.toString(2)); } - RSAKey jwk = JWTHelper.parseRSAKey(confJwk); + RSAKey jwkFed = JWTHelper.parseRSAKey(confJwkFed); - logger.info("Configured jwk\n" + jwk.toJSONString()); + logger.info("Configured jwkFed\n" + jwkFed.toJSONString()); JSONArray jsonPublicJwk = new JSONArray() - .put(new JSONObject(jwk.toPublicJWK().toJSONObject())); + .put(new JSONObject(jwkFed.toPublicJWK().toJSONObject())); - logger.info("Configured public jwk\n" + jsonPublicJwk.toString(2)); + logger.info("Configured public jwkFed\n" + jsonPublicJwk.toString(2)); - JWKSet jwkSet = new JWKSet(jwk); + logger.info("Configured jwkFed\n" + jwkFed.toJSONString()); + + JWKSet jwkCoreSet = new JWKSet(); + try { + jwkCoreSet = JWKSet.parse(confJwkCore.toString()); + } + catch (Exception e) { + logger.info("Error in parsing: " + e); + } + JWKSet jwkFedSet = new JWKSet(jwkFed); JSONObject rpJson = new JSONObject(); - rpJson.put("jwks", JWTHelper.getJWKSetAsJSONObject(jwkSet, false)); + rpJson.put("jwks", JWTHelper.getJWKSetAsJSONObject(jwkCoreSet.toPublicJWKSet(), false)); rpJson.put("application_type", options.getApplicationType()); rpJson.put("client_name", options.getApplicationName()); rpJson.put("client_id", sub); + rpJson.put("organization_name", options.getOrganizationName()); rpJson.put("client_registration_types", JSONUtil.asJSONArray("automatic")); rpJson.put("contacts", options.getContacts()); rpJson.put("grant_types", RelyingPartyOptions.SUPPORTED_GRANT_TYPES); @@ -903,7 +920,7 @@ private WellKnownData prepareOnboardingData(String sub, boolean jsonMode) json.put("iat", iat); json.put("iss", sub); json.put("sub", sub); - json.put("jwks", JWTHelper.getJWKSetAsJSONObject(jwkSet, true)); + json.put("jwks", JWTHelper.getJWKSetAsJSONObject(jwkFedSet, false)); json.put("metadata", metadataJson); json.put( "authority_hints", JSONUtil.asJSONArray(options.getDefaultTrustAnchor())); @@ -926,8 +943,10 @@ private WellKnownData prepareOnboardingData(String sub, boolean jsonMode) entity.setDefaultExpireMinutes(options.getDefaultExpiringMinutes()); entity.setDefaultSignatureAlg(JWSAlgorithm.RS256.toString()); entity.setAuthorityHints(json.getJSONArray("authority_hints").toString()); - entity.setJwks( - JWTHelper.getJWKSetAsJSONArray(jwkSet, true, false).toString()); + entity.setJwksFed( + JWTHelper.getJWKSetAsJSONArray(jwkFedSet, true, false).toString()); + entity.setJwksCore( + JWTHelper.getJWKSetAsJSONArray(jwkCoreSet,true,false).toString()); entity.setTrustMarks(json.getJSONArray("trust_marks").toString()); entity.settrustMarkIssuers("{}"); entity.setMetadata(json.getJSONObject("metadata").toString()); @@ -942,7 +961,7 @@ private WellKnownData prepareOnboardingData(String sub, boolean jsonMode) return WellKnownData.of(step, json.toString(), jsonPublicJwk.toString(2)); } - String jws = jwtHelper.createJWS(json, jwkSet); + String jws = jwtHelper.createJWS(json, jwkFedSet); return WellKnownData.of(step, jws, jsonPublicJwk.toString(2)); } diff --git a/starter-kit/src/main/java/it/spid/cie/oidc/helper/JWTHelper.java b/starter-kit/src/main/java/it/spid/cie/oidc/helper/JWTHelper.java index 7590c97..c75883f 100644 --- a/starter-kit/src/main/java/it/spid/cie/oidc/helper/JWTHelper.java +++ b/starter-kit/src/main/java/it/spid/cie/oidc/helper/JWTHelper.java @@ -1,17 +1,7 @@ package it.spid.cie.oidc.helper; -import com.nimbusds.jose.EncryptionMethod; -import com.nimbusds.jose.JOSEException; -import com.nimbusds.jose.JOSEObject; -import com.nimbusds.jose.JWEAlgorithm; -import com.nimbusds.jose.JWEDecrypter; -import com.nimbusds.jose.JWEObject; -import com.nimbusds.jose.JWSAlgorithm; -import com.nimbusds.jose.JWSHeader; -import com.nimbusds.jose.JWSObject; -import com.nimbusds.jose.JWSSigner; -import com.nimbusds.jose.JWSVerifier; -import com.nimbusds.jose.Payload; +import com.nimbusds.jose.*; +import com.nimbusds.jose.JOSEObjectType; import com.nimbusds.jose.crypto.ECDSASigner; import com.nimbusds.jose.crypto.RSADecrypter; import com.nimbusds.jose.crypto.RSASSASigner; @@ -66,7 +56,22 @@ public static RSAKey createRSAKey(JWSAlgorithm alg, KeyUse use) throws OIDCExcep throw new JWTException.Generic(e); } } + public static RSAKey createRSAEncKey(JWEAlgorithm alg, KeyUse use) throws OIDCException { + JWEAlgorithm goodAlg = GetterUtil.getObject(alg, JWEAlgorithm.RSA_OAEP_256); + // TODO: check goodAlg is RSA + + try { + return new RSAKeyGenerator(2048) + .algorithm(goodAlg) + .keyUse(use) + .keyIDFromThumbprint(true) + .generate(); + } + catch (Exception e) { + throw new JWTException.Generic(e); + } + } /** * Decode a Base64 string and return it * @@ -439,7 +444,8 @@ else if (KeyType.EC.equals(jwk.getKeyType())) { // Prepare JWS object with the payload JWSObject jwsObject = new JWSObject( - new JWSHeader.Builder(alg).keyID(jwk.getKeyID()).build(), + + new JWSHeader.Builder(alg).keyID(jwk.getKeyID()).type(new JOSEObjectType("entity-statement+jwt")).build(), new Payload(payload.toString())); // Compute the signature diff --git a/starter-kit/src/main/java/it/spid/cie/oidc/helper/OAuth2Helper.java b/starter-kit/src/main/java/it/spid/cie/oidc/helper/OAuth2Helper.java index e3b85b4..2d2c9d9 100644 --- a/starter-kit/src/main/java/it/spid/cie/oidc/helper/OAuth2Helper.java +++ b/starter-kit/src/main/java/it/spid/cie/oidc/helper/OAuth2Helper.java @@ -13,6 +13,7 @@ import java.util.Map; import java.util.UUID; +import com.nimbusds.jose.jwk.KeyUse; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -74,7 +75,7 @@ public JSONObject performAccessTokenRequest( .put("exp", JWTHelper.getExpiresOn()) .put("jti", UUID.randomUUID().toString()); - JWKSet jwkSet = JWTHelper.getJWKSetFromJSON(clientConf.getJwks()); + JWKSet jwkSet = JWTHelper.getJWKSetFromJSON(clientConf.getJwksCoreByUse(KeyUse.SIGNATURE)); String clientAssertion = jwtHelper.createJWS(payload, jwkSet); @@ -153,7 +154,7 @@ public void sendRevocationRequest( .put("exp", JWTHelper.getExpiresOn()) .put("jti", UUID.randomUUID().toString()); - JWKSet jwkSet = JWTHelper.getJWKSetFromJSON(clientConf.getJwks()); + JWKSet jwkSet = JWTHelper.getJWKSetFromJSON(clientConf.getJwksFed()); String clientAssertion = jwtHelper.createJWS(payload, jwkSet); diff --git a/starter-kit/src/main/java/it/spid/cie/oidc/model/FederationEntity.java b/starter-kit/src/main/java/it/spid/cie/oidc/model/FederationEntity.java index 9ce0854..eb71501 100644 --- a/starter-kit/src/main/java/it/spid/cie/oidc/model/FederationEntity.java +++ b/starter-kit/src/main/java/it/spid/cie/oidc/model/FederationEntity.java @@ -1,5 +1,9 @@ package it.spid.cie.oidc.model; +import com.nimbusds.jose.jwk.JWK; +import com.nimbusds.jose.jwk.JWKSet; +import com.nimbusds.jose.jwk.KeyUse; +import it.spid.cie.oidc.helper.JWTHelper; import org.json.JSONObject; import it.spid.cie.oidc.config.GlobalOptions; @@ -25,7 +29,8 @@ public class FederationEntity extends BaseModel { private int defaultExpireMinutes; private String defaultSignatureAlg = GlobalOptions.DEFAULT_SIGNING_ALG; private String authorityHints; - private String jwks; + private String jwksFed; + private String jwksCore; private String trustMarks; private String trustMarkIssuers; private String metadata; @@ -53,10 +58,27 @@ public String getDefaultSignatureAlg() { return defaultSignatureAlg; } - public String getJwks() { - return jwks; + public String getJwksFed() { + return jwksFed; + } + public String getJwksCore() { + return jwksCore; + } + public String getJwksCoreByUse(KeyUse use) { + String jwkCore=""; + try { + JWKSet keys = JWTHelper.getJWKSetFromJSON(jwksCore); + JWK jwk = keys.getKeys().stream() + .filter(key -> key.getKeyUse() == use) + .findFirst() + .orElse(null); + jwkCore = "["+jwk.toString()+"]"; + } + catch (Exception e) { + return null; + } + return jwkCore; } - public String getMetadata() { return metadata; } @@ -114,10 +136,14 @@ public void setEntityType(String entityType) { this.entityType = entityType; } - public void setJwks(String jwks) { - this.jwks = jwks; + public void setJwksFed(String jwksFed) { + this.jwksFed = jwksFed; } + public void setJwksCore(String jwksCore) { + this.jwksCore = jwksCore; + } + public FederationEntity setMetadata(String metadata) { this.metadata = metadata; diff --git a/starter-kit/src/test/java/it/spid/cie/oidc/config/TestRelyingPartyOptions.java b/starter-kit/src/test/java/it/spid/cie/oidc/config/TestRelyingPartyOptions.java index 6ee981e..d525bb8 100644 --- a/starter-kit/src/test/java/it/spid/cie/oidc/config/TestRelyingPartyOptions.java +++ b/starter-kit/src/test/java/it/spid/cie/oidc/config/TestRelyingPartyOptions.java @@ -17,7 +17,6 @@ import it.spid.cie.oidc.schemas.ClaimSection; import it.spid.cie.oidc.schemas.OIDCProfile; import it.spid.cie.oidc.schemas.SPIDClaimItem; -import it.spid.cie.oidc.schemas.Scope; import it.spid.cie.oidc.util.ArrayUtil; public class TestRelyingPartyOptions { @@ -84,15 +83,15 @@ public void testClass1() { // Jwk - String jwk = res.getJwk(); + String jwk = res.getJwkFed(); - res.setJWK(""); + res.setJWKFed(""); - assertEquals(jwk, res.getJwk()); + assertEquals(jwk, res.getJwkFed()); - res.setJWK("test"); + res.setJWKFed("test"); - assertEquals("test", res.getJwk()); + assertEquals("test", res.getJwkFed()); // Login diff --git a/starter-kit/src/test/java/it/spid/cie/oidc/handler/TestRelyingPartyHandler.java b/starter-kit/src/test/java/it/spid/cie/oidc/handler/TestRelyingPartyHandler.java index b8f7179..580c8f1 100644 --- a/starter-kit/src/test/java/it/spid/cie/oidc/handler/TestRelyingPartyHandler.java +++ b/starter-kit/src/test/java/it/spid/cie/oidc/handler/TestRelyingPartyHandler.java @@ -15,6 +15,7 @@ import java.util.List; import java.util.Map; +import com.nimbusds.jose.jwk.KeyUse; import org.json.JSONArray; import org.json.JSONObject; import org.junit.AfterClass; @@ -418,7 +419,8 @@ private RelyingPartyOptions getOptions() throws Exception { .setTrustAnchors(ArrayUtil.asSet(TRUST_ANCHOR)) .setApplicationName("JUnit RP") .setRedirectUris(ArrayUtil.asSet(RELYING_PARTY + "callback")) - .setJWK(getContent("rp-jwks.json")) + .setJWKFed(getContent("rp-jwks.json")) + .setJWKCore(getContent("rp-core-jwks.json")) .setTrustMarks(getContent("rp-trust-marks.json")); return options; @@ -642,8 +644,13 @@ private String mockedSPIDProviderToken() throws Exception { private String mockedSPIDProviderUserInfo() throws Exception { JSONObject providerJWKS = mockedSPIDProviderPrivateJWKS(); - String relyingPartyJWK = getContent("rp-jwks.json"); - + String relyingPartyJWK = getContent("rp-core-jwks.json"); + JWKSet keys = JWTHelper.getJWKSetFromJSON(relyingPartyJWK); + JWK jwk = keys.getKeys().stream() + .filter(key -> key.getKeyUse() == KeyUse.ENCRYPTION) + .findFirst() + .orElse(null); + String jwkCoreEnc = jwk.toString(); JSONObject payload = new JSONObject() .put( "sub", "e6b06083c2644bdc06f5a1cea22e6538b8fd59fc091837938c5969a8390be944") @@ -652,7 +659,7 @@ private String mockedSPIDProviderUserInfo() throws Exception { .put("email", "that@ema.il") .put("https://attributes.eid.gov.it/fiscal_number", "abcabc00a00a123a"); - return createJWE(payload, providerJWKS, relyingPartyJWK); + return createJWE(payload, providerJWKS, jwkCoreEnc); } private String mockedTrustAnchorEntityConfiguration() throws Exception { diff --git a/starter-kit/src/test/java/it/spid/cie/oidc/handler/TestRelyingPartyHandlerWellKnown.java b/starter-kit/src/test/java/it/spid/cie/oidc/handler/TestRelyingPartyHandlerWellKnown.java index 28f33ab..b433aa1 100644 --- a/starter-kit/src/test/java/it/spid/cie/oidc/handler/TestRelyingPartyHandlerWellKnown.java +++ b/starter-kit/src/test/java/it/spid/cie/oidc/handler/TestRelyingPartyHandlerWellKnown.java @@ -83,7 +83,9 @@ public void testWellKnown2b() { WellKnownData wellKnown = null; try { - options.setJWK(getContent("rp-jwks.json")); + options.setJWKFed(getContent("rp-jwks.json")); + + options.setJWKCore(getContent("rp-core-jwks.json")); RelyingPartyHandler handler = new RelyingPartyHandler( options, new MemoryStorage()); @@ -106,7 +108,8 @@ public void testWellKnown2c() { WellKnownData wellKnown = null; try { - options.setJWK(getContent("rp-jwks.json")); + options.setJWKFed(getContent("rp-jwks.json")); + options.setJWKCore(getContent("rp-core-jwks.json")); options.setTrustMarks(getContent("rp-trust-marks.json")); RelyingPartyHandler handler = new RelyingPartyHandler( @@ -131,7 +134,8 @@ public void testWellKnown2d() { WellKnownData wellKnown = null; try { - options.setJWK(getContent("rp-jwks.json")); + options.setJWKFed(getContent("rp-jwks.json")); + options.setJWKCore(getContent("rp-core-jwks.json")); options.setTrustMarks(getContent("rp-trust-marks.json")); RelyingPartyHandler handler = new RelyingPartyHandler( @@ -157,7 +161,8 @@ public void testWellKnown2e() { WellKnownData wellKnown = null; try { - options.setJWK(getContent("rp-jwks.json")); + options.setJWKFed(getContent("rp-jwks.json")); + options.setJWKCore(getContent("rp-core-jwks.json")); options.setTrustMarks(getContent("rp-trust-marks.json")); RelyingPartyHandler handler = new RelyingPartyHandler( @@ -183,14 +188,15 @@ public void testWellKnown2f() { WellKnownData wellKnown = null; try { - options.setJWK(getContent("rp-jwks.json")); + options.setJWKFed(getContent("rp-jwks.json")); + options.setJWKCore(getContent("rp-core-jwks.json")); options.setTrustMarks(getContent("rp-trust-marks.json")); RelyingPartyHandler handler = new RelyingPartyHandler( options, new MemoryStorage()); handler.getWellKnownData( - RELYING_PARTY + OIDCConstants.OIDC_FEDERATION_WELLKNOWN_URL, true); + RELYING_PARTY + OIDCConstants.OIDC_FEDERATION_WELLKNOWN_URL, true); wellKnown = handler.getWellKnownData( RELYING_PARTY + OIDCConstants.OIDC_FEDERATION_WELLKNOWN_URL, true); @@ -211,7 +217,8 @@ public void testWellKnown2g() { WellKnownData wellKnown = null; try { - options.setJWK(getContent("rp-jwks.json")); + options.setJWKFed(getContent("rp-jwks.json")); + options.setJWKCore(getContent("rp-core-jwks.json")); options.setTrustMarks(getContent("rp-trust-marks.json")); RelyingPartyHandler handler = new RelyingPartyHandler( diff --git a/starter-kit/src/test/java/it/spid/cie/oidc/helper/TestJWTHelper.java b/starter-kit/src/test/java/it/spid/cie/oidc/helper/TestJWTHelper.java index b8e1ffa..42aa386 100644 --- a/starter-kit/src/test/java/it/spid/cie/oidc/helper/TestJWTHelper.java +++ b/starter-kit/src/test/java/it/spid/cie/oidc/helper/TestJWTHelper.java @@ -633,7 +633,7 @@ private RelyingPartyOptions getOptions() throws Exception { .setTrustAnchors(ArrayUtil.asSet(TRUST_ANCHOR)) .setApplicationName("JUnit RP") .setRedirectUris(ArrayUtil.asSet(RELYING_PARTY + "callback")) - .setJWK(TestUtils.getContent("rp-jwks.json")) + .setJWKFed(TestUtils.getContent("rp-jwks.json")) .setTrustMarks(TestUtils.getContent("rp-trust-marks.json")); return options; diff --git a/starter-kit/src/test/java/it/spid/cie/oidc/helper/TestOAuth2Helper.java b/starter-kit/src/test/java/it/spid/cie/oidc/helper/TestOAuth2Helper.java index f5fcf18..bde5657 100644 --- a/starter-kit/src/test/java/it/spid/cie/oidc/helper/TestOAuth2Helper.java +++ b/starter-kit/src/test/java/it/spid/cie/oidc/helper/TestOAuth2Helper.java @@ -10,6 +10,7 @@ import java.util.HashMap; import java.util.Map; +import com.nimbusds.jose.jwk.KeyUse; import org.json.JSONObject; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -143,7 +144,7 @@ public void testClass2() { FederationEntity clientConf = new FederationEntity(); clientConf.setSubject(RELYING_PARTY); - clientConf.setJwks(mockedSPIDProviderPublicJWKS().toString()); + clientConf.setJwksFed(mockedSPIDProviderPublicJWKS().toString()); helper.performAccessTokenRequest( null, null, null, null, clientConf, SPID_PROVIDER + "test", null); @@ -160,12 +161,12 @@ public void testClass2() { catched = false; JSONObject accessToken = null; try { - JWKSet jwks = JWTHelper.getJWKSetFromJWK(options.getJwk()); + JWKSet jwks = RPTestUtils.getJwksCoreByUse(JWTHelper.getJWKSetFromJSON(options.getJwkCore()), KeyUse.SIGNATURE); FederationEntity clientConf = new FederationEntity(); clientConf.setSubject(RELYING_PARTY); - clientConf.setJwks(jwks.toString(false)); + clientConf.setJwksCore(jwks.toString(false)); accessToken = helper.performAccessTokenRequest( null, null, null, null, clientConf, SPID_PROVIDER + "test", null); @@ -189,12 +190,12 @@ public void testClass2() { WireMock.ok("invalid-json") )); - JWKSet jwks = JWTHelper.getJWKSetFromJWK(options.getJwk()); - + //JWKSet jwks = JWTHelper.getJWKSetFromJSON(options.getJwkFed()); + JWKSet jwks = RPTestUtils.getJwksCoreByUse(JWTHelper.getJWKSetFromJSON(options.getJwkCore()), KeyUse.SIGNATURE); FederationEntity clientConf = new FederationEntity(); clientConf.setSubject(RELYING_PARTY); - clientConf.setJwks(jwks.toString(false)); + clientConf.setJwksCore(jwks.toString(false)); accessToken = helper.performAccessTokenRequest( null, null, null, null, clientConf, SPID_PROVIDER + "test", null); @@ -277,7 +278,7 @@ public void testClass3() { FederationEntity clientConf = new FederationEntity(); clientConf.setSubject(RELYING_PARTY); - clientConf.setJwks(mockedSPIDProviderPublicJWKS().toString()); + clientConf.setJwksFed(mockedSPIDProviderPublicJWKS().toString()); helper.sendRevocationRequest(null, null, "test", clientConf); } @@ -293,12 +294,12 @@ public void testClass3() { catched = false; try { - JWKSet jwks = JWTHelper.getJWKSetFromJWK(options.getJwk()); + JWKSet jwks = JWTHelper.getJWKSetFromJWK(options.getJwkFed()); FederationEntity clientConf = new FederationEntity(); clientConf.setSubject(RELYING_PARTY); - clientConf.setJwks(jwks.toString(false)); + clientConf.setJwksFed(jwks.toString(false)); helper.sendRevocationRequest(null, null, "test", clientConf); } @@ -322,12 +323,12 @@ public void testClass3() { WireMock.forbidden() )); - JWKSet jwks = JWTHelper.getJWKSetFromJWK(options.getJwk()); + JWKSet jwks = JWTHelper.getJWKSetFromJWK(options.getJwkFed()); FederationEntity clientConf = new FederationEntity(); clientConf.setSubject(RELYING_PARTY); - clientConf.setJwks(jwks.toString(false)); + clientConf.setJwksFed(jwks.toString(false)); helper.sendRevocationRequest(null, null, SPID_PROVIDER + "test", clientConf); } @@ -351,12 +352,12 @@ public void testClass3() { WireMock.ok() )); - JWKSet jwks = JWTHelper.getJWKSetFromJWK(options.getJwk()); + JWKSet jwks = JWTHelper.getJWKSetFromJWK(options.getJwkFed()); FederationEntity clientConf = new FederationEntity(); clientConf.setSubject(RELYING_PARTY); - clientConf.setJwks(jwks.toString(false)); + clientConf.setJwksFed(jwks.toString(false)); helper.sendRevocationRequest(null, null, SPID_PROVIDER + "test", clientConf); } @@ -429,7 +430,8 @@ private RelyingPartyOptions getOptions() throws Exception { .setTrustAnchors(ArrayUtil.asSet(TRUST_ANCHOR)) .setApplicationName("JUnit RP") .setRedirectUris(ArrayUtil.asSet(RELYING_PARTY + "callback")) - .setJWK(TestUtils.getContent("rp-jwks.json")) + .setJWKFed(TestUtils.getContent("rp-jwks.json")) + .setJWKCore(TestUtils.getContent("rp-core-jwks.json")) .setTrustMarks(TestUtils.getContent("rp-trust-marks.json")); return options; diff --git a/starter-kit/src/test/java/it/spid/cie/oidc/helper/TestOIDCHelper.java b/starter-kit/src/test/java/it/spid/cie/oidc/helper/TestOIDCHelper.java index 1895d0b..acfc844 100644 --- a/starter-kit/src/test/java/it/spid/cie/oidc/helper/TestOIDCHelper.java +++ b/starter-kit/src/test/java/it/spid/cie/oidc/helper/TestOIDCHelper.java @@ -5,6 +5,8 @@ import java.io.IOException; +import com.nimbusds.jose.jwk.JWK; +import com.nimbusds.jose.jwk.KeyUse; import org.json.JSONObject; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -111,7 +113,13 @@ public void testOIDCHelperClass() { private String mockedSPIDProviderUserInfo() throws Exception { JSONObject providerJWKS = RPTestUtils.mockedSPIDProviderPrivateJWKS(); - String relyingPartyJWK = RPTestUtils.getContent("rp-jwks.json"); + String relyingPartyJWK = RPTestUtils.getContent("rp-core-jwks.json"); + JWKSet keys = JWTHelper.getJWKSetFromJSON(relyingPartyJWK); + JWK jwk = keys.getKeys().stream() + .filter(key -> key.getKeyUse() == KeyUse.ENCRYPTION) + .findFirst() + .orElse(null); + String jwkCoreEnc = jwk.toString(); JSONObject payload = new JSONObject() .put( @@ -121,7 +129,7 @@ private String mockedSPIDProviderUserInfo() throws Exception { .put("https://attributes.spid.gov.it/email", "that@ema.il") .put("https://attributes.spid.gov.it/fiscalNumber", "abcabc00a00a123a"); - return RPTestUtils.createJWE(payload, providerJWKS, relyingPartyJWK); + return RPTestUtils.createJWE(payload, providerJWKS, jwkCoreEnc); } diff --git a/starter-kit/src/test/java/it/spid/cie/oidc/model/TestFederationEntity.java b/starter-kit/src/test/java/it/spid/cie/oidc/model/TestFederationEntity.java index f0a441b..2f3bc1c 100644 --- a/starter-kit/src/test/java/it/spid/cie/oidc/model/TestFederationEntity.java +++ b/starter-kit/src/test/java/it/spid/cie/oidc/model/TestFederationEntity.java @@ -26,7 +26,8 @@ public void testFederationEntityClass() { model.getDefaultExpireMinutes(); model.getDefaultSignatureAlg(); model.getEntityType(); - model.getJwks(); + model.getJwksFed(); + model.getJwksCore(); model.getMetadata(); model.getSubject(); model.getTrustMarks(); @@ -45,7 +46,8 @@ public void testFederationEntityClass() { model.setDefaultExpireMinutes(30); model.setDefaultSignatureAlg("testAlg"); model.setEntityType("testEntityType"); - model.setJwks("testJwks"); + model.setJwksFed("testJwksFed"); + model.setJwksCore("testJwksCore"); model.setSubject("testSubject"); model.setTrustMarks("testTrustMarks"); model.settrustMarkIssuers("testIssuer"); diff --git a/starter-kit/src/test/java/it/spid/cie/oidc/test/util/RPTestUtils.java b/starter-kit/src/test/java/it/spid/cie/oidc/test/util/RPTestUtils.java index 6808685..fb1eb27 100644 --- a/starter-kit/src/test/java/it/spid/cie/oidc/test/util/RPTestUtils.java +++ b/starter-kit/src/test/java/it/spid/cie/oidc/test/util/RPTestUtils.java @@ -111,7 +111,7 @@ public static RelyingPartyOptions getOptions() throws Exception { .setTrustAnchors(ArrayUtil.asSet(TRUST_ANCHOR)) .setApplicationName("JUnit RP") .setRedirectUris(ArrayUtil.asSet(RELYING_PARTY + "callback")) - .setJWK(getContent("rp-jwks.json")) + .setJWKFed(getContent("rp-jwks.json")) .setTrustMarks(getContent("rp-trust-marks.json")); return options; @@ -441,4 +441,18 @@ public static JSONObject mockedTrustMark( return trustMark; } + public static JWKSet getJwksCoreByUse(JWKSet keys, KeyUse use) { + + try { + JWK jwk = keys.getKeys().stream() + .filter(key -> key.getKeyUse() == use) + .findFirst() + .orElse(null); + JWKSet jwkCore= new JWKSet(jwk); + return jwkCore; + } + catch (Exception e) { + return null; + } + } } diff --git a/starter-kit/src/test/resources/rp-core-jwks.json b/starter-kit/src/test/resources/rp-core-jwks.json new file mode 100644 index 0000000..47b7b86 --- /dev/null +++ b/starter-kit/src/test/resources/rp-core-jwks.json @@ -0,0 +1 @@ +{"keys":[{"p":"zJPEJQAwi7XPlrMTdyxOcqiLUjN6HWsJatXEeYXDz7cl1IpzAo294EfVGPr4yLBWYGEcYFVxD5xBHGDDqfYy_U2lAdWPdEdZ9Z7UlWKyIufb5ir-UFz6zU2_5682QkQJsucBXzAlDUQtEKpvKp_fo42sMSbi0L4uJfKw7lH8vOM","kty":"RSA","q":"sJNDnLBzgne5x65H_sYOUrDYmtVQXZZqJGP7CSxpUpLz_FjjhpJ84Kmrr3MNvbi83iJPVoTu9uWAYLKHGtVHsithuE14_We-utB6ozx4P02JIOjKf8MANuiGH9A7a9i34m79hGGodbfse95q-uyIZrDw3vEKtdsC3lgxemWbtp8","d":"CFqc_jyPd9lSOWQ5CnyeUngyzHXKtSiclASCpBToKHa1Sk-3z9YGiLjS3f8J-8vKOblUIPC5d7z8bBrLv1u693AEESL4A9_SlliHe_I_C1OEKmWxN7iWZwfsZh4BkTzfPLKEgqZCVsBOqv_29QDjWuZdc5reQO7pJzlCEJTae84Xu_NyyO4cuT7F3QbK2BwwK3CEfZm3Jjp_KznmQWhyMFPrOYsZM-TqcjcI3gmcxV_9R4PiMgFz3ul3tAE9MPzjNi1r6dshH5qa7ubMzj-Na3I9vAmLEjuUiaAxVWtyyUAXxgEoBzkXZxeOq9__QC27-YLD28easlF_YNiBxZkvYQ","e":"AQAB","use":"sig","kid":"5H34RM-MNDzfe6_YTZqaoXeCW3uDzBMIoR0m7MNc6j0","qi":"cqE71YWpqimQxFYevF_ROfrd3lb4Ln4C9g7KftREaVF0op_Snzzz4eUMIK9boR6EcAYBv5iB7OZxv5Nc89E9LwuCI86kBKYWFLpmdyyQBN_3DHiuBG9WUKoii322cr-TEqgCvL3ZXu8iBBRBMXxuEiBryqfN8kO4Nq4vMRktwZA","dp":"ZFbVjZBaPywddTy__2Or1nD0ZIz7CBLHu669fx0svWSHGYgOgOIkjyysSGRQQZ67vunikR1XJuDszo5naaVnvPWoSQ4GHnIgnWgZvGt8E8LFCE9uDNyN5sSLq4c0hav5VdYXxihHBAq8T8BIZg-kEQQbwL_h36Bn4hT20u1DmSE","alg":"RS256","dq":"HG7KL1v2babLwoycyTipK8WQS3ZX54oF83AqBzMgjoxdP2As2wmRlDeeDrVvHAK4XuiVb_Ad7qHMB0YYHUkEr3ru1FedSOjAvKI_bTOahU796s-xc9s5mJ3eoxbLyrTt_0cyCXQURUhlixioj1kxKaAKWUvlFp16m8UFypi79y8","n":"jRtFuvTDlwNNxU7O04Hmmo7c8UJzymE8eoeQqnX8qNUY4CHr6bAwempU51FJBz4nbHDQpQE27OVa3A495hoEboOpgtbnpKyAJKBRlPayP4JXe6LPy90KAPH5iWVS0fmygwTUh9YaMcqEtG3rNuJ3A0fPCpPqnA1VYt0_dinmtRddFuCdB8r12uWuVYY081qtknEd_7MKkrbzXS77Qrep_n7d6p35fQEcM5SEJVkNeCssAaZqtJyWGh_hMn8ac3fLpnY8_gV5QQZh4wUKgV3TXPW7e7hkKvnhMMeLTI9AofXoFJr_keBsTMo55BRqLbmZxBKYtOxenBt8yyQIhrOy_Q"},{"p":"52kXpQHMoFWWbuxmAZh3aAPZD1qj7D84-Ryw5f1vH2IY65uzywAIinAjgmDRi9CzY1fCmbdXJPneplHxv-O5nu9b8DKf2Uia7gaFNv_hK6lfDwUlKrV0s7T7LMX8TpTLIVHyriCvqPw3gmIA20nqRE3_qHJr5YrnVVhvUZkb1S8","kty":"RSA","q":"lIx1v_9w2tk_B5bxMp9gUNlfh6cUwu_uKODGX8nVEMrug2yYPobGVB5lrS3I34vzqVIiq-HjACxQA68PCmgBNbbT7b8ukwHZY9290DP03DIG51-_hzyNhFAOvXBy4EElkUahSkSThuMqdtjKcoe6u3gW3Oar3O5y3L3ZW6ZQad0","d":"JkN8A436sF_DPPdHUdrjLZwvENNLsSMTKZ8M9p_Na6a73AnuR79BZxWJ5xXf8xnAThvHPm-6fHPTfU3e3O_FqpZQiqWsagWqvICXVGtMQ3FIJ8JUULAFSEPJEQmkyUK2oZNm-LKNjcFqVz-MNtygWMlGthmQnZfCHXdR5n9eD1WZX2-LxWrDHa6JAWpkLPnOGHm5HFh-D3dkGc6Xyx0C1XiYygU2nrpUrDZix-MkSc4pIqOlu8cq9cUxzQ7-SZQcJAGYDfEigOTuOx3eRCsdrUEfBuJb3CppZjI-EnGxvYWnADDg4arrhawoRqaA5Bd4B698Nh6xSpiNNdsUumbkGQ","e":"AQAB","use":"enc","kid":"d9xO7IfRMFyVCAsQz_V85u-PQX4wicsp3AETxAxLWKM","qi":"YpScYnVA_x1NLUhNUbFX8aEK44F-vDLG1YdYVkQoPxR8l0Fzir2eP3Rue2jfmc1YzJT0bQqnUnrAWtpUrUFW0RN2h3kfHdPg83XM0mrYpHMmO8e_MeFR5mbIZt7X4SQ9ALMex0NRmHUkWCGznXL0AiFnT71O5bwv8NeGKeUFQ8c","dp":"RphX3z3KSAt0Jgi2Ibx6iN_LoxR6t4KeBdkL2k3TTZamlZHdaotrD5igLJEOvAGCCEdolW5KBny3wLN09Z4qLWNF_-Phwe6VXRHeJ-Ytsh0sY6-lI_9RR9VpXsJTc0GPKm4Og7JzBDFVWdA-BKfq8MV-vcuSQOd8JRwicZks1X8","alg":"RSA-OAEP-256","dq":"BUm-w1f3j4LeUInaCkBMMHSchvq2rX3XD5N43F4V_KQMu5b5EHjBxKrUWcbgeLzFrshivZWr_AyXyJnJwkgTivL4NmVw5gDR2VFCeY_v7orFXiU1bz4Dl6s16x5-qGcJTFOkWD16tvmNQG_VPSCB0DylK7X2dkXyxtLnUvDnue0","n":"hke5lOlmCOOa5ge1OUoNTcH3UqbH1_SLSNWb0PbNbE9yIY4B3CIRHMlN4ng1F2VPFJrBnfj3dljM-uDJ7q58XYtU4WSCVUQSSfzKPJlEQ1sOzi1uDKS-jCO23VB6bSM2_MdvFCF6kaYaaTjsMoMtIgg-1GXqk4hL2bEPSDfh0wLL0s0O4Dz7Nafdg_oGIuV1bH8O0SlifIcnDRbJ_VenLt8wqzDx6BghnGHGUr0TduVoN76lud1rY5HPMpiuctu9eGJlZvyAlE5kH8i3JbVLIMlIMNlFzw57TsUhiNS1SdIbscIc6-3Co-0OT2iAwL9Oh4DolvhcIgByFRThsCdQkw"}]} \ No newline at end of file