JWKSet.java

  1. /*
  2.  * GovWay - A customizable API Gateway
  3.  * https://govway.org
  4.  *
  5.  * Copyright (c) 2005-2025 Link.it srl (https://link.it).
  6.  *
  7.  * This program is free software: you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 3, as published by
  9.  * the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  *
  19.  */

  20. package org.openspcoop2.utils.certificate;

  21. import java.util.ArrayList;
  22. import java.util.Iterator;
  23. import java.util.List;

  24. import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
  25. import org.apache.cxf.rs.security.jose.jwk.JsonWebKeys;
  26. import org.apache.cxf.rs.security.jose.jwk.JwkReaderWriter;
  27. import org.openspcoop2.utils.UtilsException;
  28. import org.openspcoop2.utils.UtilsRuntimeException;
  29. import org.openspcoop2.utils.json.JSONUtils;

  30. import com.fasterxml.jackson.databind.JsonNode;

  31. /**
  32.  * JWKSet
  33.  *
  34.  * @author Poli Andrea (apoli@link.it)
  35.  * @author $Author$
  36.  * @version $Rev$, $Date$
  37.  */
  38. public class JWKSet {

  39.     private JwkReaderWriter engineCxf = new JwkReaderWriter();
  40.     private String jwkSetJson;
  41.     private String jwkSetJsonPretty;
  42.     private JsonWebKeys jwkSetCxf;
  43.     private com.nimbusds.jose.jwk.JWKSet jwkSetNimbusds;
  44.     private JsonNode jwkSetNode;
  45.     private List<JWK> jwkSetList = new ArrayList<>();
  46.    
  47.     public JWKSet(String json) {
  48.         this.jwkSetJson = json;
  49.     }
  50.    
  51.     public JWKSet(JsonWebKeys jwk) {
  52.         this.jwkSetCxf = jwk;
  53.     }
  54.    
  55.     public JWKSet(com.nimbusds.jose.jwk.JWKSet jwk) {
  56.         this.jwkSetNimbusds = jwk;
  57.     }
  58.    
  59.     public JWKSet(List<JWK> list) {
  60.         this.jwkSetList = list;
  61.     }
  62.    
  63.     public JWKSet() {

  64.     }
  65.    
  66.    
  67.     public void addJwk(JWK jwk) {
  68.         this.jwkSetList.add(jwk);
  69.        
  70.         // forzo rebuild
  71.         this.jwkSetJson = null;
  72.         this.jwkSetJsonPretty = null;
  73.         this.jwkSetCxf = null;
  74.         this.jwkSetNimbusds = null;
  75.         this.jwkSetNode = null;
  76.                
  77.     }
  78.    
  79.     private synchronized void initJwks() throws UtilsException {
  80.         if(this.jwkSetList==null || this.jwkSetList.isEmpty()) {
  81.             if(this.getJsonWebKeys()==null && this.getJWKSet()==null){
  82.                 throw new UtilsException("JWK Set not defined");
  83.             }
  84.             if(this.jwkSetCxf!=null) {
  85.                 initJwksFromSetCxf();
  86.             }
  87.             else {
  88.                 initJwksFromSetNimbusds();
  89.             }
  90.         }
  91.     }
  92.     private synchronized void initJwksFromSetCxf() throws UtilsException {
  93.         try {
  94.             Iterator<JsonWebKey> it = this.jwkSetCxf.getKeys().iterator();
  95.             while (it.hasNext()) {
  96.                 JsonWebKey jsonWebKey = it.next();
  97.                 this.jwkSetList.add(new JWK(jsonWebKey));
  98.             }
  99.         }catch(Exception e) {
  100.             throw new UtilsException(e.getMessage(),e);
  101.         }
  102.     }
  103.     private synchronized void initJwksFromSetNimbusds() throws UtilsException {
  104.         try {
  105.             Iterator<com.nimbusds.jose.jwk.JWK> it = this.jwkSetNimbusds.getKeys().iterator();
  106.             while (it.hasNext()) {
  107.                 com.nimbusds.jose.jwk.JWK jwk = it.next();
  108.                 this.jwkSetList.add(new JWK(jwk));
  109.             }
  110.         }catch(Exception e) {
  111.             throw new UtilsException(e.getMessage(),e);
  112.         }
  113.     }
  114.     public List<JWK> getJwks() throws UtilsException {
  115.         if(this.jwkSetList==null || this.jwkSetList.isEmpty()) {
  116.             this.initJwks();
  117.         }
  118.         return this.jwkSetList;
  119.     }
  120.    
  121.    
  122.    
  123.     private synchronized void initCxf() throws UtilsException {
  124.         if(this.jwkSetCxf==null) {
  125.             if(this.jwkSetJson==null){
  126.                 throw new UtilsException("Json not defined");
  127.             }
  128.             try {
  129.                 this.jwkSetCxf = this.engineCxf.jsonToJwkSet(this.jwkSetJson);
  130.             }catch(Exception e) {
  131.                 /* Fix bug cxf che va in errore se il keystore รจ pretty print e la , tra una chiave e l'altra struttura json va a capo.
  132.                  * Esempio:
  133.                  * {
  134.                       "keys" : [
  135.                     {
  136.                       "kty" : "RSA",
  137.                       "e" : "AQAB",
  138.                       "kid" : "KID-ApplicativoBlockingIDA01",
  139.                       "n" : "8IYnrIeYyuCCZQJvdkxL5bD5-v-L2bwAgiz4ZMJPqWqhbgsGmneyaHQIKL-ihiKRgbDT02HIDlLeJp6uXCxRu6MYVEXkpuI1Kte2xqlGzw2F-WALNkoFgaXeIrEwIugj5eeiqqBbedZdQPr7YmXHiZOSztVsQSeyRTGhIfMtvrqKUa8R4U2gFAp5wo2cgCU2Dk1gJ_B2mooxgvewi2Ea2SSuuOAJThvAEwAk1cxXwZcxVqOAjzgeKe7kPs79VgCpnGuottrhqlLtT0hPpij2T1S_r2ENZrQ9ex4hkFF8q2EpxqveKcF5bmTaNS1ezjKCthJjmq1zu-zELLFAx4bY_w"
  140.                     }
  141.                     ,
  142.                     {
  143.                       "kty" : "RSA",
  144.                       "e" : "AQAB",
  145.                       "kid" : "KID-ExampleServer",
  146.                       "n" : "4OKbeAjhuWBnATnd2FjdvRAdyks05AnW5nYNRWVt2RIvBfPsASZD858hv_ts1W2uUN1EbJTSgQzgZskufBKz3KApI1Lq3F3IEH2jLBYGywpCbus6hHNCi8xN1OzRLEDp-uaZvIeP26RDjush53j9YFvVEI5Hic6thLT0zqtFhm-u1VtDH0uEZ_1S5CUspMYbZTOkl-PEz7Y77dIGk0vfhfJ3uW3g1khWQONVHA7X4XOZLKDo1rnQxzZv3l7r__h5GlHqZRopLBwqn6hDRyoeRzZfQtrl_fMp5Pgyg0Fi5hKI5o0YLnOhHzB_MJJrgoXOjirvoFBO-qkET-BAjU6BAQ"
  147.                     }
  148.                        ]
  149.                     }
  150.                  *  Produce il seguente errore: "String index out of range: 0"
  151.                  *
  152.                  **/
  153.                 if(e.getMessage()!=null && e.getMessage().contains("String index out of range")) {
  154.                     try {
  155.                         JSONUtils jsonUtils = JSONUtils.getInstance();
  156.                         JsonNode node = jsonUtils.getAsNode(this.jwkSetJson);
  157.                         String sNonPretty = jsonUtils.toString(node);
  158.                         this.jwkSetCxf = this.engineCxf.jsonToJwkSet(sNonPretty);
  159.                     }catch(Exception eCxf) {
  160.                         // rilancio eccezione originale
  161.                         throw e;
  162.                     }
  163.                 }
  164.             }
  165.         }
  166.     }
  167.     public JsonWebKeys getJsonWebKeys() throws UtilsException {
  168.         if(this.jwkSetCxf==null) {
  169.             this.initCxf();
  170.         }
  171.         return this.jwkSetCxf;
  172.     }
  173.    
  174.     private synchronized void initNimbusds() throws UtilsException {
  175.         if(this.jwkSetNimbusds==null) {
  176.             if(this.jwkSetJson==null){
  177.                 throw new UtilsException("Json not defined");
  178.             }
  179.             try {
  180.                 this.jwkSetNimbusds = com.nimbusds.jose.jwk.JWKSet.parse(this.jwkSetJson);
  181.             }catch(Exception e) {
  182.                 throw new UtilsException(e.getMessage(),e);
  183.             }
  184.         }
  185.     }
  186.     public com.nimbusds.jose.jwk.JWKSet getJWKSet() throws UtilsException {
  187.         if(this.jwkSetNimbusds==null) {
  188.             this.initNimbusds();
  189.         }
  190.         return this.jwkSetNimbusds;
  191.     }
  192.    
  193.     private synchronized void initJson() throws UtilsException {
  194.         if(this.jwkSetJson==null) {
  195.             if( (this.jwkSetList==null || this.jwkSetList.isEmpty()) && this.jwkSetCxf==null && this.jwkSetNimbusds==null){
  196.                 throw new UtilsException("JWK Set not defined");
  197.             }
  198.             if(this.jwkSetList!=null && !this.jwkSetList.isEmpty()) {
  199.                 initJsonFromJwkSetList();
  200.             }
  201.             else if(this.jwkSetCxf!=null) {
  202.                 initJsonFromJwkSetCxf();
  203.             }
  204.             else {
  205.                 initJsonFromJwkSetNimbusds();
  206.             }
  207.         }
  208.     }
  209.     private synchronized void initJsonFromJwkSetList() throws UtilsException {
  210.         List<com.nimbusds.jose.jwk.JWK> list = new ArrayList<>();
  211.         for (JWK jwkOp : this.jwkSetList) {
  212.             list.add(jwkOp.getJWK());
  213.         }
  214.         /** NON FUNZIONA
  215.         com.nimbusds.jose.jwk.JWKSet set = new com.nimbusds.jose.jwk.JWKSet(list);
  216.         this.jwkSetJson = set.toJSONObject().toString(); */
  217.         StringBuilder sb = new StringBuilder("{\"keys\":[");
  218.         boolean first = true;
  219.         for (JWK jwkOp : this.jwkSetList) {
  220.             if(!first) {
  221.                 sb.append(",");
  222.             }
  223.             sb.append(jwkOp.getJWK().toJSONString());
  224.             first = false;
  225.         }
  226.         sb.append("]}");
  227.         this.jwkSetJson = sb.toString();
  228.     }
  229.     private synchronized void initJsonFromJwkSetCxf() throws UtilsException {
  230.         try {
  231.             this.jwkSetJson = this.engineCxf.jwkSetToJson(this.jwkSetCxf);
  232.         }catch(Exception e) {
  233.             throw new UtilsException(e.getMessage(),e);
  234.         }
  235.     }
  236.     private synchronized void initJsonFromJwkSetNimbusds() throws UtilsException {
  237.         try {
  238.             this.jwkSetJson = this.jwkSetNimbusds.toString();
  239.         }catch(Exception e) {
  240.             throw new UtilsException(e.getMessage(),e);
  241.         }
  242.     }
  243.     public String getJson() throws UtilsException {
  244.         if(this.jwkSetJson==null) {
  245.             this.initJson();
  246.         }
  247.         return this.jwkSetJson;
  248.     }
  249.    
  250.     private synchronized void initJsonPretty() throws UtilsException {
  251.         if(this.jwkSetJsonPretty==null) {
  252.             try {
  253.                 if(this.jwkSetNode==null) {
  254.                     initNode();
  255.                 }
  256.                 this.jwkSetJsonPretty = JSONUtils.getInstance(true).toString(this.jwkSetNode);
  257.             }catch(Exception e) {
  258.                 throw new UtilsException(e.getMessage(),e);
  259.             }
  260.         }
  261.     }
  262.     public String getJsonPretty() throws UtilsException {
  263.         if(this.jwkSetJsonPretty==null) {
  264.             this.initJsonPretty();
  265.         }
  266.         return this.jwkSetJsonPretty;
  267.     }
  268.    
  269.     private synchronized void initNode() throws UtilsException {
  270.         if(this.jwkSetNode==null) {
  271.             try {
  272.                 if(this.jwkSetJson==null) {
  273.                     initJson();
  274.                 }
  275.                 this.jwkSetNode = JSONUtils.getInstance().getAsNode(this.jwkSetJson);
  276.             }catch(Exception e) {
  277.                 throw new UtilsException(e.getMessage(),e);
  278.             }
  279.         }
  280.     }
  281.     public JsonNode getNode() throws UtilsException {
  282.         if(this.jwkSetNode==null) {
  283.             this.initNode();
  284.         }
  285.         return this.jwkSetNode;
  286.     }

  287.     @Override
  288.     public String toString() {
  289.         try {
  290.             return this.getJsonPretty();
  291.         }catch(Exception e) {
  292.             throw new UtilsRuntimeException(e.getMessage(),e);
  293.         }
  294.     }
  295. }