JwtHeaders.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.security;

  21. import java.net.URI;
  22. import java.security.cert.X509Certificate;
  23. import java.util.ArrayList;
  24. import java.util.HashMap;
  25. import java.util.Iterator;
  26. import java.util.List;

  27. import org.apache.cxf.common.util.Base64UrlUtility;
  28. import org.apache.cxf.rs.security.jose.common.KeyManagementUtils;
  29. import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
  30. import org.apache.cxf.rs.security.jose.jwk.JsonWebKeys;
  31. import org.apache.cxf.rs.security.jose.jwk.JwkUtils;
  32. import org.apache.cxf.rt.security.crypto.MessageDigestUtils;
  33. import org.openspcoop2.utils.UtilsException;

  34. /**
  35.  * JwtHeaders
  36.  *
  37.  * @author Poli Andrea (apoli@link.it)
  38.  * @author $Author$
  39.  * @version $Rev$, $Date$
  40.  */
  41. public class JwtHeaders {

  42.     public static final String JWT_HDR_ALG = "alg"; // (Algorithm) Header Parameter
  43.     public static final String JWT_HDR_JKU = "jku"; //  (JWK Set URL) Header Parameter
  44.     public static final String JWT_HDR_JWK = "jwk"; // (JSON Web Key) Header Parameter
  45.     public static final String JWT_HDR_KID = "kid"; // (Key ID) Header Parameter
  46.     public static final String JWT_HDR_X5U = "x5u"; // (X.509 URL) Header Parameter
  47.     public static final String JWT_HDR_X5C = "x5c"; // (X.509 Certificate Chain) Header Parameter
  48.     public static final String JWT_HDR_X5T = "x5t"; // (X.509 Certificate SHA-1 Thumbprint) Header Parameter
  49.     public static final String JWT_HDR_X5t_S256 = "x5t#S256"; // (X.509 Certificate SHA-256 Thumbprint) Header Parameter
  50.     public static final String JWT_HDR_TYP = "typ"; // (Type) Header Parameter
  51.     public static final String JWT_HDR_CTY = "cty"; // (Content Type) Header Parameter
  52.     public static final String JWT_HDR_CRIT = "crit"; // (Critical) Header Parameter
  53.     public static final String JWT_HDR_ENC = "enc"; // (Encryption Algorithm) Header Parameter [solo in jwe]
  54.     public static final String JWT_HDR_ZIP = "zip"; // (Compression Algorithm) Header Parameter [solo in jwe]
  55.      
  56.     private String type;
  57.     private String contentType;
  58.     private String kid;
  59.     private List<String> criticalHeaders = new ArrayList<>();
  60.     private URI x509Url;
  61.     private List<X509Certificate> x509c = new ArrayList<>(); // i certificati servono anche per sha1 e sha256, il field addX5C serve quindi per capire se poi far uscire anche X5C
  62.     private boolean addX5C = false;
  63.     boolean x509IncludeCertSha1 = false;
  64.     boolean x509IncludeCertSha256 = false;
  65.     private URI jwkUrl;
  66.     private JsonWebKey jwKey;
  67.     private HashMap<String, String> extensions = new HashMap<>();
  68.    
  69.     public void setType(String type) {
  70.         this.type = type;
  71.     }
  72.     public void setContentType(String contentType) {
  73.         this.contentType = contentType;
  74.     }
  75.     public String getKid() {
  76.         return this.kid;
  77.     }
  78.     public void addCriticalHeader(String hdr) {
  79.         this.criticalHeaders.add(hdr);
  80.     }
  81.     public void setX509Url(URI x509Url) {
  82.         this.x509Url = x509Url;
  83.     }
  84.     public void addX509cert(X509Certificate x509c) {
  85.         this.x509c.add(x509c);
  86.     }
  87.     public void setAddX5C(boolean addX5C) {
  88.         this.addX5C = addX5C;
  89.     }
  90.     public boolean isX509IncludeCertSha1() {
  91.         return this.x509IncludeCertSha1;
  92.     }
  93.     public boolean isX509IncludeCertSha256() {
  94.         return this.x509IncludeCertSha256;
  95.     }
  96.     public void setJwkUrl(URI jwkUrl) {
  97.         this.jwkUrl = jwkUrl;
  98.     }
  99.     public void setJwKey(JsonWebKey jwKey) {
  100.         this.jwKey = jwKey;
  101.     }
  102.     public void setJwKey(JsonWebKeys jsonWebKeys, String alias) throws UtilsException {
  103.         this.jwKey = JsonUtils.readKey(jsonWebKeys, alias);
  104.     }
  105.     public void addExtension(String hdr, String value) {
  106.         this.extensions.put(hdr, value);
  107.     }
  108.    
  109.     public String getType() {
  110.         return this.type;
  111.     }
  112.     public String getContentType() {
  113.         return this.contentType;
  114.     }
  115.     public void setKid(String kid) {
  116.         this.kid = kid;
  117.     }
  118.     public List<String> getCriticalHeaders() {
  119.         return this.criticalHeaders;
  120.     }
  121.     public URI getX509Url() {
  122.         return this.x509Url;
  123.     }
  124.     public boolean isAddX5C() {
  125.         return this.addX5C;
  126.     }
  127.     public List<X509Certificate> getX509c() {
  128.         return this.x509c;
  129.     }
  130.     public void setX509IncludeCertSha1(boolean includeCertSha1) {
  131.         this.x509IncludeCertSha1 = includeCertSha1;
  132.     }
  133.     public void setX509IncludeCertSha256(boolean includeCertSha256) {
  134.         this.x509IncludeCertSha256 = includeCertSha256;
  135.     }
  136.     public URI getJwkUrl() {
  137.         return this.jwkUrl;
  138.     }
  139.     public JsonWebKey getJwKey() {
  140.         return this.jwKey;
  141.     }
  142.     public HashMap<String, String> getExtensions() {
  143.         return this.extensions;
  144.     }
  145.    
  146.     public List<String> headers(){
  147.         List<String> list = new ArrayList<>();
  148.         if(this.type!=null) {
  149.             list.add(JWT_HDR_TYP);
  150.         }
  151.         if(this.contentType!=null) {
  152.             list.add(JWT_HDR_CTY);
  153.         }
  154.         if(this.kid!=null) {
  155.             list.add(JWT_HDR_KID);
  156.         }
  157.         if(this.criticalHeaders!=null && !this.criticalHeaders.isEmpty()) {
  158.             list.add(JWT_HDR_CRIT);
  159.         }
  160.         if(this.x509Url!=null) {
  161.             list.add(JWT_HDR_X5U);
  162.         }
  163.         if(this.x509c!=null && !this.x509c.isEmpty()) {
  164.             // fix: lo aggiungo solo se non c'è la url. Nell'oggetto JwtHreader il certificato ho dovuto mettercelo per creare i sha
  165.             //if(!list.contains(JWT_HDR_X5U)) {
  166.             // il fix era errato, aggiunto field apposito 'addX5C'
  167.             if(this.addX5C) {
  168.                 list.add(JWT_HDR_X5C);
  169.             }
  170.         }
  171.         if(this.x509IncludeCertSha1 && this.x509c!=null && !this.x509c.isEmpty()) {
  172.             list.add(JWT_HDR_X5T);
  173.         }
  174.         if(this.x509IncludeCertSha256) {
  175.             list.add(JWT_HDR_X5t_S256);
  176.         }
  177.         if(this.jwkUrl!=null) {
  178.             list.add(JWT_HDR_JKU);
  179.         }
  180.         if(this.jwKey!=null) {
  181.             list.add(JWT_HDR_JWK);
  182.         }
  183.         if(this.extensions!=null && !this.extensions.isEmpty()) {
  184.             Iterator<String> hdrIt = this.extensions.keySet().iterator();
  185.             while (hdrIt.hasNext()) {
  186.                 String hdr = (String) hdrIt.next();
  187.                 list.add(hdr);
  188.             }
  189.         }
  190.         return list;
  191.     }
  192.    
  193.     public void fillJwsHeaders(org.apache.cxf.rs.security.jose.common.JoseHeaders hdrs, boolean forceOverride, String algorithm) throws Exception {
  194.         if(this.type!=null) {
  195.             if(!hdrs.containsHeader(JWT_HDR_TYP) || forceOverride) {
  196.                 hdrs.setHeader(JWT_HDR_TYP, this.type);
  197.             }
  198.         }
  199.         if(this.contentType!=null) {
  200.             if(!hdrs.containsHeader(JWT_HDR_CTY) || forceOverride) {
  201.                 hdrs.setContentType(this.contentType);
  202.             }
  203.         }
  204.         if(this.kid!=null) {
  205.             if(!hdrs.containsHeader(JWT_HDR_KID) || forceOverride) {
  206.                 hdrs.setKeyId(this.kid);
  207.             }
  208.         }
  209.         if(this.criticalHeaders!=null && !this.criticalHeaders.isEmpty()) {
  210.             List<String> headers = new ArrayList<>();
  211.             if(hdrs.containsHeader(JWT_HDR_CRIT)) {
  212.                 headers = hdrs.getCritical();
  213.                 if(headers==null) {
  214.                     headers = new ArrayList<>();
  215.                 }
  216.             }
  217.             for (String ch : this.criticalHeaders) {
  218.                 if(headers.contains(ch)==false) {
  219.                     headers.add(ch);
  220.                 }
  221.             }
  222.             /*
  223.             StringBuilder bf = new StringBuilder();
  224.             for (String ch : headers) {
  225.                 if(bf.length()>0) {
  226.                     bf.append(",");
  227.                 }
  228.                 bf.append("\"").append(ch).append("\"");
  229.             }
  230.             hdrs.setHeader(JWT_HDR_CRIT, "["+bf.toString()+"]");*/
  231.             hdrs.setCritical(headers);
  232.         }
  233.         if(this.x509Url!=null) {
  234.             if(!hdrs.containsHeader(JWT_HDR_X5U) || forceOverride) {
  235.                 hdrs.setX509Url(this.x509Url.toString());
  236.             }
  237.         }
  238.         if(this.x509c!=null && !this.x509c.isEmpty()) {
  239.             if(!hdrs.containsHeader(JWT_HDR_X5C) || forceOverride) {
  240.                 // fix: lo aggiungo solo se non c'è la url. Nell'oggetto JwtHreader il certificato ho dovuto mettercelo per creare i sha
  241.                 //if(!hdrs.containsHeader(JWT_HDR_X5U)) {
  242.                 // il fix era errato, aggiunto field apposito 'addX5C'
  243.                 if(this.addX5C) {
  244.                     X509Certificate[] chain = this.x509c.toArray(new X509Certificate[1]);
  245.                     hdrs.setX509Chain(KeyManagementUtils.encodeX509CertificateChain(chain));
  246.                 }
  247.             }
  248.         }
  249.         if(this.x509IncludeCertSha1 && this.x509c!=null && !this.x509c.isEmpty()) {
  250.             if(!hdrs.containsHeader(JWT_HDR_X5T) || forceOverride) {
  251.                 X509Certificate[] chain = this.x509c.toArray(new X509Certificate[1]);
  252.                 byte[] digestB = MessageDigestUtils.createDigest(chain[0].getEncoded(), MessageDigestUtils.ALGO_SHA_1);
  253.                 String digest = Base64UrlUtility.encode(digestB);
  254.                 hdrs.setX509Thumbprint(digest);
  255.             }
  256.         }
  257.         if(this.x509IncludeCertSha256) {
  258.             if(!hdrs.containsHeader(JWT_HDR_X5t_S256) || forceOverride) {
  259.                 X509Certificate[] chain = this.x509c.toArray(new X509Certificate[1]);
  260.                 byte[] digestB = MessageDigestUtils.createDigest(chain[0].getEncoded(), MessageDigestUtils.ALGO_SHA_256);
  261.                 String digest = Base64UrlUtility.encode(digestB);
  262.                 hdrs.setX509ThumbprintSHA256(digest);
  263.             }
  264.         }
  265.         if(this.jwkUrl!=null) {
  266.             if(!hdrs.containsHeader(JWT_HDR_JKU) || forceOverride) {
  267.                 hdrs.setJsonWebKeysUrl(this.jwkUrl.toString());
  268.             }
  269.         }
  270.         if(this.jwKey!=null) {
  271.             if(!hdrs.containsHeader(JWT_HDR_JWK) || forceOverride) {
  272.                 JwkUtils.includeCertChain(this.jwKey, hdrs, algorithm);
  273.                 JwkUtils.includePublicKey(this.jwKey, hdrs, algorithm);
  274.             }
  275.         }
  276.         if(this.extensions!=null && !this.extensions.isEmpty()) {
  277.             Iterator<String> hdrIt = this.extensions.keySet().iterator();
  278.             while (hdrIt.hasNext()) {
  279.                 String hdr = (String) hdrIt.next();
  280.                 if(!hdrs.containsHeader(hdr) || forceOverride) {
  281.                     String value = this.extensions.get(hdr);
  282.                     hdrs.setHeader(hdr,value);
  283.                 }
  284.             }
  285.         }
  286.     }
  287.    
  288. }