diff --git a/GeneXusJWT/src/main/java/com/genexus/JWT/JWTCreator.java b/GeneXusJWT/src/main/java/com/genexus/JWT/JWTCreator.java index 513898e..de5d6aa 100644 --- a/GeneXusJWT/src/main/java/com/genexus/JWT/JWTCreator.java +++ b/GeneXusJWT/src/main/java/com/genexus/JWT/JWTCreator.java @@ -16,6 +16,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.genexus.JWT.claims.Claim; +import com.genexus.JWT.claims.HeaderParameters; import com.genexus.JWT.claims.PrivateClaims; import com.genexus.JWT.claims.PublicClaims; import com.genexus.JWT.claims.RegisteredClaim; @@ -52,6 +53,10 @@ public String doCreate(String algorithm, PrivateClaims privateClaims, JWTOptions return ""; } Builder tokenBuilder = JWT.create(); + if (!options.getHeaderParameters().isEmpty()) { + HeaderParameters parameters = options.getHeaderParameters(); + tokenBuilder.withHeader(parameters.getMap()); + } tokenBuilder = doBuildPayload(tokenBuilder, privateClaims, options); if (this.hasError()) { return ""; @@ -103,7 +108,8 @@ public boolean doVerify(String token, String expectedAlgorithm, PrivateClaims pr this.error.setError("JW005", e.getMessage()); return false; } - if (isRevoqued(decodedJWT, options) || !verifyPrivateClaims(decodedJWT, privateClaims, options)) { + if (isRevoqued(decodedJWT, options) || !verifyPrivateClaims(decodedJWT, privateClaims, options) + || !verifyHeader(decodedJWT, options)) { return false; } String algorithm = decodedJWT.getAlgorithm(); @@ -386,4 +392,54 @@ private int countingPrivateClaims(Map map, int counter) { return counter; } + private boolean verifyHeader(DecodedJWT decodedJWT, JWTOptions options) { + HeaderParameters parameters = options.getHeaderParameters(); + if (parameters.isEmpty()) { + return true; + } + + List allParms = parameters.getAll(); + if (allParms.size() + 2 != getHeaderClaimsNumber(decodedJWT)) { + return false; + } + Map map = parameters.getMap(); + for (String s : allParms) { + + if (decodedJWT.getHeaderClaim(s) == null) { + return false; + } + com.auth0.jwt.interfaces.Claim c = decodedJWT.getHeaderClaim(s); + String claimValue = null; + try { + claimValue = c.asString().trim(); + } catch (NullPointerException e) { + return false; + } + String optionsValue = ((String) map.get(s)).trim(); + if (!SecurityUtils.compareStrings(claimValue, optionsValue)) { + return false; + } + } + return true; + + } + + private int getHeaderClaimsNumber(DecodedJWT decodedJWT) { + String base64Part = decodedJWT.getHeader(); + byte[] base64Bytes = Base64.decodeBase64(base64Part); + EncodingUtil eu = new EncodingUtil(); + String plainTextPart = eu.getString(base64Bytes); + HashMap map = new HashMap(); + ObjectMapper mapper = new ObjectMapper(); + + try { + map = mapper.readValue(plainTextPart, new TypeReference>() { + }); + } catch (Exception e) { + return 0; + } + return map.size(); + + } + } diff --git a/GeneXusJWT/src/main/java/com/genexus/JWT/claims/HeaderParameters.java b/GeneXusJWT/src/main/java/com/genexus/JWT/claims/HeaderParameters.java new file mode 100644 index 0000000..3a1d288 --- /dev/null +++ b/GeneXusJWT/src/main/java/com/genexus/JWT/claims/HeaderParameters.java @@ -0,0 +1,41 @@ +package com.genexus.JWT.claims; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class HeaderParameters { + /* + * Cannot avoid typ=JWT because of RFC 7519 https://tools.ietf.org/html/rfc7519 + * https://github.com/auth0/java-jwt/issues/369 + */ + + private Map map; + + public HeaderParameters() { + map = new HashMap(); + } + + public void setParameter(String name, String value) { + map.put(name, value); + } + + public Map getMap() { + return this.map; + } + + public List getAll() { + return new ArrayList(map.keySet()); + } + + public boolean isEmpty() + { + if (getAll().size() == 0) + { + return true; + } + return false; + } + +} diff --git a/GeneXusJWT/src/main/java/com/genexus/commons/JWTOptions.java b/GeneXusJWT/src/main/java/com/genexus/commons/JWTOptions.java index 4d485a6..56cd107 100644 --- a/GeneXusJWT/src/main/java/com/genexus/commons/JWTOptions.java +++ b/GeneXusJWT/src/main/java/com/genexus/commons/JWTOptions.java @@ -2,6 +2,7 @@ import org.bouncycastle.util.encoders.Hex; +import com.genexus.JWT.claims.HeaderParameters; import com.genexus.JWT.claims.PublicClaims; import com.genexus.JWT.claims.RegisteredClaims; import com.genexus.JWT.utils.RevocationList; @@ -18,11 +19,13 @@ public class JWTOptions extends SecurityAPIObject { private RevocationList revocationList; private CertificateX509 certificate; private PrivateKeyManager privateKey; + private HeaderParameters parameters; public JWTOptions() { publicClaims = new PublicClaims(); registeredClaims = new RegisteredClaims(); revocationList = new RevocationList(); + parameters = new HeaderParameters(); } /******** EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/ @@ -70,6 +73,12 @@ public void addRevocationList(RevocationList revocationList) { public void deteleRevocationList() { this.revocationList = new RevocationList(); } + + public void addHeaderParameter(String name, String value) + { + this.parameters.setParameter(name, value); + } + /******** EXTERNAL OBJECT PUBLIC METHODS - END ********/ @@ -113,4 +122,9 @@ public CertificateX509 getCertificate() { public PrivateKeyManager getPrivateKey() { return this.privateKey; } + + public HeaderParameters getHeaderParameters() + { + return this.parameters; + } }