Alpine icon indicating copy to clipboard operation
Alpine copied to clipboard

Migrate to Jakarta EE 10, Jersey 3.x, and Jetty 12

Open nscuro opened this issue 1 year ago • 5 comments

Migrates javax namespaces to their jakarta counterparts.

Performs the following notable version bumps:

  • Jakarta Servlet API: 4.0.1 -> 6.0.0 (latest)
  • JAXB: 2.3.6 -> 4.0.5 (latest)
  • Jersey: 2.41 -> 3.1.6 (latest)
  • Jetty: 10.0.18 -> 12.0.9 (latest)

The following changes were necessary due to compatibility issues with Jakarta EE 10:

  • io.jsonwebtoken:jjwt: 0.9.1 -> 0.12.5
    • ~Signing and verifying of JWTs with Alpine's SecretKey no longer worked. I'm not sure why it worked before, but now the library complained about AES keys not being suitable for HMAC signing. I modified the JsonWebToken class to use Alpine's public/private key pair instead, which works. It changes the signature algorithm to RS512. I believe this change makes sense anyway.~
    • The above was resolved by converting the SecretKey generated for AES to an appropriate HmacSHA* algorithm (https://github.com/stevespringett/Alpine/pull/570/commits/a3687b4998b046c49f46e95d5af3282a6449040c)
  • The default implementation of jakarta.json is Eclipse Parsson. Replaced org.glassfish:javax-json with it.
  • The default implementation of jakarta.mail-api is Eclipse Angus. Added it.

Closes #402


FTR, Dependency-Track has been migrated accordingly. The test suite passes locally, and manual testing of the running application did not yield any complications. Pending PR is here: https://github.com/DependencyTrack/dependency-track/pull/3730

nscuro avatar May 17 '24 20:05 nscuro

@stevespringett Thoughts on this part?

  • io.jsonwebtoken:jjwt: 0.9.1 -> 0.12.5
    • Signing and verifying of JWTs with Alpine's SecretKey no longer worked. I'm not sure why it worked before, but now the library complained about AES keys not being suitable for HMAC signing. I modified the JsonWebToken class to use Alpine's public/private key pair instead, which works. It changes the signature algorithm to RS512. I believe this change makes sense anyway.

I was originally under the impression that the public/private key pair was used for JWT signing, but it turned out that the secret key was used instead. Is it a hard requirement to have this work with the secret key?

nscuro avatar May 17 '24 20:05 nscuro

@nscuro The SecretKey is a symmetrical key used to sign the JWT (e.g. HS512). The private/public key pair are asymmetrical keys for the encryption and decryption of data. Both key types are required.

stevespringett avatar May 17 '24 21:05 stevespringett

Hmmm yes, I was not planning to remove any of the keys. Just wondering which ones are supposed to be used for JWT signing.

At the moment, the secret key is used for both data encryption:

https://github.com/stevespringett/Alpine/blob/e747ed50be81f9fc955a44bf8f7786a26973e99f/alpine-infra/src/main/java/alpine/security/crypto/DataEncryption.java#L82-L85

and signing:

https://github.com/stevespringett/Alpine/blob/e747ed50be81f9fc955a44bf8f7786a26973e99f/alpine-server/src/main/java/alpine/server/auth/JsonWebToken.java#L94-L96

The public/private key pair is unused.

The secret key is generated with algorithm AES:

https://github.com/stevespringett/Alpine/blob/e747ed50be81f9fc955a44bf8f7786a26973e99f/alpine-infra/src/main/java/alpine/security/crypto/KeyManager.java#L166-L171

and the new JJWT version prevents AES keys from being used for HMAC signatures, i.e. it raises the following exception:

Unable to compute HS512 signature. Cause: The signing key's algorithm 'AES' does not equal a valid HmacSHA* algorithm name

IMO it would make sense to use the private key for signing, and the public key for signature verification.

nscuro avatar May 17 '24 22:05 nscuro

Another option would be to re-use the secret key's content to construct a new SecretKey with hmacSHA256 algorithm:

SecretKey originalKey = KeyManager.getInstance().getSecretKey(); // algorithm=AES
SecretKey hmacKey = new SecretKeySpec(originalKey.getEncoded(), "hmacSHA256");

JJWT's checks might be a tad too strict here. Their docs state:

[...] JJWT will assert that the specified key is allowed to be used for that algorithm when possible according to the JWT specification requirements.

There is no practical reason why a 256bit key generated for AES cannot be used for HMAC256. The way Java generates those keys is virtually the same.

Would the above be preferable over using they public/private key pair?

nscuro avatar May 19 '24 16:05 nscuro

Can you resolve the conflict?

stevespringett avatar May 23 '24 03:05 stevespringett