summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatthias Andreas Benkard <code@mail.matthias.benkard.de>2020-02-02 13:17:48 +0100
committerMatthias Andreas Benkard <code@mail.matthias.benkard.de>2020-02-02 13:17:48 +0100
commit944c0b663340a6cea517d0ee1542fbb6ad4c94e6 (patch)
treee1dc3cb9f455c77a03545c86af1a6585b98a7651 /src
parent9aab180b33c16ae56d79c9e67b258588505f0962 (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.java184
-rw-r--r--src/main/java/eu/mulk/mulkcms2/authentication/JwtCookieSetterFilter.java118
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");
- }
-}