From 2d150fccfbc1955b30daf25cd077058f0b865f7b Mon Sep 17 00:00:00 2001 From: sgrampone Date: Fri, 26 Jul 2024 16:23:16 -0300 Subject: [PATCH 01/21] GamUtils + tests --- README.md | 1 + gamutils/pom.xml | 63 ++++++++ .../main/java/com/genexus/gam/GamUtilsEO.java | 54 +++++++ .../genexus/gam/utils/CertificateUtil.java | 113 ++++++++++++++ .../main/java/com/genexus/gam/utils/Hash.java | 26 ++++ .../main/java/com/genexus/gam/utils/Jwk.java | 87 +++++++++++ .../main/java/com/genexus/gam/utils/Jwks.java | 34 +++++ .../main/java/com/genexus/gam/utils/Jwt.java | 55 +++++++ .../java/com/genexus/gam/utils/Random.java | 46 ++++++ .../gam/utils/test/CertificateTest.java | 80 ++++++++++ .../com/genexus/gam/utils/test/HashTest.java | 47 ++++++ .../com/genexus/gam/utils/test/JwkTest.java | 72 +++++++++ .../com/genexus/gam/utils/test/JwksTest.java | 41 +++++ .../com/genexus/gam/utils/test/JwtTest.java | 144 ++++++++++++++++++ .../genexus/gam/utils/test/RandomTest.java | 55 +++++++ .../test/resources/CryptographicHash.java | 38 +++++ .../RSA_sha256_2048/sha256_cert.cer | Bin 0 -> 1029 bytes .../RSA_sha256_2048/sha256_cert.crt | Bin 0 -> 1029 bytes .../RSA_sha256_2048/sha256_cert.jks | Bin 0 -> 2629 bytes .../RSA_sha256_2048/sha256_cert.key | 24 +++ .../RSA_sha256_2048/sha256_cert.p12 | Bin 0 -> 2629 bytes .../RSA_sha256_2048/sha256_cert.pem | 24 +++ .../RSA_sha256_2048/sha256_cert.pfx | Bin 0 -> 2629 bytes .../RSA_sha256_2048/sha256_cert.pkcs12 | Bin 0 -> 2629 bytes .../RSA_sha256_2048/sha256d_key.pem | 27 ++++ pom.xml | 1 + 26 files changed, 1032 insertions(+) create mode 100644 gamutils/pom.xml create mode 100644 gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java create mode 100644 gamutils/src/main/java/com/genexus/gam/utils/CertificateUtil.java create mode 100644 gamutils/src/main/java/com/genexus/gam/utils/Hash.java create mode 100644 gamutils/src/main/java/com/genexus/gam/utils/Jwk.java create mode 100644 gamutils/src/main/java/com/genexus/gam/utils/Jwks.java create mode 100644 gamutils/src/main/java/com/genexus/gam/utils/Jwt.java create mode 100644 gamutils/src/main/java/com/genexus/gam/utils/Random.java create mode 100644 gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java create mode 100644 gamutils/src/test/java/com/genexus/gam/utils/test/HashTest.java create mode 100644 gamutils/src/test/java/com/genexus/gam/utils/test/JwkTest.java create mode 100644 gamutils/src/test/java/com/genexus/gam/utils/test/JwksTest.java create mode 100644 gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java create mode 100644 gamutils/src/test/java/com/genexus/gam/utils/test/RandomTest.java create mode 100644 gamutils/src/test/java/com/genexus/gam/utils/test/resources/CryptographicHash.java create mode 100644 gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256_cert.cer create mode 100644 gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256_cert.crt create mode 100644 gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256_cert.jks create mode 100644 gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256_cert.key create mode 100644 gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256_cert.p12 create mode 100644 gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256_cert.pem create mode 100644 gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256_cert.pfx create mode 100644 gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256_cert.pkcs12 create mode 100644 gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256d_key.pem diff --git a/README.md b/README.md index 42ff396be..f2e9cfe60 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ These are the source of the GeneXus Standard Classes for Java, valid since GeneX | gxexternalproviders | Implements service provider for IBM Cloud, Google, Azure, Amazon | gxgeospatial | Geography data type implementation | gxodata | OData access +| gamutils | GAM external object with utilities The dependencies between the projects are specified in each pom.xml within their directory. diff --git a/gamutils/pom.xml b/gamutils/pom.xml new file mode 100644 index 000000000..872c585b8 --- /dev/null +++ b/gamutils/pom.xml @@ -0,0 +1,63 @@ + + + 4.0.0 + + + com.genexus + parent + ${revision}${changelist} + + + gamutils + GAM Utils EO + + + UTF-8 + + + + + ${project.groupId} + gxcommon + ${project.version} + + + com.nimbusds + nimbus-jose-jwt + 9.37.3 + + + org.bouncycastle + bcprov-jdk18on + 1.78.1 + + + org.bouncycastle + bcpkix-jdk18on + 1.78.1 + + + commons-codec + commons-codec + 1.15 + test + + + + + gamutils + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 1.8 + 1.8 + + + + + + \ No newline at end of file diff --git a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java new file mode 100644 index 000000000..d9eff0959 --- /dev/null +++ b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java @@ -0,0 +1,54 @@ +package com.genexus.gam; + +import com.genexus.gam.utils.*; + +public class GamUtilsEO { + + /********EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/ + + //**HASH**// + public static String sha512(String plainText) { + return Hash.sha512(plainText); + } + + //**RANDOM**// + public static String randomAlphanumeric(int length) { + return Random.randomAlphanumeric(length); + } + + public static String randomNumeric(int length) { + return Random.randomNumeric(length); + } + + + //**JWK**// + + public static String generateKeyPair() { + return Jwk.generateKeyPair(); + } + + public static String getPublicJwk(String jwkString) { + return Jwk.getPublic(jwkString); + } + + public static boolean jwk_verifyJWT(String jwkString, String token) { + return Jwk.verifyJWT(jwkString, token); + } + + public static String jwk_createJwt(String jwkString, String payload, String header) { + return Jwk.createJwt(jwkString, payload, header); + } + + //**JWKS**// + + public static boolean jwks_verifyJWT(String jwksString, String token, String kid) { + return Jwks.verifyJWT(jwksString, token, kid); + } + + //**JWT**// + public static boolean verifyJWTWithFile(String path, String alias, String password, String token) { + return Jwt.verify(path, alias, password, token); + } + + /********EXTERNAL OBJECT PUBLIC METHODS - END ********/ +} diff --git a/gamutils/src/main/java/com/genexus/gam/utils/CertificateUtil.java b/gamutils/src/main/java/com/genexus/gam/utils/CertificateUtil.java new file mode 100644 index 000000000..ee290d642 --- /dev/null +++ b/gamutils/src/main/java/com/genexus/gam/utils/CertificateUtil.java @@ -0,0 +1,113 @@ +package com.genexus.gam.utils; + +import com.genexus.diagnostics.core.ILogger; +import com.genexus.diagnostics.core.LogManager; +import org.apache.commons.io.FilenameUtils; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory; +import org.bouncycastle.openssl.PEMParser; + +import java.io.*; +import java.security.KeyStore; +import java.security.cert.X509Certificate; + +public enum CertificateUtil { + + crt, cer, pfx, jks, pkcs12, p12, pem, key; + + public static final ILogger logger = LogManager.getLogger(CertificateUtil.class); + + public static CertificateUtil value(String ext) { + switch (ext.toLowerCase().trim()) { + case "crt": + return crt; + case "cer": + return cer; + case "pfx": + return pfx; + case "jks": + return jks; + case "pkcs12": + return pkcs12; + case "p12": + return p12; + case "pem": + return pem; + case "key": + return key; + default: + logger.error("Invalid certificate file extension"); + return null; + } + } + + public static X509Certificate getCertificate(String path, String alias, String password) { + CertificateUtil ext = CertificateUtil.value(FilenameUtils.getExtension(path)); + if (ext == null) { + logger.error("Error reading certificate path"); + return null; + } + switch (ext) { + case crt: + case cer: + return loadFromDer(path); + case pfx: + case jks: + case pkcs12: + case p12: + return loadFromPkcs12(path, alias, password); + case pem: + case key: + return loadFromPkcs8(path); + default: + logger.error("Invalid certificate file extension"); + return null; + } + } + + private static X509Certificate loadFromPkcs8(String path) { + try (FileReader privateKeyReader = new FileReader(new File(path))) { + try (PEMParser parser = new PEMParser(privateKeyReader)) { + Object obj = parser.readObject(); + if (obj instanceof X509CertificateHolder) { + X509CertificateHolder x509 = (X509CertificateHolder) obj; + try (InputStream in = new ByteArrayInputStream(x509.getEncoded())) { + CertificateFactory certFactory = new CertificateFactory(); + return (X509Certificate) certFactory.engineGenerateCertificate(in); + } + } else { + logger.error("Error reading certificate"); + return null; + } + } + } catch (Exception e) { + logger.error("loadFromPem", e); + return null; + } + } + + private static X509Certificate loadFromPkcs12(String path, String alias, String password) { + try (FileInputStream inStream = new FileInputStream(path)) { + KeyStore ks = KeyStore.getInstance("PKCS12"); + ks.load(inStream, password.toCharArray()); + if (alias.equals("") || alias.isEmpty()) { + return (X509Certificate) ks.getCertificate(ks.aliases().nextElement()); + } else { + return (X509Certificate) ks.getCertificate(alias); + } + } catch (Exception e) { + logger.error("loadFromPkcs12", e); + return null; + } + } + + private static X509Certificate loadFromDer(String path) { + try (FileInputStream inStream = new FileInputStream(path)) { + CertificateFactory cf = new CertificateFactory(); + return (X509Certificate) cf.engineGenerateCertificate(inStream); + } catch (Exception e) { + logger.error("loadFromDer", e); + return null; + } + } +} diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Hash.java b/gamutils/src/main/java/com/genexus/gam/utils/Hash.java new file mode 100644 index 000000000..157f37c56 --- /dev/null +++ b/gamutils/src/main/java/com/genexus/gam/utils/Hash.java @@ -0,0 +1,26 @@ +package com.genexus.gam.utils; + +import com.genexus.diagnostics.core.ILogger; +import com.genexus.diagnostics.core.LogManager; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.util.encoders.Base64; + +import java.nio.charset.StandardCharsets; + +public class Hash { + public static final ILogger logger = LogManager.getLogger(Hash.class); + + public static String sha512(String plainText) { + if (plainText.isEmpty()) { + logger.error("sha512 plainText is empty"); + return ""; + } + byte[] inputBytes = plainText.getBytes(StandardCharsets.UTF_8); + Digest alg = new SHA512Digest(); + byte[] retValue = new byte[alg.getDigestSize()]; + alg.update(inputBytes, 0, inputBytes.length); + alg.doFinal(retValue, 0); + return Base64.toBase64String(retValue); + } +} \ No newline at end of file diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Jwk.java b/gamutils/src/main/java/com/genexus/gam/utils/Jwk.java new file mode 100644 index 000000000..26f53cabc --- /dev/null +++ b/gamutils/src/main/java/com/genexus/gam/utils/Jwk.java @@ -0,0 +1,87 @@ +package com.genexus.gam.utils; + +import com.genexus.diagnostics.core.ILogger; +import com.genexus.diagnostics.core.LogManager; +import com.nimbusds.jose.Algorithm; +import com.nimbusds.jose.jwk.JWK; +import com.nimbusds.jose.jwk.KeyUse; +import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; + +import java.util.UUID; + +public class Jwk { + + public static final ILogger logger = LogManager.getLogger(Jwk.class); + + public static String generateKeyPair() { + try { + String kid = UUID.randomUUID().toString(); + RSAKey key = new RSAKeyGenerator(2048) + .keyUse(KeyUse.SIGNATURE) + .keyID(kid) + .algorithm(Algorithm.parse("RS256")) + .generate(); + return key.toString(); + + } catch (Exception e) { + logger.error("generateKeyPair", e); + return ""; + } + } + + public static String getPublic(String jwkString) { + if (jwkString.isEmpty()) { + logger.error("getPublic jwkString parameter is empty"); + return ""; + } + try { + JWK jwk = JWK.parse(jwkString); + return jwk.toPublicJWK().toString(); + } catch (Exception e) { + logger.error("getPublic", e); + return ""; + } + } + + public static boolean verifyJWT(String jwkString, String token) { + if (jwkString.isEmpty()) { + logger.error("verifyJWT jwkString parameter is empty"); + return false; + } + if (token.isEmpty()) { + logger.error("verifyJWT token parameter is empty"); + return false; + } + try { + JWK jwk = JWK.parse(jwkString); + return Jwt.verify(jwk.toRSAKey().toRSAPublicKey(), token); + } catch (Exception e) { + logger.error("verifyJWT", e); + return false; + } + + } + + public static String createJwt(String jwkString, String payload, String header) { + if (jwkString.isEmpty()) { + logger.error("createJwt jwkString parameter is empty"); + return ""; + } + if (payload.isEmpty()) { + logger.error("createJwt payload parameter is empty"); + return ""; + } + if (header.isEmpty()) { + logger.error("createJwt header parameter is empty"); + return ""; + } + try { + JWK jwk = JWK.parse(jwkString); + return Jwt.create(jwk.toRSAKey().toRSAPrivateKey(), payload, header); + } catch (Exception e) { + logger.error("createJwt", e); + return ""; + } + } +} diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Jwks.java b/gamutils/src/main/java/com/genexus/gam/utils/Jwks.java new file mode 100644 index 000000000..e7ea68cc3 --- /dev/null +++ b/gamutils/src/main/java/com/genexus/gam/utils/Jwks.java @@ -0,0 +1,34 @@ +package com.genexus.gam.utils; + +import com.genexus.diagnostics.core.ILogger; +import com.genexus.diagnostics.core.LogManager; +import com.nimbusds.jose.jwk.JWK; +import com.nimbusds.jose.jwk.JWKSet; + +public class Jwks { + + public static final ILogger logger = LogManager.getLogger(Jwks.class); + + public static boolean verifyJWT(String jwksString, String token, String kid) { + if (jwksString.isEmpty()) { + logger.error("verifyJWT jwksString parameter is empty"); + return false; + } + if (token.isEmpty()) { + logger.error("verifyJWT token parameter is empty"); + return false; + } + if (kid.isEmpty()) { + logger.error("verifyJWT kid parameter is empty"); + return false; + } + try { + JWKSet set = JWKSet.parse(jwksString); + JWK jwk = set.getKeyByKeyId(kid); + return Jwt.verify(jwk.toRSAKey().toRSAPublicKey(), token); + } catch (Exception e) { + logger.error("verifyJWT", e); + return false; + } + } +} diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Jwt.java b/gamutils/src/main/java/com/genexus/gam/utils/Jwt.java new file mode 100644 index 000000000..d989c098a --- /dev/null +++ b/gamutils/src/main/java/com/genexus/gam/utils/Jwt.java @@ -0,0 +1,55 @@ +package com.genexus.gam.utils; + +import com.genexus.diagnostics.core.ILogger; +import com.genexus.diagnostics.core.LogManager; +import com.nimbusds.jose.JWSHeader; +import com.nimbusds.jose.JWSVerifier; +import com.nimbusds.jose.crypto.RSASSASigner; +import com.nimbusds.jose.crypto.RSASSAVerifier; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; +import org.apache.commons.io.FilenameUtils; + +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +public class Jwt { + + public static final ILogger logger = LogManager.getLogger(Jwt.class); + + /******** EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/ + + public static boolean verify(RSAPublicKey publicKey, String token) { + try { + SignedJWT signedJWT = SignedJWT.parse(token); + JWSVerifier verifier = new RSASSAVerifier(publicKey); + return signedJWT.verify(verifier); + } catch (Exception e) { + logger.error("verify", e); + return false; + } + } + + public static String create(RSAPrivateKey privateKey, String payload, String header) { + try { + SignedJWT signedJWT = new SignedJWT(JWSHeader.parse(header), JWTClaimsSet.parse(payload)); + signedJWT.sign(new RSASSASigner(privateKey)); + return signedJWT.serialize(); + } catch (Exception e) { + logger.error("create", e); + return ""; + } + } + + public static boolean verify(String path, String alias, String password, String token) { + return verify((RSAPublicKey) CertificateUtil.getCertificate(path, alias, password).getPublicKey(), token); + } + + /******** EXTERNAL OBJECT PUBLIC METHODS - END ********/ + + + private static boolean extensionIs(String stringPath, String extension) { + return extension.equalsIgnoreCase(FilenameUtils.getExtension(stringPath)); + } + +} diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Random.java b/gamutils/src/main/java/com/genexus/gam/utils/Random.java new file mode 100644 index 000000000..ffa67c4f1 --- /dev/null +++ b/gamutils/src/main/java/com/genexus/gam/utils/Random.java @@ -0,0 +1,46 @@ +package com.genexus.gam.utils; + +import com.genexus.diagnostics.core.ILogger; +import com.genexus.diagnostics.core.LogManager; + +import java.security.SecureRandom; + +public class Random { + + public static final ILogger logger = LogManager.getLogger(Random.class); + + private static SecureRandom instanceRandom() { + try { + return new SecureRandom(); + } catch (Exception e) { + logger.error("instanceRandom", e); + return null; + } + } + + public static String randomAlphanumeric(int length) { + SecureRandom random = instanceRandom(); + if (random == null) { + logger.error("randomAlphanumeric SecureRandom is null"); + return ""; + } + String characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + StringBuilder sb = new StringBuilder(length); + for (int i = 0; i < length; i++) + sb.append(characters.charAt(random.nextInt(characters.length()))); + return sb.toString(); + } + + public static String randomNumeric(int length) { + SecureRandom random = instanceRandom(); + if (random == null) { + logger.error("randomNumeric SecureRandom is null"); + return ""; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + sb.append(random.nextInt(10)); + } + return sb.toString(); + } +} diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java new file mode 100644 index 000000000..3cb0c8d0a --- /dev/null +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java @@ -0,0 +1,80 @@ +package com.genexus.gam.utils.test; + +import com.genexus.gam.utils.CertificateUtil; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.security.cert.X509Certificate; + +public class CertificateTest { + + private static String resources; + private static String path_RSA_sha256_2048; + private static String alias; + private static String password; + + @BeforeClass + public static void setUp() { + resources = System.getProperty("user.dir").concat("/src/test/resources"); + path_RSA_sha256_2048 = resources.concat("/dummycerts/RSA_sha256_2048/"); + alias = "1"; + password = "dummy"; + } + + @Test + public void testLoadCrt() { + X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.crt", "", ""); + Assert.assertNotNull("testLoadCrt", cert); + } + + @Test + public void testLoadCer() { + X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.cer", "", ""); + Assert.assertNotNull("testLoadCer", cert); + } + + @Test + public void testLoadPfx() { + X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.pfx", alias, password); + Assert.assertNotNull("testLoadPfx", cert); + cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.pfx", "", password); + Assert.assertNotNull("testLoadPfx empty alias", cert); + } + + @Test + public void testLoadJks() { + X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.jks", alias, password); + Assert.assertNotNull("testLoadJks", cert); + X509Certificate cert1 = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.jks", "", password); + Assert.assertNotNull("testLoadJks empty alias", cert1); + } + + @Test + public void testLoadPkcs12() { + X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.pkcs12", alias, password); + Assert.assertNotNull("testLoadPkcs12", cert); + cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.pkcs12", "", password); + Assert.assertNotNull("testLoadPkcs12 empty alias", cert); + } + + @Test + public void testLoadP12() { + X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password); + Assert.assertNotNull("testLoadP12", cert); + cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.p12", "", password); + Assert.assertNotNull("testLoadP12 empty alias", cert); + } + + @Test + public void testLoadPem() { + X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.pem", "", ""); + Assert.assertNotNull("testLoadPem", cert); + } + + @Test + public void testLoadKey() { + X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.Key", "", ""); + Assert.assertNotNull("testLoadKey", cert); + } +} diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/HashTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/HashTest.java new file mode 100644 index 000000000..9d4cac171 --- /dev/null +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/HashTest.java @@ -0,0 +1,47 @@ +package com.genexus.gam.utils.test; + +import com.genexus.gam.GamUtilsEO; +import com.genexus.gam.utils.Random; +import com.genexus.gam.utils.test.resources.CryptographicHash; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class HashTest { + + private static String one; + private static String two; + private static String three; + private static String four; + private static String five; + + private static CryptographicHash cryptographicHash; + + @BeforeClass + public static void setUp() { + one = "one"; + two = "two"; + three = "three"; + four = "four"; + five = "five"; + cryptographicHash = new CryptographicHash("SHA-512"); + } + + @Test + public void testSha512() { + Assert.assertEquals("one: ", cryptographicHash.ComputeHash(one), GamUtilsEO.sha512(one)); + Assert.assertEquals("two: ", cryptographicHash.ComputeHash(two), GamUtilsEO.sha512(two)); + Assert.assertEquals("three: ", cryptographicHash.ComputeHash(three), GamUtilsEO.sha512(three)); + Assert.assertEquals("four: ", cryptographicHash.ComputeHash(four), GamUtilsEO.sha512(four)); + Assert.assertEquals("five: ", cryptographicHash.ComputeHash(five), GamUtilsEO.sha512(five)); + } + + @Test + public void testSha512Random() { + for (int i = 0; i < 100; i++) { + String value = Random.randomAlphanumeric(15); + Assert.assertEquals("random sha512 ", cryptographicHash.ComputeHash(value), GamUtilsEO.sha512(value)); + } + } + +} \ No newline at end of file diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/JwkTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/JwkTest.java new file mode 100644 index 000000000..6870b8d06 --- /dev/null +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/JwkTest.java @@ -0,0 +1,72 @@ +package com.genexus.gam.utils.test; + +import com.genexus.gam.GamUtilsEO; +import com.nimbusds.jose.jwk.JWKSet; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.text.ParseException; + +public class JwkTest { + + private static String testJWK; + private static String header; + private static String payload; + + @BeforeClass + public static void setUp() { + testJWK = "{\"p\":\"2XZj5mZxLJlFjN0rK45gg25TtaDUrJ38-EK4F6n60X13Vb4oSeOUNWr7w1S2ibh7RFD687lKY588APrXK1zF33Ape3pRDz3JFZdPx5K_g_hK-ZlLNlHzXTk0okWqIszKdi2v_RLH-zow4GE-rwtW-bKDj3pdKB0_KWafhIv7X5c\",\"kty\":\"RSA\",\"q\":\"1ZsAPTJAcVLDVNFa_cNjzg0NS9DZZYsga22ESKPXy_pPkH0oOzlRm40BcYxiPR2yVDx0Ya7x_ekXQ9K-pKBE_U0YBE2PR6rDUV6Vr21O9BNuWUNXCg_VYosmyVF4hEG0itJty7OYXZPRCr9hAWRl7DjqGKZ1Y5wnaNMCR4gGuss\",\"d\":\"VxkWReeOVfMKlbi2Grf_XIddyMzZ0oid5BRjagXYnmtjxlddcIUrS0vJGPqSSbtyDN7-gPB98rSsJfzDBx3tbN9Vjr6vCs3pk_mi6xnCA1iKbIvW3wM3s4rP_6vCMBdwgSxIHufpLsmB9esPBuwYpOdEXJvRk_F6swSR6J6gBcNR3uL8Ht0OxtfiDP0X3C2aHe5HM9jkLlrqjcNWZDu1dXnDGh2fILF5lAPI7qssYuZzddOE5I7GMh3DuwfQ73W3ITyiezELJMnDKaEQUJAAEDWoqcGCGB14jDJwyKSNROouQtby_RP2uM-IO3_Hq1-u2Wu1QCXNK3R17NVeV_ktZw\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"c22bd870-634c-4860-9ccf-e38eca0b315b\",\"qi\":\"j5iACnxbBCPfPIv-QcGID0xLFWZAN7wU9t3B_16M-axl8OOQ0ll4ZjQ4hYmw_eYOk9TY7HbzR3SqfLoCh_As5QFvZhO1E_9JHw2IXDBBbkXY5m3vCGtrUwQXPX83nIHlVk6pJh6d5A3tfLm5ECz0nkiYbGdmtISsMiR-zfVryng\",\"dp\":\"prU01o8YGcmSYO-4RZbLdFZiw-18vKwNH0D-od2EU47sqgWyGxrlJqJSSScrHJ8ZmIDAMZGNbpvGwzWJOEvRwX3ZvzhA5f9GpU-vMF7WhNQWngwfdZATkhblu7TOPgli-IAD123Lc1Pj3k-OX2DBF4D7jEWRHsx0_EcY6OLrHRc\",\"alg\":\"RS256\",\"dq\":\"F6f03NIl5Ob_jvMompX7BaTYZh8ZFG_WBU-5qLnMemCcUyopPHXandl94W9kqdQSHdYcJX1Ue4RG-VHrnxvIyCyzjjZwucUloGtTNHxslAda3zPf_dNHFITIpN8K88q7DezEEB0xsJtgOUp8mcTerMyY0GYO9hsjGi7UP8vGwwU\",\"n\":\"tXMsASuh2-d6MJWifChlbsGKpcMYJtpczMeMdtZHdZgPBR-y2obZMOVjiuVOciU6bV8BtmLjc1IF1xENfL0LFgO9G9QvUyFfLHIhZR7c-NsELe5tC0aH_tDqYtjDTb-o9s6FZREFTrFy4R8jc6ZmfHtUPpzrv1SC3-cr1-sCi9TXlUtHRmYOLDbJFqriuRMhWxd7iPqeVac7tqGWCa_ALDERjDaZa0TLLLEbO6EubiLfk5lavO0jWOw9dxsvYouV0JGbxeczyevis5vC3XD3_yQJVC-r37lNDRiMbDD8hclMa75HXYJp7LNvScB5K6YERzfSullL7DF2q09dGVKCvQ\"}"; + header = "{\n" + + " \"alg\": \"RS256\",\n" + + " \"kid\": \"c22bd870-634c-4860-9ccf-e38eca0b315b\",\n" + + " \"typ\": \"JWT\"\n" + + "}"; + payload = "{\n" + + " \"sub\": \"1234567890\",\n" + + " \"name\": \"John Doe\",\n" + + " \"iat\": 1516239022\n" + + "}"; + } + + @Test + public void testGenerateKeyPair() { + String jwk = GamUtilsEO.generateKeyPair(); + Assert.assertFalse("Generate key pair jwk", jwk.isEmpty()); + } + + @Test + public void testPublicJwk() { + String jwk = GamUtilsEO.generateKeyPair(); + String public_jwk = GamUtilsEO.getPublicJwk(jwk); + String public_jwks = "{\"keys\": [" + public_jwk + "]}"; + try { + JWKSet jwks = JWKSet.parse(public_jwks).toPublicJWKSet(); + Assert.assertNotNull("To public JWK fail", jwks); + } catch (ParseException e) { + Assert.fail("Exception on testPublicJwk" + e.getMessage()); + } + } + + @Test + public void testCreateJwt() { + String jwt = GamUtilsEO.jwk_createJwt(testJWK, payload, header); + Assert.assertNotNull("testCreateJwt fail", jwt); + } + + @Test + public void testVerifyJwt() { + String jwt = GamUtilsEO.jwk_createJwt(testJWK, payload, header); + boolean result = GamUtilsEO.jwk_verifyJWT(testJWK, jwt); + Assert.assertTrue("testVerifyJwt fail", result); + } + + @Test + public void testVerifyJwt_wrong() { + String jwk = GamUtilsEO.generateKeyPair(); + String jwt = GamUtilsEO.jwk_createJwt(jwk, payload, header); + boolean result = GamUtilsEO.jwk_verifyJWT(testJWK, jwt); + Assert.assertFalse("testVerifyJwt_wrong fail", result); + } + +} diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/JwksTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/JwksTest.java new file mode 100644 index 000000000..7c611304a --- /dev/null +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/JwksTest.java @@ -0,0 +1,41 @@ +package com.genexus.gam.utils.test; + +import com.genexus.gam.GamUtilsEO; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class JwksTest { + + private static String testJWKs; + private static String testJWK; + private static String header; + private static String payload; + private static String kid; + + @BeforeClass + public static void setUp() { + testJWK = "{\"p\":\"2XZj5mZxLJlFjN0rK45gg25TtaDUrJ38-EK4F6n60X13Vb4oSeOUNWr7w1S2ibh7RFD687lKY588APrXK1zF33Ape3pRDz3JFZdPx5K_g_hK-ZlLNlHzXTk0okWqIszKdi2v_RLH-zow4GE-rwtW-bKDj3pdKB0_KWafhIv7X5c\",\"kty\":\"RSA\",\"q\":\"1ZsAPTJAcVLDVNFa_cNjzg0NS9DZZYsga22ESKPXy_pPkH0oOzlRm40BcYxiPR2yVDx0Ya7x_ekXQ9K-pKBE_U0YBE2PR6rDUV6Vr21O9BNuWUNXCg_VYosmyVF4hEG0itJty7OYXZPRCr9hAWRl7DjqGKZ1Y5wnaNMCR4gGuss\",\"d\":\"VxkWReeOVfMKlbi2Grf_XIddyMzZ0oid5BRjagXYnmtjxlddcIUrS0vJGPqSSbtyDN7-gPB98rSsJfzDBx3tbN9Vjr6vCs3pk_mi6xnCA1iKbIvW3wM3s4rP_6vCMBdwgSxIHufpLsmB9esPBuwYpOdEXJvRk_F6swSR6J6gBcNR3uL8Ht0OxtfiDP0X3C2aHe5HM9jkLlrqjcNWZDu1dXnDGh2fILF5lAPI7qssYuZzddOE5I7GMh3DuwfQ73W3ITyiezELJMnDKaEQUJAAEDWoqcGCGB14jDJwyKSNROouQtby_RP2uM-IO3_Hq1-u2Wu1QCXNK3R17NVeV_ktZw\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"c22bd870-634c-4860-9ccf-e38eca0b315b\",\"qi\":\"j5iACnxbBCPfPIv-QcGID0xLFWZAN7wU9t3B_16M-axl8OOQ0ll4ZjQ4hYmw_eYOk9TY7HbzR3SqfLoCh_As5QFvZhO1E_9JHw2IXDBBbkXY5m3vCGtrUwQXPX83nIHlVk6pJh6d5A3tfLm5ECz0nkiYbGdmtISsMiR-zfVryng\",\"dp\":\"prU01o8YGcmSYO-4RZbLdFZiw-18vKwNH0D-od2EU47sqgWyGxrlJqJSSScrHJ8ZmIDAMZGNbpvGwzWJOEvRwX3ZvzhA5f9GpU-vMF7WhNQWngwfdZATkhblu7TOPgli-IAD123Lc1Pj3k-OX2DBF4D7jEWRHsx0_EcY6OLrHRc\",\"alg\":\"RS256\",\"dq\":\"F6f03NIl5Ob_jvMompX7BaTYZh8ZFG_WBU-5qLnMemCcUyopPHXandl94W9kqdQSHdYcJX1Ue4RG-VHrnxvIyCyzjjZwucUloGtTNHxslAda3zPf_dNHFITIpN8K88q7DezEEB0xsJtgOUp8mcTerMyY0GYO9hsjGi7UP8vGwwU\",\"n\":\"tXMsASuh2-d6MJWifChlbsGKpcMYJtpczMeMdtZHdZgPBR-y2obZMOVjiuVOciU6bV8BtmLjc1IF1xENfL0LFgO9G9QvUyFfLHIhZR7c-NsELe5tC0aH_tDqYtjDTb-o9s6FZREFTrFy4R8jc6ZmfHtUPpzrv1SC3-cr1-sCi9TXlUtHRmYOLDbJFqriuRMhWxd7iPqeVac7tqGWCa_ALDERjDaZa0TLLLEbO6EubiLfk5lavO0jWOw9dxsvYouV0JGbxeczyevis5vC3XD3_yQJVC-r37lNDRiMbDD8hclMa75HXYJp7LNvScB5K6YERzfSullL7DF2q09dGVKCvQ\"}"; + String public_jwk = GamUtilsEO.getPublicJwk(testJWK); + testJWKs = "{\"keys\": [" + public_jwk + "]}"; + header = "{\n" + + " \"alg\": \"RS256\",\n" + + " \"kid\": \"c22bd870-634c-4860-9ccf-e38eca0b315b\",\n" + + " \"typ\": \"JWT\"\n" + + "}"; + payload = "{\n" + + " \"sub\": \"1234567890\",\n" + + " \"name\": \"John Doe\",\n" + + " \"iat\": 1516239022\n" + + "}"; + kid = "c22bd870-634c-4860-9ccf-e38eca0b315b"; + } + + @Test + public void testverifyJWT() { + String jwt = GamUtilsEO.jwk_createJwt(testJWK, payload, header); + boolean result = GamUtilsEO.jwks_verifyJWT(testJWKs, jwt, kid); + Assert.assertTrue("testverifyJWT fail ", result); + } + +} diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java new file mode 100644 index 000000000..7a1d6721a --- /dev/null +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java @@ -0,0 +1,144 @@ +package com.genexus.gam.utils.test; + +import com.genexus.gam.GamUtilsEO; +import com.genexus.gam.utils.Jwt; +import com.nimbusds.jose.Algorithm; +import com.nimbusds.jose.jwk.KeyUse; +import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.openssl.PEMKeyPair; +import org.bouncycastle.openssl.PEMParser; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.FileReader; +import java.security.KeyFactory; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.UUID; + +public class JwtTest { + + private static String resources; + private static String header; + private static String payload; + private static String kid; + private static RSAKey keypair; + private static String path_RSA_sha256_2048; + private static String alias; + private static String password; + private static String tokenFile; + + @BeforeClass + public static void setUp() { + resources = System.getProperty("user.dir").concat("/src/test/resources"); + kid = UUID.randomUUID().toString(); + header = "{\n" + + " \"alg\": \"RS256\",\n" + + " \"kid\": \"" + kid + "\",\n" + + " \"typ\": \"JWT\"\n" + + "}"; + payload = "{\n" + + " \"sub\": \"1234567890\",\n" + + " \"name\": \"John Doe\",\n" + + " \"iat\": 1516239022\n" + + "}"; + keypair = generateKeys(); + path_RSA_sha256_2048 = resources.concat("/dummycerts/RSA_sha256_2048/"); + alias = "1"; + password = "dummy"; + tokenFile = Jwt.create(loadPrivateKey(path_RSA_sha256_2048 + "sha256d_key.pem"), payload, header); + } + + private static RSAKey generateKeys() { + try { + return new RSAKeyGenerator(2048) + .keyUse(KeyUse.SIGNATURE) + .keyID(kid) + .algorithm(Algorithm.parse("RS256")) + .generate(); + } catch (Exception e) { + return null; + } + } + + @Test + public void testCreate() { + try { + String token = Jwt.create(keypair.toRSAPrivateKey(), payload, header); + Assert.assertFalse("testCreate fail", token.isEmpty()); + } catch (Exception e) { + Assert.fail("testCreate fail. Exception: " + e.getMessage()); + } + } + + @Test + public void testVerify() { + try { + String token = Jwt.create(keypair.toRSAPrivateKey(), payload, header); + boolean verifies = Jwt.verify(keypair.toRSAPublicKey(), token); + Assert.assertTrue("testVerify fail", verifies); + } catch (Exception e) { + Assert.fail("testVerify fail. Exception: " + e.getMessage()); + } + } + + @Test + public void testVerify_wrong() { + try { + String token = Jwt.create(keypair.toRSAPrivateKey(), payload, header); + boolean verifies = Jwt.verify(generateKeys().toRSAPublicKey(), token); + Assert.assertFalse("testVerify fail", verifies); + } catch (Exception e) { + Assert.fail("testVerify_wrong fail. Exception: " + e.getMessage()); + } + } + + @Test + public void testVerifyPkcs8() { + boolean result = GamUtilsEO.verifyJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.pem", "", "", tokenFile); + Assert.assertTrue("testVerifyPkcs8", result); + } + + @Test + public void testVerifyDer() { + boolean result = GamUtilsEO.verifyJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.cer", "", "", tokenFile); + Assert.assertTrue("testVerifyDer", result); + } + + @Test + public void testVerifyPkcs12() { + boolean result = GamUtilsEO.verifyJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, tokenFile); + Assert.assertTrue("testVerifyPkcs12", result); + } + + @Test + public void testVerifyPkcs12_withoutalias() { + boolean result = GamUtilsEO.verifyJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.p12", "", password, tokenFile); + Assert.assertTrue("testVerifyPkcs12_withoutalias", result); + } + + private static RSAPrivateKey loadPrivateKey(String path) { + try (FileReader privateKeyReader = new FileReader(path)) { + try (PEMParser parser = new PEMParser(privateKeyReader)) { + Object obj; + obj = parser.readObject(); + if (obj instanceof PEMKeyPair) { + PEMKeyPair pemKeyPair = (PEMKeyPair) obj; + PrivateKeyInfo privateKeyInfo = pemKeyPair.getPrivateKeyInfo(); + KeyFactory kf = KeyFactory.getInstance("RSA"); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyInfo.getEncoded()); + return (RSAPrivateKey) kf.generatePrivate(keySpec); + } else { + Assert.fail("loadPrivateKey fail, not PEMKeyPair type"); + return null; + } + } + } catch (Exception e) { + Assert.fail("loadPrivateKey fail with exception " + e.getMessage()); + return null; + } + } +} diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/RandomTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/RandomTest.java new file mode 100644 index 000000000..01cf944f7 --- /dev/null +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/RandomTest.java @@ -0,0 +1,55 @@ +package com.genexus.gam.utils.test; + +import com.genexus.gam.GamUtilsEO; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class RandomTest { + + private static int l128; + private static int l256; + + private static int l5; + + private static int l10; + + @BeforeClass + public static void setUp() { + l128 = 128; + l256 = 256; + l5 = 5; + l10 = 10; + } + + @Test + public void testRandomNumeric() { + String l5_string = GamUtilsEO.randomNumeric(l5); + Assert.assertEquals("l5 numeric: ", l5, l5_string.length()); + + String l10_string = GamUtilsEO.randomNumeric(l10); + Assert.assertEquals("l10 numeric: ", l10, l10_string.length()); + + String l128_string = GamUtilsEO.randomNumeric(l128); + Assert.assertEquals("l128 numeric: ", l128, l128_string.length()); + + String l256_string = GamUtilsEO.randomNumeric(l256); + Assert.assertEquals("l256 numeric: ", l256, l256_string.length()); + + } + + @Test + public void testRandomAlphanumeric() { + String l5_string = GamUtilsEO.randomAlphanumeric(l5); + Assert.assertEquals("l5 alphanumeric: ", l5, l5_string.length()); + + String l10_string = GamUtilsEO.randomAlphanumeric(l10); + Assert.assertEquals("l10 alphanumeric: ", l10, l10_string.length()); + + String l128_string = GamUtilsEO.randomAlphanumeric(l128); + Assert.assertEquals("l128 alphanumeric: ", l128, l128_string.length()); + + String l256_string = GamUtilsEO.randomAlphanumeric(l256); + Assert.assertEquals("l256 alphanumeric: ", l256, l256_string.length()); + } +} diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/resources/CryptographicHash.java b/gamutils/src/test/java/com/genexus/gam/utils/test/resources/CryptographicHash.java new file mode 100644 index 000000000..4ca692053 --- /dev/null +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/resources/CryptographicHash.java @@ -0,0 +1,38 @@ +package com.genexus.gam.utils.test.resources; + +import org.apache.commons.codec.CharEncoding; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class CryptographicHash { + private MessageDigest alg = null; + + // private HashAlgorithm alg; + public CryptographicHash(String algorithm) { + if (algorithm == "" || algorithm == "SHA512") + algorithm = "SHA-512"; + // Supports algorithm = {MD2, MD5, SHA-1, SHA-256, SHA-384, SHA-512} + try { + alg = MessageDigest.getInstance(algorithm); // step 2 + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + } + + public String ComputeHash(String data) { + try { + if (alg == null) alg = MessageDigest.getInstance("SHA-512"); + alg.update(data.getBytes(CharEncoding.UTF_8)); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + + byte[] bin = alg.digest(); + org.apache.commons.codec.binary.Base64 base = new org.apache.commons.codec.binary.Base64(100000); + return base.encodeToString(bin).trim(); + } +} diff --git a/gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256_cert.cer b/gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256_cert.cer new file mode 100644 index 0000000000000000000000000000000000000000..bd788b5de7701ce8e1ec5cba0657b3f339fdfdae GIT binary patch literal 1029 zcmXqLVqr9BVtToNnTe5!iIbs0YtO=)zZeq@c-c6$+C196^D;7WvoaVoPBY{-;ACSC zWnmL$3XL=rHV_1HIC!{x^Ycnl%Q90^^I?MQD1rh8d?1xvJnZhNd8rYl#fE|g{2&o- z9**GD`$@#ek za^k#31_tH^7KRq4=7#1`K&~l}YYycOUWYd^Dj^3lBP#=Q6C*!^K@%evQxhX2!`5?b zQ+{St-J9=hn#FK>o!Rq5{WRl>FKp(=U6|&u?NNE}KY7n{XReO|p_Pvw+9v?WcUNqRWZJUJpjsh8z*2TqK z2j?2y;xReAWI>3Gw^)By!rxb~%YGh=aQ+l?%S(Pw;F(1-XZN2nl~?m4cpOw5c7jEe&d{0wA)Nkf*8MT|v6*MYUuH97mwYXe&a*#jzy7u*;9F^~sI zE3-%#h&5nWzynes%))BG%*gm3In03x8yMz{42xyop3J$l{$h{JbxZHeqr8zPPUq#k zpJ#0owJzh>^`8gw{DUIAJ=+injZW{};R_xz%ZQ--8^Z))?XqEoR@!~|j3Gv@dRXEF^RU3%Za0}1%`$@#ek za^k#31_tH^7KRq4=7#1`K&~l}YYycOUWYd^Dj^3lBP#=Q6C*!^K@%evQxhX2!`5?b zQ+{St-J9=hn#FK>o!Rq5{WRl>FKp(=U6|&u?NNE}KY7n{XReO|p_Pvw+9v?WcUNqRWZJUJpjsh8z*2TqK z2j?2y;xReAWI>3Gw^)By!rxb~%YGh=aQ+l?%S(Pw;F(1-XZN2nl~?m4cpOw5c7jEe&d{0wA)Nkf*8MT|v6*MYUuH97mwYXe&a*#jzy7u*;9F^~sI zE3-%#h&5nWzynes%))BG%*gm3In03x8yMz{42xyop3J$l{$h{JbxZHeqr8zPPUq#k zpJ#0owJzh>^`8gw{DUIAJ=+injZW{};R_xz%ZQ--8^Z))?XqEoR@!~|j3Gv@dRXEF^RU3%Za0}1%kNS0ynw}bu1yKN4 z&^`hS+Cg9e#s5@5JQk4gCrYECruy^Z|7oZZP$0v<7r@jjH5G@hrj#FPa}Lvw*D z6brDNNWw%xrSSP);WF=Tsq|+w6j635H^}g8#i3eWSJHNh6)N~#b zjT8#zP%g83oD=tCX3FbqmPA_eR3fs?Hhz(6Hr3iy52tF7A?9Jt0va0pW@PO(=-(5u zHw{%sUvS;_dx5Aquj#tN3RGg^jhRthmmYKZO8XY)&aH)7!^;oBUGA(Hi&d)u)A)?= zeF^mpH!3fYVsk{q?!$#dJDPu+ySm_RWLC<&iq)65pbPH){v;T2Uc@W*zRR=Ui_MSY zJ+Wp4UxN1#x22ECZ?Q;fF)E^1T>~5N@YS0QcwMvQpeoL+wA>CM2MxyE%z%lUL3YYb zuRxnRhxA`Nk{>AEfppw58+F^6rHq^0w)z65I3e`|kC~_>1q+$f7>HaUOK3l*8k)|^ zWR{{QBGi+YcW(lm8BD~s7XTyXv5ovy84eR00&;b!dHI{GG#S;ToR2Y3(PGBJM+%~X zX4nEwqQ_@XnB>-c5TG;l*PbB#CI??ukqVz9d-vYVT(SWnD_p7j7iV`p1=8?_=}3R^ zxW|U&tsAPerAQ|zv>XZZ;|(|eI5rc*i8#}|ukL(wcVB83Ar_q7zN#0-sP=l?!|n>ENr}P73BAT77DK``|>{w%(^y$~lyD`fT+D3r#~ru03`2-%UzCbVa2@4AnU z2a0a*Imn(S8rmr17>rwdB1*Q@;&o|3Px8tubh{40%(arsR?9|&{VED%^4~9;%l2mp87M331mAn*6T%vc!wGzPuR!lhl%r6Q`pJo52L6NrR0)wP{ByoS zy4HQhj0%on%{-j8y(KlfA_g@juC0LM!ci0{goBDP4u_}H@t*J9`Urn%ZFDfY8I&hqxQ?!VnL(aUp%|N7|1J@9u{*mdW?oXdG+UTMWQpGGBxlKxPEqmW zCuKpa(?Q!CMvD&!-u=wcaWcyRt<~*oC^2D>jM*mb_VYDW&js@bG`P?Z3^-MCd~V3R zLP2j1^|=Zb)R-cHPv2@Fj$B!g=!aC9r|UrARVFHSy?ED2gc+K_jz2k8 z4Cb#sU2(Pp7DmEUYuxfTEpX1f(Tbu;$jr3Sb#G$dE_@%q{>Yv%ALU<1MR1dXcD&uyP|Dxmfv+Q6sK;CL-U?Tu%|-K z%7Nja{)cD6;jU?Bx$2kO57jdj_J29{cG`VQhG+e9_kVP;4$_>Op*Xf?yZvl<3#`Ja zVaSa*5jJG}9bV#QL%Xm5XE&)R-YdFjo_iClUG}sMkM5Nq-jkKs$Za{BaL8^Kwdd1I zH}ykCxCc^1=8I+FH3NE@EG0f5t9UK_wnNV1LmqL4PD=D&$8~i3s2aJRCCRMARncQP z^_#hj3LRgSz2Em)c(!zgMfld_W5`BjN2hjt&S|@irrigm>Vo+XI~Q#VQgT^d`KKC8 zh{ot(bG4RI>KX6IC5mh1(d+dFgLXU@B!D@Tw>`nkO79kAfgb@#(Z*`rhqg_wzP zmMaX^LWJU>iEtmj~``uK!kgQBnrx($_IzL>VFI6tazU8ub_k?8WO~SOfPx8iga^SBm<@*z84Db7nSa}SspX) zWYuORYEjwQiYYYFFV|ORf zC(;z!Jhrz%(?_hoZW>Zwtxg-N)sE|z5)$PSk_z)1pd6eK6&Y3Yg%RY93{ zcnMJc8Hd;7jMK7IE+f9!x1K-d<>j@lFe>>>_dcP>xOB9Xwq?%BfWte(axP<=~$F|6hvRH?2Wyy8i8eHdN+Q)UC=qI+i0scwOU&LE=%20L{_rk zQ+aS8RU-%^bnt_B$~o4|cNNujXp3()8L70Hwc&cPoAGn*+AnXv?CH68 zG~GJkcaii~8h`Nl`3|#7-EFUpqqp)$%>k(pnqfYH*O`}`e87g{le&E>T)mpj`OxBC z^N}qel~dtM89AcmBq)MDDLF}^$0V<;(NgM)w$Cx_(@u>YG5g7Lzx3E))*rBfiBaBM z3w>#5qJ&VWO}%Hxo?iQA2v|jCWz0LVQGpuv|adXTMZb z{jXZ2FhcOZI)d1d900Z*e}eNy4h}BLEEAp`m}K)kO+PR2uLS>iI(On9TkAB lO;dbq8Y1H8pEyk_kNS0ynw}bu1yKN4 z&^`hS+Cg9e#s5@5JQk4gCrYECruy^Z|7oZZP$0v<7r@jjH5G@hrj#FPa}Lvw*D z6brDNNWw%xrSSP);WF=Tsq|+w6j635H^}g8#i3eWSJHNh6)N~#b zjT8#zP%g83oD=tCX3FbqmPA_eR3fs?Hhz(6Hr3iy52tF7A?9Jt0va0pW@PO(=-(5u zHw{%sUvS;_dx5Aquj#tN3RGg^jhRthmmYKZO8XY)&aH)7!^;oBUGA(Hi&d)u)A)?= zeF^mpH!3fYVsk{q?!$#dJDPu+ySm_RWLC<&iq)65pbPH){v;T2Uc@W*zRR=Ui_MSY zJ+Wp4UxN1#x22ECZ?Q;fF)E^1T>~5N@YS0QcwMvQpeoL+wA>CM2MxyE%z%lUL3YYb zuRxnRhxA`Nk{>AEfppw58+F^6rHq^0w)z65I3e`|kC~_>1q+$f7>HaUOK3l*8k)|^ zWR{{QBGi+YcW(lm8BD~s7XTyXv5ovy84eR00&;b!dHI{GG#S;ToR2Y3(PGBJM+%~X zX4nEwqQ_@XnB>-c5TG;l*PbB#CI??ukqVz9d-vYVT(SWnD_p7j7iV`p1=8?_=}3R^ zxW|U&tsAPerAQ|zv>XZZ;|(|eI5rc*i8#}|ukL(wcVB83Ar_q7zN#0-sP=l?!|n>ENr}P73BAT77DK``|>{w%(^y$~lyD`fT+D3r#~ru03`2-%UzCbVa2@4AnU z2a0a*Imn(S8rmr17>rwdB1*Q@;&o|3Px8tubh{40%(arsR?9|&{VED%^4~9;%l2mp87M331mAn*6T%vc!wGzPuR!lhl%r6Q`pJo52L6NrR0)wP{ByoS zy4HQhj0%on%{-j8y(KlfA_g@juC0LM!ci0{goBDP4u_}H@t*J9`Urn%ZFDfY8I&hqxQ?!VnL(aUp%|N7|1J@9u{*mdW?oXdG+UTMWQpGGBxlKxPEqmW zCuKpa(?Q!CMvD&!-u=wcaWcyRt<~*oC^2D>jM*mb_VYDW&js@bG`P?Z3^-MCd~V3R zLP2j1^|=Zb)R-cHPv2@Fj$B!g=!aC9r|UrARVFHSy?ED2gc+K_jz2k8 z4Cb#sU2(Pp7DmEUYuxfTEpX1f(Tbu;$jr3Sb#G$dE_@%q{>Yv%ALU<1MR1dXcD&uyP|Dxmfv+Q6sK;CL-U?Tu%|-K z%7Nja{)cD6;jU?Bx$2kO57jdj_J29{cG`VQhG+e9_kVP;4$_>Op*Xf?yZvl<3#`Ja zVaSa*5jJG}9bV#QL%Xm5XE&)R-YdFjo_iClUG}sMkM5Nq-jkKs$Za{BaL8^Kwdd1I zH}ykCxCc^1=8I+FH3NE@EG0f5t9UK_wnNV1LmqL4PD=D&$8~i3s2aJRCCRMARncQP z^_#hj3LRgSz2Em)c(!zgMfld_W5`BjN2hjt&S|@irrigm>Vo+XI~Q#VQgT^d`KKC8 zh{ot(bG4RI>KX6IC5mh1(d+dFgLXU@B!D@Tw>`nkO79kAfgb@#(Z*`rhqg_wzP zmMaX^LWJU>iEtmj~``uK!kgQBnrx($_IzL>VFI6tazU8ub_k?8WO~SOfPx8iga^SBm<@*z84Db7nSa}SspX) zWYuORYEjwQiYYYFFV|ORf zC(;z!Jhrz%(?_hoZW>Zwtxg-N)sE|z5)$PSk_z)1pd6eK6&Y3Yg%RY93{ zcnMJc8Hd;7jMK7IE+f9!x1K-d<>j@lFe>>>_dcP>xOB9Xwq?%BfWte(axP<=~$F|6hvRH?2Wyy8i8eHdN+Q)UC=qI+i0scwOU&LE=%20L{_rk zQ+aS8RU-%^bnt_B$~o4|cNNujXp3()8L70Hwc&cPoAGn*+AnXv?CH68 zG~GJkcaii~8h`Nl`3|#7-EFUpqqp)$%>k(pnqfYH*O`}`e87g{le&E>T)mpj`OxBC z^N}qel~dtM89AcmBq)MDDLF}^$0V<;(NgM)w$Cx_(@u>YG5g7Lzx3E))*rBfiBaBM z3w>#5qJ&VWO}%Hxo?iQA2v|jCWz0LVQGpuv|adXTMZb z{jXZ2FhcOZI)d1d900Z*e}eNy4h}BLEEAp`m}K)kO+PR2uLS>iI(On9TkAB lO;dbq8Y1H8pEyk_kNS0ynw}bu1yKN4 z&^`hS+Cg9e#s5@5JQk4gCrYECruy^Z|7oZZP$0v<7r@jjH5G@hrj#FPa}Lvw*D z6brDNNWw%xrSSP);WF=Tsq|+w6j635H^}g8#i3eWSJHNh6)N~#b zjT8#zP%g83oD=tCX3FbqmPA_eR3fs?Hhz(6Hr3iy52tF7A?9Jt0va0pW@PO(=-(5u zHw{%sUvS;_dx5Aquj#tN3RGg^jhRthmmYKZO8XY)&aH)7!^;oBUGA(Hi&d)u)A)?= zeF^mpH!3fYVsk{q?!$#dJDPu+ySm_RWLC<&iq)65pbPH){v;T2Uc@W*zRR=Ui_MSY zJ+Wp4UxN1#x22ECZ?Q;fF)E^1T>~5N@YS0QcwMvQpeoL+wA>CM2MxyE%z%lUL3YYb zuRxnRhxA`Nk{>AEfppw58+F^6rHq^0w)z65I3e`|kC~_>1q+$f7>HaUOK3l*8k)|^ zWR{{QBGi+YcW(lm8BD~s7XTyXv5ovy84eR00&;b!dHI{GG#S;ToR2Y3(PGBJM+%~X zX4nEwqQ_@XnB>-c5TG;l*PbB#CI??ukqVz9d-vYVT(SWnD_p7j7iV`p1=8?_=}3R^ zxW|U&tsAPerAQ|zv>XZZ;|(|eI5rc*i8#}|ukL(wcVB83Ar_q7zN#0-sP=l?!|n>ENr}P73BAT77DK``|>{w%(^y$~lyD`fT+D3r#~ru03`2-%UzCbVa2@4AnU z2a0a*Imn(S8rmr17>rwdB1*Q@;&o|3Px8tubh{40%(arsR?9|&{VED%^4~9;%l2mp87M331mAn*6T%vc!wGzPuR!lhl%r6Q`pJo52L6NrR0)wP{ByoS zy4HQhj0%on%{-j8y(KlfA_g@juC0LM!ci0{goBDP4u_}H@t*J9`Urn%ZFDfY8I&hqxQ?!VnL(aUp%|N7|1J@9u{*mdW?oXdG+UTMWQpGGBxlKxPEqmW zCuKpa(?Q!CMvD&!-u=wcaWcyRt<~*oC^2D>jM*mb_VYDW&js@bG`P?Z3^-MCd~V3R zLP2j1^|=Zb)R-cHPv2@Fj$B!g=!aC9r|UrARVFHSy?ED2gc+K_jz2k8 z4Cb#sU2(Pp7DmEUYuxfTEpX1f(Tbu;$jr3Sb#G$dE_@%q{>Yv%ALU<1MR1dXcD&uyP|Dxmfv+Q6sK;CL-U?Tu%|-K z%7Nja{)cD6;jU?Bx$2kO57jdj_J29{cG`VQhG+e9_kVP;4$_>Op*Xf?yZvl<3#`Ja zVaSa*5jJG}9bV#QL%Xm5XE&)R-YdFjo_iClUG}sMkM5Nq-jkKs$Za{BaL8^Kwdd1I zH}ykCxCc^1=8I+FH3NE@EG0f5t9UK_wnNV1LmqL4PD=D&$8~i3s2aJRCCRMARncQP z^_#hj3LRgSz2Em)c(!zgMfld_W5`BjN2hjt&S|@irrigm>Vo+XI~Q#VQgT^d`KKC8 zh{ot(bG4RI>KX6IC5mh1(d+dFgLXU@B!D@Tw>`nkO79kAfgb@#(Z*`rhqg_wzP zmMaX^LWJU>iEtmj~``uK!kgQBnrx($_IzL>VFI6tazU8ub_k?8WO~SOfPx8iga^SBm<@*z84Db7nSa}SspX) zWYuORYEjwQiYYYFFV|ORf zC(;z!Jhrz%(?_hoZW>Zwtxg-N)sE|z5)$PSk_z)1pd6eK6&Y3Yg%RY93{ zcnMJc8Hd;7jMK7IE+f9!x1K-d<>j@lFe>>>_dcP>xOB9Xwq?%BfWte(axP<=~$F|6hvRH?2Wyy8i8eHdN+Q)UC=qI+i0scwOU&LE=%20L{_rk zQ+aS8RU-%^bnt_B$~o4|cNNujXp3()8L70Hwc&cPoAGn*+AnXv?CH68 zG~GJkcaii~8h`Nl`3|#7-EFUpqqp)$%>k(pnqfYH*O`}`e87g{le&E>T)mpj`OxBC z^N}qel~dtM89AcmBq)MDDLF}^$0V<;(NgM)w$Cx_(@u>YG5g7Lzx3E))*rBfiBaBM z3w>#5qJ&VWO}%Hxo?iQA2v|jCWz0LVQGpuv|adXTMZb z{jXZ2FhcOZI)d1d900Z*e}eNy4h}BLEEAp`m}K)kO+PR2uLS>iI(On9TkAB lO;dbq8Y1H8pEyk_kNS0ynw}bu1yKN4 z&^`hS+Cg9e#s5@5JQk4gCrYECruy^Z|7oZZP$0v<7r@jjH5G@hrj#FPa}Lvw*D z6brDNNWw%xrSSP);WF=Tsq|+w6j635H^}g8#i3eWSJHNh6)N~#b zjT8#zP%g83oD=tCX3FbqmPA_eR3fs?Hhz(6Hr3iy52tF7A?9Jt0va0pW@PO(=-(5u zHw{%sUvS;_dx5Aquj#tN3RGg^jhRthmmYKZO8XY)&aH)7!^;oBUGA(Hi&d)u)A)?= zeF^mpH!3fYVsk{q?!$#dJDPu+ySm_RWLC<&iq)65pbPH){v;T2Uc@W*zRR=Ui_MSY zJ+Wp4UxN1#x22ECZ?Q;fF)E^1T>~5N@YS0QcwMvQpeoL+wA>CM2MxyE%z%lUL3YYb zuRxnRhxA`Nk{>AEfppw58+F^6rHq^0w)z65I3e`|kC~_>1q+$f7>HaUOK3l*8k)|^ zWR{{QBGi+YcW(lm8BD~s7XTyXv5ovy84eR00&;b!dHI{GG#S;ToR2Y3(PGBJM+%~X zX4nEwqQ_@XnB>-c5TG;l*PbB#CI??ukqVz9d-vYVT(SWnD_p7j7iV`p1=8?_=}3R^ zxW|U&tsAPerAQ|zv>XZZ;|(|eI5rc*i8#}|ukL(wcVB83Ar_q7zN#0-sP=l?!|n>ENr}P73BAT77DK``|>{w%(^y$~lyD`fT+D3r#~ru03`2-%UzCbVa2@4AnU z2a0a*Imn(S8rmr17>rwdB1*Q@;&o|3Px8tubh{40%(arsR?9|&{VED%^4~9;%l2mp87M331mAn*6T%vc!wGzPuR!lhl%r6Q`pJo52L6NrR0)wP{ByoS zy4HQhj0%on%{-j8y(KlfA_g@juC0LM!ci0{goBDP4u_}H@t*J9`Urn%ZFDfY8I&hqxQ?!VnL(aUp%|N7|1J@9u{*mdW?oXdG+UTMWQpGGBxlKxPEqmW zCuKpa(?Q!CMvD&!-u=wcaWcyRt<~*oC^2D>jM*mb_VYDW&js@bG`P?Z3^-MCd~V3R zLP2j1^|=Zb)R-cHPv2@Fj$B!g=!aC9r|UrARVFHSy?ED2gc+K_jz2k8 z4Cb#sU2(Pp7DmEUYuxfTEpX1f(Tbu;$jr3Sb#G$dE_@%q{>Yv%ALU<1MR1dXcD&uyP|Dxmfv+Q6sK;CL-U?Tu%|-K z%7Nja{)cD6;jU?Bx$2kO57jdj_J29{cG`VQhG+e9_kVP;4$_>Op*Xf?yZvl<3#`Ja zVaSa*5jJG}9bV#QL%Xm5XE&)R-YdFjo_iClUG}sMkM5Nq-jkKs$Za{BaL8^Kwdd1I zH}ykCxCc^1=8I+FH3NE@EG0f5t9UK_wnNV1LmqL4PD=D&$8~i3s2aJRCCRMARncQP z^_#hj3LRgSz2Em)c(!zgMfld_W5`BjN2hjt&S|@irrigm>Vo+XI~Q#VQgT^d`KKC8 zh{ot(bG4RI>KX6IC5mh1(d+dFgLXU@B!D@Tw>`nkO79kAfgb@#(Z*`rhqg_wzP zmMaX^LWJU>iEtmj~``uK!kgQBnrx($_IzL>VFI6tazU8ub_k?8WO~SOfPx8iga^SBm<@*z84Db7nSa}SspX) zWYuORYEjwQiYYYFFV|ORf zC(;z!Jhrz%(?_hoZW>Zwtxg-N)sE|z5)$PSk_z)1pd6eK6&Y3Yg%RY93{ zcnMJc8Hd;7jMK7IE+f9!x1K-d<>j@lFe>>>_dcP>xOB9Xwq?%BfWte(axP<=~$F|6hvRH?2Wyy8i8eHdN+Q)UC=qI+i0scwOU&LE=%20L{_rk zQ+aS8RU-%^bnt_B$~o4|cNNujXp3()8L70Hwc&cPoAGn*+AnXv?CH68 zG~GJkcaii~8h`Nl`3|#7-EFUpqqp)$%>k(pnqfYH*O`}`e87g{le&E>T)mpj`OxBC z^N}qel~dtM89AcmBq)MDDLF}^$0V<;(NgM)w$Cx_(@u>YG5g7Lzx3E))*rBfiBaBM z3w>#5qJ&VWO}%Hxo?iQA2v|jCWz0LVQGpuv|adXTMZb z{jXZ2FhcOZI)d1d900Z*e}eNy4h}BLEEAp`m}K)kO+PR2uLS>iI(On9TkAB lO;dbq8Y1H8pEyk_gxcloudstorage-tests gxobservability gxcloudstorage-awss3-v2 + gamutils From 083bef04d9765ba3360093ddd8b204aed21a77a9 Mon Sep 17 00:00:00 2001 From: sgrampone Date: Fri, 26 Jul 2024 16:35:14 -0300 Subject: [PATCH 02/21] Fix test --- .../test/java/com/genexus/gam/utils/test/CertificateTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java index 3cb0c8d0a..5ca036e83 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java @@ -74,7 +74,7 @@ public void testLoadPem() { @Test public void testLoadKey() { - X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.Key", "", ""); + X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.key", "", ""); Assert.assertNotNull("testLoadKey", cert); } } From 77fab6657e2298b99701c8d1e43afdbf26a875ed Mon Sep 17 00:00:00 2001 From: sgrampone Date: Fri, 2 Aug 2024 15:56:14 -0300 Subject: [PATCH 03/21] Fix quality issues and Log --- gamutils/pom.xml | 16 ++++++++++------ .../com/genexus/gam/utils/CertificateUtil.java | 8 ++++---- .../main/java/com/genexus/gam/utils/Hash.java | 6 +++--- .../src/main/java/com/genexus/gam/utils/Jwk.java | 6 +++--- .../main/java/com/genexus/gam/utils/Jwks.java | 6 +++--- .../src/main/java/com/genexus/gam/utils/Jwt.java | 11 +++-------- .../main/java/com/genexus/gam/utils/Random.java | 6 +++--- .../genexus/gam/utils/test/CertificateTest.java | 3 +-- .../java/com/genexus/gam/utils/test/JwtTest.java | 3 +-- .../utils/test/resources/CryptographicHash.java | 2 +- 10 files changed, 32 insertions(+), 35 deletions(-) diff --git a/gamutils/pom.xml b/gamutils/pom.xml index 872c585b8..6a14635b9 100644 --- a/gamutils/pom.xml +++ b/gamutils/pom.xml @@ -15,13 +15,7 @@ UTF-8 - - - ${project.groupId} - gxcommon - ${project.version} - com.nimbusds nimbus-jose-jwt @@ -37,6 +31,16 @@ bcpkix-jdk18on 1.78.1 + + org.apache.logging.log4j + log4j-core + ${log4j.version} + + + commons-io + commons-io + 2.11.0 + commons-codec commons-codec diff --git a/gamutils/src/main/java/com/genexus/gam/utils/CertificateUtil.java b/gamutils/src/main/java/com/genexus/gam/utils/CertificateUtil.java index ee290d642..dd33297aa 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/CertificateUtil.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/CertificateUtil.java @@ -1,7 +1,7 @@ package com.genexus.gam.utils; -import com.genexus.diagnostics.core.ILogger; -import com.genexus.diagnostics.core.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.apache.commons.io.FilenameUtils; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory; @@ -15,7 +15,7 @@ public enum CertificateUtil { crt, cer, pfx, jks, pkcs12, p12, pem, key; - public static final ILogger logger = LogManager.getLogger(CertificateUtil.class); + private static Logger logger = LogManager.getLogger(CertificateUtil.class); public static CertificateUtil value(String ext) { switch (ext.toLowerCase().trim()) { @@ -90,7 +90,7 @@ private static X509Certificate loadFromPkcs12(String path, String alias, String try (FileInputStream inStream = new FileInputStream(path)) { KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(inStream, password.toCharArray()); - if (alias.equals("") || alias.isEmpty()) { + if (alias.isEmpty()) { return (X509Certificate) ks.getCertificate(ks.aliases().nextElement()); } else { return (X509Certificate) ks.getCertificate(alias); diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Hash.java b/gamutils/src/main/java/com/genexus/gam/utils/Hash.java index 157f37c56..34a64c848 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/Hash.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/Hash.java @@ -1,7 +1,7 @@ package com.genexus.gam.utils; -import com.genexus.diagnostics.core.ILogger; -import com.genexus.diagnostics.core.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.util.encoders.Base64; @@ -9,7 +9,7 @@ import java.nio.charset.StandardCharsets; public class Hash { - public static final ILogger logger = LogManager.getLogger(Hash.class); + private static Logger logger = LogManager.getLogger(Hash.class); public static String sha512(String plainText) { if (plainText.isEmpty()) { diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Jwk.java b/gamutils/src/main/java/com/genexus/gam/utils/Jwk.java index 26f53cabc..4faf0d7ab 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/Jwk.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/Jwk.java @@ -1,18 +1,18 @@ package com.genexus.gam.utils; -import com.genexus.diagnostics.core.ILogger; -import com.genexus.diagnostics.core.LogManager; import com.nimbusds.jose.Algorithm; import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.KeyUse; import com.nimbusds.jose.jwk.RSAKey; import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.UUID; public class Jwk { - public static final ILogger logger = LogManager.getLogger(Jwk.class); + private static Logger logger = LogManager.getLogger(Jwk.class); public static String generateKeyPair() { try { diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Jwks.java b/gamutils/src/main/java/com/genexus/gam/utils/Jwks.java index e7ea68cc3..bd0363985 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/Jwks.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/Jwks.java @@ -1,13 +1,13 @@ package com.genexus.gam.utils; -import com.genexus.diagnostics.core.ILogger; -import com.genexus.diagnostics.core.LogManager; import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.JWKSet; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class Jwks { - public static final ILogger logger = LogManager.getLogger(Jwks.class); + private static Logger logger = LogManager.getLogger(Jwks.class); public static boolean verifyJWT(String jwksString, String token, String kid) { if (jwksString.isEmpty()) { diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Jwt.java b/gamutils/src/main/java/com/genexus/gam/utils/Jwt.java index d989c098a..571c12b30 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/Jwt.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/Jwt.java @@ -1,21 +1,20 @@ package com.genexus.gam.utils; -import com.genexus.diagnostics.core.ILogger; -import com.genexus.diagnostics.core.LogManager; import com.nimbusds.jose.JWSHeader; import com.nimbusds.jose.JWSVerifier; import com.nimbusds.jose.crypto.RSASSASigner; import com.nimbusds.jose.crypto.RSASSAVerifier; import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.SignedJWT; -import org.apache.commons.io.FilenameUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; public class Jwt { - public static final ILogger logger = LogManager.getLogger(Jwt.class); + private static Logger logger = LogManager.getLogger(Jwt.class); /******** EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/ @@ -48,8 +47,4 @@ public static boolean verify(String path, String alias, String password, String /******** EXTERNAL OBJECT PUBLIC METHODS - END ********/ - private static boolean extensionIs(String stringPath, String extension) { - return extension.equalsIgnoreCase(FilenameUtils.getExtension(stringPath)); - } - } diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Random.java b/gamutils/src/main/java/com/genexus/gam/utils/Random.java index ffa67c4f1..cbcea2ad6 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/Random.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/Random.java @@ -1,13 +1,13 @@ package com.genexus.gam.utils; -import com.genexus.diagnostics.core.ILogger; -import com.genexus.diagnostics.core.LogManager; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.security.SecureRandom; public class Random { - public static final ILogger logger = LogManager.getLogger(Random.class); + private static Logger logger = LogManager.getLogger(Random.class); private static SecureRandom instanceRandom() { try { diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java index 5ca036e83..e08f28ead 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java @@ -9,14 +9,13 @@ public class CertificateTest { - private static String resources; private static String path_RSA_sha256_2048; private static String alias; private static String password; @BeforeClass public static void setUp() { - resources = System.getProperty("user.dir").concat("/src/test/resources"); + String resources = System.getProperty("user.dir").concat("/src/test/resources"); path_RSA_sha256_2048 = resources.concat("/dummycerts/RSA_sha256_2048/"); alias = "1"; password = "dummy"; diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java index 7a1d6721a..670498760 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java @@ -21,7 +21,6 @@ public class JwtTest { - private static String resources; private static String header; private static String payload; private static String kid; @@ -33,7 +32,7 @@ public class JwtTest { @BeforeClass public static void setUp() { - resources = System.getProperty("user.dir").concat("/src/test/resources"); + String resources = System.getProperty("user.dir").concat("/src/test/resources"); kid = UUID.randomUUID().toString(); header = "{\n" + " \"alg\": \"RS256\",\n" + diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/resources/CryptographicHash.java b/gamutils/src/test/java/com/genexus/gam/utils/test/resources/CryptographicHash.java index 4ca692053..006097d1c 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/resources/CryptographicHash.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/resources/CryptographicHash.java @@ -11,7 +11,7 @@ public class CryptographicHash { // private HashAlgorithm alg; public CryptographicHash(String algorithm) { - if (algorithm == "" || algorithm == "SHA512") + if (algorithm.equals("SHA512")) algorithm = "SHA-512"; // Supports algorithm = {MD2, MD5, SHA-1, SHA-256, SHA-384, SHA-512} try { From 9cb8c02aa09c132e1791752ac12e8f9abcded026 Mon Sep 17 00:00:00 2001 From: sgrampone Date: Tue, 6 Aug 2024 14:03:11 -0300 Subject: [PATCH 04/21] New features, tests and some needed refactoring --- .../main/java/com/genexus/gam/GamUtilsEO.java | 24 +++- .../java/com/genexus/gam/utils/Random.java | 20 ++- .../gam/utils/cryptography/Encryption.java | 38 +++++ .../gam/utils/{ => cryptography}/Hash.java | 2 +- .../com/genexus/gam/utils/{ => json}/Jwk.java | 2 +- .../genexus/gam/utils/{ => json}/Jwks.java | 2 +- .../com/genexus/gam/utils/{ => json}/Jwt.java | 9 +- .../gam/utils/{ => keys}/CertificateUtil.java | 29 +++- .../gam/utils/keys/PrivateKeyUtil.java | 132 ++++++++++++++++++ .../gam/utils/test/CertificateTest.java | 10 +- .../gam/utils/test/EncryptionTest.java | 20 +++ .../com/genexus/gam/utils/test/HashTest.java | 2 +- .../com/genexus/gam/utils/test/JwtTest.java | 46 +++++- .../gam/utils/test/PrivateKeyTest.java | 74 ++++++++++ .../RSA_sha256_2048/sha256d_key.key | 27 ++++ 15 files changed, 418 insertions(+), 19 deletions(-) create mode 100644 gamutils/src/main/java/com/genexus/gam/utils/cryptography/Encryption.java rename gamutils/src/main/java/com/genexus/gam/utils/{ => cryptography}/Hash.java (94%) rename gamutils/src/main/java/com/genexus/gam/utils/{ => json}/Jwk.java (98%) rename gamutils/src/main/java/com/genexus/gam/utils/{ => json}/Jwks.java (96%) rename gamutils/src/main/java/com/genexus/gam/utils/{ => json}/Jwt.java (81%) rename gamutils/src/main/java/com/genexus/gam/utils/{ => keys}/CertificateUtil.java (79%) create mode 100644 gamutils/src/main/java/com/genexus/gam/utils/keys/PrivateKeyUtil.java create mode 100644 gamutils/src/test/java/com/genexus/gam/utils/test/EncryptionTest.java create mode 100644 gamutils/src/test/java/com/genexus/gam/utils/test/PrivateKeyTest.java create mode 100644 gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256d_key.key diff --git a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java index d9eff0959..cf0f78e7a 100644 --- a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java +++ b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java @@ -1,6 +1,11 @@ package com.genexus.gam; -import com.genexus.gam.utils.*; +import com.genexus.gam.utils.Random; +import com.genexus.gam.utils.cryptography.Encryption; +import com.genexus.gam.utils.cryptography.Hash; +import com.genexus.gam.utils.json.Jwk; +import com.genexus.gam.utils.json.Jwks; +import com.genexus.gam.utils.json.Jwt; public class GamUtilsEO { @@ -11,15 +16,24 @@ public static String sha512(String plainText) { return Hash.sha512(plainText); } + //**ENCRYPTION**// + + public static String AesGcm(String input, String key, String nonce, int macSize, boolean toEncrypt) { + return Encryption.AesGcm(input, key, nonce, macSize, toEncrypt); + } + //**RANDOM**// public static String randomAlphanumeric(int length) { - return Random.randomAlphanumeric(length); + return Random.alphanumeric(length); } public static String randomNumeric(int length) { - return Random.randomNumeric(length); + return Random.numeric(length); } + public static String randomHexaBits(int bits) { + return Random.hexaBits(bits); + } //**JWK**// @@ -50,5 +64,9 @@ public static boolean verifyJWTWithFile(String path, String alias, String passwo return Jwt.verify(path, alias, password, token); } + public static String createJWTWithFile(String path, String alias, String password, String payload, String header) { + return Jwt.create(path, alias, password, payload, header); + } + /********EXTERNAL OBJECT PUBLIC METHODS - END ********/ } diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Random.java b/gamutils/src/main/java/com/genexus/gam/utils/Random.java index cbcea2ad6..bb46e1b6f 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/Random.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/Random.java @@ -18,7 +18,7 @@ private static SecureRandom instanceRandom() { } } - public static String randomAlphanumeric(int length) { + public static String alphanumeric(int length) { SecureRandom random = instanceRandom(); if (random == null) { logger.error("randomAlphanumeric SecureRandom is null"); @@ -31,7 +31,7 @@ public static String randomAlphanumeric(int length) { return sb.toString(); } - public static String randomNumeric(int length) { + public static String numeric(int length) { SecureRandom random = instanceRandom(); if (random == null) { logger.error("randomNumeric SecureRandom is null"); @@ -43,4 +43,20 @@ public static String randomNumeric(int length) { } return sb.toString(); } + + public static String hexaBits(int bits) + { + SecureRandom random = instanceRandom(); + if (random == null) { + logger.error("randomNumeric SecureRandom is null"); + return ""; + } + byte[] values = new byte[bits / 8]; + random.nextBytes(values); + StringBuilder sb = new StringBuilder(); + for (byte b : values) { + sb.append(String.format("%02x", b)); + } + return sb.toString().replaceAll("\\s", ""); + } } diff --git a/gamutils/src/main/java/com/genexus/gam/utils/cryptography/Encryption.java b/gamutils/src/main/java/com/genexus/gam/utils/cryptography/Encryption.java new file mode 100644 index 000000000..2ce4e0350 --- /dev/null +++ b/gamutils/src/main/java/com/genexus/gam/utils/cryptography/Encryption.java @@ -0,0 +1,38 @@ +package com.genexus.gam.utils.cryptography; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bouncycastle.crypto.engines.AESEngine; +import org.bouncycastle.crypto.modes.AEADBlockCipher; +import org.bouncycastle.crypto.modes.GCMBlockCipher; +import org.bouncycastle.crypto.params.AEADParameters; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.util.encoders.Base64; +import org.bouncycastle.util.encoders.Hex; + +import java.nio.charset.StandardCharsets; + +public class Encryption { + + private static Logger logger = LogManager.getLogger(Encryption.class); + + public static String AesGcm(String input, String key, String nonce, int macSize, boolean toEncrypt) { + return toEncrypt ? Base64.toBase64String(internal_AesGcm(input.getBytes(StandardCharsets.UTF_8), key, nonce, macSize, toEncrypt)) : new String(internal_AesGcm(Base64.decode(input), key, nonce, macSize, toEncrypt), StandardCharsets.UTF_8); + } + + public static byte[] internal_AesGcm(byte[] inputBytes, String key, String nonce, int macSize, boolean toEncrypt) { + logger.debug("internal_AesGcm"); + AEADBlockCipher cipher = new GCMBlockCipher(new AESEngine()); + AEADParameters AEADparams = new AEADParameters(new KeyParameter(Hex.decode(key)), macSize, Hex.decode(nonce)); + try { + cipher.init(toEncrypt, AEADparams); + byte[] outputBytes = new byte[cipher.getOutputSize(inputBytes.length)]; + int length = cipher.processBytes(inputBytes, 0, inputBytes.length, outputBytes, 0); + cipher.doFinal(outputBytes, length); + return outputBytes; + } catch (Exception e) { + logger.error("Aes_gcm", e); + return null; + } + } +} diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Hash.java b/gamutils/src/main/java/com/genexus/gam/utils/cryptography/Hash.java similarity index 94% rename from gamutils/src/main/java/com/genexus/gam/utils/Hash.java rename to gamutils/src/main/java/com/genexus/gam/utils/cryptography/Hash.java index 34a64c848..c9571be8f 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/Hash.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/cryptography/Hash.java @@ -1,4 +1,4 @@ -package com.genexus.gam.utils; +package com.genexus.gam.utils.cryptography; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Jwk.java b/gamutils/src/main/java/com/genexus/gam/utils/json/Jwk.java similarity index 98% rename from gamutils/src/main/java/com/genexus/gam/utils/Jwk.java rename to gamutils/src/main/java/com/genexus/gam/utils/json/Jwk.java index 4faf0d7ab..313c12931 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/Jwk.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/json/Jwk.java @@ -1,4 +1,4 @@ -package com.genexus.gam.utils; +package com.genexus.gam.utils.json; import com.nimbusds.jose.Algorithm; import com.nimbusds.jose.jwk.JWK; diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Jwks.java b/gamutils/src/main/java/com/genexus/gam/utils/json/Jwks.java similarity index 96% rename from gamutils/src/main/java/com/genexus/gam/utils/Jwks.java rename to gamutils/src/main/java/com/genexus/gam/utils/json/Jwks.java index bd0363985..5d73fc8d4 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/Jwks.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/json/Jwks.java @@ -1,4 +1,4 @@ -package com.genexus.gam.utils; +package com.genexus.gam.utils.json; import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.JWKSet; diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Jwt.java b/gamutils/src/main/java/com/genexus/gam/utils/json/Jwt.java similarity index 81% rename from gamutils/src/main/java/com/genexus/gam/utils/Jwt.java rename to gamutils/src/main/java/com/genexus/gam/utils/json/Jwt.java index 571c12b30..ef64bae3c 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/Jwt.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/json/Jwt.java @@ -1,5 +1,7 @@ -package com.genexus.gam.utils; +package com.genexus.gam.utils.json; +import com.genexus.gam.utils.keys.CertificateUtil; +import com.genexus.gam.utils.keys.PrivateKeyUtil; import com.nimbusds.jose.JWSHeader; import com.nimbusds.jose.JWSVerifier; import com.nimbusds.jose.crypto.RSASSASigner; @@ -44,6 +46,11 @@ public static boolean verify(String path, String alias, String password, String return verify((RSAPublicKey) CertificateUtil.getCertificate(path, alias, password).getPublicKey(), token); } + public static String create(String path, String alias, String password, String payload, String header) + { + return create(PrivateKeyUtil.getPrivateKey(path, alias, password), payload, header); + } + /******** EXTERNAL OBJECT PUBLIC METHODS - END ********/ diff --git a/gamutils/src/main/java/com/genexus/gam/utils/CertificateUtil.java b/gamutils/src/main/java/com/genexus/gam/utils/keys/CertificateUtil.java similarity index 79% rename from gamutils/src/main/java/com/genexus/gam/utils/CertificateUtil.java rename to gamutils/src/main/java/com/genexus/gam/utils/keys/CertificateUtil.java index dd33297aa..5fe3b0fd4 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/CertificateUtil.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/keys/CertificateUtil.java @@ -1,4 +1,4 @@ -package com.genexus.gam.utils; +package com.genexus.gam.utils.keys; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; @@ -6,6 +6,7 @@ import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory; import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.util.encoders.Base64; import java.io.*; import java.security.KeyStore; @@ -13,7 +14,7 @@ public enum CertificateUtil { - crt, cer, pfx, jks, pkcs12, p12, pem, key; + crt, cer, pfx, jks, pkcs12, p12, pem, key, b64; private static Logger logger = LogManager.getLogger(CertificateUtil.class); @@ -35,6 +36,8 @@ public static CertificateUtil value(String ext) { return pem; case "key": return key; + case "b64": + return b64; default: logger.error("Invalid certificate file extension"); return null; @@ -42,11 +45,8 @@ public static CertificateUtil value(String ext) { } public static X509Certificate getCertificate(String path, String alias, String password) { - CertificateUtil ext = CertificateUtil.value(FilenameUtils.getExtension(path)); - if (ext == null) { - logger.error("Error reading certificate path"); - return null; - } + String extension = FilenameUtils.getExtension(path); + CertificateUtil ext = extension.isEmpty() ? CertificateUtil.value("b64"): CertificateUtil.value(extension); switch (ext) { case crt: case cer: @@ -59,12 +59,27 @@ public static X509Certificate getCertificate(String path, String alias, String p case pem: case key: return loadFromPkcs8(path); + case b64: + return loadBase64(path); default: logger.error("Invalid certificate file extension"); return null; } } + private static X509Certificate loadBase64(String base64) + { + logger.debug("loadBase64"); + try { + ByteArrayInputStream byteArray = new ByteArrayInputStream(Base64.decode(base64)); + CertificateFactory factory = new CertificateFactory(); + return (X509Certificate) factory.engineGenerateCertificate(byteArray); + } catch (Exception e) { + logger.error("loadBase64", e); + return null; + } + } + private static X509Certificate loadFromPkcs8(String path) { try (FileReader privateKeyReader = new FileReader(new File(path))) { try (PEMParser parser = new PEMParser(privateKeyReader)) { diff --git a/gamutils/src/main/java/com/genexus/gam/utils/keys/PrivateKeyUtil.java b/gamutils/src/main/java/com/genexus/gam/utils/keys/PrivateKeyUtil.java new file mode 100644 index 000000000..7132ea241 --- /dev/null +++ b/gamutils/src/main/java/com/genexus/gam/utils/keys/PrivateKeyUtil.java @@ -0,0 +1,132 @@ +package com.genexus.gam.utils.keys; + +import org.apache.commons.io.FilenameUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.openssl.PEMKeyPair; +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.util.encoders.Base64; + +import java.io.FileReader; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.KeyFactory; +import java.security.KeyStore; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; + +public enum PrivateKeyUtil { + + pfx, jks, pkcs12, p12, pem, key, b64; + + private static Logger logger = LogManager.getLogger(PrivateKeyUtil.class); + + public static PrivateKeyUtil value(String ext) { + switch (ext.toLowerCase().trim()) { + case "pfx": + return pfx; + case "jks": + return jks; + case "pkcs12": + return pkcs12; + case "p12": + return p12; + case "pem": + return pem; + case "key": + return key; + case "b64": + return b64; + default: + logger.error("Invalid certificate file extension"); + return null; + } + } + + public static RSAPrivateKey getPrivateKey(String path, String alias, String password) { + String extension = FilenameUtils.getExtension(path); + PrivateKeyUtil ext = extension.isEmpty() ? PrivateKeyUtil.value("b64"): PrivateKeyUtil.value(extension); + switch (ext) { + case pfx: + case jks: + case pkcs12: + case p12: + return loadFromPkcs12(path, alias, password); + case pem: + case key: + return loadFromPkcs8(path); + case b64: + return loadFromBase64(path); + default: + logger.error("Invalid private key file extension"); + return null; + } + } + + private static RSAPrivateKey loadFromBase64(String base64) + { + logger.debug("loadFromBase64"); + try(ASN1InputStream stream = new ASN1InputStream(Base64.decode(base64))) { + ASN1Sequence seq = (ASN1Sequence) stream.readObject(); + return castPrivateKeyInfo(PrivateKeyInfo.getInstance(seq)); + }catch (Exception e) + { + logger.error("loadFromBase64", e); + return null; + } + } + + private static RSAPrivateKey loadFromPkcs8(String path) { + logger.debug("loadFromPkcs8"); + try (FileReader privateKeyReader = new FileReader(path)) { + try (PEMParser parser = new PEMParser(privateKeyReader)) { + Object obj; + obj = parser.readObject(); + if (obj instanceof PrivateKeyInfo) { + return castPrivateKeyInfo((PrivateKeyInfo) obj); + } else if (obj instanceof PEMKeyPair) { + PEMKeyPair pemKeyPair = (PEMKeyPair) obj; + return castPrivateKeyInfo(pemKeyPair.getPrivateKeyInfo()); + } else { + logger.error("loadFromPkcs8: Could not load private key"); + return null; + } + } + } catch (Exception e) { + logger.error("loadFromPkcs8", e); + return null; + } + } + + private static RSAPrivateKey castPrivateKeyInfo(PrivateKeyInfo privateKeyInfo) { + logger.debug("castPrivateKeyInfo"); + try { + KeyFactory kf = KeyFactory.getInstance(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm().getId()); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyInfo.getEncoded()); + return (RSAPrivateKey) kf.generatePrivate(keySpec); + } catch (Exception e) { + logger.error("castPrivateKeyInfo", e); + return null; + } + } + + private static RSAPrivateKey loadFromPkcs12(String path, String alias, String password) { + logger.debug("loadFromPkcs12"); + try (InputStream targetStream = Files.newInputStream(Paths.get(path))) { + KeyStore ks = KeyStore.getInstance("PKCS12"); + ks.load(targetStream, password.toCharArray()); + if (alias.isEmpty()) { + return (RSAPrivateKey) ks.getKey(ks.aliases().nextElement(), password.toCharArray()); + } else { + return (RSAPrivateKey) ks.getKey(alias, password.toCharArray()); + } + } catch (Exception e) { + logger.error("loadFromPkcs12", e); + return null; + } + } +} diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java index e08f28ead..2a6b1cf08 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java @@ -1,6 +1,6 @@ package com.genexus.gam.utils.test; -import com.genexus.gam.utils.CertificateUtil; +import com.genexus.gam.utils.keys.CertificateUtil; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -76,4 +76,12 @@ public void testLoadKey() { X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.key", "", ""); Assert.assertNotNull("testLoadKey", cert); } + + @Test + public void testLoadBase64() + { + String base64 = "MIIEATCCAumgAwIBAgIJAIAqvKHZ+gFhMA0GCSqGSIb3DQEBCwUAMIGWMQswCQYDVQQGEwJVWTETMBEGA1UECAwKTW9udGV2aWRlbzETMBEGA1UEBwwKTW9udGV2aWRlbzEQMA4GA1UECgwHR2VuZVh1czERMA8GA1UECwwIU2VjdXJpdHkxEjAQBgNVBAMMCXNncmFtcG9uZTEkMCIGCSqGSIb3DQEJARYVc2dyYW1wb25lQGdlbmV4dXMuY29tMB4XDTIwMDcwODE4NTcxN1oXDTI1MDcwNzE4NTcxN1owgZYxCzAJBgNVBAYTAlVZMRMwEQYDVQQIDApNb250ZXZpZGVvMRMwEQYDVQQHDApNb250ZXZpZGVvMRAwDgYDVQQKDAdHZW5lWHVzMREwDwYDVQQLDAhTZWN1cml0eTESMBAGA1UEAwwJc2dyYW1wb25lMSQwIgYJKoZIhvcNAQkBFhVzZ3JhbXBvbmVAZ2VuZXh1cy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN49AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bmZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBISeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+YUqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+KYP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAGjUDBOMB0GA1UdDgQWBBQtQAWJRWNr/OswPSAdwCQh0Eei/DAfBgNVHSMEGDAWgBQtQAWJRWNr/OswPSAdwCQh0Eei/DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCjHe3JbNKv0Ywc1zlLacUNWcjLbmzvnjs8Wq5oxtf5wG5PUlhLSYZ9MPhuf95PlibnrO/xVY292P5lo4NKhS7VOonpbPQ/PrCMO84Pz1LGfM/wCWQIowh6VHq18PiZka9zbwl6So0tgClKkFSRk4wpKrWX3+M3+Y+D0brd8sEtA6dXeYHDtqV0YgjKdZIIOx0vDT4alCoVQrQ1yAIq5INT3cSLgJezIhEadDv3Tc7bMxMFeL+81qHm9Z/9/KE6Z+JB0ZEOkF/2NSQJd+Z7MBR8CxOdTQis3ltMoXDatNkjZ2Env40sw4NICB8YYhsWMIarew5uNT+RS28YHNlbmogh"; + X509Certificate cert = CertificateUtil.getCertificate(base64, "", ""); + Assert.assertNotNull("testLoadBase64", cert); + } } diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/EncryptionTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/EncryptionTest.java new file mode 100644 index 000000000..f5b616cb4 --- /dev/null +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/EncryptionTest.java @@ -0,0 +1,20 @@ +package com.genexus.gam.utils.test; + +import com.genexus.gam.GamUtilsEO; +import org.junit.Assert; +import org.junit.Test; + +public class EncryptionTest { + + @Test + public void testAesGcm() { + String key = GamUtilsEO.randomHexaBits(256); + String nonce = GamUtilsEO.randomHexaBits(128); + String txt = "hello world"; + int macSize = 64; + String encrypted = GamUtilsEO.AesGcm(txt, key, nonce, macSize, true); + Assert.assertFalse("testAesGcm encrypt", encrypted.isEmpty()); + String decrypted = GamUtilsEO.AesGcm(encrypted, key, nonce, macSize, false); + Assert.assertEquals("testAesGcm decrypt", txt, decrypted); + } +} diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/HashTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/HashTest.java index 9d4cac171..8fe08139d 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/HashTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/HashTest.java @@ -39,7 +39,7 @@ public void testSha512() { @Test public void testSha512Random() { for (int i = 0; i < 100; i++) { - String value = Random.randomAlphanumeric(15); + String value = Random.alphanumeric(15); Assert.assertEquals("random sha512 ", cryptographicHash.ComputeHash(value), GamUtilsEO.sha512(value)); } } diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java index 670498760..4df8a7b8c 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java @@ -1,7 +1,7 @@ package com.genexus.gam.utils.test; import com.genexus.gam.GamUtilsEO; -import com.genexus.gam.utils.Jwt; +import com.genexus.gam.utils.json.Jwt; import com.nimbusds.jose.Algorithm; import com.nimbusds.jose.jwk.KeyUse; import com.nimbusds.jose.jwk.RSAKey; @@ -101,24 +101,68 @@ public void testVerifyPkcs8() { Assert.assertTrue("testVerifyPkcs8", result); } + @Test + public void testCreatePkcs8() + { + String token = GamUtilsEO.createJWTWithFile(path_RSA_sha256_2048 + "sha256d_key.pem", "", "", payload, header); + Assert.assertFalse("testCreatePkcs8", token.isEmpty()); + } + @Test public void testVerifyDer() { boolean result = GamUtilsEO.verifyJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.cer", "", "", tokenFile); Assert.assertTrue("testVerifyDer", result); } + @Test + public void testVerifyBase64() { + String base64 = "MIIEATCCAumgAwIBAgIJAIAqvKHZ+gFhMA0GCSqGSIb3DQEBCwUAMIGWMQswCQYDVQQGEwJVWTETMBEGA1UECAwKTW9udGV2aWRlbzETMBEGA1UEBwwKTW9udGV2aWRlbzEQMA4GA1UECgwHR2VuZVh1czERMA8GA1UECwwIU2VjdXJpdHkxEjAQBgNVBAMMCXNncmFtcG9uZTEkMCIGCSqGSIb3DQEJARYVc2dyYW1wb25lQGdlbmV4dXMuY29tMB4XDTIwMDcwODE4NTcxN1oXDTI1MDcwNzE4NTcxN1owgZYxCzAJBgNVBAYTAlVZMRMwEQYDVQQIDApNb250ZXZpZGVvMRMwEQYDVQQHDApNb250ZXZpZGVvMRAwDgYDVQQKDAdHZW5lWHVzMREwDwYDVQQLDAhTZWN1cml0eTESMBAGA1UEAwwJc2dyYW1wb25lMSQwIgYJKoZIhvcNAQkBFhVzZ3JhbXBvbmVAZ2VuZXh1cy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN49AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bmZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBISeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+YUqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+KYP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAGjUDBOMB0GA1UdDgQWBBQtQAWJRWNr/OswPSAdwCQh0Eei/DAfBgNVHSMEGDAWgBQtQAWJRWNr/OswPSAdwCQh0Eei/DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCjHe3JbNKv0Ywc1zlLacUNWcjLbmzvnjs8Wq5oxtf5wG5PUlhLSYZ9MPhuf95PlibnrO/xVY292P5lo4NKhS7VOonpbPQ/PrCMO84Pz1LGfM/wCWQIowh6VHq18PiZka9zbwl6So0tgClKkFSRk4wpKrWX3+M3+Y+D0brd8sEtA6dXeYHDtqV0YgjKdZIIOx0vDT4alCoVQrQ1yAIq5INT3cSLgJezIhEadDv3Tc7bMxMFeL+81qHm9Z/9/KE6Z+JB0ZEOkF/2NSQJd+Z7MBR8CxOdTQis3ltMoXDatNkjZ2Env40sw4NICB8YYhsWMIarew5uNT+RS28YHNlbmogh"; + boolean result = GamUtilsEO.verifyJWTWithFile(base64, "", "", tokenFile); + Assert.assertTrue("testVerifyBase64", result); + } + @Test public void testVerifyPkcs12() { boolean result = GamUtilsEO.verifyJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, tokenFile); Assert.assertTrue("testVerifyPkcs12", result); } + @Test + public void testCreatePkcs12() + { + String token = GamUtilsEO.createJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, payload, header); + Assert.assertFalse("testCreatePkcs12", token.isEmpty()); + } + + @Test + public void testCreateBase64() + { + String base64 = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN49AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bmZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBISeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+YUqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+KYP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAECggEBAJP8ajslcThisjzg47JWGS8z1FXi2Q8hg1Yv61o8avcHEY0y8tdEKUnkQ3TT4E0M0CgsL078ATz4cNmvhzYIv+j66aEv3w/XRRhl/NWBqx1YsQV5BWHy5sz9Nhe+WnnlbbSa5Ie+4NfpG1LDv/Mi19RZVg15p5ZwHGrkDCP47VYKgFXw51ZPxq/l3IIeq4PyueC/EPSAp4e9qei7p85k3i2yiWsHgZaHwHgDTx2Hgq1y/+/E5+HNxL2OlPr5lzlN2uIPZ9Rix2LDh0FriuCEjrXFsTJHw4LTK04rkeGledMtw6/bOTxibFbgeuQtY1XzG/M0+xlP2niBbAEA4Z6vTsECgYEA6k7LSsh6azsk0W9+dE6pbc3HisOoKI76rXi38gEQdCuF04OKt46WttQh4r1+dseO4OgjXtRMS0+5Hmx2jFXjPJexMgLftvrbwaVqg9WHenKL/qj5imCn4kVaa4Jo1VHFaIY+1b+iv+6WY/leFxGntAki9u4PRogRrUrWLRH9keUCgYEAxqLisgMHQGcpJDHJtI2N+HUgLDN065PtKlEP9o6WBwAb86/InVaTo2gmEvmslNQDYH16zdTczWMHnnBx1B012KpUD+t5CWIvMZdsTnMRDjWhdgm5ylN9NT89t5X8GPvo36WjuXAKWWjcRodzRgo57z9achCyMKhGU5yDOxh8jhkCgYAx6rtwoSlDcwQzAjfEe4Wo+PAL5gcLLPrGvjMiAYwJ08Pc/ectl9kP9j2J2qj4kSclTw9KApyGZuOfUagn2Zxhqkd7yhTzHJp4tM7uay1DrueYR1NyYYkisXfD87J1z8forsDwNLVtglzTy6p56674sgGa7bifZBmv+4OJco286QKBgQC4dGXDHGDNg36G590A1zpw8ILxyM7YPEPOOfxy3rGeypEqV6AZy13KLlq84DFM+xwvrBYvsW1hJIbcsFpjuMRZ8MGjDu0Us6JTkOO4bc32vgKzlBB9O85XdeSf6J1zrenwVOaWut5BbMiwjfOTpMdrzg71QV/XI0w7NGoApJp1cQKBgERfI6AfJTaKtEpfX3udR1B3zra1Y42ppU2TvGI5J2/cItENoyRmtyKYDp2I036/Pe63nuIzs31i6q/hCr9Tv3AGoSVKuPLpCWv5xVO/BPhGs5dwx81nUo0/P+H2X8dx7g57PQY4uf4F9+EIXeAdbPqfB8GBW7RX3FDx5NpB+Hh/"; + String token = GamUtilsEO.createJWTWithFile(base64, "", "", payload, header); + Assert.assertFalse("testCreateBase64", token.isEmpty()); + } + @Test public void testVerifyPkcs12_withoutalias() { boolean result = GamUtilsEO.verifyJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.p12", "", password, tokenFile); Assert.assertTrue("testVerifyPkcs12_withoutalias", result); } + @Test + public void testCreatePkcs12_withoutalias() { + String token = GamUtilsEO.createJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.p12", "", password, payload, header); + Assert.assertFalse("testCreatePkcs12_withoutalias", token.isEmpty()); + } + + @Test + public void testCombine() + { + String token = GamUtilsEO.createJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, payload, header); + Assert.assertFalse("testCombine create", token.isEmpty()); + boolean result = GamUtilsEO.verifyJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, tokenFile); + Assert.assertTrue("testCombine verify", result); + } + private static RSAPrivateKey loadPrivateKey(String path) { try (FileReader privateKeyReader = new FileReader(path)) { try (PEMParser parser = new PEMParser(privateKeyReader)) { diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/PrivateKeyTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/PrivateKeyTest.java new file mode 100644 index 000000000..b0642aec5 --- /dev/null +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/PrivateKeyTest.java @@ -0,0 +1,74 @@ +package com.genexus.gam.utils.test; + +import com.genexus.gam.utils.keys.PrivateKeyUtil; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.security.interfaces.RSAPrivateKey; + +public class PrivateKeyTest { + + private static String path_RSA_sha256_2048; + private static String alias; + private static String password; + + @BeforeClass + public static void setUp() { + String resources = System.getProperty("user.dir").concat("/src/test/resources"); + path_RSA_sha256_2048 = resources.concat("/dummycerts/RSA_sha256_2048/"); + alias = "1"; + password = "dummy"; + } + + @Test + public void testLoadPfx() { + RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_cert.pfx", alias, password); + Assert.assertNotNull("testLoadPfx", key); + RSAPrivateKey key1 = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_cert.pfx", "", password); + Assert.assertNotNull("testLoadPfx empty alias", key1); + } + + @Test + public void testLoadJks() { + RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_cert.jks", alias, password); + Assert.assertNotNull("testLoadJks", key); + RSAPrivateKey key1 = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_cert.jks", "", password); + Assert.assertNotNull("testLoadJks empty alias", key1); + } + + @Test + public void testLoadPkcs12() { + RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_cert.pkcs12", alias, password); + Assert.assertNotNull("testLoadPkcs12", key); + RSAPrivateKey key1 = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_cert.pkcs12", "", password); + Assert.assertNotNull("testLoadPkcs12 empty alias", key1); + } + + @Test + public void testLoadP12() { + RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password); + Assert.assertNotNull("testLoadP12", key); + RSAPrivateKey key1 = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_cert.p12", "", password); + Assert.assertNotNull("testLoadP12 empty alias", key1); + } + + @Test + public void testLoadPem() { + RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256d_key.pem", "", ""); + Assert.assertNotNull("testLoadPem", key); + } + + @Test + public void testLoadKey() { + RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256d_key.key", "", ""); + Assert.assertNotNull("testLoadKey", key); + } + + @Test + public void testLoadBase64() { + String base64 = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN49AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bmZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBISeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+YUqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+KYP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAECggEBAJP8ajslcThisjzg47JWGS8z1FXi2Q8hg1Yv61o8avcHEY0y8tdEKUnkQ3TT4E0M0CgsL078ATz4cNmvhzYIv+j66aEv3w/XRRhl/NWBqx1YsQV5BWHy5sz9Nhe+WnnlbbSa5Ie+4NfpG1LDv/Mi19RZVg15p5ZwHGrkDCP47VYKgFXw51ZPxq/l3IIeq4PyueC/EPSAp4e9qei7p85k3i2yiWsHgZaHwHgDTx2Hgq1y/+/E5+HNxL2OlPr5lzlN2uIPZ9Rix2LDh0FriuCEjrXFsTJHw4LTK04rkeGledMtw6/bOTxibFbgeuQtY1XzG/M0+xlP2niBbAEA4Z6vTsECgYEA6k7LSsh6azsk0W9+dE6pbc3HisOoKI76rXi38gEQdCuF04OKt46WttQh4r1+dseO4OgjXtRMS0+5Hmx2jFXjPJexMgLftvrbwaVqg9WHenKL/qj5imCn4kVaa4Jo1VHFaIY+1b+iv+6WY/leFxGntAki9u4PRogRrUrWLRH9keUCgYEAxqLisgMHQGcpJDHJtI2N+HUgLDN065PtKlEP9o6WBwAb86/InVaTo2gmEvmslNQDYH16zdTczWMHnnBx1B012KpUD+t5CWIvMZdsTnMRDjWhdgm5ylN9NT89t5X8GPvo36WjuXAKWWjcRodzRgo57z9achCyMKhGU5yDOxh8jhkCgYAx6rtwoSlDcwQzAjfEe4Wo+PAL5gcLLPrGvjMiAYwJ08Pc/ectl9kP9j2J2qj4kSclTw9KApyGZuOfUagn2Zxhqkd7yhTzHJp4tM7uay1DrueYR1NyYYkisXfD87J1z8forsDwNLVtglzTy6p56674sgGa7bifZBmv+4OJco286QKBgQC4dGXDHGDNg36G590A1zpw8ILxyM7YPEPOOfxy3rGeypEqV6AZy13KLlq84DFM+xwvrBYvsW1hJIbcsFpjuMRZ8MGjDu0Us6JTkOO4bc32vgKzlBB9O85XdeSf6J1zrenwVOaWut5BbMiwjfOTpMdrzg71QV/XI0w7NGoApJp1cQKBgERfI6AfJTaKtEpfX3udR1B3zra1Y42ppU2TvGI5J2/cItENoyRmtyKYDp2I036/Pe63nuIzs31i6q/hCr9Tv3AGoSVKuPLpCWv5xVO/BPhGs5dwx81nUo0/P+H2X8dx7g57PQY4uf4F9+EIXeAdbPqfB8GBW7RX3FDx5NpB+Hh/"; + RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(base64, "", ""); + Assert.assertNotNull("testLoadBase64", key); + } +} diff --git a/gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256d_key.key b/gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256d_key.key new file mode 100644 index 000000000..e41d6f252 --- /dev/null +++ b/gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256d_key.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAtc4GlPloet6fQzVqAMuuNudhL2YzePQGN8dEApwGvCTvT5O8 +50MK8RBVCoGc79BhxGFu/l/rsia+wVuEwOn7iSfGoBP25mUWco3SY6LntBTC+n25 +gmfU7MacXuKc4rKclkPI2E+CpeCN33WTVEp+F0onZwygSEngtOZq3HIQyoSJ6YmA +yePNZbAeCUxLYt0uF8v06CsGOLemrbcOs+UA4QXPmK6PmFKq7pYjgCqnH8m3vZNO +48DArxVTNYa2GCe4cBw0haNzCsGdMtoMNMOkoFQcSxaPimD96ut2+cFYQ/Jc2kof +vFHMohzNv8oxHo+xJ0Rc3XJU0jV0RTWoi5xFXQIDAQABAoIBAQCT/Go7JXE4YrI8 +4OOyVhkvM9RV4tkPIYNWL+taPGr3BxGNMvLXRClJ5EN00+BNDNAoLC9O/AE8+HDZ +r4c2CL/o+umhL98P10UYZfzVgasdWLEFeQVh8ubM/TYXvlp55W20muSHvuDX6RtS +w7/zItfUWVYNeaeWcBxq5Awj+O1WCoBV8OdWT8av5dyCHquD8rngvxD0gKeHvano +u6fOZN4tsolrB4GWh8B4A08dh4Ktcv/vxOfhzcS9jpT6+Zc5TdriD2fUYsdiw4dB +a4rghI61xbEyR8OC0ytOK5HhpXnTLcOv2zk8YmxW4HrkLWNV8xvzNPsZT9p4gWwB +AOGer07BAoGBAOpOy0rIems7JNFvfnROqW3Nx4rDqCiO+q14t/IBEHQrhdODireO +lrbUIeK9fnbHjuDoI17UTEtPuR5sdoxV4zyXsTIC37b628GlaoPVh3pyi/6o+Ypg +p+JFWmuCaNVRxWiGPtW/or/ulmP5XhcRp7QJIvbuD0aIEa1K1i0R/ZHlAoGBAMai +4rIDB0BnKSQxybSNjfh1ICwzdOuT7SpRD/aOlgcAG/OvyJ1Wk6NoJhL5rJTUA2B9 +es3U3M1jB55wcdQdNdiqVA/reQliLzGXbE5zEQ41oXYJucpTfTU/PbeV/Bj76N+l +o7lwCllo3EaHc0YKOe8/WnIQsjCoRlOcgzsYfI4ZAoGAMeq7cKEpQ3MEMwI3xHuF +qPjwC+YHCyz6xr4zIgGMCdPD3P3nLZfZD/Y9idqo+JEnJU8PSgKchmbjn1GoJ9mc +YapHe8oU8xyaeLTO7mstQ67nmEdTcmGJIrF3w/Oydc/H6K7A8DS1bYJc08uqeeuu ++LIBmu24n2QZr/uDiXKNvOkCgYEAuHRlwxxgzYN+hufdANc6cPCC8cjO2DxDzjn8 +ct6xnsqRKlegGctdyi5avOAxTPscL6wWL7FtYSSG3LBaY7jEWfDBow7tFLOiU5Dj +uG3N9r4Cs5QQfTvOV3Xkn+idc63p8FTmlrreQWzIsI3zk6THa84O9UFf1yNMOzRq +AKSadXECgYBEXyOgHyU2irRKX197nUdQd862tWONqaVNk7xiOSdv3CLRDaMkZrci +mA6diNN+vz3ut57iM7N9Yuqv4Qq/U79wBqElSrjy6Qlr+cVTvwT4RrOXcMfNZ1KN +Pz/h9l/Hce4Oez0GOLn+BffhCF3gHWz6nwfBgVu0V9xQ8eTaQfh4fw== +-----END RSA PRIVATE KEY----- From a2c7ae2ee3988033cb80ec89d6bf977f6cd3ba79 Mon Sep 17 00:00:00 2001 From: sgrampone Date: Wed, 7 Aug 2024 15:13:48 -0300 Subject: [PATCH 05/21] Load encrypted private keys + tests --- .../gam/utils/keys/PrivateKeyUtil.java | 27 ++++++++++++----- .../com/genexus/gam/utils/test/JwtTest.java | 7 +++++ .../gam/utils/test/PrivateKeyTest.java | 7 +++++ .../genexus/gam/utils/test/RandomTest.java | 21 +++++++++++++ .../dummycerts/RSA_sha256_2048/sha256_key.pem | 30 +++++++++++++++++++ 5 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256_key.pem diff --git a/gamutils/src/main/java/com/genexus/gam/utils/keys/PrivateKeyUtil.java b/gamutils/src/main/java/com/genexus/gam/utils/keys/PrivateKeyUtil.java index 7132ea241..d467912c6 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/keys/PrivateKeyUtil.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/keys/PrivateKeyUtil.java @@ -6,16 +6,22 @@ import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.operator.InputDecryptorProvider; +import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo; +import org.bouncycastle.pkcs.jcajce.JcePKCSPBEInputDecryptorProviderBuilder; import org.bouncycastle.util.encoders.Base64; +import javax.crypto.EncryptedPrivateKeyInfo; import java.io.FileReader; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Paths; import java.security.KeyFactory; import java.security.KeyStore; +import java.security.Security; import java.security.interfaces.RSAPrivateKey; import java.security.spec.PKCS8EncodedKeySpec; @@ -49,7 +55,7 @@ public static PrivateKeyUtil value(String ext) { public static RSAPrivateKey getPrivateKey(String path, String alias, String password) { String extension = FilenameUtils.getExtension(path); - PrivateKeyUtil ext = extension.isEmpty() ? PrivateKeyUtil.value("b64"): PrivateKeyUtil.value(extension); + PrivateKeyUtil ext = extension.isEmpty() ? PrivateKeyUtil.value("b64") : PrivateKeyUtil.value(extension); switch (ext) { case pfx: case jks: @@ -58,7 +64,7 @@ public static RSAPrivateKey getPrivateKey(String path, String alias, String pass return loadFromPkcs12(path, alias, password); case pem: case key: - return loadFromPkcs8(path); + return loadFromPkcs8(path, password); case b64: return loadFromBase64(path); default: @@ -67,20 +73,18 @@ public static RSAPrivateKey getPrivateKey(String path, String alias, String pass } } - private static RSAPrivateKey loadFromBase64(String base64) - { + private static RSAPrivateKey loadFromBase64(String base64) { logger.debug("loadFromBase64"); - try(ASN1InputStream stream = new ASN1InputStream(Base64.decode(base64))) { + try (ASN1InputStream stream = new ASN1InputStream(Base64.decode(base64))) { ASN1Sequence seq = (ASN1Sequence) stream.readObject(); return castPrivateKeyInfo(PrivateKeyInfo.getInstance(seq)); - }catch (Exception e) - { + } catch (Exception e) { logger.error("loadFromBase64", e); return null; } } - private static RSAPrivateKey loadFromPkcs8(String path) { + private static RSAPrivateKey loadFromPkcs8(String path, String password) { logger.debug("loadFromPkcs8"); try (FileReader privateKeyReader = new FileReader(path)) { try (PEMParser parser = new PEMParser(privateKeyReader)) { @@ -91,6 +95,13 @@ private static RSAPrivateKey loadFromPkcs8(String path) { } else if (obj instanceof PEMKeyPair) { PEMKeyPair pemKeyPair = (PEMKeyPair) obj; return castPrivateKeyInfo(pemKeyPair.getPrivateKeyInfo()); + } else if (obj instanceof EncryptedPrivateKeyInfo || obj instanceof PKCS8EncryptedPrivateKeyInfo) { + logger.debug("loadFromPkcs8 encrypted private key"); + Security.addProvider(new BouncyCastleProvider()); + PKCS8EncryptedPrivateKeyInfo encPrivKeyInfo = (PKCS8EncryptedPrivateKeyInfo) obj; + InputDecryptorProvider pkcs8Prov = new JcePKCSPBEInputDecryptorProviderBuilder().setProvider("BC") + .build(password.toCharArray()); + return castPrivateKeyInfo(encPrivKeyInfo.decryptPrivateKeyInfo(pkcs8Prov)); } else { logger.error("loadFromPkcs8: Could not load private key"); return null; diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java index 4df8a7b8c..827938bfe 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java @@ -108,6 +108,13 @@ public void testCreatePkcs8() Assert.assertFalse("testCreatePkcs8", token.isEmpty()); } + @Test + public void testCreateEncryptedPkcs8() + { + String token = GamUtilsEO.createJWTWithFile(path_RSA_sha256_2048 + "sha256_key.pem", "", password, payload, header); + Assert.assertFalse("testCreateEncryptedPkcs8", token.isEmpty()); + } + @Test public void testVerifyDer() { boolean result = GamUtilsEO.verifyJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.cer", "", "", tokenFile); diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/PrivateKeyTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/PrivateKeyTest.java index b0642aec5..cdca0b9c6 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/PrivateKeyTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/PrivateKeyTest.java @@ -71,4 +71,11 @@ public void testLoadBase64() { RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(base64, "", ""); Assert.assertNotNull("testLoadBase64", key); } + + @Test + public void testLoadEncryptedPkcs8() + { + RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_key.pem", "", password); + Assert.assertNotNull("testLoadEncryptedPkcs8", key); + } } diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/RandomTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/RandomTest.java index 01cf944f7..0ce8f4888 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/RandomTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/RandomTest.java @@ -1,6 +1,7 @@ package com.genexus.gam.utils.test; import com.genexus.gam.GamUtilsEO; +import org.bouncycastle.util.encoders.Hex; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -52,4 +53,24 @@ public void testRandomAlphanumeric() { String l256_string = GamUtilsEO.randomAlphanumeric(l256); Assert.assertEquals("l256 alphanumeric: ", l256, l256_string.length()); } + + @Test + public void testHexaBits() { + int[] lengths = new int[]{32, 64, 128, 256, 512, 1024}; + for (int n : lengths) { + String hexa = GamUtilsEO.randomHexaBits(n); + Assert.assertFalse("TestHexaBits", hexa.isEmpty()); + try + { + byte[] decoded = Hex.decode(hexa); + if(decoded.length*8 != n) + { + Assert.fail("testHexaBits wrong hexa length"); + } + }catch(Exception e) + { + Assert.fail("testHexaBits not hexa characters" + e.getMessage()); + } + } + } } diff --git a/gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256_key.pem b/gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256_key.pem new file mode 100644 index 000000000..35a78f26f --- /dev/null +++ b/gamutils/src/test/resources/dummycerts/RSA_sha256_2048/sha256_key.pem @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI5Xxbb/ckzykCAggA +MBQGCCqGSIb3DQMHBAiLR0U2DKvbeQSCBMg5y4x5chPFsx7N081HcFhNVV2xwvIx +vbRcBeBUhiVaJUuJfRSXzwm16oqV7bZj91IkbePXGwkhHPeBoyy0yrNgsfFJ+t05 +lQU7vKxSFCiTdijGVbp2nxntOb1yRPkc2pA0iSSED00QNHpjDgcpywAKPDmRJSyM +mWDmrYzQYLTzyFgmcec53B27DXfHoGHBGwq1lfdKGzlphJPDxd+w+2VuAl33Zuq4 +oriu69l4CHcg64vJAa/Y9BkW3HiAytKaEBHHAuE8W2mHYfW4DwZlBur+lo+aUiNV +4RFOH1xdej/k4feMXsOnYak93gZIbWyr/8MljbQJLNlE+NkheNzAyTT2a9P04JOv +GUqv45EO9PIdDBemJxCiK4wmeoS/KhJ/zyictOsc1W659lzdCpCIecu0t/1La5b2 +/MWIkdDmqvE4CSNEmGNykLejKKjvGwk9hTsnpckoo44eNjSiElcItd6d0nZr8o9Q +h8kK8GF0bRjYYqiXoCO5WCO6h6IcJEVmx58/Y07yQ504Djih5eU5TrbPfVcUNcYy +fWbcai0/X6SSEJXOuvHtx6s+7Y8f3Uo9mh3UI2we4C7zPABvlGTDMRliamcUc4AD +8BCahJZuOTN1mkYae+G1IpFW3E12z7+C9bQ6tuundntPuc+GJvEw/Clss6dZ5b3w ++Gf+5Kc9PlPu/UxGTUFntN5AB2GGheERtw6UFG+Wf34aHg8uYPXnOYXK1ssnhXlI +TxbKSUBiirR/LwoXVapepQdLXfVxirW/QVB42dcH0mjtkgSy5k7teaKZV3eZQhid +Ja9tGq6cMEngzd7BNWA+zzrjn/Jj5DbnnQhYuBr+w82qfiVqc6VYxTCcs2KJK1lU +LuwXfygNcksvw+7w0tLqUWNsY1M1ZtmnSWiAW76G6ARugmTevYa0WXLAo/N74c96 +ORW0n8ZSQa7zhROJgefbXsuG4brTRnQMAJc+SzH09BRU8m3xeo8bygUGrN/aDyQy +DZ37pcWwFXlLRRshYoRqCW7v8TDVnCMSM9aujGnlSyK/l/88BCJuiLziHWPiJgvk +1x68JoEN/fxLh7O3qTYpUiyfVN8LHB6tqqJe97p12BAzo1HX5WSoq2a/oYl4Hqa2 +VfCwiI11NrUpv1EIKfa2yspRk4JVz38dT+KbxB5mz0MgEL8aq/9cJ4ISersTK2UU +ZJQPgPvJzbnXU4Vh0ON4P7f724eZvTxzGiiJZAIWrqiR7TyEd4J65r3FbBU1xpLU +tTgrvv38EkA9+qoAG9CjukGTn1k0T8jNC3vxkn4f2nIMn1n9YbvsiVsjzq1UKzRt +nxHHzMOfKnt092HsO8dtXwZadrpYcoZk9qVx9xbA1RO9rv9CSqLszWThUOT6xXmG +3F2ff9jXJjHtAog70TCrU2/bXZmZCmuHG78aLtSUSyNSgCc+Lp9CBQmc0QHrqjCS +7qwHXhdriOElj0fDwuFOk9pXUfc4t4YDWQGxY7+YWnS7RXCye9YI90U/8TyhLBOs +JZY2DDlOskC0NoIkqHfb2jyHMtW1BzmQIQ0tfKTxTzyg/dOZKJuIWhvpi9LTHDCI ++Er7OrZ0vf91c5FraxPaXatdw4laiNMak9fgWNsp44jIxYHi0zVQLkjQKDuKVoZo +Vzk= +-----END ENCRYPTED PRIVATE KEY----- From 055badf3a6e11322863379d175955f0d08bdd68f Mon Sep 17 00:00:00 2001 From: sgrampone Date: Thu, 15 Aug 2024 13:04:41 -0300 Subject: [PATCH 06/21] GamUtilsEO simplification and module refactor + tests --- .../main/java/com/genexus/gam/GamUtilsEO.java | 28 +-- .../java/com/genexus/gam/utils/json/Jwk.java | 4 +- .../java/com/genexus/gam/utils/json/Jwks.java | 34 --- .../java/com/genexus/gam/utils/json/Jwt.java | 63 ++++-- .../genexus/gam/utils/json/UnixTimestamp.java | 11 + .../gam/utils/keys/PrivateKeyUtil.java | 40 +++- ...ertificateUtil.java => PublicKeyUtil.java} | 105 ++++++--- .../gam/utils/test/CertificateTest.java | 87 -------- .../com/genexus/gam/utils/test/JwkTest.java | 42 ---- .../com/genexus/gam/utils/test/JwksTest.java | 41 ---- .../com/genexus/gam/utils/test/JwtTest.java | 204 ++++++++---------- .../gam/utils/test/PrivateKeyTest.java | 81 ------- .../gam/utils/test/UnixTimestampTest.java | 44 ++++ 13 files changed, 313 insertions(+), 471 deletions(-) delete mode 100644 gamutils/src/main/java/com/genexus/gam/utils/json/Jwks.java create mode 100644 gamutils/src/main/java/com/genexus/gam/utils/json/UnixTimestamp.java rename gamutils/src/main/java/com/genexus/gam/utils/keys/{CertificateUtil.java => PublicKeyUtil.java} (52%) delete mode 100644 gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java delete mode 100644 gamutils/src/test/java/com/genexus/gam/utils/test/JwksTest.java delete mode 100644 gamutils/src/test/java/com/genexus/gam/utils/test/PrivateKeyTest.java create mode 100644 gamutils/src/test/java/com/genexus/gam/utils/test/UnixTimestampTest.java diff --git a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java index cf0f78e7a..29554d7d4 100644 --- a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java +++ b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java @@ -4,8 +4,10 @@ import com.genexus.gam.utils.cryptography.Encryption; import com.genexus.gam.utils.cryptography.Hash; import com.genexus.gam.utils.json.Jwk; -import com.genexus.gam.utils.json.Jwks; import com.genexus.gam.utils.json.Jwt; +import com.genexus.gam.utils.json.UnixTimestamp; + +import java.util.Date; public class GamUtilsEO { @@ -45,27 +47,25 @@ public static String getPublicJwk(String jwkString) { return Jwk.getPublic(jwkString); } - public static boolean jwk_verifyJWT(String jwkString, String token) { - return Jwk.verifyJWT(jwkString, token); + //**JWT**// + public static boolean verifyJwt(String path, String alias, String password, String token) { + return Jwt.verify(path, alias, password, token); } - public static String jwk_createJwt(String jwkString, String payload, String header) { - return Jwk.createJwt(jwkString, payload, header); + public static String createJwt(String path, String alias, String password, String payload, String header) { + return Jwt.create(path, alias, password, payload, header); } - //**JWKS**// - - public static boolean jwks_verifyJWT(String jwksString, String token, String kid) { - return Jwks.verifyJWT(jwksString, token, kid); + public static long createUnixTimestamp(Date date) { + return UnixTimestamp.create(date); } - //**JWT**// - public static boolean verifyJWTWithFile(String path, String alias, String password, String token) { - return Jwt.verify(path, alias, password, token); + public static String getJwtHeader(String token) { + return Jwt.getHeader(token); } - public static String createJWTWithFile(String path, String alias, String password, String payload, String header) { - return Jwt.create(path, alias, password, payload, header); + public static String getJwtPayload(String token) { + return Jwt.getPayload(token); } /********EXTERNAL OBJECT PUBLIC METHODS - END ********/ diff --git a/gamutils/src/main/java/com/genexus/gam/utils/json/Jwk.java b/gamutils/src/main/java/com/genexus/gam/utils/json/Jwk.java index 313c12931..d1c4d074a 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/json/Jwk.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/json/Jwk.java @@ -44,7 +44,7 @@ public static String getPublic(String jwkString) { } } - public static boolean verifyJWT(String jwkString, String token) { + /*public static boolean verifyJWT(String jwkString, String token) { if (jwkString.isEmpty()) { logger.error("verifyJWT jwkString parameter is empty"); return false; @@ -83,5 +83,5 @@ public static String createJwt(String jwkString, String payload, String header) logger.error("createJwt", e); return ""; } - } + }*/ } diff --git a/gamutils/src/main/java/com/genexus/gam/utils/json/Jwks.java b/gamutils/src/main/java/com/genexus/gam/utils/json/Jwks.java deleted file mode 100644 index 5d73fc8d4..000000000 --- a/gamutils/src/main/java/com/genexus/gam/utils/json/Jwks.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.genexus.gam.utils.json; - -import com.nimbusds.jose.jwk.JWK; -import com.nimbusds.jose.jwk.JWKSet; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -public class Jwks { - - private static Logger logger = LogManager.getLogger(Jwks.class); - - public static boolean verifyJWT(String jwksString, String token, String kid) { - if (jwksString.isEmpty()) { - logger.error("verifyJWT jwksString parameter is empty"); - return false; - } - if (token.isEmpty()) { - logger.error("verifyJWT token parameter is empty"); - return false; - } - if (kid.isEmpty()) { - logger.error("verifyJWT kid parameter is empty"); - return false; - } - try { - JWKSet set = JWKSet.parse(jwksString); - JWK jwk = set.getKeyByKeyId(kid); - return Jwt.verify(jwk.toRSAKey().toRSAPublicKey(), token); - } catch (Exception e) { - logger.error("verifyJWT", e); - return false; - } - } -} diff --git a/gamutils/src/main/java/com/genexus/gam/utils/json/Jwt.java b/gamutils/src/main/java/com/genexus/gam/utils/json/Jwt.java index ef64bae3c..06efd4268 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/json/Jwt.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/json/Jwt.java @@ -1,7 +1,7 @@ package com.genexus.gam.utils.json; -import com.genexus.gam.utils.keys.CertificateUtil; import com.genexus.gam.utils.keys.PrivateKeyUtil; +import com.genexus.gam.utils.keys.PublicKeyUtil; import com.nimbusds.jose.JWSHeader; import com.nimbusds.jose.JWSVerifier; import com.nimbusds.jose.crypto.RSASSASigner; @@ -16,42 +16,73 @@ public class Jwt { - private static Logger logger = LogManager.getLogger(Jwt.class); + private static final Logger logger = LogManager.getLogger(Jwt.class); /******** EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/ - public static boolean verify(RSAPublicKey publicKey, String token) { + public static boolean verify(String path, String alias, String password, String token) { + logger.debug("verify"); try { - SignedJWT signedJWT = SignedJWT.parse(token); - JWSVerifier verifier = new RSASSAVerifier(publicKey); - return signedJWT.verify(verifier); + return verify(PublicKeyUtil.getPublicKey(path, alias, password, token), token); } catch (Exception e) { logger.error("verify", e); return false; } } - public static String create(RSAPrivateKey privateKey, String payload, String header) { + public static String create(String path, String alias, String password, String payload, String header) { + logger.debug("create"); try { - SignedJWT signedJWT = new SignedJWT(JWSHeader.parse(header), JWTClaimsSet.parse(payload)); - signedJWT.sign(new RSASSASigner(privateKey)); - return signedJWT.serialize(); - } catch (Exception e) { + return create(PrivateKeyUtil.getPrivateKey(path, alias, password), payload, header); + }catch (Exception e) + { logger.error("create", e); return ""; } } - public static boolean verify(String path, String alias, String password, String token) { - return verify((RSAPublicKey) CertificateUtil.getCertificate(path, alias, password).getPublicKey(), token); + public static String getHeader(String token) { + logger.debug("getHeader"); + try { + return SignedJWT.parse(token).getHeader().toString(); + } catch (Exception e) { + logger.error("getHeader", e); + return ""; + } } - public static String create(String path, String alias, String password, String payload, String header) - { - return create(PrivateKeyUtil.getPrivateKey(path, alias, password), payload, header); + public static String getPayload(String token) { + logger.debug("getPayload"); + try { + return SignedJWT.parse(token).getPayload().toString(); + } catch (Exception e) { + logger.error("getPayload", e); + return ""; + } } /******** EXTERNAL OBJECT PUBLIC METHODS - END ********/ + private static boolean verify(RSAPublicKey publicKey, String token) { + try { + SignedJWT signedJWT = SignedJWT.parse(token); + JWSVerifier verifier = new RSASSAVerifier(publicKey); + return signedJWT.verify(verifier); + } catch (Exception e) { + logger.error("verify", e); + return false; + } + } + + private static String create(RSAPrivateKey privateKey, String payload, String header) { + try { + SignedJWT signedJWT = new SignedJWT(JWSHeader.parse(header), JWTClaimsSet.parse(payload)); + signedJWT.sign(new RSASSASigner(privateKey)); + return signedJWT.serialize(); + } catch (Exception e) { + logger.error("create", e); + return ""; + } + } } diff --git a/gamutils/src/main/java/com/genexus/gam/utils/json/UnixTimestamp.java b/gamutils/src/main/java/com/genexus/gam/utils/json/UnixTimestamp.java new file mode 100644 index 000000000..e3b1044a4 --- /dev/null +++ b/gamutils/src/main/java/com/genexus/gam/utils/json/UnixTimestamp.java @@ -0,0 +1,11 @@ +package com.genexus.gam.utils.json; + +import java.util.Date; + +public class UnixTimestamp { + + public static long create(Date gxdate) { + return gxdate.toInstant().getEpochSecond(); + } + +} diff --git a/gamutils/src/main/java/com/genexus/gam/utils/keys/PrivateKeyUtil.java b/gamutils/src/main/java/com/genexus/gam/utils/keys/PrivateKeyUtil.java index d467912c6..ca691e092 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/keys/PrivateKeyUtil.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/keys/PrivateKeyUtil.java @@ -1,5 +1,6 @@ package com.genexus.gam.utils.keys; +import com.nimbusds.jose.jwk.JWK; import org.apache.commons.io.FilenameUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -24,10 +25,11 @@ import java.security.Security; import java.security.interfaces.RSAPrivateKey; import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Objects; public enum PrivateKeyUtil { - pfx, jks, pkcs12, p12, pem, key, b64; + pfx, jks, pkcs12, p12, pem, key, b64, json; private static Logger logger = LogManager.getLogger(PrivateKeyUtil.class); @@ -47,16 +49,17 @@ public static PrivateKeyUtil value(String ext) { return key; case "b64": return b64; + case "json": + return json; default: - logger.error("Invalid certificate file extension"); + logger.error("Invalid private key file extension"); return null; } } - public static RSAPrivateKey getPrivateKey(String path, String alias, String password) { - String extension = FilenameUtils.getExtension(path); - PrivateKeyUtil ext = extension.isEmpty() ? PrivateKeyUtil.value("b64") : PrivateKeyUtil.value(extension); - switch (ext) { + public static RSAPrivateKey getPrivateKey(String path, String alias, String password) throws Exception{ + PrivateKeyUtil ext = PrivateKeyUtil.value(fixType(path)); + switch (Objects.requireNonNull(ext)) { case pfx: case jks: case pkcs12: @@ -67,12 +70,37 @@ public static RSAPrivateKey getPrivateKey(String path, String alias, String pass return loadFromPkcs8(path, password); case b64: return loadFromBase64(path); + case json: + return loadFromJson(path); default: logger.error("Invalid private key file extension"); return null; } } + private static RSAPrivateKey loadFromJson(String json) + { + logger.debug("loadFromJson"); + try { + JWK jwk = JWK.parse(json); + return jwk.toRSAKey().toRSAPrivateKey(); + } catch (Exception e) { + logger.error("loadFromJson", e); + return null; + } + } + + private static String fixType(String input) + { + try { + String extension = FilenameUtils.getExtension(input); + return extension.isEmpty() ? "b64" : extension; + }catch (IllegalArgumentException e) + { + return "json"; + } + } + private static RSAPrivateKey loadFromBase64(String base64) { logger.debug("loadFromBase64"); try (ASN1InputStream stream = new ASN1InputStream(Base64.decode(base64))) { diff --git a/gamutils/src/main/java/com/genexus/gam/utils/keys/CertificateUtil.java b/gamutils/src/main/java/com/genexus/gam/utils/keys/PublicKeyUtil.java similarity index 52% rename from gamutils/src/main/java/com/genexus/gam/utils/keys/CertificateUtil.java rename to gamutils/src/main/java/com/genexus/gam/utils/keys/PublicKeyUtil.java index 5fe3b0fd4..f7173806c 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/keys/CertificateUtil.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/keys/PublicKeyUtil.java @@ -1,8 +1,11 @@ package com.genexus.gam.utils.keys; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.LogManager; +import com.nimbusds.jose.jwk.JWK; +import com.nimbusds.jose.jwk.JWKSet; +import com.nimbusds.jwt.SignedJWT; import org.apache.commons.io.FilenameUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory; import org.bouncycastle.openssl.PEMParser; @@ -11,14 +14,43 @@ import java.io.*; import java.security.KeyStore; import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPublicKey; +import java.text.ParseException; +import java.util.Objects; -public enum CertificateUtil { +public enum PublicKeyUtil { - crt, cer, pfx, jks, pkcs12, p12, pem, key, b64; + crt, cer, pfx, jks, pkcs12, p12, pem, key, b64, json; - private static Logger logger = LogManager.getLogger(CertificateUtil.class); + private static final Logger logger = LogManager.getLogger(PublicKeyUtil.class); - public static CertificateUtil value(String ext) { + + public static RSAPublicKey getPublicKey(String path, String alias, String password, String token) throws NullPointerException{ + logger.debug("getPublicKey"); + PublicKeyUtil ext = PublicKeyUtil.value(fixType(path)); + switch (Objects.requireNonNull(ext)) { + case crt: + case cer: + return (RSAPublicKey) Objects.requireNonNull(loadFromDer(path)).getPublicKey(); + case pfx: + case jks: + case pkcs12: + case p12: + return (RSAPublicKey) Objects.requireNonNull(loadFromPkcs12(path, alias, password)).getPublicKey(); + case pem: + case key: + return (RSAPublicKey) Objects.requireNonNull(loadFromPkcs8(path)).getPublicKey(); + case b64: + return (RSAPublicKey) Objects.requireNonNull(loadFromBase64(path)).getPublicKey(); + case json: + return loadFromJson(path, token); + default: + logger.error("Invalid public key file extension"); + return null; + } + } + + private static PublicKeyUtil value(String ext) { switch (ext.toLowerCase().trim()) { case "crt": return crt; @@ -38,37 +70,51 @@ public static CertificateUtil value(String ext) { return key; case "b64": return b64; + case "json": + return json; default: logger.error("Invalid certificate file extension"); return null; } } - public static X509Certificate getCertificate(String path, String alias, String password) { - String extension = FilenameUtils.getExtension(path); - CertificateUtil ext = extension.isEmpty() ? CertificateUtil.value("b64"): CertificateUtil.value(extension); - switch (ext) { - case crt: - case cer: - return loadFromDer(path); - case pfx: - case jks: - case pkcs12: - case p12: - return loadFromPkcs12(path, alias, password); - case pem: - case key: - return loadFromPkcs8(path); - case b64: - return loadBase64(path); - default: - logger.error("Invalid certificate file extension"); - return null; + private static RSAPublicKey loadFromJson(String json, String token) { + logger.debug("loadFromJson"); + try { + JWK jwk = JWK.parse(json); + return (RSAPublicKey) jwk.toRSAKey().toPublicKey(); + } catch (ParseException e) { + return loadFromJwks(json, token); + } catch (Exception e) { + logger.error("loadFromJson", e); + return null; } } - private static X509Certificate loadBase64(String base64) - { + private static RSAPublicKey loadFromJwks(String json, String token) { + logger.debug("loadFromJwks"); + try { + com.nimbusds.jose.JWSHeader header = SignedJWT.parse(token).getHeader(); + JWKSet set = JWKSet.parse(json); + JWK jwk = set.getKeyByKeyId(header.getKeyID()); + return (RSAPublicKey) jwk.toRSAKey().toPublicKey(); + } catch (Exception e) { + logger.error("loadFromJwks", e); + return null; + } + } + + private static String fixType(String input) { + try { + String extension = FilenameUtils.getExtension(input); + return extension.isEmpty() ? "b64" : extension; + } catch (IllegalArgumentException e) { + return "json"; + } + } + + + private static X509Certificate loadFromBase64(String base64) { logger.debug("loadBase64"); try { ByteArrayInputStream byteArray = new ByteArrayInputStream(Base64.decode(base64)); @@ -81,6 +127,7 @@ private static X509Certificate loadBase64(String base64) } private static X509Certificate loadFromPkcs8(String path) { + logger.debug("loadFromPkcs8"); try (FileReader privateKeyReader = new FileReader(new File(path))) { try (PEMParser parser = new PEMParser(privateKeyReader)) { Object obj = parser.readObject(); @@ -102,6 +149,7 @@ private static X509Certificate loadFromPkcs8(String path) { } private static X509Certificate loadFromPkcs12(String path, String alias, String password) { + logger.debug("loadFromPkcs12"); try (FileInputStream inStream = new FileInputStream(path)) { KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(inStream, password.toCharArray()); @@ -117,6 +165,7 @@ private static X509Certificate loadFromPkcs12(String path, String alias, String } private static X509Certificate loadFromDer(String path) { + logger.debug("loadFromDer"); try (FileInputStream inStream = new FileInputStream(path)) { CertificateFactory cf = new CertificateFactory(); return (X509Certificate) cf.engineGenerateCertificate(inStream); diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java deleted file mode 100644 index 2a6b1cf08..000000000 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/CertificateTest.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.genexus.gam.utils.test; - -import com.genexus.gam.utils.keys.CertificateUtil; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import java.security.cert.X509Certificate; - -public class CertificateTest { - - private static String path_RSA_sha256_2048; - private static String alias; - private static String password; - - @BeforeClass - public static void setUp() { - String resources = System.getProperty("user.dir").concat("/src/test/resources"); - path_RSA_sha256_2048 = resources.concat("/dummycerts/RSA_sha256_2048/"); - alias = "1"; - password = "dummy"; - } - - @Test - public void testLoadCrt() { - X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.crt", "", ""); - Assert.assertNotNull("testLoadCrt", cert); - } - - @Test - public void testLoadCer() { - X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.cer", "", ""); - Assert.assertNotNull("testLoadCer", cert); - } - - @Test - public void testLoadPfx() { - X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.pfx", alias, password); - Assert.assertNotNull("testLoadPfx", cert); - cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.pfx", "", password); - Assert.assertNotNull("testLoadPfx empty alias", cert); - } - - @Test - public void testLoadJks() { - X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.jks", alias, password); - Assert.assertNotNull("testLoadJks", cert); - X509Certificate cert1 = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.jks", "", password); - Assert.assertNotNull("testLoadJks empty alias", cert1); - } - - @Test - public void testLoadPkcs12() { - X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.pkcs12", alias, password); - Assert.assertNotNull("testLoadPkcs12", cert); - cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.pkcs12", "", password); - Assert.assertNotNull("testLoadPkcs12 empty alias", cert); - } - - @Test - public void testLoadP12() { - X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password); - Assert.assertNotNull("testLoadP12", cert); - cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.p12", "", password); - Assert.assertNotNull("testLoadP12 empty alias", cert); - } - - @Test - public void testLoadPem() { - X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.pem", "", ""); - Assert.assertNotNull("testLoadPem", cert); - } - - @Test - public void testLoadKey() { - X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.key", "", ""); - Assert.assertNotNull("testLoadKey", cert); - } - - @Test - public void testLoadBase64() - { - String base64 = "MIIEATCCAumgAwIBAgIJAIAqvKHZ+gFhMA0GCSqGSIb3DQEBCwUAMIGWMQswCQYDVQQGEwJVWTETMBEGA1UECAwKTW9udGV2aWRlbzETMBEGA1UEBwwKTW9udGV2aWRlbzEQMA4GA1UECgwHR2VuZVh1czERMA8GA1UECwwIU2VjdXJpdHkxEjAQBgNVBAMMCXNncmFtcG9uZTEkMCIGCSqGSIb3DQEJARYVc2dyYW1wb25lQGdlbmV4dXMuY29tMB4XDTIwMDcwODE4NTcxN1oXDTI1MDcwNzE4NTcxN1owgZYxCzAJBgNVBAYTAlVZMRMwEQYDVQQIDApNb250ZXZpZGVvMRMwEQYDVQQHDApNb250ZXZpZGVvMRAwDgYDVQQKDAdHZW5lWHVzMREwDwYDVQQLDAhTZWN1cml0eTESMBAGA1UEAwwJc2dyYW1wb25lMSQwIgYJKoZIhvcNAQkBFhVzZ3JhbXBvbmVAZ2VuZXh1cy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN49AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bmZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBISeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+YUqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+KYP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAGjUDBOMB0GA1UdDgQWBBQtQAWJRWNr/OswPSAdwCQh0Eei/DAfBgNVHSMEGDAWgBQtQAWJRWNr/OswPSAdwCQh0Eei/DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCjHe3JbNKv0Ywc1zlLacUNWcjLbmzvnjs8Wq5oxtf5wG5PUlhLSYZ9MPhuf95PlibnrO/xVY292P5lo4NKhS7VOonpbPQ/PrCMO84Pz1LGfM/wCWQIowh6VHq18PiZka9zbwl6So0tgClKkFSRk4wpKrWX3+M3+Y+D0brd8sEtA6dXeYHDtqV0YgjKdZIIOx0vDT4alCoVQrQ1yAIq5INT3cSLgJezIhEadDv3Tc7bMxMFeL+81qHm9Z/9/KE6Z+JB0ZEOkF/2NSQJd+Z7MBR8CxOdTQis3ltMoXDatNkjZ2Env40sw4NICB8YYhsWMIarew5uNT+RS28YHNlbmogh"; - X509Certificate cert = CertificateUtil.getCertificate(base64, "", ""); - Assert.assertNotNull("testLoadBase64", cert); - } -} diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/JwkTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/JwkTest.java index 6870b8d06..47f451368 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/JwkTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/JwkTest.java @@ -3,32 +3,12 @@ import com.genexus.gam.GamUtilsEO; import com.nimbusds.jose.jwk.JWKSet; import org.junit.Assert; -import org.junit.BeforeClass; import org.junit.Test; import java.text.ParseException; public class JwkTest { - private static String testJWK; - private static String header; - private static String payload; - - @BeforeClass - public static void setUp() { - testJWK = "{\"p\":\"2XZj5mZxLJlFjN0rK45gg25TtaDUrJ38-EK4F6n60X13Vb4oSeOUNWr7w1S2ibh7RFD687lKY588APrXK1zF33Ape3pRDz3JFZdPx5K_g_hK-ZlLNlHzXTk0okWqIszKdi2v_RLH-zow4GE-rwtW-bKDj3pdKB0_KWafhIv7X5c\",\"kty\":\"RSA\",\"q\":\"1ZsAPTJAcVLDVNFa_cNjzg0NS9DZZYsga22ESKPXy_pPkH0oOzlRm40BcYxiPR2yVDx0Ya7x_ekXQ9K-pKBE_U0YBE2PR6rDUV6Vr21O9BNuWUNXCg_VYosmyVF4hEG0itJty7OYXZPRCr9hAWRl7DjqGKZ1Y5wnaNMCR4gGuss\",\"d\":\"VxkWReeOVfMKlbi2Grf_XIddyMzZ0oid5BRjagXYnmtjxlddcIUrS0vJGPqSSbtyDN7-gPB98rSsJfzDBx3tbN9Vjr6vCs3pk_mi6xnCA1iKbIvW3wM3s4rP_6vCMBdwgSxIHufpLsmB9esPBuwYpOdEXJvRk_F6swSR6J6gBcNR3uL8Ht0OxtfiDP0X3C2aHe5HM9jkLlrqjcNWZDu1dXnDGh2fILF5lAPI7qssYuZzddOE5I7GMh3DuwfQ73W3ITyiezELJMnDKaEQUJAAEDWoqcGCGB14jDJwyKSNROouQtby_RP2uM-IO3_Hq1-u2Wu1QCXNK3R17NVeV_ktZw\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"c22bd870-634c-4860-9ccf-e38eca0b315b\",\"qi\":\"j5iACnxbBCPfPIv-QcGID0xLFWZAN7wU9t3B_16M-axl8OOQ0ll4ZjQ4hYmw_eYOk9TY7HbzR3SqfLoCh_As5QFvZhO1E_9JHw2IXDBBbkXY5m3vCGtrUwQXPX83nIHlVk6pJh6d5A3tfLm5ECz0nkiYbGdmtISsMiR-zfVryng\",\"dp\":\"prU01o8YGcmSYO-4RZbLdFZiw-18vKwNH0D-od2EU47sqgWyGxrlJqJSSScrHJ8ZmIDAMZGNbpvGwzWJOEvRwX3ZvzhA5f9GpU-vMF7WhNQWngwfdZATkhblu7TOPgli-IAD123Lc1Pj3k-OX2DBF4D7jEWRHsx0_EcY6OLrHRc\",\"alg\":\"RS256\",\"dq\":\"F6f03NIl5Ob_jvMompX7BaTYZh8ZFG_WBU-5qLnMemCcUyopPHXandl94W9kqdQSHdYcJX1Ue4RG-VHrnxvIyCyzjjZwucUloGtTNHxslAda3zPf_dNHFITIpN8K88q7DezEEB0xsJtgOUp8mcTerMyY0GYO9hsjGi7UP8vGwwU\",\"n\":\"tXMsASuh2-d6MJWifChlbsGKpcMYJtpczMeMdtZHdZgPBR-y2obZMOVjiuVOciU6bV8BtmLjc1IF1xENfL0LFgO9G9QvUyFfLHIhZR7c-NsELe5tC0aH_tDqYtjDTb-o9s6FZREFTrFy4R8jc6ZmfHtUPpzrv1SC3-cr1-sCi9TXlUtHRmYOLDbJFqriuRMhWxd7iPqeVac7tqGWCa_ALDERjDaZa0TLLLEbO6EubiLfk5lavO0jWOw9dxsvYouV0JGbxeczyevis5vC3XD3_yQJVC-r37lNDRiMbDD8hclMa75HXYJp7LNvScB5K6YERzfSullL7DF2q09dGVKCvQ\"}"; - header = "{\n" + - " \"alg\": \"RS256\",\n" + - " \"kid\": \"c22bd870-634c-4860-9ccf-e38eca0b315b\",\n" + - " \"typ\": \"JWT\"\n" + - "}"; - payload = "{\n" + - " \"sub\": \"1234567890\",\n" + - " \"name\": \"John Doe\",\n" + - " \"iat\": 1516239022\n" + - "}"; - } - @Test public void testGenerateKeyPair() { String jwk = GamUtilsEO.generateKeyPair(); @@ -47,26 +27,4 @@ public void testPublicJwk() { Assert.fail("Exception on testPublicJwk" + e.getMessage()); } } - - @Test - public void testCreateJwt() { - String jwt = GamUtilsEO.jwk_createJwt(testJWK, payload, header); - Assert.assertNotNull("testCreateJwt fail", jwt); - } - - @Test - public void testVerifyJwt() { - String jwt = GamUtilsEO.jwk_createJwt(testJWK, payload, header); - boolean result = GamUtilsEO.jwk_verifyJWT(testJWK, jwt); - Assert.assertTrue("testVerifyJwt fail", result); - } - - @Test - public void testVerifyJwt_wrong() { - String jwk = GamUtilsEO.generateKeyPair(); - String jwt = GamUtilsEO.jwk_createJwt(jwk, payload, header); - boolean result = GamUtilsEO.jwk_verifyJWT(testJWK, jwt); - Assert.assertFalse("testVerifyJwt_wrong fail", result); - } - } diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/JwksTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/JwksTest.java deleted file mode 100644 index 7c611304a..000000000 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/JwksTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.genexus.gam.utils.test; - -import com.genexus.gam.GamUtilsEO; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -public class JwksTest { - - private static String testJWKs; - private static String testJWK; - private static String header; - private static String payload; - private static String kid; - - @BeforeClass - public static void setUp() { - testJWK = "{\"p\":\"2XZj5mZxLJlFjN0rK45gg25TtaDUrJ38-EK4F6n60X13Vb4oSeOUNWr7w1S2ibh7RFD687lKY588APrXK1zF33Ape3pRDz3JFZdPx5K_g_hK-ZlLNlHzXTk0okWqIszKdi2v_RLH-zow4GE-rwtW-bKDj3pdKB0_KWafhIv7X5c\",\"kty\":\"RSA\",\"q\":\"1ZsAPTJAcVLDVNFa_cNjzg0NS9DZZYsga22ESKPXy_pPkH0oOzlRm40BcYxiPR2yVDx0Ya7x_ekXQ9K-pKBE_U0YBE2PR6rDUV6Vr21O9BNuWUNXCg_VYosmyVF4hEG0itJty7OYXZPRCr9hAWRl7DjqGKZ1Y5wnaNMCR4gGuss\",\"d\":\"VxkWReeOVfMKlbi2Grf_XIddyMzZ0oid5BRjagXYnmtjxlddcIUrS0vJGPqSSbtyDN7-gPB98rSsJfzDBx3tbN9Vjr6vCs3pk_mi6xnCA1iKbIvW3wM3s4rP_6vCMBdwgSxIHufpLsmB9esPBuwYpOdEXJvRk_F6swSR6J6gBcNR3uL8Ht0OxtfiDP0X3C2aHe5HM9jkLlrqjcNWZDu1dXnDGh2fILF5lAPI7qssYuZzddOE5I7GMh3DuwfQ73W3ITyiezELJMnDKaEQUJAAEDWoqcGCGB14jDJwyKSNROouQtby_RP2uM-IO3_Hq1-u2Wu1QCXNK3R17NVeV_ktZw\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"c22bd870-634c-4860-9ccf-e38eca0b315b\",\"qi\":\"j5iACnxbBCPfPIv-QcGID0xLFWZAN7wU9t3B_16M-axl8OOQ0ll4ZjQ4hYmw_eYOk9TY7HbzR3SqfLoCh_As5QFvZhO1E_9JHw2IXDBBbkXY5m3vCGtrUwQXPX83nIHlVk6pJh6d5A3tfLm5ECz0nkiYbGdmtISsMiR-zfVryng\",\"dp\":\"prU01o8YGcmSYO-4RZbLdFZiw-18vKwNH0D-od2EU47sqgWyGxrlJqJSSScrHJ8ZmIDAMZGNbpvGwzWJOEvRwX3ZvzhA5f9GpU-vMF7WhNQWngwfdZATkhblu7TOPgli-IAD123Lc1Pj3k-OX2DBF4D7jEWRHsx0_EcY6OLrHRc\",\"alg\":\"RS256\",\"dq\":\"F6f03NIl5Ob_jvMompX7BaTYZh8ZFG_WBU-5qLnMemCcUyopPHXandl94W9kqdQSHdYcJX1Ue4RG-VHrnxvIyCyzjjZwucUloGtTNHxslAda3zPf_dNHFITIpN8K88q7DezEEB0xsJtgOUp8mcTerMyY0GYO9hsjGi7UP8vGwwU\",\"n\":\"tXMsASuh2-d6MJWifChlbsGKpcMYJtpczMeMdtZHdZgPBR-y2obZMOVjiuVOciU6bV8BtmLjc1IF1xENfL0LFgO9G9QvUyFfLHIhZR7c-NsELe5tC0aH_tDqYtjDTb-o9s6FZREFTrFy4R8jc6ZmfHtUPpzrv1SC3-cr1-sCi9TXlUtHRmYOLDbJFqriuRMhWxd7iPqeVac7tqGWCa_ALDERjDaZa0TLLLEbO6EubiLfk5lavO0jWOw9dxsvYouV0JGbxeczyevis5vC3XD3_yQJVC-r37lNDRiMbDD8hclMa75HXYJp7LNvScB5K6YERzfSullL7DF2q09dGVKCvQ\"}"; - String public_jwk = GamUtilsEO.getPublicJwk(testJWK); - testJWKs = "{\"keys\": [" + public_jwk + "]}"; - header = "{\n" + - " \"alg\": \"RS256\",\n" + - " \"kid\": \"c22bd870-634c-4860-9ccf-e38eca0b315b\",\n" + - " \"typ\": \"JWT\"\n" + - "}"; - payload = "{\n" + - " \"sub\": \"1234567890\",\n" + - " \"name\": \"John Doe\",\n" + - " \"iat\": 1516239022\n" + - "}"; - kid = "c22bd870-634c-4860-9ccf-e38eca0b315b"; - } - - @Test - public void testverifyJWT() { - String jwt = GamUtilsEO.jwk_createJwt(testJWK, payload, header); - boolean result = GamUtilsEO.jwks_verifyJWT(testJWKs, jwt, kid); - Assert.assertTrue("testverifyJWT fail ", result); - } - -} diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java index 827938bfe..830c3de04 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java @@ -1,39 +1,25 @@ package com.genexus.gam.utils.test; import com.genexus.gam.GamUtilsEO; -import com.genexus.gam.utils.json.Jwt; -import com.nimbusds.jose.Algorithm; -import com.nimbusds.jose.jwk.KeyUse; -import com.nimbusds.jose.jwk.RSAKey; -import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.openssl.PEMKeyPair; -import org.bouncycastle.openssl.PEMParser; +import com.nimbusds.jose.jwk.JWK; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import java.io.FileReader; -import java.security.KeyFactory; -import java.security.interfaces.RSAPrivateKey; -import java.security.spec.PKCS8EncodedKeySpec; import java.util.UUID; public class JwtTest { private static String header; private static String payload; - private static String kid; - private static RSAKey keypair; private static String path_RSA_sha256_2048; private static String alias; private static String password; - private static String tokenFile; @BeforeClass public static void setUp() { String resources = System.getProperty("user.dir").concat("/src/test/resources"); - kid = UUID.randomUUID().toString(); + String kid = UUID.randomUUID().toString(); header = "{\n" + " \"alg\": \"RS256\",\n" + " \"kid\": \"" + kid + "\",\n" + @@ -44,151 +30,129 @@ public static void setUp() { " \"name\": \"John Doe\",\n" + " \"iat\": 1516239022\n" + "}"; - keypair = generateKeys(); path_RSA_sha256_2048 = resources.concat("/dummycerts/RSA_sha256_2048/"); alias = "1"; password = "dummy"; - tokenFile = Jwt.create(loadPrivateKey(path_RSA_sha256_2048 + "sha256d_key.pem"), payload, header); - } - - private static RSAKey generateKeys() { - try { - return new RSAKeyGenerator(2048) - .keyUse(KeyUse.SIGNATURE) - .keyID(kid) - .algorithm(Algorithm.parse("RS256")) - .generate(); - } catch (Exception e) { - return null; - } - } - - @Test - public void testCreate() { - try { - String token = Jwt.create(keypair.toRSAPrivateKey(), payload, header); - Assert.assertFalse("testCreate fail", token.isEmpty()); - } catch (Exception e) { - Assert.fail("testCreate fail. Exception: " + e.getMessage()); - } } @Test - public void testVerify() { - try { - String token = Jwt.create(keypair.toRSAPrivateKey(), payload, header); - boolean verifies = Jwt.verify(keypair.toRSAPublicKey(), token); - Assert.assertTrue("testVerify fail", verifies); - } catch (Exception e) { - Assert.fail("testVerify fail. Exception: " + e.getMessage()); - } + public void test_pkcs8_pem() { + String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256d_key.pem", "", "", payload, header); + Assert.assertFalse("test_pkcs8 create", token.isEmpty()); + boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.cer", "", "", token); + Assert.assertTrue("test_pkcs8 verify cer", result); } @Test - public void testVerify_wrong() { - try { - String token = Jwt.create(keypair.toRSAPrivateKey(), payload, header); - boolean verifies = Jwt.verify(generateKeys().toRSAPublicKey(), token); - Assert.assertFalse("testVerify fail", verifies); - } catch (Exception e) { - Assert.fail("testVerify_wrong fail. Exception: " + e.getMessage()); - } + public void test_get() { + String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256d_key.pem", "", "", payload, header); + Assert.assertFalse("test_get create", token.isEmpty()); + String header_get = GamUtilsEO.getJwtHeader(token); + Assert.assertFalse("test_get getHeader", header_get.isEmpty()); + String payload_get = GamUtilsEO.getJwtPayload(token); + Assert.assertFalse("test_get getPayload", payload_get.isEmpty()); } @Test - public void testVerifyPkcs8() { - boolean result = GamUtilsEO.verifyJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.pem", "", "", tokenFile); - Assert.assertTrue("testVerifyPkcs8", result); + public void test_pkcs8_key() { + String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256d_key.key", "", "", payload, header); + Assert.assertFalse("test_pkcs8 create", token.isEmpty()); + boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.crt", "", "", token); + Assert.assertTrue("test_pkcs8 verify crt", result); } @Test - public void testCreatePkcs8() - { - String token = GamUtilsEO.createJWTWithFile(path_RSA_sha256_2048 + "sha256d_key.pem", "", "", payload, header); - Assert.assertFalse("testCreatePkcs8", token.isEmpty()); + public void test_pkcs8_encrypted() { + String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256_key.pem", "", password, payload, header); + Assert.assertFalse("test_pkcs8_encrypted", token.isEmpty()); + boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.crt", "", "", token); + Assert.assertTrue("test_pkcs8_encrypted verify crt", result); } @Test - public void testCreateEncryptedPkcs8() - { - String token = GamUtilsEO.createJWTWithFile(path_RSA_sha256_2048 + "sha256_key.pem", "", password, payload, header); - Assert.assertFalse("testCreateEncryptedPkcs8", token.isEmpty()); + public void test_pkcs12_p12() { + String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, payload, header); + Assert.assertFalse("test_pkcs12_p12 create", token.isEmpty()); + boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, token); + Assert.assertTrue("test_pkcs12_p12 verify", result); } @Test - public void testVerifyDer() { - boolean result = GamUtilsEO.verifyJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.cer", "", "", tokenFile); - Assert.assertTrue("testVerifyDer", result); + public void test_pkcs12_pkcs12() { + String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256_cert.pkcs12", alias, password, payload, header); + Assert.assertFalse("test_pkcs12_pkcs12 create", token.isEmpty()); + boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.pkcs12", alias, password, token); + Assert.assertTrue("test_pkcs12_pkcs12 verify", result); } @Test - public void testVerifyBase64() { - String base64 = "MIIEATCCAumgAwIBAgIJAIAqvKHZ+gFhMA0GCSqGSIb3DQEBCwUAMIGWMQswCQYDVQQGEwJVWTETMBEGA1UECAwKTW9udGV2aWRlbzETMBEGA1UEBwwKTW9udGV2aWRlbzEQMA4GA1UECgwHR2VuZVh1czERMA8GA1UECwwIU2VjdXJpdHkxEjAQBgNVBAMMCXNncmFtcG9uZTEkMCIGCSqGSIb3DQEJARYVc2dyYW1wb25lQGdlbmV4dXMuY29tMB4XDTIwMDcwODE4NTcxN1oXDTI1MDcwNzE4NTcxN1owgZYxCzAJBgNVBAYTAlVZMRMwEQYDVQQIDApNb250ZXZpZGVvMRMwEQYDVQQHDApNb250ZXZpZGVvMRAwDgYDVQQKDAdHZW5lWHVzMREwDwYDVQQLDAhTZWN1cml0eTESMBAGA1UEAwwJc2dyYW1wb25lMSQwIgYJKoZIhvcNAQkBFhVzZ3JhbXBvbmVAZ2VuZXh1cy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN49AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bmZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBISeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+YUqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+KYP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAGjUDBOMB0GA1UdDgQWBBQtQAWJRWNr/OswPSAdwCQh0Eei/DAfBgNVHSMEGDAWgBQtQAWJRWNr/OswPSAdwCQh0Eei/DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCjHe3JbNKv0Ywc1zlLacUNWcjLbmzvnjs8Wq5oxtf5wG5PUlhLSYZ9MPhuf95PlibnrO/xVY292P5lo4NKhS7VOonpbPQ/PrCMO84Pz1LGfM/wCWQIowh6VHq18PiZka9zbwl6So0tgClKkFSRk4wpKrWX3+M3+Y+D0brd8sEtA6dXeYHDtqV0YgjKdZIIOx0vDT4alCoVQrQ1yAIq5INT3cSLgJezIhEadDv3Tc7bMxMFeL+81qHm9Z/9/KE6Z+JB0ZEOkF/2NSQJd+Z7MBR8CxOdTQis3ltMoXDatNkjZ2Env40sw4NICB8YYhsWMIarew5uNT+RS28YHNlbmogh"; - boolean result = GamUtilsEO.verifyJWTWithFile(base64, "", "", tokenFile); - Assert.assertTrue("testVerifyBase64", result); + public void test_pkcs12_jks() { + String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256_cert.jks", alias, password, payload, header); + Assert.assertFalse("test_pkcs12_jks create", token.isEmpty()); + boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.jks", alias, password, token); + Assert.assertTrue("test_pkcs12_jks verify", result); } @Test - public void testVerifyPkcs12() { - boolean result = GamUtilsEO.verifyJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, tokenFile); - Assert.assertTrue("testVerifyPkcs12", result); + public void test_pkcs12_pfx() { + String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256_cert.pfx", alias, password, payload, header); + Assert.assertFalse("test_pkcs12_pfx create", token.isEmpty()); + boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.pfx", alias, password, token); + Assert.assertTrue("test_pkcs12_pfx verify", result); } @Test - public void testCreatePkcs12() - { - String token = GamUtilsEO.createJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, payload, header); - Assert.assertFalse("testCreatePkcs12", token.isEmpty()); + public void test_pkcs12_noalias() { + String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256_cert.jks", "", password, payload, header); + Assert.assertFalse("test_pkcs12_noalias jks create", token.isEmpty()); + boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.jks", "", password, token); + Assert.assertTrue("test_pkcs12_noalias jks verify", result); } @Test - public void testCreateBase64() - { - String base64 = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN49AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bmZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBISeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+YUqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+KYP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAECggEBAJP8ajslcThisjzg47JWGS8z1FXi2Q8hg1Yv61o8avcHEY0y8tdEKUnkQ3TT4E0M0CgsL078ATz4cNmvhzYIv+j66aEv3w/XRRhl/NWBqx1YsQV5BWHy5sz9Nhe+WnnlbbSa5Ie+4NfpG1LDv/Mi19RZVg15p5ZwHGrkDCP47VYKgFXw51ZPxq/l3IIeq4PyueC/EPSAp4e9qei7p85k3i2yiWsHgZaHwHgDTx2Hgq1y/+/E5+HNxL2OlPr5lzlN2uIPZ9Rix2LDh0FriuCEjrXFsTJHw4LTK04rkeGledMtw6/bOTxibFbgeuQtY1XzG/M0+xlP2niBbAEA4Z6vTsECgYEA6k7LSsh6azsk0W9+dE6pbc3HisOoKI76rXi38gEQdCuF04OKt46WttQh4r1+dseO4OgjXtRMS0+5Hmx2jFXjPJexMgLftvrbwaVqg9WHenKL/qj5imCn4kVaa4Jo1VHFaIY+1b+iv+6WY/leFxGntAki9u4PRogRrUrWLRH9keUCgYEAxqLisgMHQGcpJDHJtI2N+HUgLDN065PtKlEP9o6WBwAb86/InVaTo2gmEvmslNQDYH16zdTczWMHnnBx1B012KpUD+t5CWIvMZdsTnMRDjWhdgm5ylN9NT89t5X8GPvo36WjuXAKWWjcRodzRgo57z9achCyMKhGU5yDOxh8jhkCgYAx6rtwoSlDcwQzAjfEe4Wo+PAL5gcLLPrGvjMiAYwJ08Pc/ectl9kP9j2J2qj4kSclTw9KApyGZuOfUagn2Zxhqkd7yhTzHJp4tM7uay1DrueYR1NyYYkisXfD87J1z8forsDwNLVtglzTy6p56674sgGa7bifZBmv+4OJco286QKBgQC4dGXDHGDNg36G590A1zpw8ILxyM7YPEPOOfxy3rGeypEqV6AZy13KLlq84DFM+xwvrBYvsW1hJIbcsFpjuMRZ8MGjDu0Us6JTkOO4bc32vgKzlBB9O85XdeSf6J1zrenwVOaWut5BbMiwjfOTpMdrzg71QV/XI0w7NGoApJp1cQKBgERfI6AfJTaKtEpfX3udR1B3zra1Y42ppU2TvGI5J2/cItENoyRmtyKYDp2I036/Pe63nuIzs31i6q/hCr9Tv3AGoSVKuPLpCWv5xVO/BPhGs5dwx81nUo0/P+H2X8dx7g57PQY4uf4F9+EIXeAdbPqfB8GBW7RX3FDx5NpB+Hh/"; - String token = GamUtilsEO.createJWTWithFile(base64, "", "", payload, header); - Assert.assertFalse("testCreateBase64", token.isEmpty()); + public void test_b64() { + String publicKey = "MIIEATCCAumgAwIBAgIJAIAqvKHZ+gFhMA0GCSqGSIb3DQEBCwUAMIGWMQswCQYDVQQGEwJVWTETMBEGA1UECAwKTW9udGV2aWRlbzETMBEGA1UEBwwKTW9udGV2aWRlbzEQMA4GA1UECgwHR2VuZVh1czERMA8GA1UECwwIU2VjdXJpdHkxEjAQBgNVBAMMCXNncmFtcG9uZTEkMCIGCSqGSIb3DQEJARYVc2dyYW1wb25lQGdlbmV4dXMuY29tMB4XDTIwMDcwODE4NTcxN1oXDTI1MDcwNzE4NTcxN1owgZYxCzAJBgNVBAYTAlVZMRMwEQYDVQQIDApNb250ZXZpZGVvMRMwEQYDVQQHDApNb250ZXZpZGVvMRAwDgYDVQQKDAdHZW5lWHVzMREwDwYDVQQLDAhTZWN1cml0eTESMBAGA1UEAwwJc2dyYW1wb25lMSQwIgYJKoZIhvcNAQkBFhVzZ3JhbXBvbmVAZ2VuZXh1cy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN49AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bmZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBISeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+YUqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+KYP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAGjUDBOMB0GA1UdDgQWBBQtQAWJRWNr/OswPSAdwCQh0Eei/DAfBgNVHSMEGDAWgBQtQAWJRWNr/OswPSAdwCQh0Eei/DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCjHe3JbNKv0Ywc1zlLacUNWcjLbmzvnjs8Wq5oxtf5wG5PUlhLSYZ9MPhuf95PlibnrO/xVY292P5lo4NKhS7VOonpbPQ/PrCMO84Pz1LGfM/wCWQIowh6VHq18PiZka9zbwl6So0tgClKkFSRk4wpKrWX3+M3+Y+D0brd8sEtA6dXeYHDtqV0YgjKdZIIOx0vDT4alCoVQrQ1yAIq5INT3cSLgJezIhEadDv3Tc7bMxMFeL+81qHm9Z/9/KE6Z+JB0ZEOkF/2NSQJd+Z7MBR8CxOdTQis3ltMoXDatNkjZ2Env40sw4NICB8YYhsWMIarew5uNT+RS28YHNlbmogh"; + String privateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN49AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bmZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBISeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+YUqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+KYP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAECggEBAJP8ajslcThisjzg47JWGS8z1FXi2Q8hg1Yv61o8avcHEY0y8tdEKUnkQ3TT4E0M0CgsL078ATz4cNmvhzYIv+j66aEv3w/XRRhl/NWBqx1YsQV5BWHy5sz9Nhe+WnnlbbSa5Ie+4NfpG1LDv/Mi19RZVg15p5ZwHGrkDCP47VYKgFXw51ZPxq/l3IIeq4PyueC/EPSAp4e9qei7p85k3i2yiWsHgZaHwHgDTx2Hgq1y/+/E5+HNxL2OlPr5lzlN2uIPZ9Rix2LDh0FriuCEjrXFsTJHw4LTK04rkeGledMtw6/bOTxibFbgeuQtY1XzG/M0+xlP2niBbAEA4Z6vTsECgYEA6k7LSsh6azsk0W9+dE6pbc3HisOoKI76rXi38gEQdCuF04OKt46WttQh4r1+dseO4OgjXtRMS0+5Hmx2jFXjPJexMgLftvrbwaVqg9WHenKL/qj5imCn4kVaa4Jo1VHFaIY+1b+iv+6WY/leFxGntAki9u4PRogRrUrWLRH9keUCgYEAxqLisgMHQGcpJDHJtI2N+HUgLDN065PtKlEP9o6WBwAb86/InVaTo2gmEvmslNQDYH16zdTczWMHnnBx1B012KpUD+t5CWIvMZdsTnMRDjWhdgm5ylN9NT89t5X8GPvo36WjuXAKWWjcRodzRgo57z9achCyMKhGU5yDOxh8jhkCgYAx6rtwoSlDcwQzAjfEe4Wo+PAL5gcLLPrGvjMiAYwJ08Pc/ectl9kP9j2J2qj4kSclTw9KApyGZuOfUagn2Zxhqkd7yhTzHJp4tM7uay1DrueYR1NyYYkisXfD87J1z8forsDwNLVtglzTy6p56674sgGa7bifZBmv+4OJco286QKBgQC4dGXDHGDNg36G590A1zpw8ILxyM7YPEPOOfxy3rGeypEqV6AZy13KLlq84DFM+xwvrBYvsW1hJIbcsFpjuMRZ8MGjDu0Us6JTkOO4bc32vgKzlBB9O85XdeSf6J1zrenwVOaWut5BbMiwjfOTpMdrzg71QV/XI0w7NGoApJp1cQKBgERfI6AfJTaKtEpfX3udR1B3zra1Y42ppU2TvGI5J2/cItENoyRmtyKYDp2I036/Pe63nuIzs31i6q/hCr9Tv3AGoSVKuPLpCWv5xVO/BPhGs5dwx81nUo0/P+H2X8dx7g57PQY4uf4F9+EIXeAdbPqfB8GBW7RX3FDx5NpB+Hh/"; + String token = GamUtilsEO.createJwt(privateKey, "", "", payload, header); + Assert.assertFalse("test_b64 create", token.isEmpty()); + boolean result = GamUtilsEO.verifyJwt(publicKey, "", "", token); + Assert.assertTrue("test_b64 verify", result); } @Test - public void testVerifyPkcs12_withoutalias() { - boolean result = GamUtilsEO.verifyJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.p12", "", password, tokenFile); - Assert.assertTrue("testVerifyPkcs12_withoutalias", result); + public void test_json_jwk() { + String keyPair = GamUtilsEO.generateKeyPair(); + String token = GamUtilsEO.createJwt(keyPair, "", "", payload, header); + Assert.assertFalse("test_json_jwk create", token.isEmpty()); + String publicJwk = GamUtilsEO.getPublicJwk(keyPair); + boolean result = GamUtilsEO.verifyJwt(publicJwk, "", "", token); + Assert.assertTrue("test_json_jwk verify", result); } @Test - public void testCreatePkcs12_withoutalias() { - String token = GamUtilsEO.createJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.p12", "", password, payload, header); - Assert.assertFalse("testCreatePkcs12_withoutalias", token.isEmpty()); - } - - @Test - public void testCombine() - { - String token = GamUtilsEO.createJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, payload, header); - Assert.assertFalse("testCombine create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, tokenFile); - Assert.assertTrue("testCombine verify", result); - } + public void test_json_jwks() { + String keyPair = GamUtilsEO.generateKeyPair(); + String publicJwk = GamUtilsEO.getPublicJwk(keyPair); + String header_jwks = makeHeader(publicJwk); + String token = GamUtilsEO.createJwt(keyPair, "", "", payload, header_jwks); + Assert.assertFalse("test_json_jwks create", token.isEmpty()); + String publicJwks = "{\"keys\": [" + publicJwk + "]}"; + boolean result = GamUtilsEO.verifyJwt(publicJwks, "", "", token); + Assert.assertTrue("test_json_jwks verify", result); + } + + private static String makeHeader(String publicJwk) { + try { + JWK jwk = JWK.parse(publicJwk); + return "{\n" + + " \"alg\": \"RS256\",\n" + + " \"kid\": \"" + jwk.getKeyID() + "\",\n" + + " \"typ\": \"JWT\"\n" + + "}"; - private static RSAPrivateKey loadPrivateKey(String path) { - try (FileReader privateKeyReader = new FileReader(path)) { - try (PEMParser parser = new PEMParser(privateKeyReader)) { - Object obj; - obj = parser.readObject(); - if (obj instanceof PEMKeyPair) { - PEMKeyPair pemKeyPair = (PEMKeyPair) obj; - PrivateKeyInfo privateKeyInfo = pemKeyPair.getPrivateKeyInfo(); - KeyFactory kf = KeyFactory.getInstance("RSA"); - PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyInfo.getEncoded()); - return (RSAPrivateKey) kf.generatePrivate(keySpec); - } else { - Assert.fail("loadPrivateKey fail, not PEMKeyPair type"); - return null; - } - } } catch (Exception e) { - Assert.fail("loadPrivateKey fail with exception " + e.getMessage()); - return null; + e.printStackTrace(); + return ""; } } } diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/PrivateKeyTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/PrivateKeyTest.java deleted file mode 100644 index cdca0b9c6..000000000 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/PrivateKeyTest.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.genexus.gam.utils.test; - -import com.genexus.gam.utils.keys.PrivateKeyUtil; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import java.security.interfaces.RSAPrivateKey; - -public class PrivateKeyTest { - - private static String path_RSA_sha256_2048; - private static String alias; - private static String password; - - @BeforeClass - public static void setUp() { - String resources = System.getProperty("user.dir").concat("/src/test/resources"); - path_RSA_sha256_2048 = resources.concat("/dummycerts/RSA_sha256_2048/"); - alias = "1"; - password = "dummy"; - } - - @Test - public void testLoadPfx() { - RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_cert.pfx", alias, password); - Assert.assertNotNull("testLoadPfx", key); - RSAPrivateKey key1 = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_cert.pfx", "", password); - Assert.assertNotNull("testLoadPfx empty alias", key1); - } - - @Test - public void testLoadJks() { - RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_cert.jks", alias, password); - Assert.assertNotNull("testLoadJks", key); - RSAPrivateKey key1 = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_cert.jks", "", password); - Assert.assertNotNull("testLoadJks empty alias", key1); - } - - @Test - public void testLoadPkcs12() { - RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_cert.pkcs12", alias, password); - Assert.assertNotNull("testLoadPkcs12", key); - RSAPrivateKey key1 = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_cert.pkcs12", "", password); - Assert.assertNotNull("testLoadPkcs12 empty alias", key1); - } - - @Test - public void testLoadP12() { - RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password); - Assert.assertNotNull("testLoadP12", key); - RSAPrivateKey key1 = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_cert.p12", "", password); - Assert.assertNotNull("testLoadP12 empty alias", key1); - } - - @Test - public void testLoadPem() { - RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256d_key.pem", "", ""); - Assert.assertNotNull("testLoadPem", key); - } - - @Test - public void testLoadKey() { - RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256d_key.key", "", ""); - Assert.assertNotNull("testLoadKey", key); - } - - @Test - public void testLoadBase64() { - String base64 = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN49AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bmZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBISeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+YUqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+KYP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAECggEBAJP8ajslcThisjzg47JWGS8z1FXi2Q8hg1Yv61o8avcHEY0y8tdEKUnkQ3TT4E0M0CgsL078ATz4cNmvhzYIv+j66aEv3w/XRRhl/NWBqx1YsQV5BWHy5sz9Nhe+WnnlbbSa5Ie+4NfpG1LDv/Mi19RZVg15p5ZwHGrkDCP47VYKgFXw51ZPxq/l3IIeq4PyueC/EPSAp4e9qei7p85k3i2yiWsHgZaHwHgDTx2Hgq1y/+/E5+HNxL2OlPr5lzlN2uIPZ9Rix2LDh0FriuCEjrXFsTJHw4LTK04rkeGledMtw6/bOTxibFbgeuQtY1XzG/M0+xlP2niBbAEA4Z6vTsECgYEA6k7LSsh6azsk0W9+dE6pbc3HisOoKI76rXi38gEQdCuF04OKt46WttQh4r1+dseO4OgjXtRMS0+5Hmx2jFXjPJexMgLftvrbwaVqg9WHenKL/qj5imCn4kVaa4Jo1VHFaIY+1b+iv+6WY/leFxGntAki9u4PRogRrUrWLRH9keUCgYEAxqLisgMHQGcpJDHJtI2N+HUgLDN065PtKlEP9o6WBwAb86/InVaTo2gmEvmslNQDYH16zdTczWMHnnBx1B012KpUD+t5CWIvMZdsTnMRDjWhdgm5ylN9NT89t5X8GPvo36WjuXAKWWjcRodzRgo57z9achCyMKhGU5yDOxh8jhkCgYAx6rtwoSlDcwQzAjfEe4Wo+PAL5gcLLPrGvjMiAYwJ08Pc/ectl9kP9j2J2qj4kSclTw9KApyGZuOfUagn2Zxhqkd7yhTzHJp4tM7uay1DrueYR1NyYYkisXfD87J1z8forsDwNLVtglzTy6p56674sgGa7bifZBmv+4OJco286QKBgQC4dGXDHGDNg36G590A1zpw8ILxyM7YPEPOOfxy3rGeypEqV6AZy13KLlq84DFM+xwvrBYvsW1hJIbcsFpjuMRZ8MGjDu0Us6JTkOO4bc32vgKzlBB9O85XdeSf6J1zrenwVOaWut5BbMiwjfOTpMdrzg71QV/XI0w7NGoApJp1cQKBgERfI6AfJTaKtEpfX3udR1B3zra1Y42ppU2TvGI5J2/cItENoyRmtyKYDp2I036/Pe63nuIzs31i6q/hCr9Tv3AGoSVKuPLpCWv5xVO/BPhGs5dwx81nUo0/P+H2X8dx7g57PQY4uf4F9+EIXeAdbPqfB8GBW7RX3FDx5NpB+Hh/"; - RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(base64, "", ""); - Assert.assertNotNull("testLoadBase64", key); - } - - @Test - public void testLoadEncryptedPkcs8() - { - RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_key.pem", "", password); - Assert.assertNotNull("testLoadEncryptedPkcs8", key); - } -} diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/UnixTimestampTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/UnixTimestampTest.java new file mode 100644 index 000000000..43ebf395b --- /dev/null +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/UnixTimestampTest.java @@ -0,0 +1,44 @@ +package com.genexus.gam.utils.test; + +import com.genexus.gam.GamUtilsEO; +import org.junit.Assert; +import org.junit.Test; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +public class UnixTimestampTest { + + @Test + public void testCreate() { + Date one = createDate("2024/02/02 02:02:02"); //1706839322 + Date two = createDate("2023/03/03 03:03:03"); //1677812583 + Date three = createDate("2022/04/04 04:04:04"); //1649045044 + Date four = createDate("2020/02/02 02:22:22"); //1580610142 + Date five = createDate("2010/05/05 05:05:05"); //1273035905 + Date six = createDate("2000/05/05 05:05:05"); //957503105 + + Date[] arrayDates = new Date[]{one, two, three, four, five, six}; + long[] arrayStamps = new long[]{1706839322L, 1677812583L, 1649045044L, 1580610142L, 1273035905L, 957503105L}; + + for (int i = 0; i < arrayDates.length; i++) { + Assert.assertEquals("testCreate", GamUtilsEO.createUnixTimestamp(arrayDates[i]), arrayStamps[i]); + } + + } + + private static Date createDate(String date) { + + DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); + try { + return dateFormat.parse(date); + } catch (Exception e) { + + e.printStackTrace(); + return null; + } + } +} From 63abd1dcac4c42135b20b71fbf8214e7ba865ee1 Mon Sep 17 00:00:00 2001 From: sgrampone Date: Thu, 15 Aug 2024 13:30:54 -0300 Subject: [PATCH 07/21] Fix cast type error for jwk keys on gamutils --- .../gam/utils/keys/PrivateKeyUtil.java | 26 ++++++--- .../genexus/gam/utils/keys/PublicKeyUtil.java | 57 ++++++++++++------- 2 files changed, 53 insertions(+), 30 deletions(-) diff --git a/gamutils/src/main/java/com/genexus/gam/utils/keys/PrivateKeyUtil.java b/gamutils/src/main/java/com/genexus/gam/utils/keys/PrivateKeyUtil.java index ca691e092..964a43ce9 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/keys/PrivateKeyUtil.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/keys/PrivateKeyUtil.java @@ -57,7 +57,7 @@ public static PrivateKeyUtil value(String ext) { } } - public static RSAPrivateKey getPrivateKey(String path, String alias, String password) throws Exception{ + public static RSAPrivateKey getPrivateKey(String path, String alias, String password) throws Exception { PrivateKeyUtil ext = PrivateKeyUtil.value(fixType(path)); switch (Objects.requireNonNull(ext)) { case pfx: @@ -78,8 +78,7 @@ public static RSAPrivateKey getPrivateKey(String path, String alias, String pass } } - private static RSAPrivateKey loadFromJson(String json) - { + private static RSAPrivateKey loadFromJson(String json) { logger.debug("loadFromJson"); try { JWK jwk = JWK.parse(json); @@ -90,13 +89,24 @@ private static RSAPrivateKey loadFromJson(String json) } } - private static String fixType(String input) - { + private static String fixType(String input) { + logger.debug("fixType"); try { String extension = FilenameUtils.getExtension(input); - return extension.isEmpty() ? "b64" : extension; - }catch (IllegalArgumentException e) - { + if (extension.isEmpty()) { + try { + Base64.decode(input); + logger.debug("b64"); + return "b64"; + } catch (Exception e) { + logger.debug("json"); + return "json"; + } + } else { + return extension; + } + } catch (IllegalArgumentException e) { + logger.debug("json"); return "json"; } } diff --git a/gamutils/src/main/java/com/genexus/gam/utils/keys/PublicKeyUtil.java b/gamutils/src/main/java/com/genexus/gam/utils/keys/PublicKeyUtil.java index f7173806c..0b8f2e17b 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/keys/PublicKeyUtil.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/keys/PublicKeyUtil.java @@ -25,29 +25,29 @@ public enum PublicKeyUtil { private static final Logger logger = LogManager.getLogger(PublicKeyUtil.class); - public static RSAPublicKey getPublicKey(String path, String alias, String password, String token) throws NullPointerException{ + public static RSAPublicKey getPublicKey(String path, String alias, String password, String token) throws NullPointerException { logger.debug("getPublicKey"); PublicKeyUtil ext = PublicKeyUtil.value(fixType(path)); - switch (Objects.requireNonNull(ext)) { - case crt: - case cer: - return (RSAPublicKey) Objects.requireNonNull(loadFromDer(path)).getPublicKey(); - case pfx: - case jks: - case pkcs12: - case p12: - return (RSAPublicKey) Objects.requireNonNull(loadFromPkcs12(path, alias, password)).getPublicKey(); - case pem: - case key: - return (RSAPublicKey) Objects.requireNonNull(loadFromPkcs8(path)).getPublicKey(); - case b64: - return (RSAPublicKey) Objects.requireNonNull(loadFromBase64(path)).getPublicKey(); - case json: - return loadFromJson(path, token); - default: - logger.error("Invalid public key file extension"); - return null; - } + switch (Objects.requireNonNull(ext)) { + case crt: + case cer: + return (RSAPublicKey) Objects.requireNonNull(loadFromDer(path)).getPublicKey(); + case pfx: + case jks: + case pkcs12: + case p12: + return (RSAPublicKey) Objects.requireNonNull(loadFromPkcs12(path, alias, password)).getPublicKey(); + case pem: + case key: + return (RSAPublicKey) Objects.requireNonNull(loadFromPkcs8(path)).getPublicKey(); + case b64: + return (RSAPublicKey) Objects.requireNonNull(loadFromBase64(path)).getPublicKey(); + case json: + return loadFromJson(path, token); + default: + logger.error("Invalid public key file extension"); + return null; + } } private static PublicKeyUtil value(String ext) { @@ -105,10 +105,23 @@ private static RSAPublicKey loadFromJwks(String json, String token) { } private static String fixType(String input) { + logger.debug("fixType"); try { String extension = FilenameUtils.getExtension(input); - return extension.isEmpty() ? "b64" : extension; + if (extension.isEmpty()) { + try { + Base64.decode(input); + logger.debug("b64"); + return "b64"; + } catch (Exception e) { + logger.debug("json"); + return "json"; + } + } else { + return extension; + } } catch (IllegalArgumentException e) { + logger.debug("json"); return "json"; } } From c1be143e4f10576b6eddb5fce092fd4aa6020e23 Mon Sep 17 00:00:00 2001 From: sgrampone Date: Mon, 19 Aug 2024 10:59:41 -0300 Subject: [PATCH 08/21] Add DynamicCall EO to GamUtils --- gamutils/pom.xml | 5 + .../com/genexus/gam/utils/DynamicCall.java | 100 ++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 gamutils/src/main/java/com/genexus/gam/utils/DynamicCall.java diff --git a/gamutils/pom.xml b/gamutils/pom.xml index 6a14635b9..90e75af79 100644 --- a/gamutils/pom.xml +++ b/gamutils/pom.xml @@ -41,6 +41,11 @@ commons-io 2.11.0 + + ${project.groupId} + gxcommon + ${project.version} + commons-codec commons-codec diff --git a/gamutils/src/main/java/com/genexus/gam/utils/DynamicCall.java b/gamutils/src/main/java/com/genexus/gam/utils/DynamicCall.java new file mode 100644 index 000000000..45b09a73c --- /dev/null +++ b/gamutils/src/main/java/com/genexus/gam/utils/DynamicCall.java @@ -0,0 +1,100 @@ +package com.genexus.gam.utils; + +import com.genexus.ModelContext; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +@SuppressWarnings("unused") +public class DynamicCall { + private final ModelContext mContext; + private final Integer mRemoteHandle; + private static final Logger logger = LogManager.getLogger(DynamicCall.class); + + /********EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/ + + @SuppressWarnings("unused") + public DynamicCall(ModelContext context, Integer remoteHandle) { + mContext = context; + mRemoteHandle = remoteHandle; + } + + @SuppressWarnings("unused") + public boolean execute(String assembly, String typeName, boolean useContext, String method, String jsonParms, String[] jsonOutput) { + logger.debug("execute"); + return doCall(assembly, typeName, useContext, method, false, "", jsonParms, jsonOutput); + } + + @SuppressWarnings("unused") + public boolean executeEventHandler(String assembly, String typeName, boolean useContext, String method, String eventType, String jsonInput, String[] jsonOutput) { + logger.debug("executeEventHandler"); + return doCall(assembly, typeName, useContext, method, true, eventType, jsonInput, jsonOutput); + } + + /********EXTERNAL OBJECT PUBLIC METHODS - END ********/ + + + private boolean doCall(String assembly, String typeName, boolean useContext, String method, boolean isEventHandler, String parm1, String parm2, String[] jsonOutput) { + logger.debug("doCall"); + Object[] parms; + Class[] parmTypes; + if (isEventHandler) { + parms = new Object[]{parm1, parm2, new String[]{jsonOutput[0]}}; + parmTypes = new Class[]{String.class, String.class, String[].class}; + } else { + parms = new Object[]{parm2, new String[]{jsonOutput[0]}}; + parmTypes = new Class[]{String.class, String[].class}; + } + + try { + Class myClass = Class.forName(typeName); + Class[] constructorParms; + Constructor constructor; + Object instance = null; + + if (useContext && (mContext != null)) { + try { + constructorParms = new Class[]{int.class, ModelContext.class}; + constructor = myClass.getConstructor(constructorParms); + instance = constructor.newInstance(new Object[]{mRemoteHandle, mContext}); + } catch (NoSuchMethodException e) { + logger.error("doCall", e); + } + } + + if (instance == null) { + constructorParms = new Class[]{int.class}; + constructor = myClass.getConstructor(constructorParms); + instance = constructor.newInstance(new Object[]{-2}); + } + + myClass.getMethod(method, parmTypes).invoke(instance, parms); + } catch (ClassNotFoundException e) { + logger.error("doCall", e); + jsonOutput[0] = "{\"error\":\"" + " class " + typeName + " not found" + "\"}"; + return false; + } catch (NoSuchMethodException e) { + logger.error("doCall", e); + jsonOutput[0] = "{\"error\":\"" + " method " + method + " not found" + "\"}"; + return false; + } catch (InstantiationException e) { + logger.error("doCall", e); + jsonOutput[0] = "{\"error\":\"" + " cannot instantiate type " + typeName + "\"}"; + return false; + } catch (IllegalAccessException e) { + logger.error("doCall", e); + jsonOutput[0] = "{\"error\":\"" + " cannot access method " + method + "\"}"; + return false; + } catch (InvocationTargetException e) { + logger.error("doCall", e); + jsonOutput[0] = "{\"error\":\"" + " InvocationTargetException in class " + typeName + "\"}"; + return false; + } + String[] result = (String[]) parms[parms.length - 1]; + jsonOutput[0] = result[0]; + logger.debug("doCall result {}", result[0]); + return true; + } +} From 842a76142962ad87b15090030d3294fc3dcc3d3b Mon Sep 17 00:00:00 2001 From: sgrampone Date: Thu, 29 Aug 2024 17:58:23 -0300 Subject: [PATCH 09/21] Add sha256 and encoding features for PKCE implementation --- .../main/java/com/genexus/gam/GamUtilsEO.java | 10 ++++++ .../com/genexus/gam/utils/EncodingUtil.java | 22 ++++++++++++ .../genexus/gam/utils/cryptography/Hash.java | 24 ++++++++++--- .../genexus/gam/utils/test/EncodingTest.java | 35 +++++++++++++++++++ .../com/genexus/gam/utils/test/HashTest.java | 10 ++++++ 5 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 gamutils/src/main/java/com/genexus/gam/utils/EncodingUtil.java create mode 100644 gamutils/src/test/java/com/genexus/gam/utils/test/EncodingTest.java diff --git a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java index 29554d7d4..8c183a911 100644 --- a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java +++ b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java @@ -1,5 +1,6 @@ package com.genexus.gam; +import com.genexus.gam.utils.EncodingUtil; import com.genexus.gam.utils.Random; import com.genexus.gam.utils.cryptography.Encryption; import com.genexus.gam.utils.cryptography.Hash; @@ -18,6 +19,10 @@ public static String sha512(String plainText) { return Hash.sha512(plainText); } + public static String sha256(String plainText) { + return Hash.sha256(plainText); + } + //**ENCRYPTION**// public static String AesGcm(String input, String key, String nonce, int macSize, boolean toEncrypt) { @@ -68,5 +73,10 @@ public static String getJwtPayload(String token) { return Jwt.getPayload(token); } + //**ENCODING**// + public static String base64ToBase64Url(String base64) { + return EncodingUtil.b64ToB64Url(base64); + } + /********EXTERNAL OBJECT PUBLIC METHODS - END ********/ } diff --git a/gamutils/src/main/java/com/genexus/gam/utils/EncodingUtil.java b/gamutils/src/main/java/com/genexus/gam/utils/EncodingUtil.java new file mode 100644 index 000000000..f264803b1 --- /dev/null +++ b/gamutils/src/main/java/com/genexus/gam/utils/EncodingUtil.java @@ -0,0 +1,22 @@ +package com.genexus.gam.utils; + + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bouncycastle.util.encoders.Base64; +import org.bouncycastle.util.encoders.UrlBase64; + +public class EncodingUtil { + + private static final Logger logger = LogManager.getLogger(EncodingUtil.class); + + public static String b64ToB64Url(String input) { + logger.debug("b64ToB64Url"); + try { + return new String(UrlBase64.encode(Base64.decode(input)), "UTF-8").replaceAll("[\ufffd]", ""); + } catch (Exception e) { + logger.error("b64ToB64Url", e); + return ""; + } + } +} diff --git a/gamutils/src/main/java/com/genexus/gam/utils/cryptography/Hash.java b/gamutils/src/main/java/com/genexus/gam/utils/cryptography/Hash.java index c9571be8f..0a3a6515a 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/cryptography/Hash.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/cryptography/Hash.java @@ -3,24 +3,38 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.util.encoders.Base64; import java.nio.charset.StandardCharsets; public class Hash { + private static Logger logger = LogManager.getLogger(Hash.class); public static String sha512(String plainText) { + logger.debug("sha512"); + return internalHash(new SHA512Digest(), plainText); + } + + public static String sha256(String plainText) + { + logger.debug("sha256"); + return internalHash(new SHA256Digest(), plainText); + } + + private static String internalHash(Digest digest, String plainText) + { + logger.debug("internalHash"); if (plainText.isEmpty()) { - logger.error("sha512 plainText is empty"); + logger.error("hash plainText is empty"); return ""; } byte[] inputBytes = plainText.getBytes(StandardCharsets.UTF_8); - Digest alg = new SHA512Digest(); - byte[] retValue = new byte[alg.getDigestSize()]; - alg.update(inputBytes, 0, inputBytes.length); - alg.doFinal(retValue, 0); + byte[] retValue = new byte[digest.getDigestSize()]; + digest.update(inputBytes, 0, inputBytes.length); + digest.doFinal(retValue, 0); return Base64.toBase64String(retValue); } } \ No newline at end of file diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/EncodingTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/EncodingTest.java new file mode 100644 index 000000000..b534c75b1 --- /dev/null +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/EncodingTest.java @@ -0,0 +1,35 @@ +package com.genexus.gam.utils.test; + +import com.genexus.gam.GamUtilsEO; +import org.bouncycastle.util.encoders.Base64; +import org.bouncycastle.util.encoders.UrlBase64; +import org.junit.Assert; +import org.junit.Test; + +import java.nio.charset.StandardCharsets; + +public class EncodingTest { + + @Test + public void testB64ToB64Url() { + int i = 0; + do { + String randomString = GamUtilsEO.randomAlphanumeric(128); + String testing = GamUtilsEO.base64ToBase64Url(Base64.toBase64String(randomString.getBytes(StandardCharsets.UTF_8))); + Assert.assertEquals("testB64ToB64Url", randomString, b64UrlToUtf8(testing)); + i++; + } while (i < 50); + } + + private static String b64UrlToUtf8(String base64Url) { + try { + byte[] bytes = UrlBase64.decode(base64Url); + return new String(bytes, StandardCharsets.UTF_8).replaceAll("[\ufffd]", ""); + } catch (Exception e) { + e.printStackTrace(); + return ""; + } + } + + +} diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/HashTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/HashTest.java index 8fe08139d..ad81f8b3a 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/HashTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/HashTest.java @@ -43,5 +43,15 @@ public void testSha512Random() { Assert.assertEquals("random sha512 ", cryptographicHash.ComputeHash(value), GamUtilsEO.sha512(value)); } } + @Test + public void testSha256() + { + String[] arrayInputs = new String[] {one, two, three, four, five}; + String[] arrayRes= new String[] {"dpLDrTVAu4A8Ags67mbNiIcSMjTqDG5xQ8Ct1z/0Me0=", "P8TM/nRYcOLA2Z9x8w/wZWyN7dQcwdfT03aw2+aF4vM=", "i1udsME9skJWyCmqNkqpDG0uujGLkjKkq5MTuVTTVV8=", "BO+vCA9aPnThwp0cpqSFaTgsu80yTo1Z0rg+8hwDnwA=", "IisL1R/O9+ZcLmLbLtZUVwE7q1a+b6/rGe4R1FMVPIA="}; + for(int i = 0; i < arrayInputs.length; i++) + { + Assert.assertEquals("testSha256 error", GamUtilsEO.sha256(arrayInputs[i]), arrayRes[i]); + } + } } \ No newline at end of file From 5322c50fcf7a62ca26a727a880f5f9643768af50 Mon Sep 17 00:00:00 2001 From: sgrampone Date: Thu, 29 Aug 2024 18:33:18 -0300 Subject: [PATCH 10/21] Fix hash class --- .../main/java/com/genexus/gam/GamUtilsEO.java | 4 ++-- .../genexus/gam/utils/cryptography/Hash.java | 23 +++++++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java index 8c183a911..6f7f152fa 100644 --- a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java +++ b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java @@ -16,11 +16,11 @@ public class GamUtilsEO { //**HASH**// public static String sha512(String plainText) { - return Hash.sha512(plainText); + return Hash.hash(plainText, Hash.SHA512); } public static String sha256(String plainText) { - return Hash.sha256(plainText); + return Hash.hash(plainText, Hash.SHA256); } //**ENCRYPTION**// diff --git a/gamutils/src/main/java/com/genexus/gam/utils/cryptography/Hash.java b/gamutils/src/main/java/com/genexus/gam/utils/cryptography/Hash.java index 0a3a6515a..f483cc3ec 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/cryptography/Hash.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/cryptography/Hash.java @@ -9,19 +9,24 @@ import java.nio.charset.StandardCharsets; -public class Hash { +public enum Hash { - private static Logger logger = LogManager.getLogger(Hash.class); + SHA256, SHA512; - public static String sha512(String plainText) { - logger.debug("sha512"); - return internalHash(new SHA512Digest(), plainText); - } + private static final Logger logger = LogManager.getLogger(Hash.class); - public static String sha256(String plainText) + public static String hash(String plainText, Hash hash) { - logger.debug("sha256"); - return internalHash(new SHA256Digest(), plainText); + switch (hash) + { + case SHA256: + return internalHash(new SHA256Digest(), plainText); + case SHA512: + return internalHash(new SHA512Digest(), plainText); + default: + logger.error("unrecognized hash"); + return ""; + } } private static String internalHash(Digest digest, String plainText) From 09ce4c38cf65365100cf9eb1289330f4b7caff0f Mon Sep 17 00:00:00 2001 From: sgrampone Date: Fri, 30 Aug 2024 14:27:48 -0300 Subject: [PATCH 11/21] Refactor Encoding class name --- gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java | 4 ++-- .../genexus/gam/utils/{EncodingUtil.java => Encoding.java} | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename gamutils/src/main/java/com/genexus/gam/utils/{EncodingUtil.java => Encoding.java} (92%) diff --git a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java index 6f7f152fa..5b24e45e7 100644 --- a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java +++ b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java @@ -1,6 +1,6 @@ package com.genexus.gam; -import com.genexus.gam.utils.EncodingUtil; +import com.genexus.gam.utils.Encoding; import com.genexus.gam.utils.Random; import com.genexus.gam.utils.cryptography.Encryption; import com.genexus.gam.utils.cryptography.Hash; @@ -75,7 +75,7 @@ public static String getJwtPayload(String token) { //**ENCODING**// public static String base64ToBase64Url(String base64) { - return EncodingUtil.b64ToB64Url(base64); + return Encoding.b64ToB64Url(base64); } /********EXTERNAL OBJECT PUBLIC METHODS - END ********/ diff --git a/gamutils/src/main/java/com/genexus/gam/utils/EncodingUtil.java b/gamutils/src/main/java/com/genexus/gam/utils/Encoding.java similarity index 92% rename from gamutils/src/main/java/com/genexus/gam/utils/EncodingUtil.java rename to gamutils/src/main/java/com/genexus/gam/utils/Encoding.java index f264803b1..f8acb5fae 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/EncodingUtil.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/Encoding.java @@ -6,9 +6,9 @@ import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.UrlBase64; -public class EncodingUtil { +public class Encoding { - private static final Logger logger = LogManager.getLogger(EncodingUtil.class); + private static final Logger logger = LogManager.getLogger(Encoding.class); public static String b64ToB64Url(String input) { logger.debug("b64ToB64Url"); From 2bc66165ebb1155698a0bc48f0d7e9b02432b307 Mon Sep 17 00:00:00 2001 From: sgrampone Date: Tue, 14 Jan 2025 16:28:13 -0300 Subject: [PATCH 12/21] Adding missing functions --- .../main/java/com/genexus/gam/GamUtilsEO.java | 31 ++++- .../java/com/genexus/gam/utils/Encoding.java | 13 ++ .../java/com/genexus/gam/utils/Random.java | 22 ++++ .../java/com/genexus/gam/utils/json/Jwk.java | 14 +++ .../java/com/genexus/gam/utils/json/Jwt.java | 39 ++++-- .../genexus/gam/utils/test/EncodingTest.java | 26 ++++ .../com/genexus/gam/utils/test/JwkTest.java | 8 ++ .../com/genexus/gam/utils/test/JwtTest.java | 113 ++++++++++++++---- .../genexus/gam/utils/test/RandomTest.java | 24 ++++ 9 files changed, 251 insertions(+), 39 deletions(-) diff --git a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java index 5b24e45e7..7a3af4b57 100644 --- a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java +++ b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java @@ -42,6 +42,10 @@ public static String randomHexaBits(int bits) { return Random.hexaBits(bits); } + public static String randomUtf8Bits(int bits) { + return Random.utf8Bits(bits); + } + //**JWK**// public static String generateKeyPair() { @@ -52,13 +56,30 @@ public static String getPublicJwk(String jwkString) { return Jwk.getPublic(jwkString); } + public static String getJwkAlgorithm(String jwkString) { + return Jwk.getAlgorithm(jwkString); + } + //**JWT**// - public static boolean verifyJwt(String path, String alias, String password, String token) { - return Jwt.verify(path, alias, password, token); + public static boolean verifyJwtRsa(String path, String alias, String password, String token) { + return Jwt.verify(path, alias, password, token, "", false); + } + + public static String createJwtRsa(String path, String alias, String password, String payload, String header) { + return Jwt.create(path, alias, password, payload, header, "", false); } - public static String createJwt(String path, String alias, String password, String payload, String header) { - return Jwt.create(path, alias, password, payload, header); + public static boolean verifyJwtSha(String secret, String token) { + return Jwt.verify("", "", "", token, secret, true); + } + + public static boolean verifyAlgorithm(String expectedAlgorithm, String token) + { + return Jwt.verifyAlgorithm(expectedAlgorithm, token); + } + + public static String createJwtSha(String secret, String payload, String header) { + return Jwt.create("", "", "", payload, header, secret, true); } public static long createUnixTimestamp(Date date) { @@ -78,5 +99,7 @@ public static String base64ToBase64Url(String base64) { return Encoding.b64ToB64Url(base64); } + public static String hexaToBase64(String hexa) { return Encoding.hexaToBase64(hexa); } + /********EXTERNAL OBJECT PUBLIC METHODS - END ********/ } diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Encoding.java b/gamutils/src/main/java/com/genexus/gam/utils/Encoding.java index f8acb5fae..73b824c89 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/Encoding.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/Encoding.java @@ -4,6 +4,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.bouncycastle.util.encoders.Base64; +import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.encoders.UrlBase64; public class Encoding { @@ -19,4 +20,16 @@ public static String b64ToB64Url(String input) { return ""; } } + + public static String hexaToBase64(String hexa) + { + logger.debug("hexaToBase64"); + try{ + return Base64.toBase64String(Hex.decode(hexa)); + }catch (Exception e) + { + logger.error("hexaToBase64", e); + return ""; + } + } } diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Random.java b/gamutils/src/main/java/com/genexus/gam/utils/Random.java index bb46e1b6f..8042215df 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/Random.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/Random.java @@ -3,6 +3,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.nio.charset.StandardCharsets; import java.security.SecureRandom; public class Random { @@ -59,4 +60,25 @@ public static String hexaBits(int bits) } return sb.toString().replaceAll("\\s", ""); } + + public static String utf8Bits(int bits) + { + int targetBytes = (bits + 7) / 8; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < targetBytes; i++) { + sb.append("a"); + } + String result = sb.toString(); + byte[] utf8Bytes = sb.toString().getBytes(StandardCharsets.UTF_8); + if (utf8Bytes.length > targetBytes) { + return new String(utf8Bytes, 0, targetBytes, StandardCharsets.UTF_8); + } else if (utf8Bytes.length < targetBytes) { + StringBuilder paddedString = new StringBuilder(sb.toString()); + for (int i = utf8Bytes.length; i < targetBytes; i++) { + paddedString.append("0"); + } + return paddedString.toString(); + } + return result; + } } diff --git a/gamutils/src/main/java/com/genexus/gam/utils/json/Jwk.java b/gamutils/src/main/java/com/genexus/gam/utils/json/Jwk.java index d1c4d074a..c4342a299 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/json/Jwk.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/json/Jwk.java @@ -44,6 +44,20 @@ public static String getPublic(String jwkString) { } } + public static String getAlgorithm(String jwkString) { + if (jwkString.isEmpty()) { + logger.error("getAlgorithm jwkString parameter is empty"); + return ""; + } + try { + return JWK.parse(jwkString).getAlgorithm().toString(); + } catch (Exception e) { + logger.error("getPublic", e); + return ""; + } + } + + /*public static boolean verifyJWT(String jwkString, String token) { if (jwkString.isEmpty()) { logger.error("verifyJWT jwkString parameter is empty"); diff --git a/gamutils/src/main/java/com/genexus/gam/utils/json/Jwt.java b/gamutils/src/main/java/com/genexus/gam/utils/json/Jwt.java index 06efd4268..45f34f7a3 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/json/Jwt.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/json/Jwt.java @@ -2,8 +2,12 @@ import com.genexus.gam.utils.keys.PrivateKeyUtil; import com.genexus.gam.utils.keys.PublicKeyUtil; +import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.jose.JWSHeader; +import com.nimbusds.jose.JWSSigner; import com.nimbusds.jose.JWSVerifier; +import com.nimbusds.jose.crypto.MACSigner; +import com.nimbusds.jose.crypto.MACVerifier; import com.nimbusds.jose.crypto.RSASSASigner; import com.nimbusds.jose.crypto.RSASSAVerifier; import com.nimbusds.jwt.JWTClaimsSet; @@ -20,20 +24,20 @@ public class Jwt { /******** EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/ - public static boolean verify(String path, String alias, String password, String token) { + public static boolean verify(String path, String alias, String password, String token, String secret, boolean isSymmetric) { logger.debug("verify"); try { - return verify(PublicKeyUtil.getPublicKey(path, alias, password, token), token); + return !isSymmetric ? verify_internal(PublicKeyUtil.getPublicKey(path, alias, password, token), token, "", isSymmetric) : verify_internal(null, token, secret, isSymmetric); } catch (Exception e) { logger.error("verify", e); return false; } } - public static String create(String path, String alias, String password, String payload, String header) { + public static String create(String path, String alias, String password, String payload, String header, String secret, boolean isSymmetric) { logger.debug("create"); try { - return create(PrivateKeyUtil.getPrivateKey(path, alias, password), payload, header); + return !isSymmetric ? create_internal(PrivateKeyUtil.getPrivateKey(path, alias, password), payload, header, "", isSymmetric): create_internal(null, payload, header, secret, isSymmetric); }catch (Exception e) { logger.error("create", e); @@ -61,26 +65,41 @@ public static String getPayload(String token) { } } + public static boolean verifyAlgorithm(String algorithm, String token) + { + logger.debug("verifyAlgorithm"); + try{ + return SignedJWT.parse(token).getHeader().getAlgorithm().equals(JWSAlgorithm.parse(algorithm)); + }catch (Exception e) + { + logger.error("verifyAlgorithm", e); + return false; + } + } + /******** EXTERNAL OBJECT PUBLIC METHODS - END ********/ - private static boolean verify(RSAPublicKey publicKey, String token) { + private static boolean verify_internal(RSAPublicKey publicKey, String token, String secret, boolean isSymmetric){ + logger.debug("verify_internal"); try { SignedJWT signedJWT = SignedJWT.parse(token); - JWSVerifier verifier = new RSASSAVerifier(publicKey); + JWSVerifier verifier = isSymmetric ? new MACVerifier(secret):new RSASSAVerifier(publicKey); return signedJWT.verify(verifier); } catch (Exception e) { - logger.error("verify", e); + logger.error("verify_internal", e); return false; } } - private static String create(RSAPrivateKey privateKey, String payload, String header) { + private static String create_internal(RSAPrivateKey privateKey, String payload, String header, String secret, boolean isSymmetric) { + logger.debug("create_internal"); try { SignedJWT signedJWT = new SignedJWT(JWSHeader.parse(header), JWTClaimsSet.parse(payload)); - signedJWT.sign(new RSASSASigner(privateKey)); + JWSSigner signer = isSymmetric ? new MACSigner(secret): new RSASSASigner(privateKey); + signedJWT.sign(signer); return signedJWT.serialize(); } catch (Exception e) { - logger.error("create", e); + logger.error("create_internal", e); return ""; } } diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/EncodingTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/EncodingTest.java index b534c75b1..7771a54f4 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/EncodingTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/EncodingTest.java @@ -1,7 +1,10 @@ package com.genexus.gam.utils.test; import com.genexus.gam.GamUtilsEO; +import com.genexus.gam.utils.Encoding; +import com.genexus.gam.utils.Random; import org.bouncycastle.util.encoders.Base64; +import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.encoders.UrlBase64; import org.junit.Assert; import org.junit.Test; @@ -31,5 +34,28 @@ private static String b64UrlToUtf8(String base64Url) { } } + @Test + public void testHexaToBase64() + { + int i = 0; + do { + String randomHexa = Random.hexaBits(128); + String testing = b64ToHexa(Encoding.hexaToBase64(randomHexa)); + Assert.assertEquals("testB64ToB64Url", randomHexa, testing); + i++; + } while (i < 50); + } + + private static String b64ToHexa(String base64) { + try { + byte[] bytes = Base64.decode(base64); + return Hex.toHexString(bytes); + } catch (Exception e) { + e.printStackTrace(); + return ""; + } + } + + } diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/JwkTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/JwkTest.java index 47f451368..3c6a40d6c 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/JwkTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/JwkTest.java @@ -27,4 +27,12 @@ public void testPublicJwk() { Assert.fail("Exception on testPublicJwk" + e.getMessage()); } } + + @Test + public void testGetAlgorithm() + { + String jwk = GamUtilsEO.generateKeyPair(); + String algorithm = GamUtilsEO.getJwkAlgorithm(jwk); + Assert.assertEquals("testGetAlgorithm", algorithm, "RS256"); + } } diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java index 830c3de04..eb449b0d6 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java @@ -10,7 +10,7 @@ public class JwtTest { - private static String header; + private static String headerRsa; private static String payload; private static String path_RSA_sha256_2048; private static String alias; @@ -18,9 +18,10 @@ public class JwtTest { @BeforeClass public static void setUp() { + String resources = System.getProperty("user.dir").concat("/src/test/resources"); String kid = UUID.randomUUID().toString(); - header = "{\n" + + headerRsa = "{\n" + " \"alg\": \"RS256\",\n" + " \"kid\": \"" + kid + "\",\n" + " \"typ\": \"JWT\"\n" + @@ -37,15 +38,15 @@ public static void setUp() { @Test public void test_pkcs8_pem() { - String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256d_key.pem", "", "", payload, header); + String token = GamUtilsEO.createJwtRsa(path_RSA_sha256_2048 + "sha256d_key.pem", "", "", payload, headerRsa); Assert.assertFalse("test_pkcs8 create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.cer", "", "", token); + boolean result = GamUtilsEO.verifyJwtRsa(path_RSA_sha256_2048 + "sha256_cert.cer", "", "", token); Assert.assertTrue("test_pkcs8 verify cer", result); } @Test public void test_get() { - String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256d_key.pem", "", "", payload, header); + String token = GamUtilsEO.createJwtRsa(path_RSA_sha256_2048 + "sha256d_key.pem", "", "", payload, headerRsa); Assert.assertFalse("test_get create", token.isEmpty()); String header_get = GamUtilsEO.getJwtHeader(token); Assert.assertFalse("test_get getHeader", header_get.isEmpty()); @@ -55,57 +56,57 @@ public void test_get() { @Test public void test_pkcs8_key() { - String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256d_key.key", "", "", payload, header); + String token = GamUtilsEO.createJwtRsa(path_RSA_sha256_2048 + "sha256d_key.key", "", "", payload, headerRsa); Assert.assertFalse("test_pkcs8 create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.crt", "", "", token); + boolean result = GamUtilsEO.verifyJwtRsa(path_RSA_sha256_2048 + "sha256_cert.crt", "", "", token); Assert.assertTrue("test_pkcs8 verify crt", result); } @Test public void test_pkcs8_encrypted() { - String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256_key.pem", "", password, payload, header); + String token = GamUtilsEO.createJwtRsa(path_RSA_sha256_2048 + "sha256_key.pem", "", password, payload, headerRsa); Assert.assertFalse("test_pkcs8_encrypted", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.crt", "", "", token); + boolean result = GamUtilsEO.verifyJwtRsa(path_RSA_sha256_2048 + "sha256_cert.crt", "", "", token); Assert.assertTrue("test_pkcs8_encrypted verify crt", result); } @Test public void test_pkcs12_p12() { - String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, payload, header); + String token = GamUtilsEO.createJwtRsa(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, payload, headerRsa); Assert.assertFalse("test_pkcs12_p12 create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, token); + boolean result = GamUtilsEO.verifyJwtRsa(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, token); Assert.assertTrue("test_pkcs12_p12 verify", result); } @Test public void test_pkcs12_pkcs12() { - String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256_cert.pkcs12", alias, password, payload, header); + String token = GamUtilsEO.createJwtRsa(path_RSA_sha256_2048 + "sha256_cert.pkcs12", alias, password, payload, headerRsa); Assert.assertFalse("test_pkcs12_pkcs12 create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.pkcs12", alias, password, token); + boolean result = GamUtilsEO.verifyJwtRsa(path_RSA_sha256_2048 + "sha256_cert.pkcs12", alias, password, token); Assert.assertTrue("test_pkcs12_pkcs12 verify", result); } @Test public void test_pkcs12_jks() { - String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256_cert.jks", alias, password, payload, header); + String token = GamUtilsEO.createJwtRsa(path_RSA_sha256_2048 + "sha256_cert.jks", alias, password, payload, headerRsa); Assert.assertFalse("test_pkcs12_jks create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.jks", alias, password, token); + boolean result = GamUtilsEO.verifyJwtRsa(path_RSA_sha256_2048 + "sha256_cert.jks", alias, password, token); Assert.assertTrue("test_pkcs12_jks verify", result); } @Test public void test_pkcs12_pfx() { - String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256_cert.pfx", alias, password, payload, header); + String token = GamUtilsEO.createJwtRsa(path_RSA_sha256_2048 + "sha256_cert.pfx", alias, password, payload, headerRsa); Assert.assertFalse("test_pkcs12_pfx create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.pfx", alias, password, token); + boolean result = GamUtilsEO.verifyJwtRsa(path_RSA_sha256_2048 + "sha256_cert.pfx", alias, password, token); Assert.assertTrue("test_pkcs12_pfx verify", result); } @Test public void test_pkcs12_noalias() { - String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256_cert.jks", "", password, payload, header); + String token = GamUtilsEO.createJwtRsa(path_RSA_sha256_2048 + "sha256_cert.jks", "", password, payload, headerRsa); Assert.assertFalse("test_pkcs12_noalias jks create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.jks", "", password, token); + boolean result = GamUtilsEO.verifyJwtRsa(path_RSA_sha256_2048 + "sha256_cert.jks", "", password, token); Assert.assertTrue("test_pkcs12_noalias jks verify", result); } @@ -113,19 +114,19 @@ public void test_pkcs12_noalias() { public void test_b64() { String publicKey = "MIIEATCCAumgAwIBAgIJAIAqvKHZ+gFhMA0GCSqGSIb3DQEBCwUAMIGWMQswCQYDVQQGEwJVWTETMBEGA1UECAwKTW9udGV2aWRlbzETMBEGA1UEBwwKTW9udGV2aWRlbzEQMA4GA1UECgwHR2VuZVh1czERMA8GA1UECwwIU2VjdXJpdHkxEjAQBgNVBAMMCXNncmFtcG9uZTEkMCIGCSqGSIb3DQEJARYVc2dyYW1wb25lQGdlbmV4dXMuY29tMB4XDTIwMDcwODE4NTcxN1oXDTI1MDcwNzE4NTcxN1owgZYxCzAJBgNVBAYTAlVZMRMwEQYDVQQIDApNb250ZXZpZGVvMRMwEQYDVQQHDApNb250ZXZpZGVvMRAwDgYDVQQKDAdHZW5lWHVzMREwDwYDVQQLDAhTZWN1cml0eTESMBAGA1UEAwwJc2dyYW1wb25lMSQwIgYJKoZIhvcNAQkBFhVzZ3JhbXBvbmVAZ2VuZXh1cy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN49AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bmZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBISeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+YUqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+KYP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAGjUDBOMB0GA1UdDgQWBBQtQAWJRWNr/OswPSAdwCQh0Eei/DAfBgNVHSMEGDAWgBQtQAWJRWNr/OswPSAdwCQh0Eei/DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCjHe3JbNKv0Ywc1zlLacUNWcjLbmzvnjs8Wq5oxtf5wG5PUlhLSYZ9MPhuf95PlibnrO/xVY292P5lo4NKhS7VOonpbPQ/PrCMO84Pz1LGfM/wCWQIowh6VHq18PiZka9zbwl6So0tgClKkFSRk4wpKrWX3+M3+Y+D0brd8sEtA6dXeYHDtqV0YgjKdZIIOx0vDT4alCoVQrQ1yAIq5INT3cSLgJezIhEadDv3Tc7bMxMFeL+81qHm9Z/9/KE6Z+JB0ZEOkF/2NSQJd+Z7MBR8CxOdTQis3ltMoXDatNkjZ2Env40sw4NICB8YYhsWMIarew5uNT+RS28YHNlbmogh"; String privateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN49AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bmZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBISeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+YUqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+KYP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAECggEBAJP8ajslcThisjzg47JWGS8z1FXi2Q8hg1Yv61o8avcHEY0y8tdEKUnkQ3TT4E0M0CgsL078ATz4cNmvhzYIv+j66aEv3w/XRRhl/NWBqx1YsQV5BWHy5sz9Nhe+WnnlbbSa5Ie+4NfpG1LDv/Mi19RZVg15p5ZwHGrkDCP47VYKgFXw51ZPxq/l3IIeq4PyueC/EPSAp4e9qei7p85k3i2yiWsHgZaHwHgDTx2Hgq1y/+/E5+HNxL2OlPr5lzlN2uIPZ9Rix2LDh0FriuCEjrXFsTJHw4LTK04rkeGledMtw6/bOTxibFbgeuQtY1XzG/M0+xlP2niBbAEA4Z6vTsECgYEA6k7LSsh6azsk0W9+dE6pbc3HisOoKI76rXi38gEQdCuF04OKt46WttQh4r1+dseO4OgjXtRMS0+5Hmx2jFXjPJexMgLftvrbwaVqg9WHenKL/qj5imCn4kVaa4Jo1VHFaIY+1b+iv+6WY/leFxGntAki9u4PRogRrUrWLRH9keUCgYEAxqLisgMHQGcpJDHJtI2N+HUgLDN065PtKlEP9o6WBwAb86/InVaTo2gmEvmslNQDYH16zdTczWMHnnBx1B012KpUD+t5CWIvMZdsTnMRDjWhdgm5ylN9NT89t5X8GPvo36WjuXAKWWjcRodzRgo57z9achCyMKhGU5yDOxh8jhkCgYAx6rtwoSlDcwQzAjfEe4Wo+PAL5gcLLPrGvjMiAYwJ08Pc/ectl9kP9j2J2qj4kSclTw9KApyGZuOfUagn2Zxhqkd7yhTzHJp4tM7uay1DrueYR1NyYYkisXfD87J1z8forsDwNLVtglzTy6p56674sgGa7bifZBmv+4OJco286QKBgQC4dGXDHGDNg36G590A1zpw8ILxyM7YPEPOOfxy3rGeypEqV6AZy13KLlq84DFM+xwvrBYvsW1hJIbcsFpjuMRZ8MGjDu0Us6JTkOO4bc32vgKzlBB9O85XdeSf6J1zrenwVOaWut5BbMiwjfOTpMdrzg71QV/XI0w7NGoApJp1cQKBgERfI6AfJTaKtEpfX3udR1B3zra1Y42ppU2TvGI5J2/cItENoyRmtyKYDp2I036/Pe63nuIzs31i6q/hCr9Tv3AGoSVKuPLpCWv5xVO/BPhGs5dwx81nUo0/P+H2X8dx7g57PQY4uf4F9+EIXeAdbPqfB8GBW7RX3FDx5NpB+Hh/"; - String token = GamUtilsEO.createJwt(privateKey, "", "", payload, header); + String token = GamUtilsEO.createJwtRsa(privateKey, "", "", payload, headerRsa); Assert.assertFalse("test_b64 create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwt(publicKey, "", "", token); + boolean result = GamUtilsEO.verifyJwtRsa(publicKey, "", "", token); Assert.assertTrue("test_b64 verify", result); } @Test public void test_json_jwk() { String keyPair = GamUtilsEO.generateKeyPair(); - String token = GamUtilsEO.createJwt(keyPair, "", "", payload, header); + String token = GamUtilsEO.createJwtRsa(keyPair, "", "", payload, headerRsa); Assert.assertFalse("test_json_jwk create", token.isEmpty()); String publicJwk = GamUtilsEO.getPublicJwk(keyPair); - boolean result = GamUtilsEO.verifyJwt(publicJwk, "", "", token); + boolean result = GamUtilsEO.verifyJwtRsa(publicJwk, "", "", token); Assert.assertTrue("test_json_jwk verify", result); } @@ -134,13 +135,73 @@ public void test_json_jwks() { String keyPair = GamUtilsEO.generateKeyPair(); String publicJwk = GamUtilsEO.getPublicJwk(keyPair); String header_jwks = makeHeader(publicJwk); - String token = GamUtilsEO.createJwt(keyPair, "", "", payload, header_jwks); + String token = GamUtilsEO.createJwtRsa(keyPair, "", "", payload, header_jwks); Assert.assertFalse("test_json_jwks create", token.isEmpty()); String publicJwks = "{\"keys\": [" + publicJwk + "]}"; - boolean result = GamUtilsEO.verifyJwt(publicJwks, "", "", token); + boolean result = GamUtilsEO.verifyJwtRsa(publicJwks, "", "", token); Assert.assertTrue("test_json_jwks verify", result); } + @Test + public void test_json_Sha256() + { + String header = "{\n" + + " \"alg\": \"HS256\",\n" + + " \"typ\": \"JWT\"\n" + + "}"; + int[] lengths = new int[]{256, 512, 1024}; + for (int n : lengths) { + String secret = GamUtilsEO.randomUtf8Bits(n); + String token = GamUtilsEO.createJwtSha(secret, payload, header); + Assert.assertFalse("test_json_Sha256 create", token.isEmpty()); + boolean result = GamUtilsEO.verifyJwtSha(secret, token); + Assert.assertTrue("test_json_Sha256 verify", result); + } + } + + @Test + public void test_json_Sha512() + { + String header = "{\n" + + " \"alg\": \"HS512\",\n" + + " \"typ\": \"JWT\"\n" + + "}"; + int[] lengths = new int[]{512, 1024}; + for (int n : lengths) { + String secret = GamUtilsEO.randomUtf8Bits(n); + String token = GamUtilsEO.createJwtSha(secret, payload, header); + Assert.assertFalse("test_json_Sha512 create", token.isEmpty()); + boolean result = GamUtilsEO.verifyJwtSha(secret, token); + Assert.assertTrue("test_json_Sha512 verify", result); + } + } + + @Test + public void test_VerifyAlgorithm_True() + { + String header = "{\n" + + " \"alg\": \"HS512\",\n" + + " \"typ\": \"JWT\"\n" + + "}"; + String secret = GamUtilsEO.randomUtf8Bits(512); + String token = GamUtilsEO.createJwtSha(secret, payload, header); + boolean resultSha512 = GamUtilsEO.verifyAlgorithm("HS512", token); + Assert.assertTrue("test_VerifyAlgorithm_True", resultSha512); + } + + @Test + public void test_VerifyAlgorithm_False() + { + String header = "{\n" + + " \"alg\": \"HS512\",\n" + + " \"typ\": \"JWT\"\n" + + "}"; + String secret = GamUtilsEO.randomUtf8Bits(512); + String token = GamUtilsEO.createJwtSha(secret, payload, header); + boolean resultSha512 = GamUtilsEO.verifyAlgorithm("RS256", token); + Assert.assertFalse("test_VerifyAlgorithm_False", resultSha512); + } + private static String makeHeader(String publicJwk) { try { JWK jwk = JWK.parse(publicJwk); @@ -155,4 +216,6 @@ private static String makeHeader(String publicJwk) { return ""; } } + + } diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/RandomTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/RandomTest.java index 0ce8f4888..b57305edf 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/RandomTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/RandomTest.java @@ -6,6 +6,8 @@ import org.junit.BeforeClass; import org.junit.Test; +import java.nio.charset.StandardCharsets; + public class RandomTest { private static int l128; @@ -73,4 +75,26 @@ public void testHexaBits() { } } } + + @Test + public void TestUtf8Bits() + { + int[] lengths = new int[]{32, 64, 128, 256, 512, 1024}; + + for (int n : lengths) { + String utf8 = GamUtilsEO.randomUtf8Bits(n); + Assert.assertFalse("TestUtf8Bits", utf8.isEmpty()); + try + { + byte[] decoded = utf8.getBytes(StandardCharsets.UTF_8);//Hex.decode(hexa); + if(decoded.length != (n + 7) / 8) + { + Assert.fail("TestUtf8Bits wrong utf8 length"); + } + }catch(Exception e) + { + Assert.fail("TestUtf8Bits not utf8 characters" + e.getMessage()); + } + } + } } From 84b897dcf04fd21abbaaafc6106afbf9ac2643d7 Mon Sep 17 00:00:00 2001 From: sgrampone Date: Wed, 15 Jan 2025 13:48:34 -0300 Subject: [PATCH 13/21] Delete usless function --- .../main/java/com/genexus/gam/GamUtilsEO.java | 4 ---- .../java/com/genexus/gam/utils/Random.java | 21 ------------------ .../com/genexus/gam/utils/test/JwtTest.java | 12 +++++----- .../genexus/gam/utils/test/RandomTest.java | 22 ------------------- 4 files changed, 6 insertions(+), 53 deletions(-) diff --git a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java index 7a3af4b57..285e824e8 100644 --- a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java +++ b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java @@ -42,10 +42,6 @@ public static String randomHexaBits(int bits) { return Random.hexaBits(bits); } - public static String randomUtf8Bits(int bits) { - return Random.utf8Bits(bits); - } - //**JWK**// public static String generateKeyPair() { diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Random.java b/gamutils/src/main/java/com/genexus/gam/utils/Random.java index 8042215df..4586973c6 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/Random.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/Random.java @@ -60,25 +60,4 @@ public static String hexaBits(int bits) } return sb.toString().replaceAll("\\s", ""); } - - public static String utf8Bits(int bits) - { - int targetBytes = (bits + 7) / 8; - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < targetBytes; i++) { - sb.append("a"); - } - String result = sb.toString(); - byte[] utf8Bytes = sb.toString().getBytes(StandardCharsets.UTF_8); - if (utf8Bytes.length > targetBytes) { - return new String(utf8Bytes, 0, targetBytes, StandardCharsets.UTF_8); - } else if (utf8Bytes.length < targetBytes) { - StringBuilder paddedString = new StringBuilder(sb.toString()); - for (int i = utf8Bytes.length; i < targetBytes; i++) { - paddedString.append("0"); - } - return paddedString.toString(); - } - return result; - } } diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java index eb449b0d6..b17279773 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java @@ -149,9 +149,9 @@ public void test_json_Sha256() " \"alg\": \"HS256\",\n" + " \"typ\": \"JWT\"\n" + "}"; - int[] lengths = new int[]{256, 512, 1024}; + int[] lengths = new int[]{32, 64, 128}; for (int n : lengths) { - String secret = GamUtilsEO.randomUtf8Bits(n); + String secret = GamUtilsEO.randomAlphanumeric(n); String token = GamUtilsEO.createJwtSha(secret, payload, header); Assert.assertFalse("test_json_Sha256 create", token.isEmpty()); boolean result = GamUtilsEO.verifyJwtSha(secret, token); @@ -166,9 +166,9 @@ public void test_json_Sha512() " \"alg\": \"HS512\",\n" + " \"typ\": \"JWT\"\n" + "}"; - int[] lengths = new int[]{512, 1024}; + int[] lengths = new int[]{64, 128}; for (int n : lengths) { - String secret = GamUtilsEO.randomUtf8Bits(n); + String secret = GamUtilsEO.randomAlphanumeric(n); String token = GamUtilsEO.createJwtSha(secret, payload, header); Assert.assertFalse("test_json_Sha512 create", token.isEmpty()); boolean result = GamUtilsEO.verifyJwtSha(secret, token); @@ -183,7 +183,7 @@ public void test_VerifyAlgorithm_True() " \"alg\": \"HS512\",\n" + " \"typ\": \"JWT\"\n" + "}"; - String secret = GamUtilsEO.randomUtf8Bits(512); + String secret = GamUtilsEO.randomAlphanumeric(64); String token = GamUtilsEO.createJwtSha(secret, payload, header); boolean resultSha512 = GamUtilsEO.verifyAlgorithm("HS512", token); Assert.assertTrue("test_VerifyAlgorithm_True", resultSha512); @@ -196,7 +196,7 @@ public void test_VerifyAlgorithm_False() " \"alg\": \"HS512\",\n" + " \"typ\": \"JWT\"\n" + "}"; - String secret = GamUtilsEO.randomUtf8Bits(512); + String secret = GamUtilsEO.randomAlphanumeric(64); String token = GamUtilsEO.createJwtSha(secret, payload, header); boolean resultSha512 = GamUtilsEO.verifyAlgorithm("RS256", token); Assert.assertFalse("test_VerifyAlgorithm_False", resultSha512); diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/RandomTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/RandomTest.java index b57305edf..792db9832 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/RandomTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/RandomTest.java @@ -75,26 +75,4 @@ public void testHexaBits() { } } } - - @Test - public void TestUtf8Bits() - { - int[] lengths = new int[]{32, 64, 128, 256, 512, 1024}; - - for (int n : lengths) { - String utf8 = GamUtilsEO.randomUtf8Bits(n); - Assert.assertFalse("TestUtf8Bits", utf8.isEmpty()); - try - { - byte[] decoded = utf8.getBytes(StandardCharsets.UTF_8);//Hex.decode(hexa); - if(decoded.length != (n + 7) / 8) - { - Assert.fail("TestUtf8Bits wrong utf8 length"); - } - }catch(Exception e) - { - Assert.fail("TestUtf8Bits not utf8 characters" + e.getMessage()); - } - } - } } From 75fcc40247278aae14f785ee64b131f34912ef0a Mon Sep 17 00:00:00 2001 From: sgrampone Date: Tue, 21 Jan 2025 12:47:01 -0300 Subject: [PATCH 14/21] Adding Base64Url encoding functions and fixing symmetric and asymmetric --- .../src/main/java/com/genexus/gam/utils/json/JWTAlgorithm.java | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 gamutils/src/main/java/com/genexus/gam/utils/json/JWTAlgorithm.java diff --git a/gamutils/src/main/java/com/genexus/gam/utils/json/JWTAlgorithm.java b/gamutils/src/main/java/com/genexus/gam/utils/json/JWTAlgorithm.java new file mode 100644 index 000000000..5212e3e74 --- /dev/null +++ b/gamutils/src/main/java/com/genexus/gam/utils/json/JWTAlgorithm.java @@ -0,0 +1,2 @@ +package com.genexus.gam.utils.json;public class JWTAlgorithm { +} From c7e5e15624cedb5c7fe32c0dc48b5726f5bbbef7 Mon Sep 17 00:00:00 2001 From: sgrampone Date: Tue, 21 Jan 2025 12:48:25 -0300 Subject: [PATCH 15/21] Adding Base64Url encoding functions and fixing symmetric and asymmetric JWT creation and verification --- .../main/java/com/genexus/gam/GamUtilsEO.java | 20 +++--- .../java/com/genexus/gam/utils/Encoding.java | 27 +++++++ .../genexus/gam/utils/json/JWTAlgorithm.java | 70 ++++++++++++++++++- .../java/com/genexus/gam/utils/json/Jwt.java | 51 ++++++-------- .../genexus/gam/utils/test/EncodingTest.java | 12 +++- .../com/genexus/gam/utils/test/JwtTest.java | 58 +++++++-------- 6 files changed, 167 insertions(+), 71 deletions(-) diff --git a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java index 285e824e8..ee03fdbc8 100644 --- a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java +++ b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java @@ -57,16 +57,12 @@ public static String getJwkAlgorithm(String jwkString) { } //**JWT**// - public static boolean verifyJwtRsa(String path, String alias, String password, String token) { - return Jwt.verify(path, alias, password, token, "", false); + public static boolean verifyJwt(String path, String alias, String password, String token) { + return Jwt.verify(path, alias, password, token); } - public static String createJwtRsa(String path, String alias, String password, String payload, String header) { - return Jwt.create(path, alias, password, payload, header, "", false); - } - - public static boolean verifyJwtSha(String secret, String token) { - return Jwt.verify("", "", "", token, secret, true); + public static String createJwt(String path, String alias, String password, String payload, String header) { + return Jwt.create(path, alias, password, payload, header); } public static boolean verifyAlgorithm(String expectedAlgorithm, String token) @@ -74,10 +70,6 @@ public static boolean verifyAlgorithm(String expectedAlgorithm, String token) return Jwt.verifyAlgorithm(expectedAlgorithm, token); } - public static String createJwtSha(String secret, String payload, String header) { - return Jwt.create("", "", "", payload, header, secret, true); - } - public static long createUnixTimestamp(Date date) { return UnixTimestamp.create(date); } @@ -97,5 +89,9 @@ public static String base64ToBase64Url(String base64) { public static String hexaToBase64(String hexa) { return Encoding.hexaToBase64(hexa); } + public static String toBase64Url(String input) { return Encoding.toBase64Url(input); } + + public static String fromBase64Url(String base64) { return Encoding.fromBase64Url(base64); } + /********EXTERNAL OBJECT PUBLIC METHODS - END ********/ } diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Encoding.java b/gamutils/src/main/java/com/genexus/gam/utils/Encoding.java index 73b824c89..8d92fd0be 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/Encoding.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/Encoding.java @@ -1,12 +1,15 @@ package com.genexus.gam.utils; +import com.nimbusds.jose.util.Base64URL; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.encoders.UrlBase64; +import java.nio.charset.StandardCharsets; + public class Encoding { private static final Logger logger = LogManager.getLogger(Encoding.class); @@ -32,4 +35,28 @@ public static String hexaToBase64(String hexa) return ""; } } + + public static String toBase64Url(String input) + { + logger.debug("UTF8toBase64Url"); + try{ + return new String(UrlBase64.encode(input.getBytes(StandardCharsets.UTF_8))); + }catch (Exception e) + { + logger.error("UTF8toBase64Url", e); + return ""; + } + } + + public static String fromBase64Url(String base64Url) + { + logger.debug("fromBase64Url"); + try{ + return new String(UrlBase64.decode(base64Url), StandardCharsets.UTF_8); + }catch (Exception e) + { + logger.error("fromBase64Url", e); + return ""; + } + } } diff --git a/gamutils/src/main/java/com/genexus/gam/utils/json/JWTAlgorithm.java b/gamutils/src/main/java/com/genexus/gam/utils/json/JWTAlgorithm.java index 5212e3e74..a65109f12 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/json/JWTAlgorithm.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/json/JWTAlgorithm.java @@ -1,2 +1,70 @@ -package com.genexus.gam.utils.json;public class JWTAlgorithm { +package com.genexus.gam.utils.json; + +import com.nimbusds.jose.JWSAlgorithm; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public enum JWTAlgorithm { + + HS256, HS512, HS384, RS256, RS512; + + private static final Logger logger = LogManager.getLogger(JWTAlgorithm.class); + + public static JWSAlgorithm getJWSAlgorithm(JWTAlgorithm alg) + { + logger.debug("getJWSAlgorithm"); + switch (alg) + { + case HS256: + return JWSAlgorithm.HS256; + case HS512: + return JWSAlgorithm.HS512; + case HS384: + return JWSAlgorithm.HS384; + case RS256: + return JWSAlgorithm.RS512; + default: + logger.error("getJWSAlgorithm - not implemented algorithm"); + return null; + } + } + + public static JWTAlgorithm getJWTAlgoritm(String alg) + { + logger.debug("getJWTAlgoritm"); + switch (alg.trim().toUpperCase()) + { + case "HS256": + return JWTAlgorithm.HS256; + case "HS512": + return JWTAlgorithm.HS512; + case "HS384": + return JWTAlgorithm.HS384; + case "RS256": + return JWTAlgorithm.RS256; + case "RS512": + return JWTAlgorithm.RS512; + default: + logger.error("getJWTAlgoritm- not implemented algorithm"); + return null; + } + } + + public static boolean isSymmetric(JWTAlgorithm alg) + { + logger.debug("isSymmetric"); + switch (alg) + { + case HS256: + case HS384: + case HS512: + return true; + case RS256: + case RS512: + return false; + default: + logger.error("isSymmetric - not implemented algorithm"); + return false; + } + } } diff --git a/gamutils/src/main/java/com/genexus/gam/utils/json/Jwt.java b/gamutils/src/main/java/com/genexus/gam/utils/json/Jwt.java index 45f34f7a3..64709fe5b 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/json/Jwt.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/json/Jwt.java @@ -2,10 +2,7 @@ import com.genexus.gam.utils.keys.PrivateKeyUtil; import com.genexus.gam.utils.keys.PublicKeyUtil; -import com.nimbusds.jose.JWSAlgorithm; -import com.nimbusds.jose.JWSHeader; -import com.nimbusds.jose.JWSSigner; -import com.nimbusds.jose.JWSVerifier; +import com.nimbusds.jose.*; import com.nimbusds.jose.crypto.MACSigner; import com.nimbusds.jose.crypto.MACVerifier; import com.nimbusds.jose.crypto.RSASSASigner; @@ -17,6 +14,8 @@ import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; +import java.text.ParseException; +import java.util.Objects; public class Jwt { @@ -24,20 +23,20 @@ public class Jwt { /******** EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/ - public static boolean verify(String path, String alias, String password, String token, String secret, boolean isSymmetric) { + public static boolean verify(String path, String alias, String password, String token) { logger.debug("verify"); try { - return !isSymmetric ? verify_internal(PublicKeyUtil.getPublicKey(path, alias, password, token), token, "", isSymmetric) : verify_internal(null, token, secret, isSymmetric); + return verify_internal(path, alias, password, token); } catch (Exception e) { logger.error("verify", e); return false; } } - public static String create(String path, String alias, String password, String payload, String header, String secret, boolean isSymmetric) { + public static String create(String path, String alias, String password, String payload, String header) { logger.debug("create"); try { - return !isSymmetric ? create_internal(PrivateKeyUtil.getPrivateKey(path, alias, password), payload, header, "", isSymmetric): create_internal(null, payload, header, secret, isSymmetric); + return create_internal(path, alias, password, payload, header); }catch (Exception e) { logger.error("create", e); @@ -79,29 +78,25 @@ public static boolean verifyAlgorithm(String algorithm, String token) /******** EXTERNAL OBJECT PUBLIC METHODS - END ********/ - private static boolean verify_internal(RSAPublicKey publicKey, String token, String secret, boolean isSymmetric){ + private static boolean verify_internal(String path, String alias, String password, String token) throws JOSEException, ParseException { logger.debug("verify_internal"); - try { - SignedJWT signedJWT = SignedJWT.parse(token); - JWSVerifier verifier = isSymmetric ? new MACVerifier(secret):new RSASSAVerifier(publicKey); - return signedJWT.verify(verifier); - } catch (Exception e) { - logger.error("verify_internal", e); - return false; - } + JWTAlgorithm algorithm = JWTAlgorithm.getJWTAlgoritm(JWSHeader.parse(getHeader(token)).getAlgorithm().getName()); + assert algorithm != null; + boolean isSymmetric = JWTAlgorithm.isSymmetric(algorithm); + SignedJWT signedJWT = SignedJWT.parse(token); + JWSVerifier verifier = isSymmetric ? new MACVerifier(password):new RSASSAVerifier(Objects.requireNonNull(PublicKeyUtil.getPublicKey(path, alias, password, token))); + return signedJWT.verify(verifier); } - private static String create_internal(RSAPrivateKey privateKey, String payload, String header, String secret, boolean isSymmetric) { + private static String create_internal(String path, String alias, String password, String payload, String header) throws Exception { logger.debug("create_internal"); - try { - SignedJWT signedJWT = new SignedJWT(JWSHeader.parse(header), JWTClaimsSet.parse(payload)); - JWSSigner signer = isSymmetric ? new MACSigner(secret): new RSASSASigner(privateKey); - signedJWT.sign(signer); - return signedJWT.serialize(); - } catch (Exception e) { - logger.error("create_internal", e); - return ""; - } + JWSHeader parsedHeader = JWSHeader.parse(header); + JWTAlgorithm algorithm = JWTAlgorithm.getJWTAlgoritm(parsedHeader.getAlgorithm().getName()); + assert algorithm != null; + boolean isSymmetric = JWTAlgorithm.isSymmetric(algorithm); + SignedJWT signedJWT = new SignedJWT(parsedHeader, JWTClaimsSet.parse(payload)); + JWSSigner signer = isSymmetric ? new MACSigner(password): new RSASSASigner(Objects.requireNonNull(PrivateKeyUtil.getPrivateKey(path, alias, password))); + signedJWT.sign(signer); + return signedJWT.serialize(); } - } diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/EncodingTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/EncodingTest.java index 7771a54f4..fa8ebd66f 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/EncodingTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/EncodingTest.java @@ -34,6 +34,17 @@ private static String b64UrlToUtf8(String base64Url) { } } + @Test + public void testToBase64Url() { + int i = 0; + do { + String randomString = GamUtilsEO.randomAlphanumeric(128); + String testing = GamUtilsEO.toBase64Url(randomString); + Assert.assertEquals("testB64ToB64Url", randomString, GamUtilsEO.fromBase64Url(testing)); + i++; + } while (i < 50); + } + @Test public void testHexaToBase64() { @@ -57,5 +68,4 @@ private static String b64ToHexa(String base64) { } - } diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java index b17279773..45025a4ae 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java @@ -38,15 +38,15 @@ public static void setUp() { @Test public void test_pkcs8_pem() { - String token = GamUtilsEO.createJwtRsa(path_RSA_sha256_2048 + "sha256d_key.pem", "", "", payload, headerRsa); + String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256d_key.pem", "", "", payload, headerRsa); Assert.assertFalse("test_pkcs8 create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwtRsa(path_RSA_sha256_2048 + "sha256_cert.cer", "", "", token); + boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.cer", "", "", token); Assert.assertTrue("test_pkcs8 verify cer", result); } @Test public void test_get() { - String token = GamUtilsEO.createJwtRsa(path_RSA_sha256_2048 + "sha256d_key.pem", "", "", payload, headerRsa); + String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256d_key.pem", "", "", payload, headerRsa); Assert.assertFalse("test_get create", token.isEmpty()); String header_get = GamUtilsEO.getJwtHeader(token); Assert.assertFalse("test_get getHeader", header_get.isEmpty()); @@ -56,57 +56,57 @@ public void test_get() { @Test public void test_pkcs8_key() { - String token = GamUtilsEO.createJwtRsa(path_RSA_sha256_2048 + "sha256d_key.key", "", "", payload, headerRsa); + String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256d_key.key", "", "", payload, headerRsa); Assert.assertFalse("test_pkcs8 create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwtRsa(path_RSA_sha256_2048 + "sha256_cert.crt", "", "", token); + boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.crt", "", "", token); Assert.assertTrue("test_pkcs8 verify crt", result); } @Test public void test_pkcs8_encrypted() { - String token = GamUtilsEO.createJwtRsa(path_RSA_sha256_2048 + "sha256_key.pem", "", password, payload, headerRsa); + String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256_key.pem", "", password, payload, headerRsa); Assert.assertFalse("test_pkcs8_encrypted", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwtRsa(path_RSA_sha256_2048 + "sha256_cert.crt", "", "", token); + boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.crt", "", "", token); Assert.assertTrue("test_pkcs8_encrypted verify crt", result); } @Test public void test_pkcs12_p12() { - String token = GamUtilsEO.createJwtRsa(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, payload, headerRsa); + String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, payload, headerRsa); Assert.assertFalse("test_pkcs12_p12 create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwtRsa(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, token); + boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.p12", alias, password, token); Assert.assertTrue("test_pkcs12_p12 verify", result); } @Test public void test_pkcs12_pkcs12() { - String token = GamUtilsEO.createJwtRsa(path_RSA_sha256_2048 + "sha256_cert.pkcs12", alias, password, payload, headerRsa); + String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256_cert.pkcs12", alias, password, payload, headerRsa); Assert.assertFalse("test_pkcs12_pkcs12 create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwtRsa(path_RSA_sha256_2048 + "sha256_cert.pkcs12", alias, password, token); + boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.pkcs12", alias, password, token); Assert.assertTrue("test_pkcs12_pkcs12 verify", result); } @Test public void test_pkcs12_jks() { - String token = GamUtilsEO.createJwtRsa(path_RSA_sha256_2048 + "sha256_cert.jks", alias, password, payload, headerRsa); + String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256_cert.jks", alias, password, payload, headerRsa); Assert.assertFalse("test_pkcs12_jks create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwtRsa(path_RSA_sha256_2048 + "sha256_cert.jks", alias, password, token); + boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.jks", alias, password, token); Assert.assertTrue("test_pkcs12_jks verify", result); } @Test public void test_pkcs12_pfx() { - String token = GamUtilsEO.createJwtRsa(path_RSA_sha256_2048 + "sha256_cert.pfx", alias, password, payload, headerRsa); + String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256_cert.pfx", alias, password, payload, headerRsa); Assert.assertFalse("test_pkcs12_pfx create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwtRsa(path_RSA_sha256_2048 + "sha256_cert.pfx", alias, password, token); + boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.pfx", alias, password, token); Assert.assertTrue("test_pkcs12_pfx verify", result); } @Test public void test_pkcs12_noalias() { - String token = GamUtilsEO.createJwtRsa(path_RSA_sha256_2048 + "sha256_cert.jks", "", password, payload, headerRsa); + String token = GamUtilsEO.createJwt(path_RSA_sha256_2048 + "sha256_cert.jks", "", password, payload, headerRsa); Assert.assertFalse("test_pkcs12_noalias jks create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwtRsa(path_RSA_sha256_2048 + "sha256_cert.jks", "", password, token); + boolean result = GamUtilsEO.verifyJwt(path_RSA_sha256_2048 + "sha256_cert.jks", "", password, token); Assert.assertTrue("test_pkcs12_noalias jks verify", result); } @@ -114,19 +114,19 @@ public void test_pkcs12_noalias() { public void test_b64() { String publicKey = "MIIEATCCAumgAwIBAgIJAIAqvKHZ+gFhMA0GCSqGSIb3DQEBCwUAMIGWMQswCQYDVQQGEwJVWTETMBEGA1UECAwKTW9udGV2aWRlbzETMBEGA1UEBwwKTW9udGV2aWRlbzEQMA4GA1UECgwHR2VuZVh1czERMA8GA1UECwwIU2VjdXJpdHkxEjAQBgNVBAMMCXNncmFtcG9uZTEkMCIGCSqGSIb3DQEJARYVc2dyYW1wb25lQGdlbmV4dXMuY29tMB4XDTIwMDcwODE4NTcxN1oXDTI1MDcwNzE4NTcxN1owgZYxCzAJBgNVBAYTAlVZMRMwEQYDVQQIDApNb250ZXZpZGVvMRMwEQYDVQQHDApNb250ZXZpZGVvMRAwDgYDVQQKDAdHZW5lWHVzMREwDwYDVQQLDAhTZWN1cml0eTESMBAGA1UEAwwJc2dyYW1wb25lMSQwIgYJKoZIhvcNAQkBFhVzZ3JhbXBvbmVAZ2VuZXh1cy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN49AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bmZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBISeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+YUqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+KYP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAGjUDBOMB0GA1UdDgQWBBQtQAWJRWNr/OswPSAdwCQh0Eei/DAfBgNVHSMEGDAWgBQtQAWJRWNr/OswPSAdwCQh0Eei/DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCjHe3JbNKv0Ywc1zlLacUNWcjLbmzvnjs8Wq5oxtf5wG5PUlhLSYZ9MPhuf95PlibnrO/xVY292P5lo4NKhS7VOonpbPQ/PrCMO84Pz1LGfM/wCWQIowh6VHq18PiZka9zbwl6So0tgClKkFSRk4wpKrWX3+M3+Y+D0brd8sEtA6dXeYHDtqV0YgjKdZIIOx0vDT4alCoVQrQ1yAIq5INT3cSLgJezIhEadDv3Tc7bMxMFeL+81qHm9Z/9/KE6Z+JB0ZEOkF/2NSQJd+Z7MBR8CxOdTQis3ltMoXDatNkjZ2Env40sw4NICB8YYhsWMIarew5uNT+RS28YHNlbmogh"; String privateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN49AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bmZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBISeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+YUqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+KYP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAECggEBAJP8ajslcThisjzg47JWGS8z1FXi2Q8hg1Yv61o8avcHEY0y8tdEKUnkQ3TT4E0M0CgsL078ATz4cNmvhzYIv+j66aEv3w/XRRhl/NWBqx1YsQV5BWHy5sz9Nhe+WnnlbbSa5Ie+4NfpG1LDv/Mi19RZVg15p5ZwHGrkDCP47VYKgFXw51ZPxq/l3IIeq4PyueC/EPSAp4e9qei7p85k3i2yiWsHgZaHwHgDTx2Hgq1y/+/E5+HNxL2OlPr5lzlN2uIPZ9Rix2LDh0FriuCEjrXFsTJHw4LTK04rkeGledMtw6/bOTxibFbgeuQtY1XzG/M0+xlP2niBbAEA4Z6vTsECgYEA6k7LSsh6azsk0W9+dE6pbc3HisOoKI76rXi38gEQdCuF04OKt46WttQh4r1+dseO4OgjXtRMS0+5Hmx2jFXjPJexMgLftvrbwaVqg9WHenKL/qj5imCn4kVaa4Jo1VHFaIY+1b+iv+6WY/leFxGntAki9u4PRogRrUrWLRH9keUCgYEAxqLisgMHQGcpJDHJtI2N+HUgLDN065PtKlEP9o6WBwAb86/InVaTo2gmEvmslNQDYH16zdTczWMHnnBx1B012KpUD+t5CWIvMZdsTnMRDjWhdgm5ylN9NT89t5X8GPvo36WjuXAKWWjcRodzRgo57z9achCyMKhGU5yDOxh8jhkCgYAx6rtwoSlDcwQzAjfEe4Wo+PAL5gcLLPrGvjMiAYwJ08Pc/ectl9kP9j2J2qj4kSclTw9KApyGZuOfUagn2Zxhqkd7yhTzHJp4tM7uay1DrueYR1NyYYkisXfD87J1z8forsDwNLVtglzTy6p56674sgGa7bifZBmv+4OJco286QKBgQC4dGXDHGDNg36G590A1zpw8ILxyM7YPEPOOfxy3rGeypEqV6AZy13KLlq84DFM+xwvrBYvsW1hJIbcsFpjuMRZ8MGjDu0Us6JTkOO4bc32vgKzlBB9O85XdeSf6J1zrenwVOaWut5BbMiwjfOTpMdrzg71QV/XI0w7NGoApJp1cQKBgERfI6AfJTaKtEpfX3udR1B3zra1Y42ppU2TvGI5J2/cItENoyRmtyKYDp2I036/Pe63nuIzs31i6q/hCr9Tv3AGoSVKuPLpCWv5xVO/BPhGs5dwx81nUo0/P+H2X8dx7g57PQY4uf4F9+EIXeAdbPqfB8GBW7RX3FDx5NpB+Hh/"; - String token = GamUtilsEO.createJwtRsa(privateKey, "", "", payload, headerRsa); + String token = GamUtilsEO.createJwt(privateKey, "", "", payload, headerRsa); Assert.assertFalse("test_b64 create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwtRsa(publicKey, "", "", token); + boolean result = GamUtilsEO.verifyJwt(publicKey, "", "", token); Assert.assertTrue("test_b64 verify", result); } @Test public void test_json_jwk() { String keyPair = GamUtilsEO.generateKeyPair(); - String token = GamUtilsEO.createJwtRsa(keyPair, "", "", payload, headerRsa); + String token = GamUtilsEO.createJwt(keyPair, "", "", payload, headerRsa); Assert.assertFalse("test_json_jwk create", token.isEmpty()); String publicJwk = GamUtilsEO.getPublicJwk(keyPair); - boolean result = GamUtilsEO.verifyJwtRsa(publicJwk, "", "", token); + boolean result = GamUtilsEO.verifyJwt(publicJwk, "", "", token); Assert.assertTrue("test_json_jwk verify", result); } @@ -135,10 +135,10 @@ public void test_json_jwks() { String keyPair = GamUtilsEO.generateKeyPair(); String publicJwk = GamUtilsEO.getPublicJwk(keyPair); String header_jwks = makeHeader(publicJwk); - String token = GamUtilsEO.createJwtRsa(keyPair, "", "", payload, header_jwks); + String token = GamUtilsEO.createJwt(keyPair, "", "", payload, header_jwks); Assert.assertFalse("test_json_jwks create", token.isEmpty()); String publicJwks = "{\"keys\": [" + publicJwk + "]}"; - boolean result = GamUtilsEO.verifyJwtRsa(publicJwks, "", "", token); + boolean result = GamUtilsEO.verifyJwt(publicJwks, "", "", token); Assert.assertTrue("test_json_jwks verify", result); } @@ -152,9 +152,9 @@ public void test_json_Sha256() int[] lengths = new int[]{32, 64, 128}; for (int n : lengths) { String secret = GamUtilsEO.randomAlphanumeric(n); - String token = GamUtilsEO.createJwtSha(secret, payload, header); + String token = GamUtilsEO.createJwt("", "", secret, payload, header); Assert.assertFalse("test_json_Sha256 create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwtSha(secret, token); + boolean result = GamUtilsEO.verifyJwt("", "", secret, token); Assert.assertTrue("test_json_Sha256 verify", result); } } @@ -169,9 +169,9 @@ public void test_json_Sha512() int[] lengths = new int[]{64, 128}; for (int n : lengths) { String secret = GamUtilsEO.randomAlphanumeric(n); - String token = GamUtilsEO.createJwtSha(secret, payload, header); + String token = GamUtilsEO.createJwt("", "", secret, payload, header); Assert.assertFalse("test_json_Sha512 create", token.isEmpty()); - boolean result = GamUtilsEO.verifyJwtSha(secret, token); + boolean result = GamUtilsEO.verifyJwt("", "", secret, token); Assert.assertTrue("test_json_Sha512 verify", result); } } @@ -184,7 +184,7 @@ public void test_VerifyAlgorithm_True() " \"typ\": \"JWT\"\n" + "}"; String secret = GamUtilsEO.randomAlphanumeric(64); - String token = GamUtilsEO.createJwtSha(secret, payload, header); + String token = GamUtilsEO.createJwt("", "", secret, payload, header); boolean resultSha512 = GamUtilsEO.verifyAlgorithm("HS512", token); Assert.assertTrue("test_VerifyAlgorithm_True", resultSha512); } @@ -197,7 +197,7 @@ public void test_VerifyAlgorithm_False() " \"typ\": \"JWT\"\n" + "}"; String secret = GamUtilsEO.randomAlphanumeric(64); - String token = GamUtilsEO.createJwtSha(secret, payload, header); + String token = GamUtilsEO.createJwt("", "", secret, payload, header); boolean resultSha512 = GamUtilsEO.verifyAlgorithm("RS256", token); Assert.assertFalse("test_VerifyAlgorithm_False", resultSha512); } From 788dff3c72a4baab71105a5ae8b92ebdc71d470c Mon Sep 17 00:00:00 2001 From: sgrampone Date: Tue, 21 Jan 2025 15:13:17 -0300 Subject: [PATCH 16/21] Fix JWTAlgorithm bug with RSA header --- .../src/main/java/com/genexus/gam/utils/json/JWTAlgorithm.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gamutils/src/main/java/com/genexus/gam/utils/json/JWTAlgorithm.java b/gamutils/src/main/java/com/genexus/gam/utils/json/JWTAlgorithm.java index a65109f12..56ae300ab 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/json/JWTAlgorithm.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/json/JWTAlgorithm.java @@ -22,6 +22,8 @@ public static JWSAlgorithm getJWSAlgorithm(JWTAlgorithm alg) case HS384: return JWSAlgorithm.HS384; case RS256: + return JWSAlgorithm.RS256; + case RS512: return JWSAlgorithm.RS512; default: logger.error("getJWSAlgorithm - not implemented algorithm"); From 594c2645d48261263259b0aea7521ef4571a88cf Mon Sep 17 00:00:00 2001 From: sgrampone Date: Thu, 27 Feb 2025 18:50:28 -0300 Subject: [PATCH 17/21] Add Base64ToHexa function --- .../src/main/java/com/genexus/gam/GamUtilsEO.java | 2 ++ .../main/java/com/genexus/gam/utils/Encoding.java | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java index ee03fdbc8..1ad119b51 100644 --- a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java +++ b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java @@ -93,5 +93,7 @@ public static String base64ToBase64Url(String base64) { public static String fromBase64Url(String base64) { return Encoding.fromBase64Url(base64); } + public static String base64ToHexa(String base64) { return Encoding.base64ToHexa(base64); } + /********EXTERNAL OBJECT PUBLIC METHODS - END ********/ } diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Encoding.java b/gamutils/src/main/java/com/genexus/gam/utils/Encoding.java index 8d92fd0be..4e4b7d623 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/Encoding.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/Encoding.java @@ -59,4 +59,16 @@ public static String fromBase64Url(String base64Url) return ""; } } + + public static String base64ToHexa(String base64) + { + logger.debug("base64ToHexa"); + try{ + return Hex.toHexString(Base64.decode(base64)); + }catch (Exception e) + { + logger.error("base64ToHexa", e); + return ""; + } + } } From a2e02596bd647cc0352792231da672e51704561a Mon Sep 17 00:00:00 2001 From: sgrampone Date: Fri, 28 Feb 2025 18:55:24 -0300 Subject: [PATCH 18/21] GamUtilsEO add functions for PKCE --- .../main/java/com/genexus/gam/GamUtilsEO.java | 7 +++ .../main/java/com/genexus/gam/utils/Pkce.java | 54 +++++++++++++++++++ .../com/genexus/gam/utils/test/PkceTest.java | 42 +++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 gamutils/src/main/java/com/genexus/gam/utils/Pkce.java create mode 100644 gamutils/src/test/java/com/genexus/gam/utils/test/PkceTest.java diff --git a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java index 1ad119b51..bbe199f09 100644 --- a/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java +++ b/gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java @@ -1,6 +1,7 @@ package com.genexus.gam; import com.genexus.gam.utils.Encoding; +import com.genexus.gam.utils.Pkce; import com.genexus.gam.utils.Random; import com.genexus.gam.utils.cryptography.Encryption; import com.genexus.gam.utils.cryptography.Hash; @@ -95,5 +96,11 @@ public static String base64ToBase64Url(String base64) { public static String base64ToHexa(String base64) { return Encoding.base64ToHexa(base64); } + //**PKCE**// + + public static String pkce_create(int len, String option) { return Pkce.create(len, option); } + + public static boolean pkce_verify(String code_verifier, String code_challenge, String option) { return Pkce.verify(code_verifier, code_challenge, option); } + /********EXTERNAL OBJECT PUBLIC METHODS - END ********/ } diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Pkce.java b/gamutils/src/main/java/com/genexus/gam/utils/Pkce.java new file mode 100644 index 000000000..dfbf79ebd --- /dev/null +++ b/gamutils/src/main/java/com/genexus/gam/utils/Pkce.java @@ -0,0 +1,54 @@ +package com.genexus.gam.utils; + + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.util.encoders.UrlBase64; + +import java.nio.charset.StandardCharsets; +import java.text.MessageFormat; + +@SuppressWarnings("LoggingSimilarMessage") +public class Pkce { + + private static final Logger logger = LogManager.getLogger(Pkce.class); + + public static String create(int len, String option) { + logger.trace("create"); + String code_verifier = Random.alphanumeric(len); + switch (option.toUpperCase().trim()) { + case "S256": + byte[] digest = hash(new SHA256Digest(), code_verifier.getBytes(StandardCharsets.UTF_8)); + return MessageFormat.format("{0},{1}", code_verifier.trim(), new String(UrlBase64.encode(digest))); + case "PLAIN": + return MessageFormat.format("{0},{1}", code_verifier.trim(), Encoding.toBase64Url(code_verifier.trim())); + default: + logger.error("Unknown PKCE option"); + return ""; + } + } + + public static boolean verify(String code_verifier, String code_challenge, String option) { + logger.trace("verify"); + switch (option.toUpperCase().trim()) { + case "S256": + byte[] digest = hash(new SHA256Digest(), code_verifier.trim().getBytes(StandardCharsets.UTF_8)); + return (new String(UrlBase64.encode(digest))).equals(code_challenge.trim()); + case "PLAIN": + byte[] bytes_plain = UrlBase64.decode(code_challenge.trim().getBytes(StandardCharsets.UTF_8)); + return new String(bytes_plain).equals(code_verifier.trim()); + default: + logger.error("Unknown PKCE option"); + return false; + } + } + + private static byte[] hash(Digest digest, byte[] inputBytes) { + byte[] retValue = new byte[digest.getDigestSize()]; + digest.update(inputBytes, 0, inputBytes.length); + digest.doFinal(retValue, 0); + return retValue; + } +} diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/PkceTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/PkceTest.java new file mode 100644 index 000000000..eb588e7db --- /dev/null +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/PkceTest.java @@ -0,0 +1,42 @@ +package com.genexus.gam.utils.test; + +import com.genexus.gam.GamUtilsEO; +import com.genexus.gam.utils.Pkce; +import org.junit.Assert; +import org.junit.Test; + +import java.text.MessageFormat; + +public class PkceTest { + + @Test + public void testPkceS256() + { + int i = 0; + while (i<50) + { + String[] s256_true = GamUtilsEO.pkce_create(20, "S256").split(","); + Assert.assertTrue("testPkceS256 true", GamUtilsEO.pkce_verify(s256_true[0], s256_true[1], "S256")); + + String[] s256_false = GamUtilsEO.pkce_create(20, "S256").split(","); + Assert.assertFalse("testPkceS256 false", GamUtilsEO.pkce_verify(MessageFormat.format("{0}tralala",s256_false[0]), s256_false[1], "S256")); + i++; + } + } + + @Test + public void testPkcePlain() + { + int i = 0; + while (i<50) + { + String[] plain_true = GamUtilsEO.pkce_create(20, "PLAIN").split(","); + Assert.assertTrue("testPkceS256", GamUtilsEO.pkce_verify(plain_true[0], plain_true[1], "PLAIN")); + + String[] plain_false = GamUtilsEO.pkce_create(20, "PLAIN").split(","); + Assert.assertFalse("testPkceS256 false", GamUtilsEO.pkce_verify(MessageFormat.format("{0}tralala",plain_false[0]), plain_false[1], "PLAIN")); + i++; + } + } + +} From f077408dfe1b7371f57746b33e8ceea416465a16 Mon Sep 17 00:00:00 2001 From: sgrampone Date: Tue, 25 Mar 2025 21:12:33 -0300 Subject: [PATCH 19/21] Fix pkce functions --- .../main/java/com/genexus/gam/utils/Pkce.java | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Pkce.java b/gamutils/src/main/java/com/genexus/gam/utils/Pkce.java index dfbf79ebd..d72da2c91 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/Pkce.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/Pkce.java @@ -5,10 +5,11 @@ import org.apache.logging.log4j.Logger; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.util.encoders.UrlBase64; import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; import java.text.MessageFormat; +import java.util.Base64; @SuppressWarnings("LoggingSimilarMessage") public class Pkce { @@ -17,28 +18,29 @@ public class Pkce { public static String create(int len, String option) { logger.trace("create"); - String code_verifier = Random.alphanumeric(len); + byte[] code_verifier_bytes = getRandomBytes(len); + String code_verifier = Base64.getUrlEncoder().withoutPadding().encodeToString(code_verifier_bytes); switch (option.toUpperCase().trim()) { case "S256": - byte[] digest = hash(new SHA256Digest(), code_verifier.getBytes(StandardCharsets.UTF_8)); - return MessageFormat.format("{0},{1}", code_verifier.trim(), new String(UrlBase64.encode(digest))); + byte[] digest = hash(new SHA256Digest(), code_verifier.getBytes(StandardCharsets.US_ASCII)); + return MessageFormat.format("{0},{1}", code_verifier, Base64.getUrlEncoder().withoutPadding().encodeToString(digest)); case "PLAIN": - return MessageFormat.format("{0},{1}", code_verifier.trim(), Encoding.toBase64Url(code_verifier.trim())); + return MessageFormat.format("{0},{1}", code_verifier, code_verifier); default: logger.error("Unknown PKCE option"); return ""; } + } public static boolean verify(String code_verifier, String code_challenge, String option) { logger.trace("verify"); switch (option.toUpperCase().trim()) { case "S256": - byte[] digest = hash(new SHA256Digest(), code_verifier.trim().getBytes(StandardCharsets.UTF_8)); - return (new String(UrlBase64.encode(digest))).equals(code_challenge.trim()); + byte[] digest = hash(new SHA256Digest(), code_verifier.trim().getBytes(StandardCharsets.US_ASCII)); + return Base64.getUrlEncoder().withoutPadding().encodeToString(digest).equals(code_challenge.trim()); case "PLAIN": - byte[] bytes_plain = UrlBase64.decode(code_challenge.trim().getBytes(StandardCharsets.UTF_8)); - return new String(bytes_plain).equals(code_verifier.trim()); + return code_challenge.trim().equals(code_verifier.trim()); default: logger.error("Unknown PKCE option"); return false; @@ -51,4 +53,12 @@ private static byte[] hash(Digest digest, byte[] inputBytes) { digest.doFinal(retValue, 0); return retValue; } + + private static byte[] getRandomBytes(int len) { + logger.trace("getRandomBytes"); + SecureRandom secureRandom = new SecureRandom(); + byte[] bytes = new byte[len]; + secureRandom.nextBytes(bytes); + return bytes; + } } From 5c3eb3c7de204851c96ea46d3b9de314e286aef3 Mon Sep 17 00:00:00 2001 From: sgrampone Date: Thu, 27 Mar 2025 11:49:30 -0300 Subject: [PATCH 20/21] Change Base64Url functions --- .../main/java/com/genexus/gam/utils/Encoding.java | 6 +++--- .../com/genexus/gam/utils/test/EncodingTest.java | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/gamutils/src/main/java/com/genexus/gam/utils/Encoding.java b/gamutils/src/main/java/com/genexus/gam/utils/Encoding.java index 4e4b7d623..7b25fd0e3 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/Encoding.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/Encoding.java @@ -17,7 +17,7 @@ public class Encoding { public static String b64ToB64Url(String input) { logger.debug("b64ToB64Url"); try { - return new String(UrlBase64.encode(Base64.decode(input)), "UTF-8").replaceAll("[\ufffd]", ""); + return java.util.Base64.getUrlEncoder().withoutPadding().encodeToString(Base64.decode(input)); } catch (Exception e) { logger.error("b64ToB64Url", e); return ""; @@ -40,7 +40,7 @@ public static String toBase64Url(String input) { logger.debug("UTF8toBase64Url"); try{ - return new String(UrlBase64.encode(input.getBytes(StandardCharsets.UTF_8))); + return java.util.Base64.getUrlEncoder().withoutPadding().encodeToString(input.getBytes(StandardCharsets.UTF_8)); }catch (Exception e) { logger.error("UTF8toBase64Url", e); @@ -52,7 +52,7 @@ public static String fromBase64Url(String base64Url) { logger.debug("fromBase64Url"); try{ - return new String(UrlBase64.decode(base64Url), StandardCharsets.UTF_8); + return new String(java.util.Base64.getUrlDecoder().decode(base64Url), StandardCharsets.ISO_8859_1); }catch (Exception e) { logger.error("fromBase64Url", e); diff --git a/gamutils/src/test/java/com/genexus/gam/utils/test/EncodingTest.java b/gamutils/src/test/java/com/genexus/gam/utils/test/EncodingTest.java index fa8ebd66f..1aaed898c 100644 --- a/gamutils/src/test/java/com/genexus/gam/utils/test/EncodingTest.java +++ b/gamutils/src/test/java/com/genexus/gam/utils/test/EncodingTest.java @@ -5,11 +5,11 @@ import com.genexus.gam.utils.Random; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; -import org.bouncycastle.util.encoders.UrlBase64; import org.junit.Assert; import org.junit.Test; import java.nio.charset.StandardCharsets; +import java.text.MessageFormat; public class EncodingTest { @@ -26,14 +26,23 @@ public void testB64ToB64Url() { private static String b64UrlToUtf8(String base64Url) { try { - byte[] bytes = UrlBase64.decode(base64Url); - return new String(bytes, StandardCharsets.UTF_8).replaceAll("[\ufffd]", ""); + return new String(java.util.Base64.getUrlDecoder().decode(base64Url), StandardCharsets.ISO_8859_1); } catch (Exception e) { e.printStackTrace(); return ""; } } + @Test + public void testBase64Url() { + String[] utf8 = new String[]{"GQTuYnnS9AbcKXndwxiZbxk4Q60nhuEd", "rf7tZx8aWO28YOKLISDWY33HuarNHkIZ", "sF7Ic0iuZxE50nz3W5Jnj7R0nQlRD0b1", "GGKmW2ubkhnA9ASaVlVAKM6FQdPCQ1pj", "LMW0GSCVyeGiGzf84eIwuX6OHAfur9fp", "zq9Kni7W1r0UIzG9hjYeiqJhSYlWVZSa", "WcyhGLQNyQkP2YmOjVtIilpqcHgYCzjq", "DuhO4PBiXRDDj50RBRo8wNUU8R3UXbp0", "pkPfYXOyoLUsEwm4HjjDB6E2c3aUjYNh", "fgbrZoKKMym9HN5zlKj0a8ohgQlJm3PM", "owGXQ7p6BeFeK1KFVOsdbSRd0sMwgFRU"}; + String[] b64 = new String[]{"R1FUdVlublM5QWJjS1huZHd4aVpieGs0UTYwbmh1RWQ", "cmY3dFp4OGFXTzI4WU9LTElTRFdZMzNIdWFyTkhrSVo", "c0Y3SWMwaXVaeEU1MG56M1c1Sm5qN1IwblFsUkQwYjE", "R0dLbVcydWJraG5BOUFTYVZsVkFLTTZGUWRQQ1ExcGo", "TE1XMEdTQ1Z5ZUdpR3pmODRlSXd1WDZPSEFmdXI5ZnA", "enE5S25pN1cxcjBVSXpHOWhqWWVpcUpoU1lsV1ZaU2E", "V2N5aEdMUU55UWtQMlltT2pWdElpbHBxY0hnWUN6anE", "RHVoTzRQQmlYUkREajUwUkJSbzh3TlVVOFIzVVhicDA", "cGtQZllYT3lvTFVzRXdtNEhqakRCNkUyYzNhVWpZTmg", "ZmdiclpvS0tNeW05SE41emxLajBhOG9oZ1FsSm0zUE0", "b3dHWFE3cDZCZUZlSzFLRlZPc2RiU1JkMHNNd2dGUlU"}; + for (int i = 0; i < utf8.length; i++) { + Assert.assertEquals(MessageFormat.format("testBase64Url toBase64Url fail index: {0}", i), b64[i], Encoding.toBase64Url(utf8[i])); + Assert.assertEquals(MessageFormat.format("testBase64Url fromBase64Url fail index: {0}", i), utf8[i], Encoding.fromBase64Url(b64[i])); + } + } + @Test public void testToBase64Url() { int i = 0; From c8ba835f09364b422baa3cfd11ff62b2a431a5fd Mon Sep 17 00:00:00 2001 From: sgrampone Date: Tue, 29 Apr 2025 17:40:12 -0300 Subject: [PATCH 21/21] Fix key extension detection for azure OIDC discovery --- .../src/main/java/com/genexus/gam/utils/keys/PublicKeyUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gamutils/src/main/java/com/genexus/gam/utils/keys/PublicKeyUtil.java b/gamutils/src/main/java/com/genexus/gam/utils/keys/PublicKeyUtil.java index 0b8f2e17b..02e6ce314 100644 --- a/gamutils/src/main/java/com/genexus/gam/utils/keys/PublicKeyUtil.java +++ b/gamutils/src/main/java/com/genexus/gam/utils/keys/PublicKeyUtil.java @@ -108,7 +108,7 @@ private static String fixType(String input) { logger.debug("fixType"); try { String extension = FilenameUtils.getExtension(input); - if (extension.isEmpty()) { + if (extension.isEmpty() || extension.contains("}")) { try { Base64.decode(input); logger.debug("b64");