From 374c9cffaf8734495dc8bc7b81b0d4138dffae2b Mon Sep 17 00:00:00 2001 From: wwan13 Date: Sun, 9 Jun 2024 14:08:36 +0900 Subject: [PATCH 1/7] feat : Util class that extract attribute from http request --- .../resolve/util/AttributeExtractor.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/main/java/io/wwan13/wintersecurity/resolve/util/AttributeExtractor.java diff --git a/src/main/java/io/wwan13/wintersecurity/resolve/util/AttributeExtractor.java b/src/main/java/io/wwan13/wintersecurity/resolve/util/AttributeExtractor.java new file mode 100644 index 0000000..e6c7a11 --- /dev/null +++ b/src/main/java/io/wwan13/wintersecurity/resolve/util/AttributeExtractor.java @@ -0,0 +1,52 @@ +/* + * 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.resolve.util; + +import io.wwan13.wintersecurity.constant.Constants; +import io.wwan13.wintersecurity.jwt.TokenClaims; + +import javax.servlet.http.HttpServletRequest; +import java.util.Objects; + +public class AttributeExtractor { + + private AttributeExtractor() { + throw new IllegalStateException("Cannot instantiate a utility class!"); + } + + public static Object extract( + HttpServletRequest request, + String attributeKey + ) { + return extractAttributeWithNullChecking(request, attributeKey); + } + + public static TokenClaims extractClaims(HttpServletRequest request) { + return (TokenClaims) extractAttributeWithNullChecking(request, Constants.ATTRIBUTE_CLAIMS_KEY); + } + + private static Object extractAttributeWithNullChecking( + HttpServletRequest request, + String attributeKey + ) { + Object claims = request.getAttribute(attributeKey); + if (Objects.isNull(claims)) { + throw new IllegalStateException("cannot extract claims"); + } + return claims; + } +} From 4f3b4919505fa7f309a087a0feb79e3aa7c61c8a Mon Sep 17 00:00:00 2001 From: wwan13 Date: Sun, 9 Jun 2024 14:09:07 +0900 Subject: [PATCH 2/7] feat : Util class that convert java type using object mapper --- .../wintersecurity/util/TypeConverter.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/main/java/io/wwan13/wintersecurity/util/TypeConverter.java diff --git a/src/main/java/io/wwan13/wintersecurity/util/TypeConverter.java b/src/main/java/io/wwan13/wintersecurity/util/TypeConverter.java new file mode 100644 index 0000000..b7f7e2c --- /dev/null +++ b/src/main/java/io/wwan13/wintersecurity/util/TypeConverter.java @@ -0,0 +1,34 @@ +/* + * 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.util; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class TypeConverter { + + private static final ObjectMapper objectMapper = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + private TypeConverter() { + throw new IllegalStateException("Cannot instantiate a utility class!"); + } + + public static Object convertTo(Object originValue, Class targetClazz) { + return objectMapper.convertValue(originValue, targetClazz); + } +} From 0df6464f8809af06e07be6205637f8abdf3dc005 Mon Sep 17 00:00:00 2001 From: wwan13 Date: Sun, 9 Jun 2024 14:15:12 +0900 Subject: [PATCH 3/7] feat : Component that resolve token subject to controller's argument --- .../resolve/SubjectResolver.java | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/main/java/io/wwan13/wintersecurity/resolve/SubjectResolver.java diff --git a/src/main/java/io/wwan13/wintersecurity/resolve/SubjectResolver.java b/src/main/java/io/wwan13/wintersecurity/resolve/SubjectResolver.java new file mode 100644 index 0000000..615e493 --- /dev/null +++ b/src/main/java/io/wwan13/wintersecurity/resolve/SubjectResolver.java @@ -0,0 +1,69 @@ +/* + * 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.resolve; + +import io.wwan13.wintersecurity.jwt.PayloadAnalysis; +import io.wwan13.wintersecurity.jwt.TokenClaims; +import io.wwan13.wintersecurity.resolve.util.AttributeExtractor; +import io.wwan13.wintersecurity.util.TypeConverter; +import org.springframework.core.MethodParameter; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +import javax.servlet.http.HttpServletRequest; + +public class SubjectResolver implements HandlerMethodArgumentResolver { + + private final TargetAnnotations targetAnnotations; + private final PayloadAnalysis payloadAnalysis; + + public SubjectResolver( + TargetAnnotations targetAnnotations, + PayloadAnalysis payloadAnalysis + ) { + this.targetAnnotations = targetAnnotations; + this.payloadAnalysis = payloadAnalysis; + } + + @Override + public boolean supportsParameter(MethodParameter parameter) { + boolean hasAnnotation = targetAnnotations.forSubject().stream() + .anyMatch(parameter::hasParameterAnnotation); + boolean isValidType = payloadAnalysis.subject().getType() + .isAssignableFrom(parameter.getParameterType()); + + return hasAnnotation && isValidType; + } + + @Override + public Object resolveArgument( + MethodParameter parameter, + ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, + WebDataBinderFactory binderFactory + ) { + HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); + TokenClaims claims = AttributeExtractor.extractClaims(request); + + return TypeConverter.convertTo( + claims.getSubject(), + parameter.getParameterType() + ); + } +} From a335ecc0726e2f131addff22957e856bfde55936 Mon Sep 17 00:00:00 2001 From: wwan13 Date: Sun, 9 Jun 2024 14:15:19 +0900 Subject: [PATCH 4/7] feat : Component that resolve token roles to controller's argument --- .../wintersecurity/resolve/RolesResolver.java | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 src/main/java/io/wwan13/wintersecurity/resolve/RolesResolver.java diff --git a/src/main/java/io/wwan13/wintersecurity/resolve/RolesResolver.java b/src/main/java/io/wwan13/wintersecurity/resolve/RolesResolver.java new file mode 100644 index 0000000..3a6d910 --- /dev/null +++ b/src/main/java/io/wwan13/wintersecurity/resolve/RolesResolver.java @@ -0,0 +1,77 @@ +/* + * 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.resolve; + +import io.wwan13.wintersecurity.jwt.PayloadAnalysis; +import io.wwan13.wintersecurity.jwt.TokenClaims; +import io.wwan13.wintersecurity.resolve.util.AttributeExtractor; +import io.wwan13.wintersecurity.util.TypeConverter; +import org.springframework.core.MethodParameter; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +import javax.servlet.http.HttpServletRequest; +import java.util.Collection; + +public class RolesResolver implements HandlerMethodArgumentResolver { + + private final TargetAnnotations targetAnnotations; + private final PayloadAnalysis payloadAnalysis; + + public RolesResolver( + TargetAnnotations targetAnnotations, + PayloadAnalysis payloadAnalysis + ) { + this.targetAnnotations = targetAnnotations; + this.payloadAnalysis = payloadAnalysis; + } + + @Override + public boolean supportsParameter(MethodParameter parameter) { + boolean hasAnnotation = targetAnnotations.forRoles().stream() + .anyMatch(parameter::hasParameterAnnotation); + boolean isValidType = payloadAnalysis.roles().getType() + .isAssignableFrom(parameter.getParameterType()); + + return hasAnnotation && isValidType; + } + + @Override + public Object resolveArgument( + MethodParameter parameter, + ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, + WebDataBinderFactory binderFactory + ) { + HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); + + TokenClaims claims = AttributeExtractor.extractClaims(request); + + boolean isCollection = Collection.class.isAssignableFrom(parameter.getParameterType()); + if (!isCollection) { + String role = claims.getRoles().stream() + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Empty role entered")); + + return TypeConverter.convertTo(role, parameter.getParameterType()); + } + + return TypeConverter.convertTo(claims.getRoles(), parameter.getParameterType()); + } +} From c21afa059ca1f297513f63a1463b07735c102ed9 Mon Sep 17 00:00:00 2001 From: wwan13 Date: Sun, 9 Jun 2024 14:16:10 +0900 Subject: [PATCH 5/7] test : Stub classes for testing HandlerMethodArgumentResolver --- .../auth/stub/StubHttpServletRequest.java | 7 + .../resolve/stub/StubMethodParameter.java | 82 ++++++++ .../stub/StubModerAndViesContainer.java | 22 +++ .../resolve/stub/StubNativeWebRequest.java | 181 ++++++++++++++++++ .../stub/StubWebDataBinderFactory.java | 28 +++ 5 files changed, 320 insertions(+) create mode 100644 src/test/java/io/wwan13/wintersecurity/resolve/stub/StubMethodParameter.java create mode 100644 src/test/java/io/wwan13/wintersecurity/resolve/stub/StubModerAndViesContainer.java create mode 100644 src/test/java/io/wwan13/wintersecurity/resolve/stub/StubNativeWebRequest.java create mode 100644 src/test/java/io/wwan13/wintersecurity/resolve/stub/StubWebDataBinderFactory.java diff --git a/src/test/java/io/wwan13/wintersecurity/auth/stub/StubHttpServletRequest.java b/src/test/java/io/wwan13/wintersecurity/auth/stub/StubHttpServletRequest.java index f10b1e4..d938f28 100644 --- a/src/test/java/io/wwan13/wintersecurity/auth/stub/StubHttpServletRequest.java +++ b/src/test/java/io/wwan13/wintersecurity/auth/stub/StubHttpServletRequest.java @@ -43,6 +43,13 @@ public void getRequestUriWillReturn(String uri) { this.uri = uri; } + public StubHttpServletRequest(Map attribute) { + this.attribute = attribute; + } + + public StubHttpServletRequest() { + } + @Override public String getHeader(String name) { return expectedHeader; diff --git a/src/test/java/io/wwan13/wintersecurity/resolve/stub/StubMethodParameter.java b/src/test/java/io/wwan13/wintersecurity/resolve/stub/StubMethodParameter.java new file mode 100644 index 0000000..1ebd213 --- /dev/null +++ b/src/test/java/io/wwan13/wintersecurity/resolve/stub/StubMethodParameter.java @@ -0,0 +1,82 @@ +/* + * 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.resolve.stub; + +import org.springframework.core.MethodParameter; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Set; + +public class StubMethodParameter extends MethodParameter { + + private Class parameterType; + private Set> declaredAnnotations; + + public StubMethodParameter() { + super( + Arrays.stream(StubMethodParameter.class.getMethods()) + .filter(method -> method.getName().equals("hasParameterAnnotation")) + .findFirst() + .orElseThrow(IllegalStateException::new), + 0); + } + + public StubMethodParameter(Method method, int parameterIndex) { + super(method, parameterIndex); + } + + public StubMethodParameter(Method method, int parameterIndex, int nestingLevel) { + super(method, parameterIndex, nestingLevel); + } + + public StubMethodParameter(Constructor constructor, int parameterIndex) { + super(constructor, parameterIndex); + } + + public StubMethodParameter(Constructor constructor, int parameterIndex, int nestingLevel) { + super(constructor, parameterIndex, nestingLevel); + } + + public StubMethodParameter(MethodParameter original) { + super(original); + } + + public void parameterTypeWillBe(Class parameterType) { + this.parameterType = parameterType; + } + + public void declaredAnnotationsWillBe(Set> annotations) { + this.declaredAnnotations = annotations; + } + + public void declaredAnnotationsWillBe(Class annotation) { + this.declaredAnnotations = Set.of(annotation); + } + + @Override + public Class getParameterType() { + return this.parameterType; + } + + @Override + public boolean hasParameterAnnotation(Class annotationType) { + return declaredAnnotations.contains(annotationType); + } +} diff --git a/src/test/java/io/wwan13/wintersecurity/resolve/stub/StubModerAndViesContainer.java b/src/test/java/io/wwan13/wintersecurity/resolve/stub/StubModerAndViesContainer.java new file mode 100644 index 0000000..bca4ded --- /dev/null +++ b/src/test/java/io/wwan13/wintersecurity/resolve/stub/StubModerAndViesContainer.java @@ -0,0 +1,22 @@ +/* + * 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.resolve.stub; + +import org.springframework.web.method.support.ModelAndViewContainer; + +public class StubModerAndViesContainer extends ModelAndViewContainer { +} diff --git a/src/test/java/io/wwan13/wintersecurity/resolve/stub/StubNativeWebRequest.java b/src/test/java/io/wwan13/wintersecurity/resolve/stub/StubNativeWebRequest.java new file mode 100644 index 0000000..95b0636 --- /dev/null +++ b/src/test/java/io/wwan13/wintersecurity/resolve/stub/StubNativeWebRequest.java @@ -0,0 +1,181 @@ +/* + * 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.resolve.stub; + +import io.wwan13.wintersecurity.auth.stub.StubHttpServletRequest; +import io.wwan13.wintersecurity.jwt.TokenClaims; +import org.springframework.web.context.request.NativeWebRequest; + +import java.security.Principal; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; + +public class StubNativeWebRequest implements NativeWebRequest { + + Map attribute = new HashMap<>(); + + public void requestAttributesWillBe(TokenClaims claims) { + this.attribute.put("claims", claims); + } + + @Override + public Object getNativeRequest() { + return new StubHttpServletRequest(attribute); + } + + @Override + public Object getNativeResponse() { + return null; + } + + @Override + public T getNativeRequest(Class requiredType) { + return null; + } + + @Override + public T getNativeResponse(Class requiredType) { + return null; + } + + @Override + public String getHeader(String headerName) { + return null; + } + + @Override + public String[] getHeaderValues(String headerName) { + return new String[0]; + } + + @Override + public Iterator getHeaderNames() { + return null; + } + + @Override + public String getParameter(String paramName) { + return null; + } + + @Override + public String[] getParameterValues(String paramName) { + return new String[0]; + } + + @Override + public Iterator getParameterNames() { + return null; + } + + @Override + public Map getParameterMap() { + return null; + } + + @Override + public Locale getLocale() { + return null; + } + + @Override + public String getContextPath() { + return null; + } + + @Override + public String getRemoteUser() { + return null; + } + + @Override + public Principal getUserPrincipal() { + return null; + } + + @Override + public boolean isUserInRole(String role) { + return false; + } + + @Override + public boolean isSecure() { + return false; + } + + @Override + public boolean checkNotModified(long lastModifiedTimestamp) { + return false; + } + + @Override + public boolean checkNotModified(String etag) { + return false; + } + + @Override + public boolean checkNotModified(String etag, long lastModifiedTimestamp) { + return false; + } + + @Override + public String getDescription(boolean includeClientInfo) { + return null; + } + + @Override + public Object getAttribute(String name, int scope) { + return null; + } + + @Override + public void setAttribute(String name, Object value, int scope) { + + } + + @Override + public void removeAttribute(String name, int scope) { + + } + + @Override + public String[] getAttributeNames(int scope) { + return new String[0]; + } + + @Override + public void registerDestructionCallback(String name, Runnable callback, int scope) { + + } + + @Override + public Object resolveReference(String key) { + return null; + } + + @Override + public String getSessionId() { + return null; + } + + @Override + public Object getSessionMutex() { + return null; + } +} diff --git a/src/test/java/io/wwan13/wintersecurity/resolve/stub/StubWebDataBinderFactory.java b/src/test/java/io/wwan13/wintersecurity/resolve/stub/StubWebDataBinderFactory.java new file mode 100644 index 0000000..e3230eb --- /dev/null +++ b/src/test/java/io/wwan13/wintersecurity/resolve/stub/StubWebDataBinderFactory.java @@ -0,0 +1,28 @@ +/* + * 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.resolve.stub; + +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; + +public class StubWebDataBinderFactory implements WebDataBinderFactory { + @Override + public WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) throws Exception { + return null; + } +} From 2b234c27ef816c2fa0f0d0b5e52540c26a215181 Mon Sep 17 00:00:00 2001 From: wwan13 Date: Sun, 9 Jun 2024 14:16:25 +0900 Subject: [PATCH 6/7] test : Unit test for SubjectResolver --- .../resolve/ResolveTestContainer.java | 63 +++++++++ .../resolve/SubjectResolverTest.java | 120 ++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 src/test/java/io/wwan13/wintersecurity/resolve/ResolveTestContainer.java create mode 100644 src/test/java/io/wwan13/wintersecurity/resolve/SubjectResolverTest.java diff --git a/src/test/java/io/wwan13/wintersecurity/resolve/ResolveTestContainer.java b/src/test/java/io/wwan13/wintersecurity/resolve/ResolveTestContainer.java new file mode 100644 index 0000000..7c8dea5 --- /dev/null +++ b/src/test/java/io/wwan13/wintersecurity/resolve/ResolveTestContainer.java @@ -0,0 +1,63 @@ +/* + * 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.resolve; + +import io.wwan13.wintersecurity.jwt.PayloadAnalysis; +import io.wwan13.wintersecurity.jwt.PayloadAnalyst; +import io.wwan13.wintersecurity.jwt.TokenClaims; +import io.wwan13.wintersecurity.jwt.payload.annotation.Roles; +import io.wwan13.wintersecurity.jwt.payload.annotation.Subject; +import io.wwan13.wintersecurity.jwt.payload.support.DefaultPayloadAnalyst; + +import java.util.Map; +import java.util.Set; + +public class ResolveTestContainer { + + public static TargetAnnotations targetAnnotations = new TargetAnnotations( + Set.of(RequestUserSubject.class, RequestUserId.class), + Set.of(RequestUserRoles.class) + ); + + public static PayloadAnalysis payloadAnalysis; + + static { + PayloadAnalyst payloadAnalyst = new DefaultPayloadAnalyst(); + payloadAnalysis = payloadAnalyst.analyze(ResolveTestPayload.class); + } + + public static TokenClaims defaultTestClaims = new TokenClaims( + Map.of( + "sub", "1", + "roles", "ROLE_USER" + ) + ); + + public static class ResolveTestPayload { + @Subject + Long subject; + @Roles + Set roles; + } + + public static class ResolveTestPayloadWithStringRole { + @Subject + Long subject; + @Roles + String role; + } +} diff --git a/src/test/java/io/wwan13/wintersecurity/resolve/SubjectResolverTest.java b/src/test/java/io/wwan13/wintersecurity/resolve/SubjectResolverTest.java new file mode 100644 index 0000000..848d101 --- /dev/null +++ b/src/test/java/io/wwan13/wintersecurity/resolve/SubjectResolverTest.java @@ -0,0 +1,120 @@ +/* + * 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.resolve; + +import io.wwan13.wintersecurity.UnitTest; +import io.wwan13.wintersecurity.resolve.stub.StubMethodParameter; +import io.wwan13.wintersecurity.resolve.stub.StubModerAndViesContainer; +import io.wwan13.wintersecurity.resolve.stub.StubNativeWebRequest; +import io.wwan13.wintersecurity.resolve.stub.StubWebDataBinderFactory; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +class SubjectResolverTest extends UnitTest { + + static SubjectResolver subjectResolver = new SubjectResolver( + ResolveTestContainer.targetAnnotations, + ResolveTestContainer.payloadAnalysis + ); + + @Test + void should_ReturnTrue_when_AnnotationDeclaredWithValidParameterType() { + // given + final StubMethodParameter methodParameter = new StubMethodParameter(); + + methodParameter.declaredAnnotationsWillBe(RequestUserId.class); + methodParameter.parameterTypeWillBe(Long.class); + + // when + boolean result = subjectResolver.supportsParameter(methodParameter); + + // then + assertThat(result).isTrue(); + } + + @Test + void should_ReturnFalse_when_InValidParameterType() { + // given + final StubMethodParameter methodParameter = new StubMethodParameter(); + + methodParameter.declaredAnnotationsWillBe(RequestUserId.class); + methodParameter.parameterTypeWillBe(String.class); + + // when + boolean result = subjectResolver.supportsParameter(methodParameter); + + // then + assertThat(result).isFalse(); + } + + @Test + void should_ReturnFalse_when_AnnotationNotDeclared() { + // given + final StubMethodParameter methodParameter = new StubMethodParameter(); + + methodParameter.declaredAnnotationsWillBe(Set.of()); + methodParameter.parameterTypeWillBe(Long.class); + + // when + boolean result = subjectResolver.supportsParameter(methodParameter); + + // then + assertThat(result).isFalse(); + } + + @Test + void should_ReturnFalse_when_InValidParameterTypeIsDataType() { + // given + final StubMethodParameter methodParameter = new StubMethodParameter(); + + methodParameter.declaredAnnotationsWillBe(RequestUserId.class); + methodParameter.parameterTypeWillBe(String.class); + + // when + boolean result = subjectResolver.supportsParameter(methodParameter); + + // then + assertThat(result).isFalse(); + } + + @Test + void should_ResolveSubject() { + // given + final StubMethodParameter methodParameter = new StubMethodParameter(); + final StubModerAndViesContainer modelAndViewContainer = new StubModerAndViesContainer(); + final StubNativeWebRequest nativeWebRequest = new StubNativeWebRequest(); + final StubWebDataBinderFactory webDataBinderFactory = new StubWebDataBinderFactory(); + + nativeWebRequest.requestAttributesWillBe(ResolveTestContainer.defaultTestClaims); + methodParameter.parameterTypeWillBe(Long.class); + + // when + Object value = subjectResolver.resolveArgument( + methodParameter, + modelAndViewContainer, + nativeWebRequest, + webDataBinderFactory + ); + + // then + assertThat(value.getClass()).isAssignableFrom(Long.class); + assertThat((Long) value).isEqualTo(1L); + } +} \ No newline at end of file From 94e9a1fc835e5ae5d736ee2537e0a9158d7424ad Mon Sep 17 00:00:00 2001 From: wwan13 Date: Sun, 9 Jun 2024 14:16:40 +0900 Subject: [PATCH 7/7] test : Unit test for RolesResolver --- .../resolve/RolesResolverTest.java | 158 ++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 src/test/java/io/wwan13/wintersecurity/resolve/RolesResolverTest.java diff --git a/src/test/java/io/wwan13/wintersecurity/resolve/RolesResolverTest.java b/src/test/java/io/wwan13/wintersecurity/resolve/RolesResolverTest.java new file mode 100644 index 0000000..12a372c --- /dev/null +++ b/src/test/java/io/wwan13/wintersecurity/resolve/RolesResolverTest.java @@ -0,0 +1,158 @@ +/* + * 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.resolve; + +import io.wwan13.wintersecurity.jwt.PayloadAnalysis; +import io.wwan13.wintersecurity.jwt.PayloadAnalyst; +import io.wwan13.wintersecurity.jwt.TokenClaims; +import io.wwan13.wintersecurity.jwt.payload.support.DefaultPayloadAnalyst; +import io.wwan13.wintersecurity.resolve.stub.StubMethodParameter; +import io.wwan13.wintersecurity.resolve.stub.StubModerAndViesContainer; +import io.wwan13.wintersecurity.resolve.stub.StubNativeWebRequest; +import io.wwan13.wintersecurity.resolve.stub.StubWebDataBinderFactory; +import org.junit.jupiter.api.Test; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +class RolesResolverTest { + + static RolesResolver rolesResolver = new RolesResolver( + ResolveTestContainer.targetAnnotations, + ResolveTestContainer.payloadAnalysis + ); + + @Test + void should_ReturnTrue_when_AnnotationDeclaredWithValidParameterType() { + // given + final StubMethodParameter methodParameter = new StubMethodParameter(); + + methodParameter.declaredAnnotationsWillBe(RequestUserRoles.class); + methodParameter.parameterTypeWillBe(Set.class); + + // when + boolean result = rolesResolver.supportsParameter(methodParameter); + + // then + assertThat(result).isTrue(); + } + + @Test + void should_ReturnFalse_when_InValidParameterType() { + // given + final StubMethodParameter methodParameter = new StubMethodParameter(); + + methodParameter.declaredAnnotationsWillBe(RequestUserRoles.class); + methodParameter.parameterTypeWillBe(Long.class); + + // when + boolean result = rolesResolver.supportsParameter(methodParameter); + + // then + assertThat(result).isFalse(); + } + + @Test + void should_ReturnFalse_when_AnnotationNotDeclared() { + // given + final StubMethodParameter methodParameter = new StubMethodParameter(); + + methodParameter.declaredAnnotationsWillBe(Set.of()); + methodParameter.parameterTypeWillBe(Set.class); + + // when + boolean result = rolesResolver.supportsParameter(methodParameter); + + // then + assertThat(result).isFalse(); + } + + @Test + void should_ReturnFalse_when_InValidParameterTypeIsDataType() { + // given + final StubMethodParameter methodParameter = new StubMethodParameter(); + + methodParameter.declaredAnnotationsWillBe(RequestUserRoles.class); + methodParameter.parameterTypeWillBe(Long.class); + + // when + boolean result = rolesResolver.supportsParameter(methodParameter); + + // then + assertThat(result).isFalse(); + } + + @Test + void should_ResolveRoles() { + // given + final StubMethodParameter methodParameter = new StubMethodParameter(); + final StubModerAndViesContainer modelAndViewContainer = new StubModerAndViesContainer(); + final StubNativeWebRequest nativeWebRequest = new StubNativeWebRequest(); + final StubWebDataBinderFactory webDataBinderFactory = new StubWebDataBinderFactory(); + + nativeWebRequest.requestAttributesWillBe(ResolveTestContainer.defaultTestClaims); + methodParameter.parameterTypeWillBe(Set.class); + + // when + Object value = rolesResolver.resolveArgument( + methodParameter, + modelAndViewContainer, + nativeWebRequest, + webDataBinderFactory + ); + + // then + assertThat(value.getClass()).isAssignableFrom(HashSet.class); + assertThat((Set) value).contains("ROLE_USER"); + } + + @Test + void should_ResolveStringRole_when_NoneCollectionTypeRoleEntered() { + // given + final StubMethodParameter methodParameter = new StubMethodParameter(); + final StubModerAndViesContainer modelAndViewContainer = new StubModerAndViesContainer(); + final StubNativeWebRequest nativeWebRequest = new StubNativeWebRequest(); + final StubWebDataBinderFactory webDataBinderFactory = new StubWebDataBinderFactory(); + + final PayloadAnalyst payloadAnalyst = new DefaultPayloadAnalyst(); + final PayloadAnalysis payloadAnalysis = + payloadAnalyst.analyze(ResolveTestContainer.ResolveTestPayloadWithStringRole.class); + + nativeWebRequest.requestAttributesWillBe(new TokenClaims(Map.of("roles", "ROLE_USER"))); + methodParameter.parameterTypeWillBe(String.class); + + final RolesResolver rolesResolver = new RolesResolver( + ResolveTestContainer.targetAnnotations, + payloadAnalysis + ); + + // when + Object value = rolesResolver.resolveArgument( + methodParameter, + modelAndViewContainer, + nativeWebRequest, + webDataBinderFactory + ); + + // then + assertThat(value.getClass()).isAssignableFrom(String.class); + assertThat((String) value).isEqualTo("ROLE_USER"); + } +} \ No newline at end of file