diff --git a/src/main/java/io/wwan13/wintersecurity/config/AuthConfiguration.java b/src/main/java/io/wwan13/wintersecurity/config/AuthConfiguration.java index f1cf221..c8f5157 100644 --- a/src/main/java/io/wwan13/wintersecurity/config/AuthConfiguration.java +++ b/src/main/java/io/wwan13/wintersecurity/config/AuthConfiguration.java @@ -24,10 +24,21 @@ import io.wwan13.wintersecurity.auth.provider.BearerTokenExtractor; import io.wwan13.wintersecurity.auth.provider.HttpRequestAccessManager; import io.wwan13.wintersecurity.jwt.TokenDecoder; +import io.wwan13.wintersecurity.jwt.provider.JwtTokenDecoder; +import io.wwan13.wintersecurity.secretkey.SecretKey; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; public class AuthConfiguration { + @Bean + @ConditionalOnMissingBean(TokenDecoder.class) + public TokenDecoder tokenDecoder(SecretKey secretKey) { + return new JwtTokenDecoder(secretKey); + } + @Bean public TokenExtractor tokenExtractor() { return new BearerTokenExtractor(); @@ -50,4 +61,9 @@ public AbstractInterceptorAuthProcessor authProcessor( requestAccessManager ); } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } } diff --git a/src/main/java/io/wwan13/wintersecurity/config/AuthorizedRequestRegistrar.java b/src/main/java/io/wwan13/wintersecurity/config/AuthorizedRequestRegistrar.java index 2b15eb9..46454b9 100644 --- a/src/main/java/io/wwan13/wintersecurity/config/AuthorizedRequestRegistrar.java +++ b/src/main/java/io/wwan13/wintersecurity/config/AuthorizedRequestRegistrar.java @@ -24,16 +24,16 @@ public class AuthorizedRequestRegistrar { - private final WebSecurityConfigurer webSecurityConfigurer; + private final SecureRequestConfigurer secureRequestConfigurer; - public AuthorizedRequestRegistrar(WebSecurityConfigurer webSecurityConfigurer) { - this.webSecurityConfigurer = webSecurityConfigurer; + public AuthorizedRequestRegistrar(SecureRequestConfigurer secureRequestConfigurer) { + this.secureRequestConfigurer = secureRequestConfigurer; } @Bean public AuthorizedRequest authorizedRequest() { AuthorizedRequestRegistry registry = AuthorizedRequestRegistry.of(); - webSecurityConfigurer.registerAuthPatterns(registry); + secureRequestConfigurer.registerAuthPatterns(registry); return AuthorizedRequestApplier.apply(registry); } } diff --git a/src/main/java/io/wwan13/wintersecurity/config/EnableWebSecurity.java b/src/main/java/io/wwan13/wintersecurity/config/EnableJwtProvider.java similarity index 76% rename from src/main/java/io/wwan13/wintersecurity/config/EnableWebSecurity.java rename to src/main/java/io/wwan13/wintersecurity/config/EnableJwtProvider.java index f5ae16e..6182f02 100644 --- a/src/main/java/io/wwan13/wintersecurity/config/EnableWebSecurity.java +++ b/src/main/java/io/wwan13/wintersecurity/config/EnableJwtProvider.java @@ -18,19 +18,19 @@ import org.springframework.context.annotation.Import; -import java.lang.annotation.*; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Import({ - AuthorizedRequestRegistrar.class, - AuthConfiguration.class, - AuthProcessorRegistrar.class, JwtPropertiesRegistrar.class, JwtConfiguration.class, - PasswordEncoderConfiguration.class, - TargetAnnotationsRegistrar.class + SecretKeyRegistrar.class }) -public @interface EnableWebSecurity { -} +public @interface EnableJwtProvider { +} \ No newline at end of file diff --git a/src/main/java/io/wwan13/wintersecurity/config/EnableSecureRequest.java b/src/main/java/io/wwan13/wintersecurity/config/EnableSecureRequest.java new file mode 100644 index 0000000..f6de8da --- /dev/null +++ b/src/main/java/io/wwan13/wintersecurity/config/EnableSecureRequest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.wwan13.wintersecurity.config; + +import org.springframework.context.annotation.Import; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +@Import({ + AuthorizedRequestRegistrar.class, + AuthConfiguration.class, + AuthProcessorRegistrar.class, + TargetAnnotationsRegistrar.class, + SecretKeyRegistrar.class +}) +public @interface EnableSecureRequest { +} diff --git a/src/main/java/io/wwan13/wintersecurity/config/JwtConfiguration.java b/src/main/java/io/wwan13/wintersecurity/config/JwtConfiguration.java index af5a120..d25117f 100644 --- a/src/main/java/io/wwan13/wintersecurity/config/JwtConfiguration.java +++ b/src/main/java/io/wwan13/wintersecurity/config/JwtConfiguration.java @@ -26,34 +26,33 @@ import io.wwan13.wintersecurity.jwt.payload.support.ReflectionPayloadAnalyst; import io.wwan13.wintersecurity.jwt.provider.JwtTokenDecoder; import io.wwan13.wintersecurity.jwt.provider.JwtTokenGenerator; +import io.wwan13.wintersecurity.secretkey.SecretKey; import org.springframework.context.annotation.Bean; public class JwtConfiguration { - private final JwtProperties jwtProperties; - - public JwtConfiguration(JwtProperties jwtProperties) { - this.jwtProperties = jwtProperties; - } - @Bean - public TokenGenerator tokenGenerator() { - return new JwtTokenGenerator(jwtProperties, payloadParser()); + public TokenGenerator tokenGenerator( + SecretKey secretKey, + JwtProperties jwtProperties, + PayloadParser payloadParser + ) { + return new JwtTokenGenerator(secretKey, jwtProperties, payloadParser); } @Bean - public TokenDecoder tokenDecoder() { - return new JwtTokenDecoder(jwtProperties); + public TokenDecoder tokenDecoder(SecretKey secretKey) { + return new JwtTokenDecoder(secretKey); } @Bean - public PayloadAnalysis payloadAnalysis() { + public PayloadAnalysis payloadAnalysis(JwtProperties jwtProperties) { PayloadAnalyst payloadAnalyst = new ReflectionPayloadAnalyst(); return payloadAnalyst.analyze(jwtProperties); } @Bean - public PayloadParser payloadParser() { - return new JwtPayloadParser(payloadAnalysis()); + public PayloadParser payloadParser(PayloadAnalysis payloadAnalysis) { + return new JwtPayloadParser(payloadAnalysis); } } diff --git a/src/main/java/io/wwan13/wintersecurity/config/JwtPropertiesRegistrar.java b/src/main/java/io/wwan13/wintersecurity/config/JwtPropertiesRegistrar.java index 84d91fc..112d762 100644 --- a/src/main/java/io/wwan13/wintersecurity/config/JwtPropertiesRegistrar.java +++ b/src/main/java/io/wwan13/wintersecurity/config/JwtPropertiesRegistrar.java @@ -23,17 +23,16 @@ public class JwtPropertiesRegistrar { - private final WebSecurityConfigurer webSecurityConfigurer; + private final JwtProviderConfigurer jwtProviderConfigurer; - public JwtPropertiesRegistrar(WebSecurityConfigurer webSecurityConfigurer) { - this.webSecurityConfigurer = webSecurityConfigurer; + public JwtPropertiesRegistrar(JwtProviderConfigurer jwtProviderConfigurer) { + this.jwtProviderConfigurer = jwtProviderConfigurer; } - @Bean public JwtProperties jwtProperties() { JwtPropertiesRegistry registry = new JwtPropertiesRegistry(); - webSecurityConfigurer.configureJwt(registry); + jwtProviderConfigurer.configureJwt(registry); return JwtPropertiesApplier.apply(registry); } } diff --git a/src/main/java/io/wwan13/wintersecurity/config/PasswordEncoderConfiguration.java b/src/main/java/io/wwan13/wintersecurity/config/JwtProviderConfigurer.java similarity index 65% rename from src/main/java/io/wwan13/wintersecurity/config/PasswordEncoderConfiguration.java rename to src/main/java/io/wwan13/wintersecurity/config/JwtProviderConfigurer.java index 80c8baa..bb0d163 100644 --- a/src/main/java/io/wwan13/wintersecurity/config/PasswordEncoderConfiguration.java +++ b/src/main/java/io/wwan13/wintersecurity/config/JwtProviderConfigurer.java @@ -16,14 +16,9 @@ package io.wwan13.wintersecurity.config; -import org.springframework.context.annotation.Bean; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; +import io.wwan13.wintersecurity.jwt.support.JwtPropertiesRegistry; -public class PasswordEncoderConfiguration { +public interface JwtProviderConfigurer extends SecretKeyConfigurer { - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } + void configureJwt(JwtPropertiesRegistry registry); } diff --git a/src/main/java/io/wwan13/wintersecurity/config/SecretKeyConfigurer.java b/src/main/java/io/wwan13/wintersecurity/config/SecretKeyConfigurer.java new file mode 100644 index 0000000..39aab43 --- /dev/null +++ b/src/main/java/io/wwan13/wintersecurity/config/SecretKeyConfigurer.java @@ -0,0 +1,24 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.wwan13.wintersecurity.config; + +import io.wwan13.wintersecurity.secretkey.support.SecretKeyRegistry; + +public interface SecretKeyConfigurer { + + void configureSecretKey(SecretKeyRegistry registry); +} diff --git a/src/main/java/io/wwan13/wintersecurity/config/SecretKeyRegistrar.java b/src/main/java/io/wwan13/wintersecurity/config/SecretKeyRegistrar.java new file mode 100644 index 0000000..b3b77da --- /dev/null +++ b/src/main/java/io/wwan13/wintersecurity/config/SecretKeyRegistrar.java @@ -0,0 +1,38 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.wwan13.wintersecurity.config; + +import io.wwan13.wintersecurity.secretkey.SecretKey; +import io.wwan13.wintersecurity.secretkey.support.SecretKetApplier; +import io.wwan13.wintersecurity.secretkey.support.SecretKeyRegistry; +import org.springframework.context.annotation.Bean; + +public class SecretKeyRegistrar { + + private final SecretKeyConfigurer configurer; + + public SecretKeyRegistrar(SecretKeyConfigurer configurer) { + this.configurer = configurer; + } + + @Bean + public SecretKey secretKey() { + SecretKeyRegistry registry = new SecretKeyRegistry(); + configurer.configureSecretKey(registry); + return SecretKetApplier.apply(registry); + } +} diff --git a/src/main/java/io/wwan13/wintersecurity/config/WebSecurityConfigurer.java b/src/main/java/io/wwan13/wintersecurity/config/SecureRequestConfigurer.java similarity index 79% rename from src/main/java/io/wwan13/wintersecurity/config/WebSecurityConfigurer.java rename to src/main/java/io/wwan13/wintersecurity/config/SecureRequestConfigurer.java index 7fc87cc..f79f522 100644 --- a/src/main/java/io/wwan13/wintersecurity/config/WebSecurityConfigurer.java +++ b/src/main/java/io/wwan13/wintersecurity/config/SecureRequestConfigurer.java @@ -17,14 +17,11 @@ package io.wwan13.wintersecurity.config; import io.wwan13.wintersecurity.auth.authorizedrequest.support.AuthorizedRequestRegistry; -import io.wwan13.wintersecurity.jwt.support.JwtPropertiesRegistry; import io.wwan13.wintersecurity.resolve.support.TargetAnnotationsRegistry; -public interface WebSecurityConfigurer { +public interface SecureRequestConfigurer extends SecretKeyConfigurer { void registerAuthPatterns(AuthorizedRequestRegistry registry); - void configureJwt(JwtPropertiesRegistry registry); - - void registerResolveTargets(TargetAnnotationsRegistry registry); + void registerTargetAnnotations(TargetAnnotationsRegistry registry); } diff --git a/src/main/java/io/wwan13/wintersecurity/config/TargetAnnotationsRegistrar.java b/src/main/java/io/wwan13/wintersecurity/config/TargetAnnotationsRegistrar.java index ebfbdf1..2bbd8e6 100644 --- a/src/main/java/io/wwan13/wintersecurity/config/TargetAnnotationsRegistrar.java +++ b/src/main/java/io/wwan13/wintersecurity/config/TargetAnnotationsRegistrar.java @@ -23,16 +23,16 @@ public class TargetAnnotationsRegistrar { - private final WebSecurityConfigurer webSecurityConfigurer; + private final SecureRequestConfigurer secureRequestConfigurer; - public TargetAnnotationsRegistrar(WebSecurityConfigurer webSecurityConfigurer) { - this.webSecurityConfigurer = webSecurityConfigurer; + public TargetAnnotationsRegistrar(SecureRequestConfigurer secureRequestConfigurer) { + this.secureRequestConfigurer = secureRequestConfigurer; } @Bean public TargetAnnotations targetAnnotations() { TargetAnnotationsRegistry registry = new TargetAnnotationsRegistry(); - webSecurityConfigurer.registerResolveTargets(registry); + secureRequestConfigurer.registerTargetAnnotations(registry); return TargetAnnotationsApplier.apply(registry); } } diff --git a/src/main/java/io/wwan13/wintersecurity/jwt/JwtProperties.java b/src/main/java/io/wwan13/wintersecurity/jwt/JwtProperties.java index 79ed671..ac4495d 100644 --- a/src/main/java/io/wwan13/wintersecurity/jwt/JwtProperties.java +++ b/src/main/java/io/wwan13/wintersecurity/jwt/JwtProperties.java @@ -16,14 +16,10 @@ package io.wwan13.wintersecurity.jwt; -import java.security.Key; - public record JwtProperties( - String secretKey, long accessTokenValidity, long refreshTokenValidity, Class payloadClazz, - Class subjectClazz, - Key key + Class subjectClazz ) { } diff --git a/src/main/java/io/wwan13/wintersecurity/jwt/provider/JwtTokenDecoder.java b/src/main/java/io/wwan13/wintersecurity/jwt/provider/JwtTokenDecoder.java index 60ec9ae..d0cefe4 100644 --- a/src/main/java/io/wwan13/wintersecurity/jwt/provider/JwtTokenDecoder.java +++ b/src/main/java/io/wwan13/wintersecurity/jwt/provider/JwtTokenDecoder.java @@ -19,17 +19,18 @@ import io.jsonwebtoken.*; import io.wwan13.wintersecurity.exception.unauthirized.ExpiredJwtTokenException; import io.wwan13.wintersecurity.exception.unauthirized.InvalidJwtTokenException; -import io.wwan13.wintersecurity.jwt.JwtProperties; import io.wwan13.wintersecurity.jwt.TokenDecoder; +import io.wwan13.wintersecurity.secretkey.SecretKey; +import java.security.Key; import java.util.Map; public class JwtTokenDecoder implements TokenDecoder { - private final JwtProperties jwtProperties; + private final SecretKey secretKey; - public JwtTokenDecoder(JwtProperties jwtProperties) { - this.jwtProperties = jwtProperties; + public JwtTokenDecoder(SecretKey secretKey) { + this.secretKey = secretKey; } @Override @@ -40,7 +41,7 @@ public Map decode(String token) { public Claims parseClaimsWithExceptionHandling(String token) { try { return Jwts.parserBuilder() - .setSigningKey(jwtProperties.key()) + .setSigningKey(secretKey.value()) .build() .parseClaimsJws(token) .getBody(); diff --git a/src/main/java/io/wwan13/wintersecurity/jwt/provider/JwtTokenGenerator.java b/src/main/java/io/wwan13/wintersecurity/jwt/provider/JwtTokenGenerator.java index c3d984f..fa6e366 100644 --- a/src/main/java/io/wwan13/wintersecurity/jwt/provider/JwtTokenGenerator.java +++ b/src/main/java/io/wwan13/wintersecurity/jwt/provider/JwtTokenGenerator.java @@ -22,16 +22,26 @@ import io.wwan13.wintersecurity.jwt.PayloadParser; import io.wwan13.wintersecurity.jwt.TokenGenerator; import io.wwan13.wintersecurity.jwt.payload.util.RoleSerializer; +import io.wwan13.wintersecurity.secretkey.SecretKey; import io.wwan13.wintersecurity.util.DateUtil; -import static io.wwan13.wintersecurity.constant.Constants.*; +import static io.wwan13.wintersecurity.constant.Constants.PAYLOAD_KEY_TOKEN_TYPE; +import static io.wwan13.wintersecurity.constant.Constants.PAYLOAD_KEY_USER_ROLE; +import static io.wwan13.wintersecurity.constant.Constants.TOKEN_TYPE_ACCESS; +import static io.wwan13.wintersecurity.constant.Constants.TOKEN_TYPE_REFRESH; public class JwtTokenGenerator implements TokenGenerator { + private final SecretKey secretKey; private final JwtProperties properties; private final PayloadParser payloadParser; - public JwtTokenGenerator(JwtProperties properties, PayloadParser payloadParser) { + public JwtTokenGenerator( + SecretKey secretKey, + JwtProperties properties, + PayloadParser payloadParser + ) { + this.secretKey = secretKey; this.properties = properties; this.payloadParser = payloadParser; } @@ -46,7 +56,7 @@ public String accessToken(Payload payload) { .claim(PAYLOAD_KEY_TOKEN_TYPE, TOKEN_TYPE_ACCESS) .claim(PAYLOAD_KEY_USER_ROLE, RoleSerializer.serialize(payloadParser.asRoles(payload))) .addClaims(payloadParser.asAdditionalClaims(payload)) - .signWith(properties.key()) + .signWith(secretKey.value()) .compact(); } @@ -60,7 +70,7 @@ public String refreshToken(Payload payload) { .claim(PAYLOAD_KEY_TOKEN_TYPE, TOKEN_TYPE_REFRESH) .claim(PAYLOAD_KEY_USER_ROLE, RoleSerializer.serialize(payloadParser.asRoles(payload))) .addClaims(payloadParser.asAdditionalClaims(payload)) - .signWith(properties.key()) + .signWith(secretKey.value()) .compact(); } diff --git a/src/main/java/io/wwan13/wintersecurity/jwt/support/JwtPropertiesRegistry.java b/src/main/java/io/wwan13/wintersecurity/jwt/support/JwtPropertiesRegistry.java index e822465..f8e9ecc 100644 --- a/src/main/java/io/wwan13/wintersecurity/jwt/support/JwtPropertiesRegistry.java +++ b/src/main/java/io/wwan13/wintersecurity/jwt/support/JwtPropertiesRegistry.java @@ -16,27 +16,23 @@ package io.wwan13.wintersecurity.jwt.support; -import io.jsonwebtoken.security.Keys; import io.wwan13.wintersecurity.jwt.JwtProperties; import io.wwan13.wintersecurity.jwt.Payload; import java.util.Objects; -import static io.wwan13.wintersecurity.constant.Constants.*; +import static io.wwan13.wintersecurity.constant.Constants.DEFAULT_ACCESS_TOKEN_VALIDITY; +import static io.wwan13.wintersecurity.constant.Constants.DEFAULT_PAYLOAD_CLAZZ; +import static io.wwan13.wintersecurity.constant.Constants.DEFAULT_REFRESH_TOKEN_VALIDITY; +import static io.wwan13.wintersecurity.constant.Constants.DEFAULT_SUBJECT_CLAZZ; public class JwtPropertiesRegistry { - private String secretKey; private long accessTokenValidity; private long refreshTokenValidity; private Class payloadClazz; private Class subjectClazz; - public JwtPropertiesRegistry secretKey(String secretKey) { - this.secretKey = secretKey; - return this; - } - public JwtPropertiesRegistry accessTokenValidity(long accessTokenValidityInSecond) { this.accessTokenValidity = accessTokenValidityInSecond; return this; @@ -47,7 +43,7 @@ public JwtPropertiesRegistry refreshTokenValidity(long refreshTokenValidityInSec return this; } - public JwtPropertiesRegistry payloadClazz(Class payloadClazz) { + public JwtPropertiesRegistry payloadClazz(Class payloadClazz) { this.payloadClazz = payloadClazz; return this; } @@ -58,27 +54,14 @@ public JwtPropertiesRegistry subjectClazz(Class subjectClazz) { } protected JwtProperties apply() { - validateSecretKey(); return new JwtProperties( - secretKey, existOrDefaultValidity(accessTokenValidity, DEFAULT_ACCESS_TOKEN_VALIDITY), existOrDefaultValidity(refreshTokenValidity, DEFAULT_REFRESH_TOKEN_VALIDITY), existOrDefaultPayload(payloadClazz), - existOrDefaultSubject(subjectClazz), - Keys.hmacShaKeyFor(secretKey.getBytes()) + existOrDefaultSubject(subjectClazz) ); } - private void validateSecretKey() { - if (secretKey == null || secretKey.isEmpty()) { - throw new IllegalArgumentException("Secret key cannot be empty!"); - } - - if (secretKey.length() < 32) { - throw new IllegalArgumentException("Secret key must be longer than 32!"); - } - } - private long existOrDefaultValidity(long validityInSecond, long defaultValidityInSecond) { if (validityInSecond == 0) { return defaultValidityInSecond; diff --git a/src/main/java/io/wwan13/wintersecurity/secretkey/SecretKey.java b/src/main/java/io/wwan13/wintersecurity/secretkey/SecretKey.java new file mode 100644 index 0000000..cf4e96d --- /dev/null +++ b/src/main/java/io/wwan13/wintersecurity/secretkey/SecretKey.java @@ -0,0 +1,30 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.wwan13.wintersecurity.secretkey; + +import io.jsonwebtoken.security.Keys; + +import java.security.Key; + +public record SecretKey( + Key value +) { + + public static SecretKey of(String secretKey) { + return new SecretKey(Keys.hmacShaKeyFor(secretKey.getBytes())); + } +} diff --git a/src/main/java/io/wwan13/wintersecurity/secretkey/support/SecretKetApplier.java b/src/main/java/io/wwan13/wintersecurity/secretkey/support/SecretKetApplier.java new file mode 100644 index 0000000..0e8a72a --- /dev/null +++ b/src/main/java/io/wwan13/wintersecurity/secretkey/support/SecretKetApplier.java @@ -0,0 +1,30 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.wwan13.wintersecurity.secretkey.support; + +import io.wwan13.wintersecurity.secretkey.SecretKey; + +public class SecretKetApplier { + + private SecretKetApplier() { + throw new IllegalStateException("Cannot instantiate a utility class!"); + } + + public static SecretKey apply(SecretKeyRegistry registry) { + return registry.apply(); + } +} diff --git a/src/main/java/io/wwan13/wintersecurity/secretkey/support/SecretKeyRegistry.java b/src/main/java/io/wwan13/wintersecurity/secretkey/support/SecretKeyRegistry.java new file mode 100644 index 0000000..90d2828 --- /dev/null +++ b/src/main/java/io/wwan13/wintersecurity/secretkey/support/SecretKeyRegistry.java @@ -0,0 +1,44 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.wwan13.wintersecurity.secretkey.support; + +import io.wwan13.wintersecurity.secretkey.SecretKey; + +public class SecretKeyRegistry { + + private String secretKey; + + public SecretKeyRegistry secretKey(String secretKey) { + this.secretKey = secretKey; + return this; + } + + protected SecretKey apply() { + validateSecretKey(); + return SecretKey.of(secretKey); + } + + private void validateSecretKey() { + if (secretKey == null || secretKey.isEmpty()) { + throw new IllegalArgumentException("Secret key cannot be empty!"); + } + + if (secretKey.length() < 32) { + throw new IllegalArgumentException("Secret key must be longer than 32!"); + } + } +} diff --git a/src/test/java/io/wwan13/wintersecurity/context/AuthConfigurationContextTest.java b/src/test/java/io/wwan13/wintersecurity/context/AuthConfigurationContextTest.java deleted file mode 100644 index 25f5828..0000000 --- a/src/test/java/io/wwan13/wintersecurity/context/AuthConfigurationContextTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.wwan13.wintersecurity.context; - -import io.wwan13.wintersecurity.ContextTest; -import io.wwan13.wintersecurity.auth.AuthProcessor; -import io.wwan13.wintersecurity.auth.RequestAccessManager; -import io.wwan13.wintersecurity.auth.TokenExtractor; -import io.wwan13.wintersecurity.auth.processor.AbstractInterceptorAuthProcessor; -import io.wwan13.wintersecurity.auth.processor.InterceptorAuthProcessor; -import io.wwan13.wintersecurity.auth.provider.BearerTokenExtractor; -import io.wwan13.wintersecurity.auth.provider.HttpRequestAccessManager; -import io.wwan13.wintersecurity.context.config.TestContextConfig; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Import; -import org.springframework.web.servlet.HandlerInterceptor; - -import static org.assertj.core.api.Assertions.assertThat; - -@Import({TestContextConfig.class}) -public class AuthConfigurationContextTest extends ContextTest { - - @Autowired - TokenExtractor tokenExtractor; - - @Autowired - RequestAccessManager requestAccessManager; - - @Autowired - AbstractInterceptorAuthProcessor authProcessor; - - @Test - void should_RegisteredInSpringIocWithEnteredValue_when_ContextLoaded() { - // given, then, then - assertThat(tokenExtractor) - .isInstanceOf(TokenExtractor.class) - .isExactlyInstanceOf(BearerTokenExtractor.class); - - assertThat(requestAccessManager) - .isInstanceOf(RequestAccessManager.class) - .isExactlyInstanceOf(HttpRequestAccessManager.class); - - assertThat(authProcessor) - .isInstanceOf(AuthProcessor.class) - .isInstanceOf(HandlerInterceptor.class) - .isExactlyInstanceOf(InterceptorAuthProcessor.class); - } -} diff --git a/src/test/java/io/wwan13/wintersecurity/context/AuthorizedRequestContextTest.java b/src/test/java/io/wwan13/wintersecurity/context/AuthorizedRequestContextTest.java deleted file mode 100644 index fa85c0e..0000000 --- a/src/test/java/io/wwan13/wintersecurity/context/AuthorizedRequestContextTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.wwan13.wintersecurity.context; - -import io.wwan13.wintersecurity.ContextTest; -import io.wwan13.wintersecurity.auth.authorizedrequest.AuthorizedRequest; -import io.wwan13.wintersecurity.context.config.TestContextConfig; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Import; -import org.springframework.http.HttpMethod; - -import java.util.Set; - -import static org.assertj.core.api.Assertions.assertThat; - -@Import({TestContextConfig.class}) -public class AuthorizedRequestContextTest extends ContextTest { - - @Autowired - AuthorizedRequest authorizedRequest; - - @ParameterizedTest - @CsvSource({ - "GET, /api/test/hello, ROLE_ADMIN, true", - "GET, /api/bad/hello, ROLE_ADMIN, false", - }) - void should_RegisteredInSpringIocWithEnteredValue_when_ContextLoaded( - final String requestMethod, - final String requestUri, - final String requestRole, - final boolean expected - ) { - // given, when - boolean result = authorizedRequest - .isAccessibleRequest(HttpMethod.resolve(requestMethod), requestUri, Set.of(requestRole)); - - // then - assertThat(result).isEqualTo(expected); - } -} diff --git a/src/test/java/io/wwan13/wintersecurity/context/JwtConfigurationContextTest.java b/src/test/java/io/wwan13/wintersecurity/context/JwtConfigurationContextTest.java deleted file mode 100644 index abeb1a3..0000000 --- a/src/test/java/io/wwan13/wintersecurity/context/JwtConfigurationContextTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.wwan13.wintersecurity.context; - -import io.wwan13.wintersecurity.ContextTest; -import io.wwan13.wintersecurity.context.config.TestContextConfig; -import io.wwan13.wintersecurity.jwt.PayloadAnalysis; -import io.wwan13.wintersecurity.jwt.PayloadParser; -import io.wwan13.wintersecurity.jwt.TokenDecoder; -import io.wwan13.wintersecurity.jwt.TokenGenerator; -import io.wwan13.wintersecurity.jwt.payload.support.JwtPayloadParser; -import io.wwan13.wintersecurity.jwt.provider.JwtTokenDecoder; -import io.wwan13.wintersecurity.jwt.provider.JwtTokenGenerator; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Import; - -import static org.assertj.core.api.Assertions.assertThat; - -@Import({TestContextConfig.class}) -public class JwtConfigurationContextTest extends ContextTest { - - @Autowired - TokenGenerator tokenGenerator; - - @Autowired - TokenDecoder tokenDecoder; - - @Autowired - PayloadAnalysis payloadAnalysis; - - @Autowired - PayloadParser payloadParser; - - @Test - void should_RegisteredInSpringIocWithEnteredValue_when_ContextLoaded() { - // given, then, then - assertThat(tokenGenerator) - .isInstanceOf(TokenGenerator.class) - .isExactlyInstanceOf(JwtTokenGenerator.class); - - assertThat(tokenDecoder) - .isInstanceOf(TokenDecoder.class) - .isExactlyInstanceOf(JwtTokenDecoder.class); - - assertThat(payloadAnalysis) - .isInstanceOf(PayloadAnalysis.class); - - assertThat(payloadParser) - .isInstanceOf(PayloadParser.class) - .isExactlyInstanceOf(JwtPayloadParser.class); - } -} diff --git a/src/test/java/io/wwan13/wintersecurity/context/JwtPropertiesContextTest.java b/src/test/java/io/wwan13/wintersecurity/context/JwtPropertiesContextTest.java deleted file mode 100644 index ed9cbc7..0000000 --- a/src/test/java/io/wwan13/wintersecurity/context/JwtPropertiesContextTest.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.wwan13.wintersecurity.context; - -import io.wwan13.wintersecurity.ContextTest; -import io.wwan13.wintersecurity.context.config.TestContextConfig; -import io.wwan13.wintersecurity.jwt.JwtProperties; -import io.wwan13.wintersecurity.jwt.payload.DefaultPayload; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Import; - -import static org.assertj.core.api.Assertions.assertThat; - -@Import({TestContextConfig.class}) -public class JwtPropertiesContextTest extends ContextTest { - - @Autowired - JwtProperties jwtProperties; - - @Test - void should_RegisteredInSpringIocWithEnteredValue_when_ContextLoaded() { - // given, then, then - assertThat(jwtProperties.secretKey()) - .isEqualTo("secretkey123123123123123123123123123123123123123123123123"); - assertThat(jwtProperties.accessTokenValidity()).isEqualTo(1000L); - assertThat(jwtProperties.refreshTokenValidity()).isEqualTo(1000L); - assertThat(jwtProperties.payloadClazz()).isEqualTo(DefaultPayload.class); - assertThat(jwtProperties.subjectClazz()).isEqualTo(long.class); - } -} diff --git a/src/test/java/io/wwan13/wintersecurity/context/PasswordEncoderConfigurationContextTest.java b/src/test/java/io/wwan13/wintersecurity/context/PasswordEncoderConfigurationContextTest.java deleted file mode 100644 index a5fa0d9..0000000 --- a/src/test/java/io/wwan13/wintersecurity/context/PasswordEncoderConfigurationContextTest.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.wwan13.wintersecurity.context; - -import io.wwan13.wintersecurity.ContextTest; -import io.wwan13.wintersecurity.context.config.TestContextConfig; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Import; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; - -import static org.assertj.core.api.Assertions.assertThat; - -@Import(TestContextConfig.class) -public class PasswordEncoderConfigurationContextTest extends ContextTest { - - @Autowired - PasswordEncoder passwordEncoder; - - @Test - void should_RegisteredInSpringIocWithEnteredValue_when_ContextLoaded() { - // given, then, then - assertThat(passwordEncoder) - .isInstanceOf(PasswordEncoder.class) - .isExactlyInstanceOf(BCryptPasswordEncoder.class); - } -} diff --git a/src/test/java/io/wwan13/wintersecurity/context/TargetAnnotationsContextTest.java b/src/test/java/io/wwan13/wintersecurity/context/allconfigures/AllConfiguresContextTest.java similarity index 54% rename from src/test/java/io/wwan13/wintersecurity/context/TargetAnnotationsContextTest.java rename to src/test/java/io/wwan13/wintersecurity/context/allconfigures/AllConfiguresContextTest.java index 4b6ad5b..8c40719 100644 --- a/src/test/java/io/wwan13/wintersecurity/context/TargetAnnotationsContextTest.java +++ b/src/test/java/io/wwan13/wintersecurity/context/allconfigures/AllConfiguresContextTest.java @@ -14,27 +14,16 @@ * limitations under the License. */ -package io.wwan13.wintersecurity.context; +package io.wwan13.wintersecurity.context.allconfigures; import io.wwan13.wintersecurity.ContextTest; -import io.wwan13.wintersecurity.context.config.TestContextConfig; -import io.wwan13.wintersecurity.resolve.TargetAnnotations; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Import; -import static org.assertj.core.api.Assertions.assertThat; - -@Import(TestContextConfig.class) -public class TargetAnnotationsContextTest extends ContextTest { - - @Autowired - TargetAnnotations targetAnnotations; +@Import(AllConfiguresTestConfigure.class) +public class AllConfiguresContextTest extends ContextTest { @Test - void should_RegisteredInSpringIocWithEnteredValue_when_ContextLoaded() { - // given, then, then - assertThat(targetAnnotations) - .isInstanceOf(TargetAnnotations.class); + void contextLoad() { } } diff --git a/src/test/java/io/wwan13/wintersecurity/context/allconfigures/AllConfiguresTestConfigure.java b/src/test/java/io/wwan13/wintersecurity/context/allconfigures/AllConfiguresTestConfigure.java new file mode 100644 index 0000000..d336dad --- /dev/null +++ b/src/test/java/io/wwan13/wintersecurity/context/allconfigures/AllConfiguresTestConfigure.java @@ -0,0 +1,66 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.wwan13.wintersecurity.context.allconfigures; + +import io.wwan13.wintersecurity.auth.authorizedrequest.support.AuthorizedRequestRegistry; +import io.wwan13.wintersecurity.config.EnableJwtProvider; +import io.wwan13.wintersecurity.config.EnableSecureRequest; +import io.wwan13.wintersecurity.config.JwtProviderConfigurer; +import io.wwan13.wintersecurity.config.SecureRequestConfigurer; +import io.wwan13.wintersecurity.jwt.support.JwtPropertiesRegistry; +import io.wwan13.wintersecurity.resolve.RequestUserId; +import io.wwan13.wintersecurity.resolve.RequestUserRoles; +import io.wwan13.wintersecurity.resolve.support.TargetAnnotationsRegistry; +import io.wwan13.wintersecurity.secretkey.support.SecretKeyRegistry; +import org.springframework.boot.test.context.TestConfiguration; + +@TestConfiguration +@EnableJwtProvider +@EnableSecureRequest +public class AllConfiguresTestConfigure + implements JwtProviderConfigurer, SecureRequestConfigurer { + + @Override + public void configureJwt(JwtPropertiesRegistry registry) { + registry + .accessTokenValidity(100000000000L) + .refreshTokenValidity(100000000000L); + } + + @Override + public void configureSecretKey(SecretKeyRegistry registry) { + registry + .secretKey("asdfghjklqwertyuiopzxcvbnmasddfgwerasf"); + } + + @Override + public void registerAuthPatterns(AuthorizedRequestRegistry registry) { + registry + .uriPatterns("/api/test/**") + .allHttpMethods() + .permitAll() + + .elseRequestAuthenticated(); + } + + @Override + public void registerTargetAnnotations(TargetAnnotationsRegistry registry) { + registry + .addSubjectResolveAnnotation(RequestUserId.class) + .addRolesResolveAnnotation(RequestUserRoles.class); + } +} diff --git a/src/test/java/io/wwan13/wintersecurity/context/jwtprovider/JwtProviderContextTest.java b/src/test/java/io/wwan13/wintersecurity/context/jwtprovider/JwtProviderContextTest.java new file mode 100644 index 0000000..a50d5be --- /dev/null +++ b/src/test/java/io/wwan13/wintersecurity/context/jwtprovider/JwtProviderContextTest.java @@ -0,0 +1,29 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.wwan13.wintersecurity.context.jwtprovider; + +import io.wwan13.wintersecurity.ContextTest; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +@Import(JwtProviderTestConfig.class) +public class JwtProviderContextTest extends ContextTest { + + @Test + void contextLoad() { + } +} diff --git a/src/test/java/io/wwan13/wintersecurity/context/jwtprovider/JwtProviderTestConfig.java b/src/test/java/io/wwan13/wintersecurity/context/jwtprovider/JwtProviderTestConfig.java new file mode 100644 index 0000000..a0e8358 --- /dev/null +++ b/src/test/java/io/wwan13/wintersecurity/context/jwtprovider/JwtProviderTestConfig.java @@ -0,0 +1,41 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.wwan13.wintersecurity.context.jwtprovider; + +import io.wwan13.wintersecurity.config.EnableJwtProvider; +import io.wwan13.wintersecurity.config.JwtProviderConfigurer; +import io.wwan13.wintersecurity.jwt.support.JwtPropertiesRegistry; +import io.wwan13.wintersecurity.secretkey.support.SecretKeyRegistry; +import org.springframework.boot.test.context.TestConfiguration; + +@TestConfiguration +@EnableJwtProvider +public class JwtProviderTestConfig implements JwtProviderConfigurer { + + @Override + public void configureJwt(JwtPropertiesRegistry registry) { + registry + .accessTokenValidity(100000000000L) + .refreshTokenValidity(100000000000L); + } + + @Override + public void configureSecretKey(SecretKeyRegistry registry) { + registry + .secretKey("asdfghjklqwertyuiopzxcvbnmasddfgwerasf"); + } +} diff --git a/src/test/java/io/wwan13/wintersecurity/context/securerequest/SecureRequestContextTest.java b/src/test/java/io/wwan13/wintersecurity/context/securerequest/SecureRequestContextTest.java new file mode 100644 index 0000000..bc9d67c --- /dev/null +++ b/src/test/java/io/wwan13/wintersecurity/context/securerequest/SecureRequestContextTest.java @@ -0,0 +1,29 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.wwan13.wintersecurity.context.securerequest; + +import io.wwan13.wintersecurity.ContextTest; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +@Import(SecureRequestTestConfig.class) +public class SecureRequestContextTest extends ContextTest { + + @Test + void contextLoad() { + } +} diff --git a/src/test/java/io/wwan13/wintersecurity/context/config/TestContextConfig.java b/src/test/java/io/wwan13/wintersecurity/context/securerequest/SecureRequestTestConfig.java similarity index 64% rename from src/test/java/io/wwan13/wintersecurity/context/config/TestContextConfig.java rename to src/test/java/io/wwan13/wintersecurity/context/securerequest/SecureRequestTestConfig.java index 61c4d28..dba38d0 100644 --- a/src/test/java/io/wwan13/wintersecurity/context/config/TestContextConfig.java +++ b/src/test/java/io/wwan13/wintersecurity/context/securerequest/SecureRequestTestConfig.java @@ -14,21 +14,26 @@ * limitations under the License. */ -package io.wwan13.wintersecurity.context.config; +package io.wwan13.wintersecurity.context.securerequest; import io.wwan13.wintersecurity.auth.authorizedrequest.support.AuthorizedRequestRegistry; -import io.wwan13.wintersecurity.config.EnableWebSecurity; -import io.wwan13.wintersecurity.config.WebSecurityConfigurer; -import io.wwan13.wintersecurity.jwt.payload.DefaultPayload; -import io.wwan13.wintersecurity.jwt.support.JwtPropertiesRegistry; +import io.wwan13.wintersecurity.config.EnableSecureRequest; +import io.wwan13.wintersecurity.config.SecureRequestConfigurer; import io.wwan13.wintersecurity.resolve.RequestUserId; import io.wwan13.wintersecurity.resolve.RequestUserRoles; import io.wwan13.wintersecurity.resolve.support.TargetAnnotationsRegistry; +import io.wwan13.wintersecurity.secretkey.support.SecretKeyRegistry; import org.springframework.boot.test.context.TestConfiguration; @TestConfiguration -@EnableWebSecurity -public class TestContextConfig implements WebSecurityConfigurer { +@EnableSecureRequest +public class SecureRequestTestConfig implements SecureRequestConfigurer { + + @Override + public void configureSecretKey(SecretKeyRegistry registry) { + registry + .secretKey("asdfghjklqwertyuiopzxcvbnmasddfgwerasf"); + } @Override public void registerAuthPatterns(AuthorizedRequestRegistry registry) { @@ -41,17 +46,7 @@ public void registerAuthPatterns(AuthorizedRequestRegistry registry) { } @Override - public void configureJwt(JwtPropertiesRegistry registry) { - registry - .secretKey("secretkey123123123123123123123123123123123123123123123123") - .accessTokenValidity(1000L) - .refreshTokenValidity(1000L) - .payloadClazz(DefaultPayload.class) - .subjectClazz(long.class); - } - - @Override - public void registerResolveTargets(TargetAnnotationsRegistry registry) { + public void registerTargetAnnotations(TargetAnnotationsRegistry registry) { registry .addSubjectResolveAnnotation(RequestUserId.class) .addRolesResolveAnnotation(RequestUserRoles.class); diff --git a/src/test/java/io/wwan13/wintersecurity/jwt/JwtPropertiesTest.java b/src/test/java/io/wwan13/wintersecurity/jwt/JwtPropertiesTest.java index 5753117..73e0ea1 100644 --- a/src/test/java/io/wwan13/wintersecurity/jwt/JwtPropertiesTest.java +++ b/src/test/java/io/wwan13/wintersecurity/jwt/JwtPropertiesTest.java @@ -16,13 +16,10 @@ package io.wwan13.wintersecurity.jwt; -import io.jsonwebtoken.security.Keys; import io.wwan13.wintersecurity.UnitTest; import io.wwan13.wintersecurity.jwt.payload.DefaultPayload; import org.junit.jupiter.api.Test; -import java.security.Key; - import static org.assertj.core.api.Assertions.assertThat; class JwtPropertiesTest extends UnitTest { @@ -30,29 +27,23 @@ class JwtPropertiesTest extends UnitTest { @Test void should_CreateJwtPropertiesClass_when_DateEntered() { // given - final String secretKey = "secretkey123123123123123123123123123123123123123123123123"; final long accessTokenValidity = 1000L; final long refreshTokenValidity = 1000L; final Class payloadClass = DefaultPayload.class; final Class subjectClass = long.class; - final Key key = Keys.hmacShaKeyFor(secretKey.getBytes()); // when JwtProperties jwtProperties = new JwtProperties( - secretKey, accessTokenValidity, refreshTokenValidity, payloadClass, - subjectClass, - key + subjectClass ); // then - assertThat(jwtProperties.secretKey()).isEqualTo(secretKey); assertThat(jwtProperties.accessTokenValidity()).isEqualTo(accessTokenValidity); assertThat(jwtProperties.refreshTokenValidity()).isEqualTo(refreshTokenValidity); assertThat(jwtProperties.payloadClazz()).isEqualTo(payloadClass); assertThat(jwtProperties.subjectClazz()).isEqualTo(subjectClass); - assertThat(jwtProperties.key()).isEqualTo(key); } } \ No newline at end of file diff --git a/src/test/java/io/wwan13/wintersecurity/jwt/payload/support/PayloadParserTest.java b/src/test/java/io/wwan13/wintersecurity/jwt/payload/support/PayloadParserTest.java index 3484b92..356a3b8 100644 --- a/src/test/java/io/wwan13/wintersecurity/jwt/payload/support/PayloadParserTest.java +++ b/src/test/java/io/wwan13/wintersecurity/jwt/payload/support/PayloadParserTest.java @@ -17,7 +17,11 @@ package io.wwan13.wintersecurity.jwt.payload.support; import io.wwan13.wintersecurity.UnitTest; -import io.wwan13.wintersecurity.jwt.*; +import io.wwan13.wintersecurity.jwt.JwtProperties; +import io.wwan13.wintersecurity.jwt.Payload; +import io.wwan13.wintersecurity.jwt.PayloadAnalysis; +import io.wwan13.wintersecurity.jwt.PayloadAnalyst; +import io.wwan13.wintersecurity.jwt.PayloadParser; import io.wwan13.wintersecurity.jwt.support.JwtPropertiesApplier; import io.wwan13.wintersecurity.jwt.support.JwtPropertiesRegistry; import org.junit.jupiter.api.Test; @@ -225,7 +229,6 @@ void should_KeyIsFieldName_when_ValueIsNotEntered() { private PayloadAnalysis getPayloadAnalysis(Class payloadClazz) { JwtProperties jwtProperties = JwtPropertiesApplier.apply( new JwtPropertiesRegistry() - .secretKey("asdasdasdasdasdasdasdasdasdasdasdasdasdasdasd") .payloadClazz(payloadClazz) .subjectClazz(long.class) ); diff --git a/src/test/java/io/wwan13/wintersecurity/jwt/payload/support/ReflectionPayloadAnalystTest.java b/src/test/java/io/wwan13/wintersecurity/jwt/payload/support/ReflectionPayloadAnalystTest.java index f8bceb1..57ab3b8 100644 --- a/src/test/java/io/wwan13/wintersecurity/jwt/payload/support/ReflectionPayloadAnalystTest.java +++ b/src/test/java/io/wwan13/wintersecurity/jwt/payload/support/ReflectionPayloadAnalystTest.java @@ -98,7 +98,6 @@ void should_ThrowException_when_MoreThanTwoRolesDeclared() { private JwtProperties getJwtProperties(Class payloadClazz) { return JwtPropertiesApplier.apply( new JwtPropertiesRegistry() - .secretKey("asdasdasdasdasdasdasdasdasdasdasdasdasd") .payloadClazz(payloadClazz) .subjectClazz(long.class) ); diff --git a/src/test/java/io/wwan13/wintersecurity/jwt/provider/JwtTokenDecoderTest.java b/src/test/java/io/wwan13/wintersecurity/jwt/provider/JwtTokenDecoderTest.java index 232b47b..ce57390 100644 --- a/src/test/java/io/wwan13/wintersecurity/jwt/provider/JwtTokenDecoderTest.java +++ b/src/test/java/io/wwan13/wintersecurity/jwt/provider/JwtTokenDecoderTest.java @@ -18,7 +18,6 @@ import io.wwan13.wintersecurity.exception.unauthirized.ExpiredJwtTokenException; import io.wwan13.wintersecurity.exception.unauthirized.InvalidJwtTokenException; -import io.wwan13.wintersecurity.exception.unauthirized.UnauthorizedException; import io.wwan13.wintersecurity.jwt.JwtProperties; import io.wwan13.wintersecurity.jwt.Payload; import io.wwan13.wintersecurity.jwt.TokenDecoder; @@ -26,6 +25,7 @@ import io.wwan13.wintersecurity.jwt.payload.util.RoleSerializer; import io.wwan13.wintersecurity.jwt.support.JwtPropertiesApplier; import io.wwan13.wintersecurity.jwt.support.JwtPropertiesRegistry; +import io.wwan13.wintersecurity.secretkey.SecretKey; import org.junit.jupiter.api.Test; import java.util.Map; @@ -72,14 +72,17 @@ void should_ThrowException_when_InvalidTokenEntered() { @Test void should_ThrowException_when_ExpiredTokenEntered() { // given + final SecretKey secretKey = SecretKey.of( + "secret-key-secret-key-secret-key-secret-key-secret-key-secret-key" + ); final JwtProperties properties = JwtPropertiesApplier.apply( new JwtPropertiesRegistry() - .secretKey("secretsecretsecretsecretsecretsecretsecretsecretsecretsecret") .accessTokenValidity(-1L) .payloadClazz(ProviderTestContainer.TestPayload.class) ); - final TokenGenerator tokenGenerator = new JwtTokenGenerator(properties, ProviderTestContainer.payloadParser); - final TokenDecoder tokenDecoder = new JwtTokenDecoder(properties); + final TokenGenerator tokenGenerator = + new JwtTokenGenerator(secretKey, properties, ProviderTestContainer.payloadParser); + final TokenDecoder tokenDecoder = new JwtTokenDecoder(secretKey); final long id = 1L; final String role = "role"; diff --git a/src/test/java/io/wwan13/wintersecurity/jwt/provider/ProviderTestContainer.java b/src/test/java/io/wwan13/wintersecurity/jwt/provider/ProviderTestContainer.java index 6ba9ba6..319ba40 100644 --- a/src/test/java/io/wwan13/wintersecurity/jwt/provider/ProviderTestContainer.java +++ b/src/test/java/io/wwan13/wintersecurity/jwt/provider/ProviderTestContainer.java @@ -16,7 +16,13 @@ package io.wwan13.wintersecurity.jwt.provider; -import io.wwan13.wintersecurity.jwt.*; +import io.wwan13.wintersecurity.jwt.JwtProperties; +import io.wwan13.wintersecurity.jwt.Payload; +import io.wwan13.wintersecurity.jwt.PayloadAnalysis; +import io.wwan13.wintersecurity.jwt.PayloadAnalyst; +import io.wwan13.wintersecurity.jwt.PayloadParser; +import io.wwan13.wintersecurity.jwt.TokenDecoder; +import io.wwan13.wintersecurity.jwt.TokenGenerator; import io.wwan13.wintersecurity.jwt.payload.annotation.Claim; import io.wwan13.wintersecurity.jwt.payload.annotation.Roles; import io.wwan13.wintersecurity.jwt.payload.annotation.Subject; @@ -24,6 +30,7 @@ import io.wwan13.wintersecurity.jwt.payload.support.ReflectionPayloadAnalyst; import io.wwan13.wintersecurity.jwt.support.JwtPropertiesApplier; import io.wwan13.wintersecurity.jwt.support.JwtPropertiesRegistry; +import io.wwan13.wintersecurity.secretkey.SecretKey; public class ProviderTestContainer { @@ -57,9 +64,12 @@ public String getClaim() { } } + public static SecretKey secretKey = SecretKey.of( + "secret-key-secret-key-secret-key-secret-key-secret-key-secret-key" + ); + public static JwtProperties jwtProperties = JwtPropertiesApplier.apply( new JwtPropertiesRegistry() - .secretKey("secret-key-secret-key-secret-key-secret-key-secret-key-secret-key") .accessTokenValidity(100000000000L) .refreshTokenValidity(100000000000L) .payloadClazz(TestPayload.class) @@ -73,7 +83,8 @@ public static PayloadAnalysis payloadAnalysis() { public static PayloadParser payloadParser = new JwtPayloadParser(payloadAnalysis()); - public static TokenGenerator tokenGenerator = new JwtTokenGenerator(jwtProperties, payloadParser); + public static TokenGenerator tokenGenerator = + new JwtTokenGenerator(secretKey, jwtProperties, payloadParser); - public static TokenDecoder tokenDecoder = new JwtTokenDecoder(jwtProperties); + public static TokenDecoder tokenDecoder = new JwtTokenDecoder(secretKey); } diff --git a/src/test/java/io/wwan13/wintersecurity/jwt/support/JwtPropertiesApplierTest.java b/src/test/java/io/wwan13/wintersecurity/jwt/support/JwtPropertiesApplierTest.java index 4ebd449..4c0238f 100644 --- a/src/test/java/io/wwan13/wintersecurity/jwt/support/JwtPropertiesApplierTest.java +++ b/src/test/java/io/wwan13/wintersecurity/jwt/support/JwtPropertiesApplierTest.java @@ -36,7 +36,6 @@ void should_ReturnJwtProperties_when_RegistryEntered() { final Class subjectClass = long.class; JwtPropertiesRegistry registry = new JwtPropertiesRegistry() - .secretKey(secretKey) .accessTokenValidity(accessTokenValidity) .refreshTokenValidity(refreshTokenValidity) .payloadClazz(payloadClass) @@ -47,7 +46,6 @@ void should_ReturnJwtProperties_when_RegistryEntered() { // then assertThat(jwtProperties).isInstanceOf(JwtProperties.class); - assertThat(jwtProperties.secretKey()).isEqualTo(secretKey); assertThat(jwtProperties.accessTokenValidity()).isEqualTo(accessTokenValidity); assertThat(jwtProperties.refreshTokenValidity()).isEqualTo(refreshTokenValidity); assertThat(jwtProperties.payloadClazz()).isEqualTo(payloadClass); diff --git a/src/test/java/io/wwan13/wintersecurity/jwt/support/JwtPropertiesRegistryTest.java b/src/test/java/io/wwan13/wintersecurity/jwt/support/JwtPropertiesRegistryTest.java index 54d2cd0..8ddedb4 100644 --- a/src/test/java/io/wwan13/wintersecurity/jwt/support/JwtPropertiesRegistryTest.java +++ b/src/test/java/io/wwan13/wintersecurity/jwt/support/JwtPropertiesRegistryTest.java @@ -16,15 +16,11 @@ package io.wwan13.wintersecurity.jwt.support; -import io.jsonwebtoken.security.Keys; import io.wwan13.wintersecurity.constant.Constants; import io.wwan13.wintersecurity.jwt.JwtProperties; import io.wwan13.wintersecurity.jwt.Payload; import io.wwan13.wintersecurity.jwt.payload.DefaultPayload; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.NullAndEmptySource; -import org.junit.jupiter.params.provider.ValueSource; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -34,7 +30,6 @@ class JwtPropertiesRegistryTest { @Test void should_CreateJwtPropertiesClass_when_UsingJwtPropertiesRegistry() { // given - final String secretKey = "secretkey123123123123123123123123123123123123123123123123"; final long accessTokenValidity = 1000L; final long refreshTokenValidity = 1000L; final Class payloadClass = DefaultPayload.class; @@ -42,7 +37,6 @@ void should_CreateJwtPropertiesClass_when_UsingJwtPropertiesRegistry() { // when JwtProperties jwtProperties = new JwtPropertiesRegistry() - .secretKey(secretKey) .accessTokenValidity(accessTokenValidity) .refreshTokenValidity(refreshTokenValidity) .payloadClazz(payloadClass) @@ -51,51 +45,16 @@ void should_CreateJwtPropertiesClass_when_UsingJwtPropertiesRegistry() { // then assertThat(jwtProperties).isInstanceOf(JwtProperties.class); - assertThat(jwtProperties.secretKey()).isEqualTo(secretKey); assertThat(jwtProperties.accessTokenValidity()).isEqualTo(accessTokenValidity); assertThat(jwtProperties.refreshTokenValidity()).isEqualTo(refreshTokenValidity); assertThat(jwtProperties.payloadClazz()).isEqualTo(payloadClass); assertThat(jwtProperties.subjectClazz()).isEqualTo(subjectClass); } - @Test - void should_CreateKeyFromSecretKey_when_JwtPropertiesApplied() { - // given - final String secretKey = "secretkey123123123123123123123123123123123123123123123123"; - - // when - JwtProperties jwtProperties = new JwtPropertiesRegistry() - .secretKey(secretKey) - .apply(); - - // then - assertThat(jwtProperties.key()).isEqualTo(Keys.hmacShaKeyFor(secretKey.getBytes())); - } - - @ParameterizedTest(name = "{index} : {0}") - @NullAndEmptySource - @ValueSource(strings = { - "short secret key", - "1234567890123456789012345678901" - }) - void should_ThrowsException_when_SecretKeyIsEmptyOrLessThen32(final String secretKey) { - // given - JwtPropertiesRegistry jwtPropertiesRegistry = new JwtPropertiesRegistry() - .secretKey(secretKey); - - // when, then - assertThatThrownBy(jwtPropertiesRegistry::apply) - .isInstanceOf(IllegalArgumentException.class); - } - @Test void should_ReplaceToDefaultValue_when_ValidityAndClazzValuesNotEntered() { - // given - final String secretKey = "secretkey123123123123123123123123123123123123123123123123"; - - // when + // given, when JwtProperties jwtProperties = new JwtPropertiesRegistry() - .secretKey(secretKey) .apply(); // then diff --git a/src/test/java/io/wwan13/wintersecurity/secretkey/support/SecretKeyRegistryTest.java b/src/test/java/io/wwan13/wintersecurity/secretkey/support/SecretKeyRegistryTest.java new file mode 100644 index 0000000..3168de7 --- /dev/null +++ b/src/test/java/io/wwan13/wintersecurity/secretkey/support/SecretKeyRegistryTest.java @@ -0,0 +1,62 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.wwan13.wintersecurity.secretkey.support; + +import io.wwan13.wintersecurity.UnitTest; +import io.wwan13.wintersecurity.secretkey.SecretKey; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; + +import java.security.Key; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +class SecretKeyRegistryTest extends UnitTest { + + @Test + void should_ContainsSecretKey() { + // given + final String secretKey = "secretkey123123123123123123123123123123123123123123123123"; + + // when + SecretKey result = new SecretKeyRegistry() + .secretKey(secretKey) + .apply(); + + // then + assertThat(result.value()).isInstanceOf(Key.class); + } + + @ParameterizedTest(name = "{index} : {0}") + @NullAndEmptySource + @ValueSource(strings = { + "short secret key", + "1234567890123456789012345678901" + }) + void should_ThrowsException_when_SecretKeyIsEmptyOrLessThen32(final String secretKey) { + // given + SecretKeyRegistry registry = new SecretKeyRegistry() + .secretKey(secretKey); + + // when, then + assertThatThrownBy(registry::apply) + .isInstanceOf(IllegalArgumentException.class); + } +} \ No newline at end of file