From 05361409b2c75b304afa4f8fd07b69f4afd6bb6f Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Sat, 3 Oct 2026 21:08:32 +0100 Subject: [PATCH] wip --- .../ddf/vodsystem/VodSystemApplication.java | 3 ++ .../vodsystem/controllers/UserController.java | 2 +- .../dto/properties/AuthProperties.java | 23 +++++++++++++++ .../vodsystem/security/GoogleAuthConfig.java | 28 +++++++++++++++++++ .../ddf/vodsystem/security/JwtService.java | 8 +++--- .../ddf/vodsystem/services/UserService.java | 27 ++++++------------ src/main/resources/application.properties | 8 +++--- .../vodsystem/services/UserServiceTest.java | 7 +++++ 8 files changed, 79 insertions(+), 27 deletions(-) create mode 100644 src/main/java/com/ddf/vodsystem/dto/properties/AuthProperties.java create mode 100644 src/main/java/com/ddf/vodsystem/security/GoogleAuthConfig.java create mode 100644 src/test/java/com/ddf/vodsystem/services/UserServiceTest.java diff --git a/src/main/java/com/ddf/vodsystem/VodSystemApplication.java b/src/main/java/com/ddf/vodsystem/VodSystemApplication.java index ff02ad6..7f26e6c 100644 --- a/src/main/java/com/ddf/vodsystem/VodSystemApplication.java +++ b/src/main/java/com/ddf/vodsystem/VodSystemApplication.java @@ -1,13 +1,16 @@ package com.ddf.vodsystem; +import com.ddf.vodsystem.dto.properties.AuthProperties; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @EnableScheduling @EnableAsync +@EnableConfigurationProperties(AuthProperties.class) public class VodSystemApplication { /** diff --git a/src/main/java/com/ddf/vodsystem/controllers/UserController.java b/src/main/java/com/ddf/vodsystem/controllers/UserController.java index 47baf7a..d776076 100644 --- a/src/main/java/com/ddf/vodsystem/controllers/UserController.java +++ b/src/main/java/com/ddf/vodsystem/controllers/UserController.java @@ -20,7 +20,7 @@ import java.util.Optional; public class UserController { private final UserService userService; - @Value("${jwt.expiration}") + @Value("${app.security.expiration.jwt}") private long jwtExpiration; private static final String SUCCESS = "success"; diff --git a/src/main/java/com/ddf/vodsystem/dto/properties/AuthProperties.java b/src/main/java/com/ddf/vodsystem/dto/properties/AuthProperties.java new file mode 100644 index 0000000..ea4c3af --- /dev/null +++ b/src/main/java/com/ddf/vodsystem/dto/properties/AuthProperties.java @@ -0,0 +1,23 @@ +package com.ddf.vodsystem.dto.properties; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +import java.time.Duration; + +@Validated +@ConfigurationProperties(prefix = "app.security") +public record AuthProperties ( + @NotBlank @Size(min = 32) String jwtSecret, + @Valid @NotNull Expiration expiration +) { + public record Expiration ( + @NotNull Duration jwt, + @NotNull Duration refreshToken, + @NotNull Duration tokenFamily + ) {} +} diff --git a/src/main/java/com/ddf/vodsystem/security/GoogleAuthConfig.java b/src/main/java/com/ddf/vodsystem/security/GoogleAuthConfig.java new file mode 100644 index 0000000..6edde2f --- /dev/null +++ b/src/main/java/com/ddf/vodsystem/security/GoogleAuthConfig.java @@ -0,0 +1,28 @@ +package com.ddf.vodsystem.security; + +import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.gson.GsonFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Collections; + +@Configuration +public class GoogleAuthConfig { + + /** + * Provides the verifier used to validate Google ID tokens issued for this application's client ID. + * + * @param googleClientId the OAuth client ID that tokens must be issued for + * @return the configured {@link GoogleIdTokenVerifier} + */ + @Bean + public GoogleIdTokenVerifier googleIdTokenVerifier( + @Value("${spring.security.oauth2.client.registration.google.client-id}") String googleClientId) { + return new GoogleIdTokenVerifier.Builder(new NetHttpTransport(), new GsonFactory()) + .setAudience(Collections.singletonList(googleClientId)) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/com/ddf/vodsystem/security/JwtService.java b/src/main/java/com/ddf/vodsystem/security/JwtService.java index ce8bfb5..df2a05e 100644 --- a/src/main/java/com/ddf/vodsystem/security/JwtService.java +++ b/src/main/java/com/ddf/vodsystem/security/JwtService.java @@ -7,6 +7,7 @@ import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.exceptions.TokenExpiredException; import com.auth0.jwt.interfaces.DecodedJWT; +import com.ddf.vodsystem.dto.properties.AuthProperties; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.oauth2.jwt.JwtException; import org.springframework.stereotype.Service; @@ -20,10 +21,9 @@ public class JwtService { private static final String USER_ID_CLAIM = "userId"; private static final String ISSUER = "vodsystem"; - public JwtService(@Value("${jwt.secret.key}") String jwtSecretKey, - @Value("${jwt.expiration}") long jwtExpiration) { - this.jwtExpiration = jwtExpiration; - this.algorithm = Algorithm.HMAC256(jwtSecretKey); + public JwtService(AuthProperties props) { + this.jwtExpiration = props.expiration().jwt().toMillis(); + this.algorithm = Algorithm.HMAC256(props.jwtSecret()); } /** diff --git a/src/main/java/com/ddf/vodsystem/services/UserService.java b/src/main/java/com/ddf/vodsystem/services/UserService.java index fc3354c..d53ab70 100644 --- a/src/main/java/com/ddf/vodsystem/services/UserService.java +++ b/src/main/java/com/ddf/vodsystem/services/UserService.java @@ -1,6 +1,7 @@ package com.ddf.vodsystem.services; import com.ddf.vodsystem.dto.TokenPackage; +import com.ddf.vodsystem.dto.properties.AuthProperties; import com.ddf.vodsystem.entities.RefreshToken; import com.ddf.vodsystem.entities.TokenFamily; import com.ddf.vodsystem.entities.User; @@ -9,11 +10,7 @@ import com.ddf.vodsystem.repositories.UserRepository; import com.ddf.vodsystem.security.JwtService; import com.ddf.vodsystem.security.TokenService; import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; -import com.google.api.client.http.javanet.NetHttpTransport; -import com.google.api.client.json.JsonFactory; -import com.google.api.client.json.gson.GsonFactory; import org.springframework.transaction.annotation.Transactional; -import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier; @@ -24,7 +21,6 @@ import java.security.GeneralSecurityException; import java.security.SecureRandom; import java.time.Duration; import java.time.Instant; -import java.util.Collections; import java.util.HexFormat; import java.util.Optional; @@ -34,11 +30,8 @@ public class UserService { private final UserRepository userRepository; private final JwtService jwtService; - @Value("token-family.expiration") - private long tokenFamilyExpirationMs; - - @Value("refresh-token.expiration") - private long refreshTokenExpirationMs; + private final long tokenFamilyExpirationMs; + private final long refreshTokenExpirationMs; private static final SecureRandom SECURE_RANDOM = new SecureRandom(); private static final int REFRESH_GRACE_PERIOD_SECONDS = 5; @@ -46,18 +39,16 @@ public class UserService { public UserService(UserRepository userRepository, JwtService jwtService, - @Value("${google.client.id}") String googleClientId, + GoogleIdTokenVerifier verifier, + AuthProperties props, TokenService tokenService) { this.userRepository = userRepository; - - NetHttpTransport transport = new NetHttpTransport(); - JsonFactory jsonFactory = new GsonFactory(); - - this.verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory) - .setAudience(Collections.singletonList(googleClientId)) - .build(); + this.verifier = verifier; this.jwtService = jwtService; this.tokenService = tokenService; + + this.refreshTokenExpirationMs = props.expiration().refreshToken().toMillis(); + this.tokenFamilyExpirationMs = props.expiration().tokenFamily().toMillis(); } /** diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 1109b33..380feb4 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -20,13 +20,13 @@ spring.flyway.locations=classpath:db/migrations spring.security.oauth2.client.registration.google.client-id=${GOOGLE_CLIENT_ID} spring.security.oauth2.client.registration.google.client-secret=${GOOGLE_CLIENT_SECRET} spring.security.oauth2.client.registration.google.scope=profile,email -jwt.secret.key=${JWT_SECRET_KEY} +app.security.jwt-secret=${JWT_SECRET_KEY} # 1 Hour -jwt.expiration=3600000 +app.security.expiration.jwt=3600000 # 7 days -refresh-token.expiration=604800000 +app.security.expiration.refresh-token=604800000 # 90 days -token-family.expiration=7776000000 +app.security.expiration.token-family=7776000000 # Frontend frontend.url=${FRONTEND_URL} diff --git a/src/test/java/com/ddf/vodsystem/services/UserServiceTest.java b/src/test/java/com/ddf/vodsystem/services/UserServiceTest.java new file mode 100644 index 0000000..0b5eb3e --- /dev/null +++ b/src/test/java/com/ddf/vodsystem/services/UserServiceTest.java @@ -0,0 +1,7 @@ +package com.ddf.vodsystem.services; + +import static org.junit.jupiter.api.Assertions.*; + +class UserServiceTest { + +} \ No newline at end of file