From efd6be775e720a3d5784f7e3a4f94a06ae6ed80f Mon Sep 17 00:00:00 2001 From: Peter Siegmund Date: Wed, 28 Aug 2024 22:37:20 +0200 Subject: [PATCH] update JWT handling for external services Signed-off-by: Peter Siegmund --- build.gradle | 2 + .../mars3142/fhq/edge/AuthGatewayFilter.java | 76 +++++++++++++++++++ .../mars3142/fhq/edge/GCPGatewayFilter.java | 3 +- .../exceptions/AuthUnauthorizedException.java | 9 +++ src/main/resources/application.yaml | 18 +++-- 5 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 src/main/java/dev/mars3142/fhq/edge/AuthGatewayFilter.java create mode 100644 src/main/java/dev/mars3142/fhq/edge/exceptions/AuthUnauthorizedException.java diff --git a/build.gradle b/build.gradle index a6c23bc..4d18c37 100644 --- a/build.gradle +++ b/build.gradle @@ -38,6 +38,8 @@ dependencies { implementation 'com.google.cloud:spring-cloud-gcp-starter' implementation 'com.google.auth:google-auth-library-oauth2-http' implementation 'io.grpc:grpc-netty' + implementation 'io.netty:netty-all' + implementation 'com.nimbusds:nimbus-jose-jwt:9.40' testImplementation 'io.projectreactor:reactor-test' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' diff --git a/src/main/java/dev/mars3142/fhq/edge/AuthGatewayFilter.java b/src/main/java/dev/mars3142/fhq/edge/AuthGatewayFilter.java new file mode 100644 index 0000000..34d52e0 --- /dev/null +++ b/src/main/java/dev/mars3142/fhq/edge/AuthGatewayFilter.java @@ -0,0 +1,76 @@ +package dev.mars3142.fhq.edge; + +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.jwk.source.JWKSourceBuilder; +import com.nimbusds.jose.proc.JWSVerificationKeySelector; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.proc.DefaultJWTClaimsVerifier; +import com.nimbusds.jwt.proc.DefaultJWTProcessor; +import dev.mars3142.fhq.edge.exceptions.AuthUnauthorizedException; +import java.net.URI; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class AuthGatewayFilter extends AbstractGatewayFilterFactory { + + public AuthGatewayFilter() { + super(Config.class); + } + + @Override + public GatewayFilter apply(Config config) { + return (exchange, chain) -> { + val bearer = exchange.getRequest().getHeaders().getFirst(HttpHeaders.AUTHORIZATION); + if (bearer == null) { + log.error("No authorization header"); + throw new AuthUnauthorizedException(); + } + val token = bearer.substring("Bearer ".length()); + if (token.isEmpty()) { + log.error("Empty token"); + throw new AuthUnauthorizedException(); + } + + try { + val claimsSet = verifyToken(config, token); + + exchange.getRequest() + .mutate() + .header("x-user-id", claimsSet.getStringClaim("user_id")); + return chain.filter(exchange); + } catch (Exception e) { + log.error("Error while verifying token", e); + throw new AuthUnauthorizedException(); + } + }; + } + + private JWTClaimsSet verifyToken(Config config, String token) throws Exception { + val url = new URI( + "https://www.googleapis.com/service_accounts/v1/jwk/securetoken%40system.gserviceaccount.com").toURL(); + val keySource = JWKSourceBuilder.create(url).build(); + val algorithm = JWSAlgorithm.RS256; + val selector = new JWSVerificationKeySelector<>(algorithm, keySource); + val jwtClaimsSet = new JWTClaimsSet.Builder().issuer("https://securetoken.google.com/firmware-hq") + .audience(config.audience).build(); + val claimsVerifier = new DefaultJWTClaimsVerifier<>(config.audience, jwtClaimsSet, null); + claimsVerifier.verify(jwtClaimsSet, null); + val processor = new DefaultJWTProcessor<>(); + processor.setJWSKeySelector(selector); + processor.setJWTClaimsSetVerifier(claimsVerifier); + return processor.process(token, null); + } + + @Setter + public static class Config { + + private String audience; + } +} \ No newline at end of file diff --git a/src/main/java/dev/mars3142/fhq/edge/GCPGatewayFilter.java b/src/main/java/dev/mars3142/fhq/edge/GCPGatewayFilter.java index d4d51cd..ad41520 100644 --- a/src/main/java/dev/mars3142/fhq/edge/GCPGatewayFilter.java +++ b/src/main/java/dev/mars3142/fhq/edge/GCPGatewayFilter.java @@ -44,14 +44,13 @@ public class GCPGatewayFilter extends AbstractGatewayFilterFactory