diff options
author | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2020-02-02 13:17:48 +0100 |
---|---|---|
committer | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2020-02-02 13:17:48 +0100 |
commit | 944c0b663340a6cea517d0ee1542fbb6ad4c94e6 (patch) | |
tree | e1dc3cb9f455c77a03545c86af1a6585b98a7651 /src | |
parent | 9aab180b33c16ae56d79c9e67b258588505f0962 (diff) |
Remove the JWT cookie filters again.
They were pointless: quarkus-oidc's CodeAuthenticationMechanism
already takes care of setting a session cookie, which it uses in
preference over an IdP redirect.
The reason the cookie did not stick before is still unclear, but it
was fixed by tweaking the Keycloak settings for the MulkCMS client.
Change-Id: Ie547ee0af23b6532515a990c2699ba9ffa686a5a
Diffstat (limited to 'src')
-rw-r--r-- | src/main/java/eu/mulk/mulkcms2/authentication/JwtCookieLoginFilter.java | 184 | ||||
-rw-r--r-- | src/main/java/eu/mulk/mulkcms2/authentication/JwtCookieSetterFilter.java | 118 |
2 files changed, 0 insertions, 302 deletions
diff --git a/src/main/java/eu/mulk/mulkcms2/authentication/JwtCookieLoginFilter.java b/src/main/java/eu/mulk/mulkcms2/authentication/JwtCookieLoginFilter.java deleted file mode 100644 index 53903f7..0000000 --- a/src/main/java/eu/mulk/mulkcms2/authentication/JwtCookieLoginFilter.java +++ /dev/null @@ -1,184 +0,0 @@ -package eu.mulk.mulkcms2.authentication; - -import io.quarkus.security.credential.Credential; -import io.quarkus.security.identity.AuthenticationRequestContext; -import io.quarkus.security.identity.IdentityProvider; -import io.quarkus.security.identity.SecurityIdentity; -import io.quarkus.security.identity.request.TokenAuthenticationRequest; -import io.quarkus.smallrye.jwt.runtime.auth.JWTAuthMechanism; -import io.smallrye.jwt.auth.principal.DefaultJWTCallerPrincipal; -import java.io.FileInputStream; -import java.io.IOException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.Permission; -import java.security.Principal; -import java.security.PublicKey; -import java.security.cert.CertificateException; -import java.time.Duration; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import javax.annotation.PostConstruct; -import javax.enterprise.context.ApplicationScoped; -import org.eclipse.microprofile.config.inject.ConfigProperty; -import org.jose4j.jwa.AlgorithmConstraints; -import org.jose4j.jws.AlgorithmIdentifiers; -import org.jose4j.jwt.MalformedClaimException; -import org.jose4j.jwt.consumer.InvalidJwtException; -import org.jose4j.jwt.consumer.JwtConsumerBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Interprets a possibly present JWT cookie and uses it to authenticate the user. - * - * <p>JWT cookies are used to authenticate further requests based on initial authentication. This - * way, there is no need to route the user through an OpenID Connect IdP on each request, for - * example. - * - * @see JWTAuthMechanism - * @see JwtCookieSetterFilter - */ -@ApplicationScoped -public class JwtCookieLoginFilter implements IdentityProvider<TokenAuthenticationRequest> { - - @ConfigProperty(name = "mulkcms.jwt.signing-key") - String signingKeyAlias; - - @ConfigProperty(name = "mulkcms.jwt.keystore.file") - String signingKeyFile; - - @ConfigProperty(name = "mulkcms.jwt.keystore.passphrase") - String signingKeyPassphrase; - - @ConfigProperty(name = "mulkcms.jwt.issuer") - String issuer; - - @ConfigProperty(name = "mulkcms.jwt.validity") - Duration validity; - - private static final Logger log = LoggerFactory.getLogger(JwtCookieLoginFilter.class); - - private PublicKey signingKey; - - @PostConstruct - public void postCostruct() - throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException { - log.info("Hello!"); - try (var is = new FileInputStream(signingKeyFile)) { - var keystore = KeyStore.getInstance(KeyStore.getDefaultType()); - keystore.load(is, signingKeyPassphrase.toCharArray()); - signingKey = keystore.getCertificate(signingKeyAlias).getPublicKey(); - Objects.requireNonNull(signingKey); - } - } - - @Override - public CompletionStage<SecurityIdentity> authenticate( - TokenAuthenticationRequest request, AuthenticationRequestContext context) { - - log.info("Starting JWT verification."); - - return context.runBlocking( - () -> { - try { - log.info("JWT verification started."); - - /* - AbstractBearerTokenExtractor extractor = - new BearerTokenExtractor(requestContext, authContextInfo); - String bearerToken = extractor.getBearerToken(); - */ - - // FIXME: But how does this know how the token is extracted? What passes it here? - // Look up JWTAuthMechanism. - var bearerToken = request.getToken().getToken(); - - var jwtConsumer = - new JwtConsumerBuilder() - .setJwsAlgorithmConstraints( - new AlgorithmConstraints( - AlgorithmConstraints.ConstraintType.WHITELIST, - AlgorithmIdentifiers.RSA_USING_SHA256, - AlgorithmIdentifiers.RSA_USING_SHA384, - AlgorithmIdentifiers.RSA_USING_SHA512, - AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256, - AlgorithmIdentifiers.ECDSA_USING_P384_CURVE_AND_SHA384, - AlgorithmIdentifiers.ECDSA_USING_P521_CURVE_AND_SHA512)) - .setVerificationKey(signingKey) - .setRequireExpirationTime() - .setAllowedClockSkewInSeconds(60) - .build(); - - var claims = jwtConsumer.process(bearerToken).getJwtClaims(); - claims.getSubject(); - - var jwtPrincipal = new DefaultJWTCallerPrincipal(claims); - log.info("JWT verified: {}", jwtPrincipal); - - return new CookieIdentity(jwtPrincipal); - } catch (InvalidJwtException | MalformedClaimException e) { - log.info("JWT verification failed", e); - return null; - } - }); - } - - @Override - public Class<TokenAuthenticationRequest> getRequestType() { - return TokenAuthenticationRequest.class; - } - - private static class CookieIdentity implements SecurityIdentity { - - private Principal jwtPrincipal; - - private CookieIdentity(Principal jwtPrincipal) { - this.jwtPrincipal = jwtPrincipal; - } - - @Override - public Principal getPrincipal() { - return jwtPrincipal; - } - - @Override - public boolean isAnonymous() { - return false; - } - - @Override - public Set<String> getRoles() { - return Set.of(); - } - - @Override - public <T extends Credential> T getCredential(Class<T> credentialType) { - return null; - } - - @Override - public Set<Credential> getCredentials() { - return Set.of(); - } - - @Override - public <T> T getAttribute(String name) { - return null; - } - - @Override - public Map<String, Object> getAttributes() { - return Map.of(); - } - - @Override - public CompletionStage<Boolean> checkPermission(Permission permission) { - return CompletableFuture.completedFuture(false); - } - } -} diff --git a/src/main/java/eu/mulk/mulkcms2/authentication/JwtCookieSetterFilter.java b/src/main/java/eu/mulk/mulkcms2/authentication/JwtCookieSetterFilter.java deleted file mode 100644 index baa51d4..0000000 --- a/src/main/java/eu/mulk/mulkcms2/authentication/JwtCookieSetterFilter.java +++ /dev/null @@ -1,118 +0,0 @@ -package eu.mulk.mulkcms2.authentication; - -import io.quarkus.security.identity.SecurityIdentity; -import io.smallrye.jwt.build.Jwt; -import java.io.FileInputStream; -import java.io.IOException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; -import java.time.Duration; -import javax.annotation.PostConstruct; -import javax.annotation.Priority; -import javax.inject.Inject; -import javax.ws.rs.container.ContainerRequestContext; -import javax.ws.rs.container.ContainerResponseContext; -import javax.ws.rs.container.ContainerResponseFilter; -import javax.ws.rs.core.NewCookie; -import javax.ws.rs.ext.Provider; -import org.eclipse.microprofile.config.inject.ConfigProperty; -import org.eclipse.microprofile.jwt.Claims; -import org.eclipse.microprofile.jwt.JsonWebToken; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Adds a JWT cookie to every authenticated request. - * - * <p>JWT cookies are used to authenticate further requests based on initial authentication. This - * way, there is no need to route the user through an OpenID Connect IdP on each request, for - * example. - * - * @see JwtCookieLoginFilter - */ -@Provider -@Priority(1100) -public class JwtCookieSetterFilter implements ContainerResponseFilter { - - @ConfigProperty(name = "mulkcms.jwt.signing-key") - String signingKeyAlias; - - @ConfigProperty(name = "mulkcms.jwt.keystore.file") - String signingKeyFile; - - @ConfigProperty(name = "mulkcms.jwt.keystore.passphrase") - String signingKeyPassphrase; - - @ConfigProperty(name = "mulkcms.jwt.issuer") - String issuer; - - @ConfigProperty(name = "mulkcms.jwt.validity") - Duration validity; - - @Inject SecurityIdentity identity; - - private static final Logger log = LoggerFactory.getLogger(JwtCookieSetterFilter.class); - - private PrivateKey signingKey; - - @PostConstruct - public void postCostruct() - throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, - UnrecoverableKeyException { - try (var is = new FileInputStream(signingKeyFile)) { - var keystore = KeyStore.getInstance(KeyStore.getDefaultType()); - keystore.load(is, signingKeyPassphrase.toCharArray()); - signingKey = - (PrivateKey) keystore.getKey(signingKeyAlias, signingKeyPassphrase.toCharArray()); - } - } - - @Override - public void filter( - ContainerRequestContext requestContext, ContainerResponseContext responseContext) - throws IOException { - - if (identity.isAnonymous()) { - return; - } - - var currentTimeSeconds = System.currentTimeMillis() / 1000; - - if (identity instanceof JsonWebToken - && ((JsonWebToken) identity).getExpirationTime() < currentTimeSeconds) { - return; - } - - var claims = Jwt.claims(); - - claims.issuedAt(currentTimeSeconds); - claims.claim(Claims.auth_time.name(), currentTimeSeconds); - claims.expiresAt(currentTimeSeconds + validity.toSeconds()); - claims.issuer(issuer); - claims.preferredUserName(identity.getPrincipal().getName()); - claims.subject(identity.getPrincipal().getName()); - - var token = claims.jws().signatureKeyId(signingKeyAlias).sign(signingKey); - responseContext - .getHeaders() - .add( - "Set-Cookie", - new NewCookie( - "Bearer", - token, - null, - null, - 1, - null, - (int) validity.toSeconds(), - null, - false, - true) - .toString() - + ";SameSite=Strict"); - } -} |