Skip to content

Commit 15eed4d

Browse files
authored
Merge pull request #26 from wwan13/feature/resolve
Resolvers
2 parents 74922c8 + 94e9a1f commit 15eed4d

File tree

12 files changed

+893
-0
lines changed

12 files changed

+893
-0
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.wwan13.wintersecurity.resolve;
18+
19+
import io.wwan13.wintersecurity.jwt.PayloadAnalysis;
20+
import io.wwan13.wintersecurity.jwt.TokenClaims;
21+
import io.wwan13.wintersecurity.resolve.util.AttributeExtractor;
22+
import io.wwan13.wintersecurity.util.TypeConverter;
23+
import org.springframework.core.MethodParameter;
24+
import org.springframework.web.bind.support.WebDataBinderFactory;
25+
import org.springframework.web.context.request.NativeWebRequest;
26+
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
27+
import org.springframework.web.method.support.ModelAndViewContainer;
28+
29+
import javax.servlet.http.HttpServletRequest;
30+
import java.util.Collection;
31+
32+
public class RolesResolver implements HandlerMethodArgumentResolver {
33+
34+
private final TargetAnnotations targetAnnotations;
35+
private final PayloadAnalysis payloadAnalysis;
36+
37+
public RolesResolver(
38+
TargetAnnotations targetAnnotations,
39+
PayloadAnalysis payloadAnalysis
40+
) {
41+
this.targetAnnotations = targetAnnotations;
42+
this.payloadAnalysis = payloadAnalysis;
43+
}
44+
45+
@Override
46+
public boolean supportsParameter(MethodParameter parameter) {
47+
boolean hasAnnotation = targetAnnotations.forRoles().stream()
48+
.anyMatch(parameter::hasParameterAnnotation);
49+
boolean isValidType = payloadAnalysis.roles().getType()
50+
.isAssignableFrom(parameter.getParameterType());
51+
52+
return hasAnnotation && isValidType;
53+
}
54+
55+
@Override
56+
public Object resolveArgument(
57+
MethodParameter parameter,
58+
ModelAndViewContainer mavContainer,
59+
NativeWebRequest webRequest,
60+
WebDataBinderFactory binderFactory
61+
) {
62+
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
63+
64+
TokenClaims claims = AttributeExtractor.extractClaims(request);
65+
66+
boolean isCollection = Collection.class.isAssignableFrom(parameter.getParameterType());
67+
if (!isCollection) {
68+
String role = claims.getRoles().stream()
69+
.findFirst()
70+
.orElseThrow(() -> new IllegalArgumentException("Empty role entered"));
71+
72+
return TypeConverter.convertTo(role, parameter.getParameterType());
73+
}
74+
75+
return TypeConverter.convertTo(claims.getRoles(), parameter.getParameterType());
76+
}
77+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.wwan13.wintersecurity.resolve;
18+
19+
import io.wwan13.wintersecurity.jwt.PayloadAnalysis;
20+
import io.wwan13.wintersecurity.jwt.TokenClaims;
21+
import io.wwan13.wintersecurity.resolve.util.AttributeExtractor;
22+
import io.wwan13.wintersecurity.util.TypeConverter;
23+
import org.springframework.core.MethodParameter;
24+
import org.springframework.web.bind.support.WebDataBinderFactory;
25+
import org.springframework.web.context.request.NativeWebRequest;
26+
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
27+
import org.springframework.web.method.support.ModelAndViewContainer;
28+
29+
import javax.servlet.http.HttpServletRequest;
30+
31+
public class SubjectResolver implements HandlerMethodArgumentResolver {
32+
33+
private final TargetAnnotations targetAnnotations;
34+
private final PayloadAnalysis payloadAnalysis;
35+
36+
public SubjectResolver(
37+
TargetAnnotations targetAnnotations,
38+
PayloadAnalysis payloadAnalysis
39+
) {
40+
this.targetAnnotations = targetAnnotations;
41+
this.payloadAnalysis = payloadAnalysis;
42+
}
43+
44+
@Override
45+
public boolean supportsParameter(MethodParameter parameter) {
46+
boolean hasAnnotation = targetAnnotations.forSubject().stream()
47+
.anyMatch(parameter::hasParameterAnnotation);
48+
boolean isValidType = payloadAnalysis.subject().getType()
49+
.isAssignableFrom(parameter.getParameterType());
50+
51+
return hasAnnotation && isValidType;
52+
}
53+
54+
@Override
55+
public Object resolveArgument(
56+
MethodParameter parameter,
57+
ModelAndViewContainer mavContainer,
58+
NativeWebRequest webRequest,
59+
WebDataBinderFactory binderFactory
60+
) {
61+
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
62+
TokenClaims claims = AttributeExtractor.extractClaims(request);
63+
64+
return TypeConverter.convertTo(
65+
claims.getSubject(),
66+
parameter.getParameterType()
67+
);
68+
}
69+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.wwan13.wintersecurity.resolve.util;
18+
19+
import io.wwan13.wintersecurity.constant.Constants;
20+
import io.wwan13.wintersecurity.jwt.TokenClaims;
21+
22+
import javax.servlet.http.HttpServletRequest;
23+
import java.util.Objects;
24+
25+
public class AttributeExtractor {
26+
27+
private AttributeExtractor() {
28+
throw new IllegalStateException("Cannot instantiate a utility class!");
29+
}
30+
31+
public static Object extract(
32+
HttpServletRequest request,
33+
String attributeKey
34+
) {
35+
return extractAttributeWithNullChecking(request, attributeKey);
36+
}
37+
38+
public static TokenClaims extractClaims(HttpServletRequest request) {
39+
return (TokenClaims) extractAttributeWithNullChecking(request, Constants.ATTRIBUTE_CLAIMS_KEY);
40+
}
41+
42+
private static Object extractAttributeWithNullChecking(
43+
HttpServletRequest request,
44+
String attributeKey
45+
) {
46+
Object claims = request.getAttribute(attributeKey);
47+
if (Objects.isNull(claims)) {
48+
throw new IllegalStateException("cannot extract claims");
49+
}
50+
return claims;
51+
}
52+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.wwan13.wintersecurity.util;
18+
19+
import com.fasterxml.jackson.databind.DeserializationFeature;
20+
import com.fasterxml.jackson.databind.ObjectMapper;
21+
22+
public class TypeConverter {
23+
24+
private static final ObjectMapper objectMapper = new ObjectMapper()
25+
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
26+
27+
private TypeConverter() {
28+
throw new IllegalStateException("Cannot instantiate a utility class!");
29+
}
30+
31+
public static Object convertTo(Object originValue, Class<?> targetClazz) {
32+
return objectMapper.convertValue(originValue, targetClazz);
33+
}
34+
}

src/test/java/io/wwan13/wintersecurity/auth/stub/StubHttpServletRequest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ public void getRequestUriWillReturn(String uri) {
4343
this.uri = uri;
4444
}
4545

46+
public StubHttpServletRequest(Map<String, Object> attribute) {
47+
this.attribute = attribute;
48+
}
49+
50+
public StubHttpServletRequest() {
51+
}
52+
4653
@Override
4754
public String getHeader(String name) {
4855
return expectedHeader;
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.wwan13.wintersecurity.resolve;
18+
19+
import io.wwan13.wintersecurity.jwt.PayloadAnalysis;
20+
import io.wwan13.wintersecurity.jwt.PayloadAnalyst;
21+
import io.wwan13.wintersecurity.jwt.TokenClaims;
22+
import io.wwan13.wintersecurity.jwt.payload.annotation.Roles;
23+
import io.wwan13.wintersecurity.jwt.payload.annotation.Subject;
24+
import io.wwan13.wintersecurity.jwt.payload.support.DefaultPayloadAnalyst;
25+
26+
import java.util.Map;
27+
import java.util.Set;
28+
29+
public class ResolveTestContainer {
30+
31+
public static TargetAnnotations targetAnnotations = new TargetAnnotations(
32+
Set.of(RequestUserSubject.class, RequestUserId.class),
33+
Set.of(RequestUserRoles.class)
34+
);
35+
36+
public static PayloadAnalysis payloadAnalysis;
37+
38+
static {
39+
PayloadAnalyst payloadAnalyst = new DefaultPayloadAnalyst();
40+
payloadAnalysis = payloadAnalyst.analyze(ResolveTestPayload.class);
41+
}
42+
43+
public static TokenClaims defaultTestClaims = new TokenClaims(
44+
Map.of(
45+
"sub", "1",
46+
"roles", "ROLE_USER"
47+
)
48+
);
49+
50+
public static class ResolveTestPayload {
51+
@Subject
52+
Long subject;
53+
@Roles
54+
Set<String> roles;
55+
}
56+
57+
public static class ResolveTestPayloadWithStringRole {
58+
@Subject
59+
Long subject;
60+
@Roles
61+
String role;
62+
}
63+
}

0 commit comments

Comments
 (0)