Skip to content

Commit

Permalink
Add JwtCreator for signing and encrypting JWT
Browse files Browse the repository at this point in the history
  • Loading branch information
iriale authored and ihostage committed Nov 4, 2020
1 parent ada29d5 commit 6a1f360
Show file tree
Hide file tree
Showing 13 changed files with 760 additions and 234 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@
import java.util.Collection;
import java.util.Map;

import static play.mvc.Http.HeaderNames.COOKIE;

import static java.lang.String.format;
import static java.util.Collections.emptySet;
import static java.util.stream.Collectors.toList;
import static play.mvc.Http.HeaderNames.COOKIE;

/**
* <p>Implementation web context of PAC4J for Lagom framework.</p>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.pac4j.lagom.javadsl.transport;

import com.lightbend.lagom.javadsl.api.transport.RequestHeader;
import com.nimbusds.jwt.JWT;

import java.util.function.Function;

import static org.pac4j.core.context.HttpConstants.AUTHORIZATION_HEADER;
import static org.pac4j.core.context.HttpConstants.BEARER_HEADER_PREFIX;

/**
* Helper functions for {@link RequestHeader}.
*
* @author Sergey Morgunov
* @since 2.2.1
*/
public final class RequestHeaderHelper {

/**
* Puts {@code Authorization} header to {@link RequestHeader}.
* @param jwt JWT
*/
public static Function<RequestHeader, RequestHeader> authorizationBearer(String jwt) {
return header -> header.withHeader(AUTHORIZATION_HEADER, BEARER_HEADER_PREFIX.concat(jwt));
}

/**
* Puts {@code Authorization} header to {@link RequestHeader}.
* @param jwt JWT
*/
public static Function<RequestHeader, RequestHeader> authorizationBearer(JWT jwt) {
return authorizationBearer(jwt.serialize());
}

/**
* Copies specified header from sourced {@link RequestHeader} to target.
* @param source sourced {@link RequestHeader}
* @param name name of copying header
*/
public static Function<RequestHeader, RequestHeader> forwardHeader(RequestHeader source, String name) {
return header -> source.getHeader(name).map(value -> header.withHeader(name, value)).orElse(header);
}

/**
* Copies {@code Authorization} header from sourced {@link RequestHeader} to target.
* @param source sourced {@link RequestHeader}
*/
public static Function<RequestHeader, RequestHeader> forwardAuthorization(RequestHeader source) {
return forwardHeader(source, AUTHORIZATION_HEADER);
}

private RequestHeaderHelper() {
}
}
149 changes: 108 additions & 41 deletions shared/src/main/java/org/pac4j/lagom/jwt/JwtAuthenticatorHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,12 @@
import com.typesafe.config.ConfigRenderOptions;
import org.pac4j.jwt.config.encryption.AbstractEncryptionConfiguration;
import org.pac4j.jwt.config.encryption.ECEncryptionConfiguration;
import org.pac4j.jwt.config.encryption.EncryptionConfiguration;
import org.pac4j.jwt.config.encryption.RSAEncryptionConfiguration;
import org.pac4j.jwt.config.encryption.SecretEncryptionConfiguration;
import org.pac4j.jwt.config.signature.AbstractSignatureConfiguration;
import org.pac4j.jwt.config.signature.ECSignatureConfiguration;
import org.pac4j.jwt.config.signature.RSASignatureConfiguration;
import org.pac4j.jwt.config.signature.SecretSignatureConfiguration;
import org.pac4j.jwt.config.signature.SignatureConfiguration;
import org.pac4j.jwt.credentials.authenticator.JwtAuthenticator;

import java.net.MalformedURLException;
Expand All @@ -38,6 +36,7 @@
import static com.nimbusds.jose.jwk.source.RemoteJWKSet.DEFAULT_HTTP_CONNECT_TIMEOUT;
import static com.nimbusds.jose.jwk.source.RemoteJWKSet.DEFAULT_HTTP_READ_TIMEOUT;
import static com.nimbusds.jose.jwk.source.RemoteJWKSet.DEFAULT_HTTP_SIZE_LIMIT;
import static java.util.stream.Collectors.toList;

/**
* Helper for parsing {@link JwtAuthenticator} from Lagom configuration.
Expand All @@ -47,64 +46,114 @@
*/
public final class JwtAuthenticatorHelper {

private static AbstractSignatureConfiguration parseSignature(JWK jwk) throws JOSEException {
AbstractSignatureConfiguration signature = null;
protected static class Conf<T> {
private final String keyId;
private final T configuration;

public Conf(String keyId, T configuration) {
this.keyId = keyId;
this.configuration = configuration;
}

public String getKeyId() {
return keyId;
}

public T getConfiguration() {
return configuration;
}
}

protected static class SignConf extends Conf<AbstractSignatureConfiguration> {
public SignConf(String keyId, AbstractSignatureConfiguration configuration) {
super(keyId, configuration);
}
}

protected static class EncryptConf extends Conf<AbstractEncryptionConfiguration> {
public EncryptConf(String keyId, AbstractEncryptionConfiguration configuration) {
super(keyId, configuration);
}
}

protected static class Configurations {
protected final List<SignConf> signatures;
protected final List<EncryptConf> encryptions;

public Configurations(List<SignConf> signatures, List<EncryptConf> encryptions) {
this.signatures = signatures;
this.encryptions = encryptions;
}
}

private static SignConf parseSignature(JWK jwk) throws JOSEException {
SignConf signature = null;
if (jwk instanceof OctetSequenceKey) {
signature = new SecretSignatureConfiguration(((OctetSequenceKey) jwk).toByteArray());
signature = new SignConf(
jwk.getKeyID(),
new SecretSignatureConfiguration(((OctetSequenceKey) jwk).toByteArray())
);
} else if (jwk instanceof RSAKey) {
signature = new RSASignatureConfiguration(((RSAKey) jwk).toKeyPair());
signature = new SignConf(
jwk.getKeyID(),
new RSASignatureConfiguration(((RSAKey) jwk).toKeyPair())
);
} else if (jwk instanceof ECKey) {
signature = new ECSignatureConfiguration(((ECKey) jwk).toKeyPair());
signature = new SignConf(
jwk.getKeyID(),
new ECSignatureConfiguration(((ECKey) jwk).toKeyPair())
);
}
return signature;
}

private static SignatureConfiguration parseSignature(Config conf) throws ParseException, JOSEException {
private static SignConf parseSignature(Config conf) throws ParseException, JOSEException {
if (!conf.hasPath("jwk")) return null;
AbstractSignatureConfiguration signature = parseSignature(
SignConf signature = parseSignature(
JWK.parse(conf.getConfig("jwk").root().render(ConfigRenderOptions.concise()))
);
if (signature != null && conf.hasPath("algorithm")) {
signature.setAlgorithm(JWSAlgorithm.parse(conf.getString("algorithm")));
signature.getConfiguration().setAlgorithm(JWSAlgorithm.parse(conf.getString("algorithm")));
}
return signature;
}

private static AbstractEncryptionConfiguration parseEncryption(JWK jwk) throws JOSEException {
AbstractEncryptionConfiguration encryption = null;
private static EncryptConf parseEncryption(JWK jwk) throws JOSEException {
EncryptConf encryption = null;
if (jwk instanceof OctetSequenceKey) {
encryption = new SecretEncryptionConfiguration(((OctetSequenceKey) jwk).toByteArray());
encryption = new EncryptConf(
jwk.getKeyID(),
new SecretEncryptionConfiguration(((OctetSequenceKey) jwk).toByteArray())
);
} else if (jwk instanceof RSAKey) {
encryption = new RSAEncryptionConfiguration(((RSAKey) jwk).toKeyPair());
encryption = new EncryptConf(
jwk.getKeyID(),
new RSAEncryptionConfiguration(((RSAKey) jwk).toKeyPair())
);
} else if (jwk instanceof ECKey) {
encryption = new ECEncryptionConfiguration(((ECKey) jwk).toKeyPair());
encryption = new EncryptConf(
jwk.getKeyID(),
new ECEncryptionConfiguration(((ECKey) jwk).toKeyPair())
);
}
return encryption;
}

private static EncryptionConfiguration parseEncryption(Config conf) throws ParseException, JOSEException {
private static EncryptConf parseEncryption(Config conf) throws ParseException, JOSEException {
if (!conf.hasPath("jwk")) return null;
AbstractEncryptionConfiguration encryption = parseEncryption(
EncryptConf encryption = parseEncryption(
JWK.parse(conf.getConfig("jwk").root().render(ConfigRenderOptions.concise()))
);
if (encryption != null) {
if (conf.hasPath("algorithm")) encryption.setAlgorithm(JWEAlgorithm.parse(conf.getString("algorithm")));
if (conf.hasPath("method")) encryption.setMethod(EncryptionMethod.parse(conf.getString("method")));
if (conf.hasPath("algorithm")) encryption.getConfiguration().setAlgorithm(JWEAlgorithm.parse(conf.getString("algorithm")));
if (conf.hasPath("method")) encryption.getConfiguration().setMethod(EncryptionMethod.parse(conf.getString("method")));
}
return encryption;
}

/**
* Parse {@link JwtAuthenticator} from Lagom conf.
*
* @param conf Configuration of authenticator
* @return JWT authenticator
* @throws ParseException a parse exception
* @throws JOSEException a signing/encryption exception
*/
public static JwtAuthenticator parse(Config conf) throws ParseException, JOSEException, MalformedURLException {
List<SignatureConfiguration> signatures = new ArrayList<>();
List<EncryptionConfiguration> encryptions = new ArrayList<>();
protected static Configurations parseConfigurations(Config conf) throws ParseException, JOSEException, MalformedURLException {
List<SignConf> signatures = new ArrayList<>();
List<EncryptConf> encryptions = new ArrayList<>();
ResourceRetriever jwkRetriever = null;
if (conf.hasPath("jwk-retriever")) {
Config retrieverConf = conf.getConfig("jwk-retriever");
Expand All @@ -120,31 +169,49 @@ public static JwtAuthenticator parse(Config conf) throws ParseException, JOSEExc
JWKSelector jwkSelector = new JWKSelector(new JWKMatcher.Builder().keyUse(KeyUse.SIGNATURE).build());
List<JWK> jwks = jwkSet.get(jwkSelector, null);
for (JWK jwk : jwks) {
SignatureConfiguration signatureConfiguration = parseSignature(jwk);
if (signatureConfiguration != null) signatures.add(signatureConfiguration);
SignConf signConfiguration = parseSignature(jwk);
if (signConfiguration != null) signatures.add(signConfiguration);
}
jwkSelector = new JWKSelector(new JWKMatcher.Builder().keyUse(KeyUse.ENCRYPTION).build());
jwks = jwkSet.get(jwkSelector, null);
for (JWK jwk : jwks) {
EncryptionConfiguration encryptionConfiguration = parseEncryption(jwk);
if (encryptionConfiguration != null) encryptions.add(encryptionConfiguration);
EncryptConf encryptConfiguration = parseEncryption(jwk);
if (encryptConfiguration != null) encryptions.add(encryptConfiguration);
}
}
}
if (conf.hasPath("signatures")) {
for (Config signature : conf.getConfigList("signatures")) {
SignatureConfiguration signatureConfiguration = parseSignature(signature);
if (signatureConfiguration != null) signatures.add(signatureConfiguration);
SignConf signConfiguration = parseSignature(signature);
if (signConfiguration != null) signatures.add(signConfiguration);
}
}
if (conf.hasPath("encryptions")) {
for (Config signature : conf.getConfigList("encryptions")) {
EncryptionConfiguration encryptionConfiguration = parseEncryption(signature);
if (encryptionConfiguration != null) encryptions.add(encryptionConfiguration);
for (Config encryption : conf.getConfigList("encryptions")) {
EncryptConf encryptConfiguration = parseEncryption(encryption);
if (encryptConfiguration != null) encryptions.add(encryptConfiguration);
}
}
return new JwtAuthenticator(signatures, encryptions);
return new Configurations(signatures, encryptions);
}

private JwtAuthenticatorHelper() {}
/**
* Parse {@link JwtAuthenticator} from Lagom conf.
*
* @param conf Configuration of authenticator
* @return JWT authenticator
* @throws ParseException a parse exception
* @throws JOSEException a signing/encryption exception
* @throws MalformedURLException a download JWK exception
*/
public static JwtAuthenticator parse(Config conf) throws ParseException, JOSEException, MalformedURLException {
Configurations configurations = parseConfigurations(conf);
return new JwtAuthenticator(
configurations.signatures.stream().map(Conf::getConfiguration).collect(toList()),
configurations.encryptions.stream().map(Conf::getConfiguration).collect(toList())
);
}

private JwtAuthenticatorHelper() {
}
}
Loading

0 comments on commit 6a1f360

Please sign in to comment.