From 468fe42531990cbc5d6a97497839a8fdfcbc6619 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Fri, 27 Oct 2023 21:38:42 +0200 Subject: [PATCH 1/9] feat: added federation_entity metadata parameters --- .../relying/party/RelyingPartyWrapper.java | 6 ++ .../boot/relying/party/config/OidcConfig.java | 36 ++++++++++ .../src/main/resources/application.yml | 8 +++ .../spid/cie/oidc/config/OIDCConstants.java | 2 +- .../cie/oidc/config/RelyingPartyOptions.java | 68 ++++++++++++++++++- .../cie/oidc/handler/RelyingPartyHandler.java | 13 ++++ .../oidc/config/TestRelyingPartyOptions.java | 40 ++++++++++- 7 files changed, 170 insertions(+), 3 deletions(-) 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 5a7bb30..c7a94a4 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 @@ -104,6 +104,12 @@ private void postConstruct() throws OIDCException { .setUserinfoEncryptedResponseAlg(oidcConfig.getRelyingParty().getUserinfoEncryptedResponseAlg()) .setUserinfoEncryptedResponseEnc(oidcConfig.getRelyingParty().getUserinfoEncryptedResponseEnc()) .setTokenEndpointAuthMethod(oidcConfig.getRelyingParty().getTokenEndpointAuthMethod()) + .setFederationResolveEndpoint(oidcConfig.getRelyingParty().getFederationResolveEndpoint()) + .setOrganizationName(oidcConfig.getRelyingParty().getOrganizationName()) + .setHomepageUri(oidcConfig.getRelyingParty().getHomepageUri()) + .setLogoUri(oidcConfig.getRelyingParty().getLogoUri()) + .setPolicyUri(oidcConfig.getRelyingParty().getPolicyUri()) + .setFederationContacts(oidcConfig.getRelyingParty().getFederationContacts()) .setJWK(jwk) .setTrustMarks(trustMarks); 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 0592005..fa4a864 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 @@ -191,6 +191,15 @@ public String getUserinfoEncryptedResponseAlg() { public String getTokenEndpointAuthMethod() { return tokenEndpointAuthMethod; } + public String getFederationResolveEndpoint() { return federationResolveEndpoint; } + public String getOrganizationName() { return organizationName; } + public String getHomepageUri() { return homepageUri; } + public String getPolicyUri() { return policyUri; } + public String getLogoUri() { return logoUri; } + public Set getFederationContacts() { + return Collections.unmodifiableSet(federationContacts); + } + public Set getRedirectUris() { return Collections.unmodifiableSet(redirectUris); } @@ -238,6 +247,26 @@ public void setUserinfoEncryptedResponseEnc(String userinfoEncryptedResponseEnc) public void setTokenEndpointAuthMethod(String tokenEndpointAuthMethod) { this.tokenEndpointAuthMethod = tokenEndpointAuthMethod; } + + public void setFederationResolveEndpoint(String federationResolveEndpoint) { + this.federationResolveEndpoint = federationResolveEndpoint; + } + public void setOrganizationName(String organizationName) { + this.organizationName = organizationName; + } + public void setHomepageUri(String homepageUri) { + this.homepageUri = homepageUri; + } + public void setPolicyUri(String policyUri) { + this.policyUri = policyUri; + } + public void setLogoUri(String logoUri) { + this.logoUri = logoUri; + } + public void setFederationContacts(Set federationContacts) { + this.federationContacts = federationContacts; + } + // public void setJwk(String jwk) { // this.jwk = jwk; // } @@ -300,6 +329,13 @@ public JSONObject toJSON() { private String userinfoEncryptedResponseEnc; private String tokenEndpointAuthMethod; + private String federationResolveEndpoint; + private String organizationName; + private String homepageUri; + private String policyUri; + private String logoUri; + private Set federationContacts = new HashSet<>(); + } } 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 520ba9c..4e88e0b 100644 --- a/examples/relying-party-spring-boot/src/main/resources/application.yml +++ b/examples/relying-party-spring-boot/src/main/resources/application.yml @@ -66,6 +66,14 @@ oidc: userinfo-encrypted-response-alg: "RSA-OAEP" userinfo-encrypted-response-enc: "A128CBC-HS256" + federation-resolve-endpoint: "http://${oidc.hosts.relying-party}:8080/resolve/" + organization-name: "PA OIDC Relying Party" + homepage-uri: "http://${oidc.hosts.relying-party}:8080/oidc/rp/landing" + policy-uri: "http://${oidc.hosts.relying-party}:8080/oidc/rp/policy" + logo-uri: "http://${oidc.hosts.relying-party}:8080/static/logo.svg" + federation-contacts: + - "federation-dev@example.com" + client-id: "http://${oidc.hosts.relying-party}:8080/oidc/rp/" redirect-uris: - "http://${oidc.hosts.relying-party}:8080/oidc/rp/callback" diff --git a/starter-kit/src/main/java/it/spid/cie/oidc/config/OIDCConstants.java b/starter-kit/src/main/java/it/spid/cie/oidc/config/OIDCConstants.java index 852d2f9..29e1c5c 100644 --- a/starter-kit/src/main/java/it/spid/cie/oidc/config/OIDCConstants.java +++ b/starter-kit/src/main/java/it/spid/cie/oidc/config/OIDCConstants.java @@ -8,7 +8,7 @@ public class OIDCConstants { public static final String OPENID_PROVIDER = "openid_provider"; public static final String OPENID_RELYING_PARTY = "openid_relying_party"; - + public static final String FEDERATION_ENTITY = "federation_entity"; public static final String SCOPE_OPENID = "openid"; } 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 1b837ff..c7db36d 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 @@ -65,8 +65,15 @@ public class RelyingPartyOptions extends GlobalOptions { private String userinfoSignedResponseAlg; private String userinfoEncryptedResponseAlg; private String userinfoEncryptedResponseEnc; - private String tokenEndpointAuthMethod; + + private String federationResolveEndpoint; + private String organizationName; + private String homepageUri; + private String policyUri; + private String logoUri; + private Set federationContacts = new HashSet<>(); + private Map acrMap = new HashMap<>(); private Map> scopeMap = new HashMap<>(); private Map requestedClaimsMap = new HashMap<>(); @@ -197,6 +204,20 @@ public String getTokenEndpointAuthMethod() { return tokenEndpointAuthMethod; } + public String getFederationResolveEndpoint() { return federationResolveEndpoint; } + + public String getOrganizationName() { return organizationName; } + + public String getHomepageUri() { return homepageUri; } + + public String getPolicyUri() { return policyUri; } + + public String getLogoUri() { return logoUri; } + + public Set getFederationContacts() { + return Collections.unmodifiableSet(federationContacts); + } + public String getUserKeyClaim() { return userKeyClaim; } @@ -296,6 +317,51 @@ public RelyingPartyOptions setTokenEndpointAuthMethod(String tokenEndpointAuthMe return this; } + + public RelyingPartyOptions setFederationResolveEndpoint(String federationResolveEndpoint) { + if (!Validator.isNullOrEmpty(federationResolveEndpoint)) { + this.federationResolveEndpoint = federationResolveEndpoint; + } + + return this; + } + public RelyingPartyOptions setOrganizationName(String organizationName) { + if (!Validator.isNullOrEmpty(organizationName)) { + this.organizationName = organizationName; + } + + return this; + } + public RelyingPartyOptions setHomepageUri(String homepageUri) { + if (!Validator.isNullOrEmpty(homepageUri)) { + this.homepageUri = homepageUri; + } + + return this; + } + public RelyingPartyOptions setPolicyUri(String policyUri) { + if (!Validator.isNullOrEmpty(policyUri)) { + this.policyUri = policyUri; + } + + return this; + } + public RelyingPartyOptions setLogoUri(String logoUri) { + if (!Validator.isNullOrEmpty(logoUri)) { + this.logoUri = logoUri; + } + + return this; + } + public RelyingPartyOptions setFederationContacts(Collection federationContacts) { + if (federationContacts != null && !federationContacts.isEmpty()) { + this.federationContacts.clear(); + this.federationContacts.addAll(federationContacts); + } + + return this; + } + public RelyingPartyOptions setContacts(Collection contacts) { if (contacts != null && !contacts.isEmpty()) { this.contacts.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 e9b165a..ad5006e 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 @@ -878,10 +878,23 @@ private WellKnownData prepareOnboardingData(String sub, boolean jsonMode) rpJson.put("userinfo_encrypted_response_enc", options.getUserinfoEncryptedResponseEnc()); rpJson.put("token_endpoint_auth_method", options.getTokenEndpointAuthMethod()); + + JSONObject fedJson = new JSONObject(); + + fedJson.put("federation_resolve_endpoint", options.getFederationResolveEndpoint()); + fedJson.put("organization_name", options.getOrganizationName()); + fedJson.put("homepage_uri", options.getHomepageUri()); + fedJson.put("policy_uri", options.getPolicyUri()); + fedJson.put("logo_uri", options.getLogoUri()); + fedJson.put("contacts",options.getFederationContacts()); + + JSONObject metadataJson = new JSONObject(); metadataJson.put(OIDCConstants.OPENID_RELYING_PARTY, rpJson); + metadataJson.put(OIDCConstants.FEDERATION_ENTITY, fedJson); + long iat = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC); JSONObject json = new JSONObject(); 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 3923a69..6ee981e 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 @@ -319,7 +319,6 @@ public void testClass1() { assertEquals("test", res.getTokenEndpointAuthMethod()); - res.setUserinfoEncryptedResponseEnc("test"); assertEquals("test", res.getTokenEndpointAuthMethod()); @@ -335,6 +334,45 @@ public void testClass1() { res.setIdTokenSignedResponseAlg("test"); assertEquals("test", res.getIdTokenSignedResponseAlg()); + + //federation_entity metadata + res.setFederationResolveEndpoint("test"); + + assertEquals("test", res.getFederationResolveEndpoint()); + + res.setOrganizationName("test"); + + assertEquals("test", res.getOrganizationName()); + + res.setPolicyUri("test"); + + assertEquals("test", res.getPolicyUri()); + + res.setHomepageUri("test"); + + assertEquals("test", res.getHomepageUri()); + + res.setLogoUri("test"); + + assertEquals("test", res.getLogoUri()); + + // Federation Contacts + + res.setFederationContacts(null); + + assertTrue(res.getFederationContacts().size() == 0); + + Set federationContacts = new HashSet<>(); + + res.setFederationContacts(federationContacts); + + assertTrue(res.getFederationContacts().size() == 0); + + federationContacts.add("test@test.com"); + + res.setFederationContacts(federationContacts); + + assertTrue(res.getFederationContacts().size() == 1); } @Test From 44eeadc36dd7ad63ae871b295c46ca07f0062544 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Sat, 28 Oct 2023 08:51:48 +0200 Subject: [PATCH 2/9] feat: added policy page --- .../party/controller/PolicyController.java | 29 ++ .../src/main/resources/application.yml | 2 +- .../src/main/resources/templates/policy.html | 422 ++++++++++++++++++ 3 files changed, 452 insertions(+), 1 deletion(-) create mode 100644 examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/controller/PolicyController.java create mode 100644 examples/relying-party-spring-boot/src/main/resources/templates/policy.html diff --git a/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/controller/PolicyController.java b/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/controller/PolicyController.java new file mode 100644 index 0000000..fd84afa --- /dev/null +++ b/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/controller/PolicyController.java @@ -0,0 +1,29 @@ +package it.spid.cie.oidc.spring.boot.relying.party.controller; + +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.ModelAndView; + +import it.spid.cie.oidc.schemas.OIDCProfile; +import it.spid.cie.oidc.schemas.ProviderButtonInfo; +import it.spid.cie.oidc.spring.boot.relying.party.RelyingPartyWrapper; + +@RestController +@RequestMapping("/oidc/rp") +public class PolicyController { + @GetMapping("/policy") + public ModelAndView home(HttpServletRequest request) + throws Exception { + + ModelAndView mav = new ModelAndView("policy"); + + return mav; + } + +} \ No newline at end of file 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 4e88e0b..023e8ea 100644 --- a/examples/relying-party-spring-boot/src/main/resources/application.yml +++ b/examples/relying-party-spring-boot/src/main/resources/application.yml @@ -70,7 +70,7 @@ oidc: organization-name: "PA OIDC Relying Party" homepage-uri: "http://${oidc.hosts.relying-party}:8080/oidc/rp/landing" policy-uri: "http://${oidc.hosts.relying-party}:8080/oidc/rp/policy" - logo-uri: "http://${oidc.hosts.relying-party}:8080/static/logo.svg" + logo-uri: "http://${oidc.hosts.relying-party}:8080/static/images/logo-it.svg" federation-contacts: - "federation-dev@example.com" diff --git a/examples/relying-party-spring-boot/src/main/resources/templates/policy.html b/examples/relying-party-spring-boot/src/main/resources/templates/policy.html new file mode 100644 index 0000000..7b4a4af --- /dev/null +++ b/examples/relying-party-spring-boot/src/main/resources/templates/policy.html @@ -0,0 +1,422 @@ + + + + + + + + + OIDC Relying Party JAVA - Privacy Policy + + + + + + + + + + + + + + + + +
+ +
+
+
+
+
+ OIDC Relying Party + JAVA + +
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ + + +
+
+ Seguici su + +
+
+ Cerca + + + + + +
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+
+
+

Privacy Policy - Information on the processing of + personal data

+

+ pursuant to articles 13 and 14 of Regulation (EU) 2016/679 of the + European Parliament and of the Council .

+
+
+ This page describes how the personal data of users who consult this website + are processed. The information provided does not concern other sites, pages + or online services accessible via hypertext links referring to resources + external to the domain of this website. +
    +
  • Owner of the processing of personal data: +
      +
    • The Controller - Tal dei tali street
    • +
    • DPO: dpo@controller.example
    • +
    +
  • Italian Data Protection Authority: + +
  • +
+
+

Categories and sources of personal data, purposes and + legal basis of processing + Browsing data

+ + The computer systems and software procedures used to operate the site + acquire, during their normal operation, some personal data whose + transmission is implicit in the use of internet communication protocols + (e.g.: personal data acquired through access logs to the site). These data + are processed for the technical management of the website and for the + collection of analytical data on the related traffic. +
+

Cookies and other tracking systems

+ +

Cookies are small fragments of text that the website sends to the user's + browser, where they are stored before being re-transmitted to the site + on the next visit.

+

This site uses technical session cookies and analytical cookies aimed at + collecting information, in aggregate form, on the number of users and + how they visit the site.

+

In order to respect the privacy of our users, the IP addresses of those + who browse the website are made anonymous. The site uses the external + service Hotjar , whose privacy policy is available .

+

The cookies used by the site do not allow identification or profiling of + the user, who can always choose to enable or disable cookies by changing + the settings of their browser according to the instructions made + available by the relevant suppliers at the links indicated below: +

    +
  • Chrome
  • +
  • Firefox
  • +
  • Safari for mobile devices
  • +
  • Safari
  • +
  • Internet Explorer
  • +
  • Edge
  • +
  • Opera
  • +
+

+
+
+

Data provided by the user

+ + Access to the platform with SPID technology involves the acquisition of all + data explicitly authorized by the user during the authentication procedure: + name, surname, tax code, SPID code. + + In addition to these data, registration also requires the indication of a + contact email address, entered directly by the user. + + Such data, the failure to indicate which does not allow registration with + our platform, are processed for the sole purpose of supporting the member's + authentication and authorization functions. + + Sending messages to the Controller's contact addresses and institutional + profiles on social media involves the acquisition of all personal data + voluntarily included by the sender in the text of their communication, + processed for the sole purpose of providing the requested feedback. + + The legal basis of the processing is identified in the execution of tasks of + public interest or connected to the exercise of public institutional powers + assigned to the Controller. +
+

Categories of recipients of personal data

+ + the Controller will process personal data independently through its staff. + The suppliers of technical and telematic services, designated as data + controllers, are also recipients of personal data. + + the Controller does not transfer any personal data to third countries or + international organisations. +
+

Personal data retention period

+ + Browsing data is not kept for more than 30 days from the time of collection, + without prejudice to any need for the investigation of crimes by the + judicial authority. + + The personal data provided by users are retained for 30 days following the + cancellation of the user. +
+

User rights

+ + Interested parties have the right to obtain from the Controller access to + their personal data, the rectification or cancellation of the same, the + limitation of the related processing, the right to object and the right to + data portability, where the conditions are met. Requests should be addressed + to the Controller by contacting the DPO at the address indicated above. + + Without prejudice to any other administrative or jurisdictional appeal, + interested parties have the right to lodge a complaint with the Guarantor + for the protection of personal data if they believe that the processing of + their data violates the Regulation. + + the Controller guarantees that no form of exclusively automated + decision-making process is envisaged which entails legal effects on the + interested party. + + +
+
+
+
+
+
+
+
+
+ + +
+ + + + + \ No newline at end of file From dd516ab0efce4e6e6432e8cd200316d6cf0363ed Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Sat, 28 Oct 2023 22:04:55 +0200 Subject: [PATCH 3/9] feat: first add federation resolve endpoint in example --- .../controller/EntityStatementController.java | 75 +++++++++++++++++++ .../model/TrustChainRepository.java | 2 +- .../src/main/resources/application.yml | 2 +- 3 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/controller/EntityStatementController.java 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 new file mode 100644 index 0000000..48df73d --- /dev/null +++ b/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/controller/EntityStatementController.java @@ -0,0 +1,75 @@ +package it.spid.cie.oidc.spring.boot.relying.party.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.json.JSONObject; +import org.json.JSONArray; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import it.spid.cie.oidc.config.RelyingPartyOptions; +import it.spid.cie.oidc.exception.OIDCException; +import it.spid.cie.oidc.model.FederationEntity; +import it.spid.cie.oidc.spring.boot.relying.party.RelyingPartyWrapper; +import it.spid.cie.oidc.spring.boot.relying.party.config.OidcConfig; +import it.spid.cie.oidc.spring.boot.relying.party.persistence.H2PersistenceImpl; +import it.spid.cie.oidc.model.TrustChain; +import it.spid.cie.oidc.helper.JWTHelper; + +@RestController +@RequestMapping("/oidc/rp") +public class EntityStatementController { + private static final Logger logger = LoggerFactory.getLogger(RelyingPartyWrapper.class); + @Autowired + private OidcConfig oidcConfig; + @Autowired + private H2PersistenceImpl persistenceImpl; + + @GetMapping("/resolve") + public ResponseEntity resolveEntityStatement( + @RequestParam String sub, + @RequestParam String anchor, + @RequestParam(defaultValue = "jose") String format + ) throws OIDCException { + + if (sub == null || anchor == null) { + return new ResponseEntity<>("sub and anchor parameters are REQUIRED.", HttpStatus.NOT_FOUND); + } + String iss = oidcConfig.getRelyingParty().getClientId(); + + FederationEntity entityConfiguration = persistenceImpl.fetchFederationEntity(iss, true); + + TrustChain entity = persistenceImpl.fetchTrustChain(sub, anchor); + + if (entity == null) { + return new ResponseEntity<>("entity not found.", HttpStatus.NOT_FOUND); + } + JSONObject metadata = new JSONObject(entity.getMetadata()); + JSONArray trust_chain = new JSONArray(entity.getChain()); + + JSONObject response = new JSONObject(); + response.put("iss", iss); + response.put("sub", sub); + response.put("iat", entity.getIssuedAt()); + response.put("exp", entity.getExpiresOn()); + response.put("trust_marks", entity.getTrustMarks()); + response.put("metadata", metadata); + response.put("trust_chain",trust_chain); + + if ("json".equals(format)) { + logger.info("resolve endpoint for {}, {}", sub, anchor); + return ResponseEntity.ok() + .contentType(MediaType.APPLICATION_JSON) + .body(response.toString()); + } else { + JWTHelper jws = new JWTHelper(new RelyingPartyOptions()); + return new ResponseEntity<>(jws.createJWS(response, JWTHelper.getJWKSetFromJSON(entityConfiguration.getJwks())), 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/persistence/model/TrustChainRepository.java b/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/persistence/model/TrustChainRepository.java index fa03684..4b8a255 100644 --- a/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/persistence/model/TrustChainRepository.java +++ b/examples/relying-party-spring-boot/src/main/java/it/spid/cie/oidc/spring/boot/relying/party/persistence/model/TrustChainRepository.java @@ -31,7 +31,7 @@ public interface TrustChainRepository extends CrudRepository Date: Mon, 30 Oct 2023 19:13:21 +0100 Subject: [PATCH 4/9] fix: chain returned as JWT's --- .../party/controller/EntityStatementController.java | 3 ++- .../java/it/spid/cie/oidc/config/RelyingPartyOptions.java | 6 +++--- .../it/spid/cie/oidc/handler/RelyingPartyHandler.java | 4 ++-- .../java/it/spid/cie/oidc/model/TrustChainBuilder.java | 8 ++++++++ .../it/spid/cie/oidc/model/TestTrustChainBuilder.java | 1 + 5 files changed, 16 insertions(+), 6 deletions(-) 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 48df73d..00e1e78 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 @@ -62,8 +62,9 @@ public ResponseEntity resolveEntityStatement( response.put("metadata", metadata); response.put("trust_chain",trust_chain); + logger.info("resolve endpoint for {}, {}", sub, anchor); + if ("json".equals(format)) { - logger.info("resolve endpoint for {}, {}", sub, anchor); return ResponseEntity.ok() .contentType(MediaType.APPLICATION_JSON) .body(response.toString()); 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 c7db36d..87b09d5 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 @@ -555,9 +555,9 @@ public void validate() throws OIDCException { acrMap.put(OIDCProfile.CIE.value(), AcrValue.L2.value()); } - if (Validator.isNullOrEmpty(logoutRedirectURL)) { - throw new ConfigException("no-logout-redirect-url"); - } +// if (Validator.isNullOrEmpty(logoutRedirectURL)) { +// throw new ConfigException("no-logout-redirect-url"); +// } validateRequestedClaims(); validateUserKeyClaim(); 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 ad5006e..fb0ae3b 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 @@ -595,7 +595,7 @@ else if (Validator.isNullOrEmpty(tcb.getFinalMetadata())) { .setSubject(subject) .setType(metadataType) .setExpiresOn(tcb.getExpiresOn()) - .setChain(tcb.getChainAsString()) + .setChain(tcb.getChain()) .setPartiesInvolved(tcb.getPartiesInvolvedAsString()) .setProcessingStart(LocalDateTime.now()) .setActive(true) @@ -607,7 +607,7 @@ else if (Validator.isNullOrEmpty(tcb.getFinalMetadata())) { else { trustChain = trustChain .setExpiresOn(tcb.getExpiresOn()) - .setChain(tcb.getChainAsString()) + .setChain(tcb.getChain()) .setPartiesInvolved(tcb.getPartiesInvolvedAsString()) .setProcessingStart(LocalDateTime.now()) .setActive(true) diff --git a/starter-kit/src/main/java/it/spid/cie/oidc/model/TrustChainBuilder.java b/starter-kit/src/main/java/it/spid/cie/oidc/model/TrustChainBuilder.java index d0a59ea..e798455 100644 --- a/starter-kit/src/main/java/it/spid/cie/oidc/model/TrustChainBuilder.java +++ b/starter-kit/src/main/java/it/spid/cie/oidc/model/TrustChainBuilder.java @@ -56,6 +56,14 @@ public TrustChainBuilder(String subject, String metadataType, JWTHelper jwtHelpe this.subject = subject; } + public String getChain() { + StringJoiner sj = new StringJoiner(",", "[", "]"); + for (EntityConfiguration ec : trustPath) { + sj.add(ec.getJwt()); + } + return sj.toString(); + } + public String getChainAsString() { StringJoiner sj = new StringJoiner(",", "[", "]"); diff --git a/starter-kit/src/test/java/it/spid/cie/oidc/model/TestTrustChainBuilder.java b/starter-kit/src/test/java/it/spid/cie/oidc/model/TestTrustChainBuilder.java index d078281..e717d5f 100644 --- a/starter-kit/src/test/java/it/spid/cie/oidc/model/TestTrustChainBuilder.java +++ b/starter-kit/src/test/java/it/spid/cie/oidc/model/TestTrustChainBuilder.java @@ -63,6 +63,7 @@ public void testTrustChainBuilderClass() { catched = false; try { + tcb.getChain(); tcb.getChainAsString(); tcb.getExpiresOn(); tcb.getFinalMetadata(); From 827a61efaa827cd7bb24387c15aac3f900c21e88 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Mon, 30 Oct 2023 20:49:26 +0100 Subject: [PATCH 5/9] fix: removed unused function getChainAsString --- .../cie/oidc/model/TrustChainBuilder.java | 36 +++++++++---------- .../cie/oidc/model/TestTrustChainBuilder.java | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/starter-kit/src/main/java/it/spid/cie/oidc/model/TrustChainBuilder.java b/starter-kit/src/main/java/it/spid/cie/oidc/model/TrustChainBuilder.java index e798455..6f1df8c 100644 --- a/starter-kit/src/main/java/it/spid/cie/oidc/model/TrustChainBuilder.java +++ b/starter-kit/src/main/java/it/spid/cie/oidc/model/TrustChainBuilder.java @@ -64,24 +64,24 @@ public String getChain() { return sj.toString(); } - public String getChainAsString() { - StringJoiner sj = new StringJoiner(",", "[", "]"); - - for (EntityConfiguration ec : trustPath) { - sj.add(ec.getPayload()); - if (ec.hasVerifiedDescendantStatement()) { - StringJoiner sj2 = new StringJoiner(",", "[", "]"); - - for (String value : ec.getVerifiedDescendantStatement()) { - sj2.add(value); - } - - sj.add(sj2.toString()); - } - } - - return sj.toString(); - } +// public String getChainAsString() { +// StringJoiner sj = new StringJoiner(",", "[", "]"); +// +// for (EntityConfiguration ec : trustPath) { +// sj.add(ec.getPayload()); +// if (ec.hasVerifiedDescendantStatement()) { +// StringJoiner sj2 = new StringJoiner(",", "[", "]"); +// +// for (String value : ec.getVerifiedDescendantStatement()) { +// sj2.add(value); +// } +// +// sj.add(sj2.toString()); +// } +// } +// +// return sj.toString(); +// } public LocalDateTime getExpiresOn() { return LocalDateTime.ofEpochSecond(exp, 0, ZoneOffset.UTC); diff --git a/starter-kit/src/test/java/it/spid/cie/oidc/model/TestTrustChainBuilder.java b/starter-kit/src/test/java/it/spid/cie/oidc/model/TestTrustChainBuilder.java index e717d5f..9ba11e4 100644 --- a/starter-kit/src/test/java/it/spid/cie/oidc/model/TestTrustChainBuilder.java +++ b/starter-kit/src/test/java/it/spid/cie/oidc/model/TestTrustChainBuilder.java @@ -64,7 +64,7 @@ public void testTrustChainBuilderClass() { try { tcb.getChain(); - tcb.getChainAsString(); + //tcb.getChainAsString(); tcb.getExpiresOn(); tcb.getFinalMetadata(); tcb.getPartiesInvolvedAsString(); From 58e10845f3249d67b5adf5b641034c53b06151fb Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Tue, 31 Oct 2023 11:30:18 +0100 Subject: [PATCH 6/9] fix: added nested entity statements --- .../cie/oidc/model/EntityConfiguration.java | 11 +- .../cie/oidc/model/TrustChainBuilder.java | 1125 ++++++++--------- .../oidc/model/TestEntityConfiguration.java | 5 +- 3 files changed, 564 insertions(+), 577 deletions(-) diff --git a/starter-kit/src/main/java/it/spid/cie/oidc/model/EntityConfiguration.java b/starter-kit/src/main/java/it/spid/cie/oidc/model/EntityConfiguration.java index 46aa05c..e212319 100644 --- a/starter-kit/src/main/java/it/spid/cie/oidc/model/EntityConfiguration.java +++ b/starter-kit/src/main/java/it/spid/cie/oidc/model/EntityConfiguration.java @@ -41,6 +41,7 @@ public class EntityConfiguration { private EntityConfiguration trustAnchor; //private JSONObject header; private JSONObject payload; + private String verifiedDescendantStatementJwt; private String sub; private String iss; private long exp; @@ -307,7 +308,9 @@ public List getVerifiedDescendantStatement() { return Collections.unmodifiableList(result); } - + public String getVerifiedDescendantStatementJwt() { + return this.verifiedDescendantStatementJwt; + } public Set getVerifiedTrustMarks() { return Collections.unmodifiableSet(verifiedTrustMarks); } @@ -354,7 +357,9 @@ public boolean isValid() { public void setAllowedTrustMarks(String[] allowedTrustMarks) { this.allowedTrustMarks = Arrays.asList(allowedTrustMarks); } - + public void setVerifiedDescendantStatementJwt(String jwt) { + this.verifiedDescendantStatementJwt = jwt; + } @Override public String toString() { return String.format("(%s valid:%b", this.sub, this.valid); @@ -514,7 +519,7 @@ public boolean validateBySuperior(String jwt, EntityConfiguration ec) if (valid) { ec.addVerifiedDescendantStatement(getSubject(), payload); - + ec.setVerifiedDescendantStatementJwt(jwt); this.verifiedBySuperiors.put(payload.getString("iss"), ec); this.valid = true; } diff --git a/starter-kit/src/main/java/it/spid/cie/oidc/model/TrustChainBuilder.java b/starter-kit/src/main/java/it/spid/cie/oidc/model/TrustChainBuilder.java index 6f1df8c..1cb5307 100644 --- a/starter-kit/src/main/java/it/spid/cie/oidc/model/TrustChainBuilder.java +++ b/starter-kit/src/main/java/it/spid/cie/oidc/model/TrustChainBuilder.java @@ -32,37 +32,46 @@ */ public class TrustChainBuilder { - private static final Logger logger = LoggerFactory.getLogger( - TrustChainBuilder.class); - - private final JWTHelper jwtHelper; - private final String metadataType; - private final String subject; - private EntityConfiguration subjectConfiguration; - private EntityConfiguration trustAnchorConfiguration; - private int maxPathLength = 0; - private int maxAuthorityHints = 10; - private String[] requiredTrustMasks = new String[0]; - private Map> trustsTree = new TreeMap<>(); - private List trustPath = new ArrayList<>(); - private long exp = 0; - private boolean valid = false; - private JSONObject finalMetadata; - private Set verifiedTrustMasks = new HashSet<>(); - - public TrustChainBuilder(String subject, String metadataType, JWTHelper jwtHelper) { - this.jwtHelper = jwtHelper; - this.metadataType = metadataType; - this.subject = subject; - } - - public String getChain() { - StringJoiner sj = new StringJoiner(",", "[", "]"); - for (EntityConfiguration ec : trustPath) { - sj.add(ec.getJwt()); - } - return sj.toString(); - } + private static final Logger logger = LoggerFactory.getLogger( + TrustChainBuilder.class); + + private final JWTHelper jwtHelper; + private final String metadataType; + private final String subject; + private EntityConfiguration subjectConfiguration; + private EntityConfiguration trustAnchorConfiguration; + private int maxPathLength = 0; + private int maxAuthorityHints = 10; + private String[] requiredTrustMasks = new String[0]; + private Map> trustsTree = new TreeMap<>(); + private List trustPath = new ArrayList<>(); + private long exp = 0; + private boolean valid = false; + private JSONObject finalMetadata; + private Set verifiedTrustMasks = new HashSet<>(); + + public TrustChainBuilder(String subject, String metadataType, JWTHelper jwtHelper) { + this.jwtHelper = jwtHelper; + this.metadataType = metadataType; + this.subject = subject; + } + + public String getChain() { + StringJoiner sj = new StringJoiner(",", "[", "]"); + for (EntityConfiguration ec : trustPath) { + sj.add("\""+ec.getJwt()+"\""); + if (ec.hasVerifiedDescendantStatement()) { + String descendant = ec.getVerifiedDescendantStatementJwt(); + + StringJoiner sj2 = new StringJoiner(",", "[", "]"); + sj2.add("\""+descendant+"\""); + + sj.add(sj2.toString()); + } + } + + return sj.toString(); + } // public String getChainAsString() { // StringJoiner sj = new StringJoiner(",", "[", "]"); @@ -83,555 +92,527 @@ public String getChain() { // return sj.toString(); // } - public LocalDateTime getExpiresOn() { - return LocalDateTime.ofEpochSecond(exp, 0, ZoneOffset.UTC); - } + public LocalDateTime getExpiresOn() { + return LocalDateTime.ofEpochSecond(exp, 0, ZoneOffset.UTC); + } - public String getFinalMetadata() { - if (finalMetadata == null) { - return null; - } + public String getFinalMetadata() { + if (finalMetadata == null) { + return null; + } - return this.finalMetadata.toString(); - } + return this.finalMetadata.toString(); + } - public String getPartiesInvolvedAsString() { - StringJoiner sj = new StringJoiner(",", "[", "]"); + public String getPartiesInvolvedAsString() { + StringJoiner sj = new StringJoiner(",", "[", "]"); - for (EntityConfiguration ec : trustPath) { - sj.add(ec.getSubject()); - } + for (EntityConfiguration ec : trustPath) { + sj.add(ec.getSubject()); + } - return sj.toString(); - } + return sj.toString(); + } - public String getSubject() { - return this.subject; - } + public String getSubject() { + return this.subject; + } - public String getVerifiedTrustMarksAsString() { - JSONArray result = new JSONArray(); - - for (TrustMark trustMark : this.verifiedTrustMasks) { - result.put(trustMark.toJSON()); - } + public String getVerifiedTrustMarksAsString() { + JSONArray result = new JSONArray(); - return result.toString(); - } + for (TrustMark trustMark : this.verifiedTrustMasks) { + result.put(trustMark.toJSON()); + } - public boolean isValid() { - return this.valid; - } - - /** - * Means how much authorityHints to follow on each hop - * - * @param maxAuthorityHints - * @return - */ - public TrustChainBuilder setMaxAuthorityHints(int maxAuthorityHints) { - this.maxAuthorityHints = maxAuthorityHints; - - return this; - } - - public TrustChainBuilder setRequiredTrustMask(String[] requiredTrustMasks) { - this.requiredTrustMasks = requiredTrustMasks; - - return this; - } - - public TrustChainBuilder setSubjectConfiguration( - EntityConfiguration subjectConfiguration) { - - this.subjectConfiguration = subjectConfiguration; - - return this; - } - - public TrustChainBuilder setTrustAnchor(EntityConfiguration trustAnchor) { - trustAnchorConfiguration = trustAnchor; - - return this; - } - - public TrustChainBuilder setTrustAnchor(String trustAnchor) throws OIDCException { - if (logger.isInfoEnabled()) { - logger.info("Starting Metadata Discovery for {}", subject); - } - - String jwt = EntityHelper.getEntityConfiguration(trustAnchor); - - trustAnchorConfiguration = new EntityConfiguration(jwt, jwtHelper); - - return this; - } - - public TrustChainBuilder start() throws OIDCException { - try { - processTrustAnchorConfiguration(); - processSubjectConfiguration(); - discovery(); - } - catch (Exception e) { - logger.error(e.getMessage(), e); - - this.valid = false; - - if (e instanceof OIDCException) { - throw e; - } - else { - throw new OIDCException(e); - } - } - - return this; - } - - /** - * Filters the trust path from subject to trust anchor, apply the metadata - * policies along the path and returns the final metadata - * - * @throws Exception - */ - protected void applyMetadataPolicy() throws OIDCException { - if (trustPath.isEmpty()) { - trustPath.add(subjectConfiguration); - } - else { - EntityConfiguration ec = ListUtil.getLast(trustPath); - - if (trustAnchorConfiguration.getSubject().equals(ec.getSubject())) { - return; - } - } - - if (logger.isInfoEnabled()) { - logger.info( - "Applying metadata policy for {} over {} starting from {}", - this.subject, trustAnchorConfiguration.getSubject(), - ListUtil.getLast(trustPath)); - } - - List lastNodeEcs = trustsTree.get(trustPath.size() - 1); - - boolean pathFound = false; - final String trustAnchorSubject = trustAnchorConfiguration.getSubject(); - - for (EntityConfiguration ec : lastNodeEcs) { - for (EntityConfiguration supEc : ec.getVerifiedBySuperiors()) { - while ((trustPath.size() - 2) < maxPathLength) { - if (supEc.getSubject().equals(trustAnchorSubject)) { - trustPath.add(supEc); - pathFound = true; - break; - } - - if (supEc.hasVerifiedBySuperiors()) { - trustPath.add(supEc); - - applyMetadataPolicy(); - } - else { - if (logger.isInfoEnabled()) { - logger.info( - "'Huston, we have a problem' in {} for {} to {}", - supEc.getSubject(), this.subject, - trustAnchorConfiguration.getSubject()); - } - - trustPath.add(this.subjectConfiguration); - break; - } - } - } - } - - // once I filtered a concrete and unique trust path I can apply the metadata - // policy - - if (pathFound) { - logger.info("Found a trust path: {}", this.trustPath); - - this.finalMetadata = this.subjectConfiguration - .getPayloadMetadata() - .optJSONObject(metadataType); - - if (this.finalMetadata == null) { - logger.error( - "Missing {} in {}", - this.metadataType, this.subjectConfiguration.getPayloadMetadata()); - - return; - } - - for (int x = trustPath.size(); x > 0; x--) { - EntityConfiguration ec = trustPath.get(x - 1); - - JSONObject pol = ec.getVerifiedDescendantPayloadMetadataPolicy( - metadataType); - - if (pol != null) { - this.finalMetadata = applyPolicy(this.finalMetadata, pol); - } - } - } - - setExpiration(); - } - - protected JSONObject applyPolicy(JSONObject metadata, JSONObject policy) - throws OIDCException { - - for (String key : policy.keySet()) { - - // First Level is always a JSON Object - JSONObject p = policy.getJSONObject(key); - - if (!metadata.has(key)) { - if (p.has("value")) { - metadata.put(key, p.get("value")); - } - else if (p.has("add")) { - metadata.put(key, p.get("add")); - } - else if (p.has("default")) { - metadata.put(key, p.get("default")); - } - else if (p.has("essential")) { - // TODO: essential on policy? - } - - continue; - } - - if (p.has("value")) { - metadata.put(key, p.get("value")); - } - else if (p.has("one_of")) { - JSONArray oneOf = p.getJSONArray("one_of"); - JSONArray ar = metadata.optJSONArray(key); - - if (ar != null) { - boolean good = false; - - for (int x = 0; x < ar.length(); x++) { - if (jsonArrayContains(oneOf, ar.get(x))) { - metadata.put(key, ar.get(x)); - good = true; - break; - } - } - - if (!good) { - throw new TrustChainBuilderException( - String.format( - "%s: None of %s among %s", key, ar.toString(), - oneOf.toString())); - } - } - else { - Object o = metadata.get(key); - - if (!jsonArrayContains(oneOf, o)) { - throw new TrustChainBuilderException( - String.format( - "%s: %s not among %s", key, String.valueOf(ar), - oneOf.toString())); - } - } - } - else if (p.has("add")) { - metadata.put(key, jsonArrayUnion(metadata.get(key), p.get("add"))); - } - else if (p.has("subset_of")) { - JSONArray ar = jsonArrayIntersect(p.get("subset_of"), metadata.get(key)); - - if (!ar.isEmpty()) { - metadata.put(key, ar); - } - else { - throw new TrustChainBuilderException( - String.format( - "%s: %s not subset of %s", key, metadata.get(key), - p.get("subset_of"))); - } - } - else if (p.has("superset_of")) { - JSONArray ar = jsonArrayDifference( - p.get("superset_of"), metadata.get(key)); - - if (!ar.isEmpty()) { - metadata.put(key, ar); - } - else { - throw new TrustChainBuilderException( - String.format( - "%s: %s not superset of %s", key, metadata.get(key), - p.get("superset_of"))); - } - } - } - - return metadata; - } - - /** - * @return return a chain of verified statements from the lower up to the trust anchor - * @throws OIDCException - */ - protected boolean discovery() throws OIDCException { - logger.info("Starting a Walk into Metadata Discovery for " + subject); - - trustsTree.put(0, Arrays.asList(subjectConfiguration)); - - List processedSubjects = new ArrayList<>(); - - List superiorHints = Arrays.asList( - this.trustAnchorConfiguration); - - while ((trustsTree.size() -2) < maxPathLength) { - List entities = trustsTree.get(trustsTree.size() -1); - - List supEcs = new ArrayList<>(); - - for (EntityConfiguration ec : entities) { - if (processedSubjects.contains(ec.getSubject())) { - logger.warn( - "Metadata discovery loop detection for {}. " + - "Already present in {}. " + - "Discovery blocked for this path.", ec.getSubject(), - processedSubjects); - - continue; - } - - try { - Map superiors = ec.getSuperiors( - this.maxAuthorityHints, superiorHints); - - Map verifiedSuperiors = - ec.validateBySuperiors(superiors.values()); - - supEcs.addAll(verifiedSuperiors.values()); - - processedSubjects.add(ec.getSubject()); - } - catch (Exception e) { - logger.error( - "Metadata discovery exception for {}: {}", ec.getSubject(), e); - } - } - - if (!supEcs.isEmpty()) { - trustsTree.put(trustsTree.size(), supEcs); - } - else { - break; - } - } - - EntityConfiguration first = getTrustsTreeNodeValue(0, 0); - EntityConfiguration last = getTrustsTreeNodeValue(-1, 0); - - if (first != null && first.isValid() && last != null && last.isValid()) { - this.valid = true; - applyMetadataPolicy(); - } - - return this.valid; - } - - /** - * Ensure the provided Subject Entity Configuration is valid (self validable) and - * complete (at least by required elements) - * - * @throws OIDCException - * - * @throws OIDCException - */ - protected void processSubjectConfiguration() throws OIDCException { - if (subjectConfiguration != null) { - return; - } - - try { - String jwt = EntityHelper.getEntityConfiguration(subject); - - subjectConfiguration = new EntityConfiguration( - jwt, trustAnchorConfiguration, jwtHelper); - - subjectConfiguration.validateItself(); - } - catch (Exception e) { - String msg = String.format( - "Entity Configuration for %s failed: %s", subject, - e.getMessage()); - - logger.error(msg); - - throw new TrustChainBuilderException(msg); - } - - // Trust Mark filter - - if (requiredTrustMasks.length > 0) { - subjectConfiguration.setAllowedTrustMarks(requiredTrustMasks); - - if (!subjectConfiguration.validateByAllowedTrustMarks()) { - throw new TrustChainException.InvalidRequiredTrustMark( - "The required Trust Marks are not valid"); - } - - this.verifiedTrustMasks.addAll(subjectConfiguration.getVerifiedTrustMarks()); - } - } - - /** - * Ensure the provided TrustAnchor Entity Configuration is valid (self validable) and - * complete (at least by required elements) - * - * @throws OIDCException - */ - protected void processTrustAnchorConfiguration() throws OIDCException { - if (trustAnchorConfiguration == null) { - throw new TrustChainBuilderException("Please set TrustAnchor"); - } - - try { - trustAnchorConfiguration.validateItself(false); - } - catch (Exception e) { - String message = - "Trust Anchor Entity Configuration validation failed with " + e; - - logger.error(message); - - throw new TrustChainBuilderException(message); - } - - if (trustAnchorConfiguration.hasConstraint("max_path_length")) { - this.maxPathLength = trustAnchorConfiguration.getConstraint( - "max_path_length", 0); - } - } - - protected void setExpiration() { - this.exp = 0; - - for (EntityConfiguration ec : this.trustPath) { - if (this.exp == 0) { - this.exp = ec.getExp(); - } - else if (ec.getExp() > this.exp) { - this.exp = ec.getExp(); - } - } - } - - private EntityConfiguration getTrustsTreeNodeValue(int nodeIdx, int valueIdx) { - List value; - - if (nodeIdx >= 0) { - value = trustsTree.get(nodeIdx); - } - else { - value = trustsTree.get(trustsTree.size() - 1); - } - - if (value != null && !value.isEmpty()) { - if (valueIdx < 0) { - return value.get(value.size() - 1); - } - else if (valueIdx < value.size()) { - return value.get(valueIdx); - } - } - - return null; - } - - private boolean jsonArrayContains(JSONArray array, Object value) { - for (int x = 0; x < array.length(); x++) { - if (Objects.equals(value, array.get(x))) { - return true; - } - } - - return false; - } - - private JSONArray jsonArrayUnion(Object o1, Object o2) { - Set result = new HashSet<>(); - - if (o1 instanceof JSONArray) { - result.addAll(((JSONArray)o1).toList()); - } - else { - result.add(o1); - } - if (o2 instanceof JSONArray) { - result.addAll(((JSONArray)o2).toList()); - } - else { - result.add(o2); - } - - return new JSONArray(result); - } - - private JSONArray jsonArrayIntersect(Object o1, Object o2) { - Set s1 = new HashSet<>(); - - if (o1 instanceof JSONArray) { - s1.addAll(((JSONArray)o1).toList()); - } - else { - s1.add(o1); - } - - Set s2 = new HashSet<>(); - - if (o2 instanceof JSONArray) { - s2.addAll(((JSONArray)o2).toList()); - } - else { - s2.add(o2); - } - - s1.retainAll(s2); - - return new JSONArray(s1); - } - - /** - * @param o1 first set - * @param o2 second set - * @return elements of first set non present in the second set - */ - private JSONArray jsonArrayDifference(Object o1, Object o2) { - Set s1 = new HashSet<>(); - - if (o1 instanceof JSONArray) { - s1.addAll(((JSONArray)o1).toList()); - } - else { - s1.add(o1); - } - - Set s2 = new HashSet<>(); - - if (o2 instanceof JSONArray) { - s2.addAll(((JSONArray)o2).toList()); - } - else { - s2.add(o2); - } - - s1.removeAll(s2); - - return new JSONArray(s1); - } + return result.toString(); + } + + public boolean isValid() { + return this.valid; + } + + /** + * Means how much authorityHints to follow on each hop + * + * @param maxAuthorityHints + * @return + */ + public TrustChainBuilder setMaxAuthorityHints(int maxAuthorityHints) { + this.maxAuthorityHints = maxAuthorityHints; + + return this; + } + + public TrustChainBuilder setRequiredTrustMask(String[] requiredTrustMasks) { + this.requiredTrustMasks = requiredTrustMasks; + + return this; + } + + public TrustChainBuilder setSubjectConfiguration( + EntityConfiguration subjectConfiguration) { + + this.subjectConfiguration = subjectConfiguration; + + return this; + } + + public TrustChainBuilder setTrustAnchor(EntityConfiguration trustAnchor) { + trustAnchorConfiguration = trustAnchor; + + return this; + } + + public TrustChainBuilder setTrustAnchor(String trustAnchor) throws OIDCException { + if (logger.isInfoEnabled()) { + logger.info("Starting Metadata Discovery for {}", subject); + } + + String jwt = EntityHelper.getEntityConfiguration(trustAnchor); + + trustAnchorConfiguration = new EntityConfiguration(jwt, jwtHelper); + + return this; + } + + public TrustChainBuilder start() throws OIDCException { + try { + processTrustAnchorConfiguration(); + processSubjectConfiguration(); + discovery(); + } catch (Exception e) { + logger.error(e.getMessage(), e); + + this.valid = false; + + if (e instanceof OIDCException) { + throw e; + } else { + throw new OIDCException(e); + } + } + + return this; + } + + /** + * Filters the trust path from subject to trust anchor, apply the metadata + * policies along the path and returns the final metadata + * + * @throws Exception + */ + protected void applyMetadataPolicy() throws OIDCException { + if (trustPath.isEmpty()) { + trustPath.add(subjectConfiguration); + } else { + EntityConfiguration ec = ListUtil.getLast(trustPath); + + if (trustAnchorConfiguration.getSubject().equals(ec.getSubject())) { + return; + } + } + + if (logger.isInfoEnabled()) { + logger.info( + "Applying metadata policy for {} over {} starting from {}", + this.subject, trustAnchorConfiguration.getSubject(), + ListUtil.getLast(trustPath)); + } + + List lastNodeEcs = trustsTree.get(trustPath.size() - 1); + + boolean pathFound = false; + final String trustAnchorSubject = trustAnchorConfiguration.getSubject(); + + for (EntityConfiguration ec : lastNodeEcs) { + for (EntityConfiguration supEc : ec.getVerifiedBySuperiors()) { + while ((trustPath.size() - 2) < maxPathLength) { + if (supEc.getSubject().equals(trustAnchorSubject)) { + trustPath.add(supEc); + pathFound = true; + break; + } + + if (supEc.hasVerifiedBySuperiors()) { + trustPath.add(supEc); + + applyMetadataPolicy(); + } else { + if (logger.isInfoEnabled()) { + logger.info( + "'Huston, we have a problem' in {} for {} to {}", + supEc.getSubject(), this.subject, + trustAnchorConfiguration.getSubject()); + } + + trustPath.add(this.subjectConfiguration); + break; + } + } + } + } + + // once I filtered a concrete and unique trust path I can apply the metadata + // policy + + if (pathFound) { + logger.info("Found a trust path: {}", this.trustPath); + + this.finalMetadata = this.subjectConfiguration + .getPayloadMetadata() + .optJSONObject(metadataType); + + if (this.finalMetadata == null) { + logger.error( + "Missing {} in {}", + this.metadataType, this.subjectConfiguration.getPayloadMetadata()); + + return; + } + + for (int x = trustPath.size(); x > 0; x--) { + EntityConfiguration ec = trustPath.get(x - 1); + + JSONObject pol = ec.getVerifiedDescendantPayloadMetadataPolicy( + metadataType); + + if (pol != null) { + this.finalMetadata = applyPolicy(this.finalMetadata, pol); + } + } + } + + setExpiration(); + } + + protected JSONObject applyPolicy(JSONObject metadata, JSONObject policy) + throws OIDCException { + + for (String key : policy.keySet()) { + + // First Level is always a JSON Object + JSONObject p = policy.getJSONObject(key); + + if (!metadata.has(key)) { + if (p.has("value")) { + metadata.put(key, p.get("value")); + } else if (p.has("add")) { + metadata.put(key, p.get("add")); + } else if (p.has("default")) { + metadata.put(key, p.get("default")); + } else if (p.has("essential")) { + // TODO: essential on policy? + } + + continue; + } + + if (p.has("value")) { + metadata.put(key, p.get("value")); + } else if (p.has("one_of")) { + JSONArray oneOf = p.getJSONArray("one_of"); + JSONArray ar = metadata.optJSONArray(key); + + if (ar != null) { + boolean good = false; + + for (int x = 0; x < ar.length(); x++) { + if (jsonArrayContains(oneOf, ar.get(x))) { + metadata.put(key, ar.get(x)); + good = true; + break; + } + } + + if (!good) { + throw new TrustChainBuilderException( + String.format( + "%s: None of %s among %s", key, ar.toString(), + oneOf.toString())); + } + } else { + Object o = metadata.get(key); + + if (!jsonArrayContains(oneOf, o)) { + throw new TrustChainBuilderException( + String.format( + "%s: %s not among %s", key, String.valueOf(ar), + oneOf.toString())); + } + } + } else if (p.has("add")) { + metadata.put(key, jsonArrayUnion(metadata.get(key), p.get("add"))); + } else if (p.has("subset_of")) { + JSONArray ar = jsonArrayIntersect(p.get("subset_of"), metadata.get(key)); + + if (!ar.isEmpty()) { + metadata.put(key, ar); + } else { + throw new TrustChainBuilderException( + String.format( + "%s: %s not subset of %s", key, metadata.get(key), + p.get("subset_of"))); + } + } else if (p.has("superset_of")) { + JSONArray ar = jsonArrayDifference( + p.get("superset_of"), metadata.get(key)); + + if (!ar.isEmpty()) { + metadata.put(key, ar); + } else { + throw new TrustChainBuilderException( + String.format( + "%s: %s not superset of %s", key, metadata.get(key), + p.get("superset_of"))); + } + } + } + + return metadata; + } + + /** + * @return return a chain of verified statements from the lower up to the trust anchor + * @throws OIDCException + */ + protected boolean discovery() throws OIDCException { + logger.info("Starting a Walk into Metadata Discovery for " + subject); + + trustsTree.put(0, Arrays.asList(subjectConfiguration)); + + List processedSubjects = new ArrayList<>(); + + List superiorHints = Arrays.asList( + this.trustAnchorConfiguration); + + while ((trustsTree.size() - 2) < maxPathLength) { + List entities = trustsTree.get(trustsTree.size() - 1); + + List supEcs = new ArrayList<>(); + + for (EntityConfiguration ec : entities) { + if (processedSubjects.contains(ec.getSubject())) { + logger.warn( + "Metadata discovery loop detection for {}. " + + "Already present in {}. " + + "Discovery blocked for this path.", ec.getSubject(), + processedSubjects); + + continue; + } + + try { + Map superiors = ec.getSuperiors( + this.maxAuthorityHints, superiorHints); + + Map verifiedSuperiors = + ec.validateBySuperiors(superiors.values()); + + supEcs.addAll(verifiedSuperiors.values()); + + processedSubjects.add(ec.getSubject()); + } catch (Exception e) { + logger.error( + "Metadata discovery exception for {}: {}", ec.getSubject(), e); + } + } + + if (!supEcs.isEmpty()) { + trustsTree.put(trustsTree.size(), supEcs); + } else { + break; + } + } + + EntityConfiguration first = getTrustsTreeNodeValue(0, 0); + EntityConfiguration last = getTrustsTreeNodeValue(-1, 0); + + if (first != null && first.isValid() && last != null && last.isValid()) { + this.valid = true; + applyMetadataPolicy(); + } + + return this.valid; + } + + /** + * Ensure the provided Subject Entity Configuration is valid (self validable) and + * complete (at least by required elements) + * + * @throws OIDCException + * @throws OIDCException + */ + protected void processSubjectConfiguration() throws OIDCException { + if (subjectConfiguration != null) { + return; + } + + try { + String jwt = EntityHelper.getEntityConfiguration(subject); + + subjectConfiguration = new EntityConfiguration( + jwt, trustAnchorConfiguration, jwtHelper); + + subjectConfiguration.validateItself(); + } catch (Exception e) { + String msg = String.format( + "Entity Configuration for %s failed: %s", subject, + e.getMessage()); + + logger.error(msg); + + throw new TrustChainBuilderException(msg); + } + + // Trust Mark filter + + if (requiredTrustMasks.length > 0) { + subjectConfiguration.setAllowedTrustMarks(requiredTrustMasks); + + if (!subjectConfiguration.validateByAllowedTrustMarks()) { + throw new TrustChainException.InvalidRequiredTrustMark( + "The required Trust Marks are not valid"); + } + + this.verifiedTrustMasks.addAll(subjectConfiguration.getVerifiedTrustMarks()); + } + } + + /** + * Ensure the provided TrustAnchor Entity Configuration is valid (self validable) and + * complete (at least by required elements) + * + * @throws OIDCException + */ + protected void processTrustAnchorConfiguration() throws OIDCException { + if (trustAnchorConfiguration == null) { + throw new TrustChainBuilderException("Please set TrustAnchor"); + } + + try { + trustAnchorConfiguration.validateItself(false); + } catch (Exception e) { + String message = + "Trust Anchor Entity Configuration validation failed with " + e; + + logger.error(message); + + throw new TrustChainBuilderException(message); + } + + if (trustAnchorConfiguration.hasConstraint("max_path_length")) { + this.maxPathLength = trustAnchorConfiguration.getConstraint( + "max_path_length", 0); + } + } + + protected void setExpiration() { + this.exp = 0; + + for (EntityConfiguration ec : this.trustPath) { + if (this.exp == 0) { + this.exp = ec.getExp(); + } else if (ec.getExp() > this.exp) { + this.exp = ec.getExp(); + } + } + } + + private EntityConfiguration getTrustsTreeNodeValue(int nodeIdx, int valueIdx) { + List value; + + if (nodeIdx >= 0) { + value = trustsTree.get(nodeIdx); + } else { + value = trustsTree.get(trustsTree.size() - 1); + } + + if (value != null && !value.isEmpty()) { + if (valueIdx < 0) { + return value.get(value.size() - 1); + } else if (valueIdx < value.size()) { + return value.get(valueIdx); + } + } + + return null; + } + + private boolean jsonArrayContains(JSONArray array, Object value) { + for (int x = 0; x < array.length(); x++) { + if (Objects.equals(value, array.get(x))) { + return true; + } + } + + return false; + } + + private JSONArray jsonArrayUnion(Object o1, Object o2) { + Set result = new HashSet<>(); + + if (o1 instanceof JSONArray) { + result.addAll(((JSONArray) o1).toList()); + } else { + result.add(o1); + } + if (o2 instanceof JSONArray) { + result.addAll(((JSONArray) o2).toList()); + } else { + result.add(o2); + } + + return new JSONArray(result); + } + + private JSONArray jsonArrayIntersect(Object o1, Object o2) { + Set s1 = new HashSet<>(); + + if (o1 instanceof JSONArray) { + s1.addAll(((JSONArray) o1).toList()); + } else { + s1.add(o1); + } + + Set s2 = new HashSet<>(); + + if (o2 instanceof JSONArray) { + s2.addAll(((JSONArray) o2).toList()); + } else { + s2.add(o2); + } + + s1.retainAll(s2); + + return new JSONArray(s1); + } + + /** + * @param o1 first set + * @param o2 second set + * @return elements of first set non present in the second set + */ + private JSONArray jsonArrayDifference(Object o1, Object o2) { + Set s1 = new HashSet<>(); + + if (o1 instanceof JSONArray) { + s1.addAll(((JSONArray) o1).toList()); + } else { + s1.add(o1); + } + + Set s2 = new HashSet<>(); + + if (o2 instanceof JSONArray) { + s2.addAll(((JSONArray) o2).toList()); + } else { + s2.add(o2); + } + + s1.removeAll(s2); + + return new JSONArray(s1); + } } diff --git a/starter-kit/src/test/java/it/spid/cie/oidc/model/TestEntityConfiguration.java b/starter-kit/src/test/java/it/spid/cie/oidc/model/TestEntityConfiguration.java index 87c2567..2131bb6 100644 --- a/starter-kit/src/test/java/it/spid/cie/oidc/model/TestEntityConfiguration.java +++ b/starter-kit/src/test/java/it/spid/cie/oidc/model/TestEntityConfiguration.java @@ -24,9 +24,7 @@ import com.nimbusds.jose.jwk.JWKSet; import it.spid.cie.oidc.config.OIDCConstants; -import it.spid.cie.oidc.handler.RelyingPartyHandler; import it.spid.cie.oidc.helper.JWTHelper; -import it.spid.cie.oidc.schemas.SPIDClaimItem; import it.spid.cie.oidc.test.util.RPTestUtils; import it.spid.cie.oidc.util.JSONUtil; @@ -96,6 +94,9 @@ public void testEntityConfigurationClass() { assertFalse(ec.hasJWK("test")); assertFalse(ec.hasJWK("")); + ec.setVerifiedDescendantStatementJwt("test"); + assertEquals(ec.getVerifiedDescendantStatementJwt(), "test"); + catched = false; EntityConfiguration ec2 = null; From 28f912cd24ffb93b301a880fbfef3dc659008e12 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Thu, 2 Nov 2023 16:37:13 +0100 Subject: [PATCH 7/9] test: added getVerifiedDescendantStatement test --- .../java/it/spid/cie/oidc/model/TestEntityConfiguration.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/starter-kit/src/test/java/it/spid/cie/oidc/model/TestEntityConfiguration.java b/starter-kit/src/test/java/it/spid/cie/oidc/model/TestEntityConfiguration.java index 2131bb6..e877a56 100644 --- a/starter-kit/src/test/java/it/spid/cie/oidc/model/TestEntityConfiguration.java +++ b/starter-kit/src/test/java/it/spid/cie/oidc/model/TestEntityConfiguration.java @@ -97,6 +97,10 @@ public void testEntityConfigurationClass() { ec.setVerifiedDescendantStatementJwt("test"); assertEquals(ec.getVerifiedDescendantStatementJwt(), "test"); + ec.addVerifiedDescendantStatement("1",new JSONObject().put("test","test")); + List descendant = ec.getVerifiedDescendantStatement(); + assertEquals(descendant.size(),1); + catched = false; EntityConfiguration ec2 = null; From 331ca7eb52f81c3cd1dceae46b8279e3d9fb88f9 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Thu, 2 Nov 2023 19:50:55 +0100 Subject: [PATCH 8/9] chore: reformat code --- .../it/spid/cie/oidc/model/TrustChainBuilder.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/starter-kit/src/main/java/it/spid/cie/oidc/model/TrustChainBuilder.java b/starter-kit/src/main/java/it/spid/cie/oidc/model/TrustChainBuilder.java index 1cb5307..cc6ad5a 100644 --- a/starter-kit/src/main/java/it/spid/cie/oidc/model/TrustChainBuilder.java +++ b/starter-kit/src/main/java/it/spid/cie/oidc/model/TrustChainBuilder.java @@ -59,12 +59,20 @@ public TrustChainBuilder(String subject, String metadataType, JWTHelper jwtHelpe public String getChain() { StringJoiner sj = new StringJoiner(",", "[", "]"); for (EntityConfiguration ec : trustPath) { - sj.add("\""+ec.getJwt()+"\""); + String statement = (new StringBuilder()) + .append("\"") + .append(ec.getJwt()) + .append("\"").toString(); + sj.add(statement); if (ec.hasVerifiedDescendantStatement()) { String descendant = ec.getVerifiedDescendantStatementJwt(); StringJoiner sj2 = new StringJoiner(",", "[", "]"); - sj2.add("\""+descendant+"\""); + String descendantStatement = (new StringBuilder()) + .append("\"") + .append(descendant) + .append("\"").toString(); + sj2.add(descendantStatement); sj.add(sj2.toString()); } From f824f2b1dc2f071e6db3806ce875f33dc74aa8ce Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Thu, 2 Nov 2023 22:23:28 +0100 Subject: [PATCH 9/9] fix: aligned claims "trust_mark_issuer", "trust_marks_issuers" to trust_mark_issuers --- .../persistence/model/FederationEntityModel.java | 16 ++++++++-------- .../src/main/resources/sql/schema.sql | 2 +- .../cie/oidc/handler/RelyingPartyHandler.java | 2 +- .../spid/cie/oidc/model/EntityConfiguration.java | 12 ++++++------ .../it/spid/cie/oidc/model/FederationEntity.java | 10 +++++----- .../oidc/handler/TestRelyingPartyHandler.java | 4 ++-- .../cie/oidc/model/TestEntityConfiguration.java | 12 ++++++------ .../cie/oidc/model/TestFederationEntity.java | 4 ++-- .../cie/oidc/model/TestTrustChainBuilder.java | 8 ++++---- .../it/spid/cie/oidc/model/TestTrustMark.java | 4 ++-- .../it/spid/cie/oidc/test/util/RPTestUtils.java | 8 ++++---- 11 files changed, 41 insertions(+), 41 deletions(-) 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 ee0d1a1..4c8c40d 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 @@ -32,7 +32,7 @@ public static FederationEntityModel of(FederationEntity source) { target.setConstraints(source.getConstraints()); target.setJwks(source.getJwks()); target.setTrustMarks(source.getTrustMarks()); - target.setTrustMarksIssuers(source.getTrustMarksIssuers()); + target.setTrustMarkIssuers(source.gettrustMarkIssuers()); target.setMetadata(source.getMetadata()); return target; @@ -79,8 +79,8 @@ public String getTrustMarks() { return trustMarks; } - public String getTrustMarksIssuers() { - return trustMarksIssuers; + public String getTrustMarkIssuers() { + return trustMarkIssuers; } public String getMetadata() { @@ -134,8 +134,8 @@ public void setTrustMarks(String trustMarks) { this.trustMarks = trustMarks; } - public void setTrustMarksIssuers(String trustMarksIssuers) { - this.trustMarksIssuers = trustMarksIssuers; + public void setTrustMarkIssuers(String trustMarkIssuers) { + this.trustMarkIssuers = trustMarkIssuers; } public void setMetadata(String metadata) { @@ -169,7 +169,7 @@ public FederationEntity toFederationEntity() { target.setConstraints(getConstraints()); target.setJwks(getJwks()); target.setTrustMarks(getTrustMarks()); - target.setTrustMarksIssuers(getTrustMarksIssuers()); + target.settrustMarkIssuers(getTrustMarkIssuers()); target.setMetadata(getMetadata()); return target; @@ -218,8 +218,8 @@ private String getStorageId() { @Column(name = "trust_marks", nullable = false, length = 2000) private String trustMarks; - @Column(name = "trust_marks_issuers", nullable = false, length = 2000) - private String trustMarksIssuers; + @Column(name = "trust_mark_issuers", nullable = false, length = 2000) + private String trustMarkIssuers; @Column(nullable = false, length = 5000) private String metadata; 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 d1ed951..97d86a8 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 @@ -40,7 +40,7 @@ CREATE TABLE IF NOT EXISTS federation_entity_configuration ( authority_hints VARCHAR NOT NULL, jwks VARCHAR NOT NULL, trust_marks VARCHAR NOT NULL, - trust_marks_issuers VARCHAR NOT NULL, + trust_mark_issuers VARCHAR NOT NULL, metadata VARCHAR NOT NULL, constraints VARCHAR NOT NULL, is_active BOOLEAN NOT NULL, 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 fb0ae3b..f8122bb 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 @@ -929,7 +929,7 @@ private WellKnownData prepareOnboardingData(String sub, boolean jsonMode) entity.setJwks( JWTHelper.getJWKSetAsJSONArray(jwkSet, true, false).toString()); entity.setTrustMarks(json.getJSONArray("trust_marks").toString()); - entity.setTrustMarksIssuers("{}"); + entity.settrustMarkIssuers("{}"); entity.setMetadata(json.getJSONObject("metadata").toString()); entity.setActive(true); entity.setConstraints("{}"); diff --git a/starter-kit/src/main/java/it/spid/cie/oidc/model/EntityConfiguration.java b/starter-kit/src/main/java/it/spid/cie/oidc/model/EntityConfiguration.java index e212319..d219b92 100644 --- a/starter-kit/src/main/java/it/spid/cie/oidc/model/EntityConfiguration.java +++ b/starter-kit/src/main/java/it/spid/cie/oidc/model/EntityConfiguration.java @@ -250,14 +250,14 @@ public Map getSuperiors( return this.verifiedSuperiors; } - public Map> getTrustMarksIssuers() { + public Map> gettrustMarkIssuers() { Map> result = new HashMap<>(); - JSONObject trustMarksIssuers = payload.optJSONObject( - "trust_marks_issuers", new JSONObject()); + JSONObject trustMarkIssuers = payload.optJSONObject( + "trust_mark_issuers", new JSONObject()); - for (String key : trustMarksIssuers.keySet()) { - JSONArray jsonArray = trustMarksIssuers.optJSONArray(key); + for (String key : trustMarkIssuers.keySet()) { + JSONArray jsonArray = trustMarkIssuers.optJSONArray(key); if (jsonArray == null) { continue; @@ -422,7 +422,7 @@ else if (!isTrustMarkAllowed(jsonTrustMark)) { "Required Trust marks are missing."); } - Map> trustAnchorIssuers = trustAnchor.getTrustMarksIssuers(); + Map> trustAnchorIssuers = trustAnchor.gettrustMarkIssuers(); boolean valid = false; 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 78bb1d4..9ce0854 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 @@ -27,7 +27,7 @@ public class FederationEntity extends BaseModel { private String authorityHints; private String jwks; private String trustMarks; - private String trustMarksIssuers; + private String trustMarkIssuers; private String metadata; private boolean active = false; private String constraints; @@ -80,8 +80,8 @@ public String getTrustMarks() { return trustMarks; } - public String getTrustMarksIssuers() { - return trustMarksIssuers; + public String gettrustMarkIssuers() { + return trustMarkIssuers; } public boolean isActive() { @@ -134,8 +134,8 @@ public void setTrustMarks(String trustMarks) { this.trustMarks = trustMarks; } - public void setTrustMarksIssuers(String trustMarksIssuers) { - this.trustMarksIssuers = trustMarksIssuers; + public void settrustMarkIssuers(String trustMarkIssuers) { + this.trustMarkIssuers = trustMarkIssuers; } 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 3e891bf..b8f7179 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 @@ -675,7 +675,7 @@ private String mockedTrustAnchorEntityConfiguration() throws Exception { payload.put( "metadata", new JSONObject().put("federation_entity", trustAnchorMetadata)); - JSONObject trustMarksIssuers = new JSONObject() + JSONObject trustMarkIssuers = new JSONObject() .put( "https://www.spid.gov.it/certification/rp/public", JSONUtil.asJSONArray( "https://registry.spid.agid.gov.it", @@ -688,7 +688,7 @@ private String mockedTrustAnchorEntityConfiguration() throws Exception { "https://sgd.aa.it/onboarding", JSONUtil.asJSONArray( "https://sgd.aa.it")); - payload.put("trust_marks_issuers", trustMarksIssuers); + payload.put("trust_mark_issuers", trustMarkIssuers); payload.put("constraints", new JSONObject().put("max_path_length", 1)); JSONObject jwks = mockedTrustAnchorPrivateJWKS(); diff --git a/starter-kit/src/test/java/it/spid/cie/oidc/model/TestEntityConfiguration.java b/starter-kit/src/test/java/it/spid/cie/oidc/model/TestEntityConfiguration.java index e877a56..1b5cb89 100644 --- a/starter-kit/src/test/java/it/spid/cie/oidc/model/TestEntityConfiguration.java +++ b/starter-kit/src/test/java/it/spid/cie/oidc/model/TestEntityConfiguration.java @@ -260,7 +260,7 @@ public void test_validateBySuperiors() { } @Test - public void test_getTrustMarksIssuers() { + public void test_gettrustMarkIssuers() { JWTHelper jwtHelper = null; EntityConfiguration ec = null; boolean catched = false; @@ -283,7 +283,7 @@ public void test_getTrustMarksIssuers() { Map> res = null; try { - res = ec.getTrustMarksIssuers(); + res = ec.gettrustMarkIssuers(); } catch (Exception e) { catched = true; @@ -762,7 +762,7 @@ private String mockedTrustAnchorEntityConfigurationC1() payload.put( "metadata", new JSONObject().put("federation_entity", trustAnchorMetadata)); - JSONObject trustMarksIssuers = new JSONObject() + JSONObject trustMarkIssuers = new JSONObject() .put( "https://www.spid.gov.it/certification/rp/public", JSONUtil.asJSONArray( "https://registry.spid.agid.gov.it", @@ -775,7 +775,7 @@ private String mockedTrustAnchorEntityConfigurationC1() "https://sgd.aa.it/onboarding", JSONUtil.asJSONArray( "https://sgd.aa.it")); - payload.put("trust_marks_issuers", trustMarksIssuers); + payload.put("trust_mark_issuers", trustMarkIssuers); payload.put("constraints", new JSONObject().put("max_path_length", 1)); JSONObject jwks = RPTestUtils.mockedTrustAnchorPrivateJWKS(); @@ -805,7 +805,7 @@ private String mockedTrustAnchorEntityConfigurationC2() payload.put( "metadata", new JSONObject().put("federation_entity", trustAnchorMetadata)); - JSONObject trustMarksIssuers = new JSONObject() + JSONObject trustMarkIssuers = new JSONObject() .put( "https://www.spid.gov.it/certification/rp/public", JSONUtil.asJSONArray( "https://registry.spid.agid.gov.it", @@ -819,7 +819,7 @@ private String mockedTrustAnchorEntityConfigurationC2() "https://sgd.aa.it/onboarding", JSONUtil.asJSONArray( "https://sgd.aa.it")); - payload.put("trust_marks_issuers", trustMarksIssuers); + payload.put("trust_mark_issuers", trustMarkIssuers); //payload.put("constraints", new JSONObject().put("max_path_length", 1)); JSONObject jwks = RPTestUtils.mockedTrustAnchorPrivateJWKS(); 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 8d786f3..f0a441b 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 @@ -30,7 +30,7 @@ public void testFederationEntityClass() { model.getMetadata(); model.getSubject(); model.getTrustMarks(); - model.getTrustMarksIssuers(); + model.gettrustMarkIssuers(); model.isActive(); LocalDateTime now = LocalDateTime.now(); @@ -48,7 +48,7 @@ public void testFederationEntityClass() { model.setJwks("testJwks"); model.setSubject("testSubject"); model.setTrustMarks("testTrustMarks"); - model.setTrustMarksIssuers("testIssuer"); + model.settrustMarkIssuers("testIssuer"); JSONObject metadata = new JSONObject() .put("testKey", new JSONObject().put("test", "ok")); diff --git a/starter-kit/src/test/java/it/spid/cie/oidc/model/TestTrustChainBuilder.java b/starter-kit/src/test/java/it/spid/cie/oidc/model/TestTrustChainBuilder.java index 9ba11e4..86823c7 100644 --- a/starter-kit/src/test/java/it/spid/cie/oidc/model/TestTrustChainBuilder.java +++ b/starter-kit/src/test/java/it/spid/cie/oidc/model/TestTrustChainBuilder.java @@ -747,7 +747,7 @@ private static String mockedTrustAnchorEntityConfigurationC3(JWKSet jwkSet) payload.put( "metadata", new JSONObject().put("federation_entity", trustAnchorMetadata)); - JSONObject trustMarksIssuers = new JSONObject() + JSONObject trustMarkIssuers = new JSONObject() .put( "https://www.spid.gov.it/certification/rp/public", JSONUtil.asJSONArray( "https://registry.spid.agid.gov.it", @@ -760,7 +760,7 @@ private static String mockedTrustAnchorEntityConfigurationC3(JWKSet jwkSet) "https://sgd.aa.it/onboarding", JSONUtil.asJSONArray( "https://sgd.aa.it")); - payload.put("trust_marks_issuers", trustMarksIssuers); + payload.put("trust_mark_issuers", trustMarkIssuers); payload.put("constraints", new JSONObject().put("max_path_length", 1)); JSONObject jwks = new JSONObject(jwkSet.toJSONObject(false)); @@ -790,7 +790,7 @@ private static String mockedTrustAnchorEntityConfigurationC4() payload.put( "metadata", new JSONObject().put("federation_entity", trustAnchorMetadata)); - JSONObject trustMarksIssuers = new JSONObject() + JSONObject trustMarkIssuers = new JSONObject() .put( "https://www.spid.gov.it/certification/rp/public", JSONUtil.asJSONArray( "https://registry.spid.agid.gov.it", @@ -803,7 +803,7 @@ private static String mockedTrustAnchorEntityConfigurationC4() "https://sgd.aa.it/onboarding", JSONUtil.asJSONArray( "https://sgd.aa.it")); - payload.put("trust_marks_issuers", trustMarksIssuers); + payload.put("trust_mark_issuers", trustMarkIssuers); payload.put("constraints", new JSONObject().put("max_path_length", 1)); JSONObject jwks = new JSONObject(RPTestUtils.createJWKSet().toJSONObject(false)); diff --git a/starter-kit/src/test/java/it/spid/cie/oidc/model/TestTrustMark.java b/starter-kit/src/test/java/it/spid/cie/oidc/model/TestTrustMark.java index 6c93be3..1736848 100644 --- a/starter-kit/src/test/java/it/spid/cie/oidc/model/TestTrustMark.java +++ b/starter-kit/src/test/java/it/spid/cie/oidc/model/TestTrustMark.java @@ -297,7 +297,7 @@ private static String doMockedTrustAnchorEntityConfiguration( payload.put( "metadata", new JSONObject().put("federation_entity", trustAnchorMetadata)); - JSONObject trustMarksIssuers = new JSONObject() + JSONObject trustMarkIssuers = new JSONObject() .put( "https://www.spid.gov.it/certification/rp/public", JSONUtil.asJSONArray( "https://registry.spid.agid.gov.it", @@ -310,7 +310,7 @@ private static String doMockedTrustAnchorEntityConfiguration( "https://sgd.aa.it/onboarding", JSONUtil.asJSONArray( "https://sgd.aa.it")); - payload.put("trust_marks_issuers", trustMarksIssuers); + payload.put("trust_mark_issuers", trustMarkIssuers); payload.put("constraints", new JSONObject().put("max_path_length", 1)); return RPTestUtils.createJWS(payload, privateJwks); 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 9e365e4..6808685 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 @@ -322,7 +322,7 @@ public static String mockedTrustAnchorEntityConfiguration() throws Exception { payload.put( "metadata", new JSONObject().put("federation_entity", trustAnchorMetadata)); - JSONObject trustMarksIssuers = new JSONObject() + JSONObject trustMarkIssuers = new JSONObject() .put( "https://www.spid.gov.it/certification/rp/public", JSONUtil.asJSONArray( TM_ISSUER1, TM_ISSUER2)) @@ -333,7 +333,7 @@ public static String mockedTrustAnchorEntityConfiguration() throws Exception { "https://sgd.aa.it/onboarding", JSONUtil.asJSONArray( TM_ISSUER1)); - payload.put("trust_marks_issuers", trustMarksIssuers); + payload.put("trust_mark_issuers", trustMarkIssuers); payload.put("constraints", new JSONObject().put("max_path_length", 1)); JSONObject jwks = mockedTrustAnchorPrivateJWKS(); @@ -361,7 +361,7 @@ public static String mockedTrustMarkIssuer1EntityConfiguration() throws Exceptio payload.put( "metadata", new JSONObject().put("federation_entity", trustAnchorMetadata)); -// JSONObject trustMarksIssuers = new JSONObject() +// JSONObject trustMarkIssuers = new JSONObject() // .put( // "https://www.spid.gov.it/certification/rp/public", JSONUtil.asJSONArray( // TM_ISSUER1, TM_ISSUER2)) @@ -372,7 +372,7 @@ public static String mockedTrustMarkIssuer1EntityConfiguration() throws Exceptio // "https://sgd.aa.it/onboarding", JSONUtil.asJSONArray( // TM_ISSUER1)); // -// payload.put("trust_marks_issuers", trustMarksIssuers); +// payload.put("trust_mark_issuers", trustMarkIssuers); payload.put("constraints", new JSONObject().put("max_path_length", 1)); JSONObject jwks = mockedTrustAnchorPrivateJWKS();