Skip to content

Commit

Permalink
refactor signing / encryption for JWT: WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
leleuj committed Aug 3, 2016
1 parent 17b6d93 commit 15e6409
Show file tree
Hide file tree
Showing 10 changed files with 504 additions and 197 deletions.
2 changes: 1 addition & 1 deletion pac4j-jwt/pom.xml
Expand Up @@ -13,7 +13,7 @@
<name>pac4j for JWT</name> <name>pac4j for JWT</name>


<properties> <properties>
<jose-jwt.version>4.22</jose-jwt.version> <jose-jwt.version>4.23</jose-jwt.version>
<bcprov.version>1.54</bcprov.version> <bcprov.version>1.54</bcprov.version>
</properties> </properties>


Expand Down
@@ -0,0 +1,99 @@
package org.pac4j.jwt.config;

import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.DirectDecrypter;
import com.nimbusds.jose.crypto.DirectEncrypter;
import com.nimbusds.jwt.EncryptedJWT;
import com.nimbusds.jwt.SignedJWT;
import org.pac4j.core.exception.TechnicalException;
import org.pac4j.core.util.CommonHelper;
import org.pac4j.core.util.InitializableObject;

import java.io.UnsupportedEncodingException;

/**
* Direct encryption configuration.
*
* @author Jerome Leleu
* @since 1.9.2
*/
public class DirectEncryptionConfiguration extends InitializableObject implements EncryptionConfiguration {

private String secret;

private EncryptionMethod method = EncryptionMethod.A256GCM;

public DirectEncryptionConfiguration() {}

public DirectEncryptionConfiguration(final String secret) {
this.secret = secret;
}

public DirectEncryptionConfiguration(final String secret, final EncryptionMethod method) {
this.secret = secret;
this.method = method;
}

@Override
protected void internalInit() {
CommonHelper.assertNotBlank("secret", secret);
CommonHelper.assertNotNull("method", method);
}

@Override
public String encrypt(final SignedJWT signedJWT) {
init();

// Create JWE object with signed JWT as payload
final JWEObject jweObject = new JWEObject(
new JWEHeader.Builder(JWEAlgorithm.DIR, this.method).contentType("JWT").build(),
new Payload(signedJWT));

try {
// Perform encryption
jweObject.encrypt(new DirectEncrypter(this.secret.getBytes("UTF-8")));
} catch (final UnsupportedEncodingException | JOSEException e) {
throw new TechnicalException(e);
}

// Serialise to JWE compact form
return jweObject.serialize();
}

@Override
public SignedJWT decrypt(EncryptedJWT encryptedJWT) {
init();

try {
final JWEObject jweObject = encryptedJWT;
jweObject.decrypt(new DirectDecrypter(this.secret.getBytes("UTF-8")));

// Extract payload
return jweObject.getPayload().toSignedJWT();

} catch (final UnsupportedEncodingException | JOSEException e) {
throw new TechnicalException(e);
}
}

public String getSecret() {
return secret;
}

public void setSecret(String secret) {
this.secret = secret;
}

public EncryptionMethod getMethod() {
return method;
}

public void setMethod(EncryptionMethod method) {
this.method = method;
}

@Override
public String toString() {
return CommonHelper.toString(this.getClass(), "secret", "[protected]", "method", method);
}
}
@@ -0,0 +1,83 @@
package org.pac4j.jwt.config;

import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.crypto.ECDSASigner;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import org.pac4j.core.exception.TechnicalException;
import org.pac4j.core.util.CommonHelper;
import org.pac4j.core.util.InitializableObject;

import java.security.interfaces.ECPrivateKey;

/**
* Elliptic curve signing configuration: http://connect2id.com/products/nimbus-jose-jwt/examples/jwt-with-rsa-signature
*
* @author Jerome Leleu
* @since 1.9.2
*/
public class ECSigningConfiguration extends InitializableObject implements SigningConfiguration {

private ECPrivateKey key;

private JWSAlgorithm algorithm = JWSAlgorithm.ES256;

public ECSigningConfiguration() {}

public ECSigningConfiguration(final ECPrivateKey key) {
this.key = key;
}

public ECSigningConfiguration(final ECPrivateKey key, final JWSAlgorithm algorithm) {
this.key = key;
this.algorithm = algorithm;
}

@Override
protected void internalInit() {
CommonHelper.assertNotNull("algorithm", algorithm);
CommonHelper.assertNotNull("key", key);

if (algorithm != JWSAlgorithm.ES256 && algorithm != JWSAlgorithm.ES384 && algorithm != JWSAlgorithm.ES512) {
throw new TechnicalException("Only the ES256, ES384 and ES512 algorithms are supported for elliptic curve signature");
}
}

@Override
public SignedJWT sign(JWTClaimsSet claims) {
init();

try {
final JWSSigner signer = new ECDSASigner(this.key);
final SignedJWT signedJWT = new SignedJWT(new JWSHeader(algorithm), claims);
signedJWT.sign(signer);
return signedJWT;
} catch (final JOSEException e) {
throw new TechnicalException(e);
}
}

public ECPrivateKey getKey() {
return key;
}

public void setKey(final ECPrivateKey key) {
this.key = key;
}

public JWSAlgorithm getAlgorithm() {
return algorithm;
}

public void setAlgorithm(final JWSAlgorithm algorithm) {
this.algorithm = algorithm;
}

@Override
public String toString() {
return CommonHelper.toString(this.getClass(), "key", "[protected]", "algorithm", algorithm);
}
}
@@ -0,0 +1,29 @@
package org.pac4j.jwt.config;

import com.nimbusds.jwt.EncryptedJWT;
import com.nimbusds.jwt.SignedJWT;

/**
* Encryption configuration.
*
* @author Jerome Leleu
* @since 1.9.2
*/
public interface EncryptionConfiguration {

/**
* Encrypt a signed JWT.
*
* @param signedJWT the signed JWT
* @return the encrypted signed JWT
*/
String encrypt(SignedJWT signedJWT);

/**
* Decrypt an encrypted (signed) JWT.
*
* @param encryptedJWT the encrypted JWT
* @return the decrypted (signed) JWT
*/
SignedJWT decrypt(EncryptedJWT encryptedJWT);
}
@@ -0,0 +1,78 @@
package org.pac4j.jwt.config;

import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import org.pac4j.core.exception.TechnicalException;
import org.pac4j.core.util.CommonHelper;
import org.pac4j.core.util.InitializableObject;

/**
* HMac signing configuration: http://connect2id.com/products/nimbus-jose-jwt/examples/jwt-with-hmac
*
* @author Jerome Leleu
* @since 1.9.2
*/
public class MacSigningConfiguration extends InitializableObject implements SigningConfiguration {

private String secret;

private JWSAlgorithm algorithm = JWSAlgorithm.HS256;

public MacSigningConfiguration() {}

public MacSigningConfiguration(final String secret) {
this.secret = secret;
}

public MacSigningConfiguration(final String secret, final JWSAlgorithm algorithm) {
this.secret = secret;
this.algorithm = algorithm;
}

@Override
protected void internalInit() {
CommonHelper.assertNotNull("algorithm", algorithm);
CommonHelper.assertNotBlank("secret", secret);

if (algorithm != JWSAlgorithm.HS256 && algorithm != JWSAlgorithm.HS384 && algorithm != JWSAlgorithm.HS512) {
throw new TechnicalException("Only the HS256, HS384 and HS512 algorithms are supported for HMac signature");
}
}

@Override
public SignedJWT sign(JWTClaimsSet claims) {
init();

try {
final JWSSigner signer = new MACSigner(this.secret);
final SignedJWT signedJWT = new SignedJWT(new JWSHeader(algorithm), claims);
signedJWT.sign(signer);
return signedJWT;
} catch (final JOSEException e) {
throw new TechnicalException(e);
}
}

public String getSecret() {
return secret;
}

public void setSecret(final String secret) {
this.secret = secret;
}

public JWSAlgorithm getAlgorithm() {
return algorithm;
}

public void setAlgorithm(final JWSAlgorithm algorithm) {
this.algorithm = algorithm;
}

@Override
public String toString() {
return CommonHelper.toString(this.getClass(), "secret", "[protected]", "algorithm", algorithm);
}
}
@@ -0,0 +1,84 @@
package org.pac4j.jwt.config;

import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import org.pac4j.core.exception.TechnicalException;
import org.pac4j.core.util.CommonHelper;
import org.pac4j.core.util.InitializableObject;

import java.security.interfaces.RSAPrivateKey;

/**
* RSA signing configuration: http://connect2id.com/products/nimbus-jose-jwt/examples/jwt-with-rsa-signature
*
* @author Jerome Leleu
* @since 1.9.2
*/
public class RSASigningConfiguration extends InitializableObject implements SigningConfiguration {

private RSAPrivateKey key;

private JWSAlgorithm algorithm = JWSAlgorithm.RS256;

public RSASigningConfiguration() {}

public RSASigningConfiguration(final RSAPrivateKey key) {
this.key = key;
}

public RSASigningConfiguration(final RSAPrivateKey key, final JWSAlgorithm algorithm) {
this.key = key;
this.algorithm = algorithm;
}

@Override
protected void internalInit() {
CommonHelper.assertNotNull("algorithm", algorithm);
CommonHelper.assertNotNull("key", key);

if (algorithm != JWSAlgorithm.RS256 && algorithm != JWSAlgorithm.RS384 && algorithm != JWSAlgorithm.RS512 &&
algorithm != JWSAlgorithm.PS256 && algorithm != JWSAlgorithm.PS384 && algorithm != JWSAlgorithm.PS512) {
throw new TechnicalException("Only the RS256, RS384, RS512, PS256, PS384 and PS512 algorithms are supported for RSA signature");
}
}

@Override
public SignedJWT sign(JWTClaimsSet claims) {
init();

try {
final JWSSigner signer = new RSASSASigner(this.key);
final SignedJWT signedJWT = new SignedJWT(new JWSHeader(algorithm), claims);
signedJWT.sign(signer);
return signedJWT;
} catch (final JOSEException e) {
throw new TechnicalException(e);
}
}

public RSAPrivateKey getKey() {
return key;
}

public void setKey(final RSAPrivateKey key) {
this.key = key;
}

public JWSAlgorithm getAlgorithm() {
return algorithm;
}

public void setAlgorithm(final JWSAlgorithm algorithm) {
this.algorithm = algorithm;
}

@Override
public String toString() {
return CommonHelper.toString(this.getClass(), "key", "[protected]", "algorithm", algorithm);
}
}

0 comments on commit 15e6409

Please sign in to comment.