Skip to content

Commit a6d901f

Browse files
author
nigel.zheng
committed
refactor: update all annotations with @AttachClaims inside
1 parent c0b97b9 commit a6d901f

File tree

6 files changed

+77
-49
lines changed

6 files changed

+77
-49
lines changed

README.md

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,18 @@ Attach Map-based claims to mocked user as authentication details, the claims can
1111
_Note: Most code came from the open network. I refactor and enhanced the code, then we have this java-library._
1212

1313
## Features
14-
- @WithMockOAuth2Client
15-
- @WithMockOAuth2User
14+
- `@WithMockOAuth2Client`
15+
- `@WithMockOAuth2User`
1616
- mock an oauth2 user, attach claims to OAuth2Authentication details
17-
- @AttachClaims
18-
- attach Map-based claims to current authentication, should work with @WithMockUser
19-
- @WithMockUserAndClaims
20-
- enhanced @WithMockUser, attach Map-based claims as authentication details
21-
- equal to @WithMockUser + @AttachClaims
22-
- @WithToken
17+
- `@AttachClaims`
18+
- attach Map-based claims to current authentication, should work with `@WithMockUser`
19+
- `@WithMockUserAndClaims`
20+
- enhanced `@WithMockUser`, attach Map-based claims as authentication details
21+
- equal to `@WithMockUser` + `@AttachClaims`
22+
- `@WithToken`
2323
- add `bearer` token to request header to extract a `PreAuthenticatedAuthenticationToken`,
2424
load existing OAuth2Authentication from SecurityContext
25+
- require `@MockTokenServices` on test class
2526

2627
## How to use
2728

@@ -37,38 +38,51 @@ allprojects {
3738
## Step 2. Add the dependency
3839
```groovy
3940
dependencies {
40-
implementation 'com.github.ahunigel:spring-security-oauth2-test:master-SNAPSHOT'
41+
implementation 'com.github.ahunigel:spring-security-oauth2-test:{version}'
4142
}
4243
```
43-
## Step 3. Write test
44+
_Refer to https://jitpack.io/#ahunigel/spring-security-oauth2-test for details._
45+
46+
## Step 3. Write tests
4447
```java
4548
@WithMockOAuth2User(
46-
client = @WithMockOAuth2Client(
47-
clientId = "custom-client",
48-
scope = {"custom-scope", "other-scope"},
49-
authorities = {"custom-authority", "ROLE_CUSTOM_CLIENT"}),
50-
user = @WithMockUser(
51-
username = "custom-username",
52-
authorities = {"custom-user-authority"}),
53-
claims = {
54-
@Claim(name = "user_id", value = "6", type = Long.class),
55-
@Claim(name = "role_id", value = "1"),
56-
@Claim(name = "is_social_user", value = "false")
57-
})
49+
client = @WithMockOAuth2Client(
50+
clientId = "custom-client",
51+
scope = {"custom-scope", "other-scope"},
52+
authorities = {"custom-authority", "ROLE_CUSTOM_CLIENT"}),
53+
user = @WithMockUser(
54+
username = "custom-username",
55+
authorities = {"custom-user-authority"}),
56+
claims = @AttachClaims({
57+
@Claim(name = "user_id", value = "6", type = Long.class),
58+
@Claim(name = "role_id", value = "1"),
59+
@Claim(name = "is_social_user", value = "false")
60+
})
61+
}
5862
```
5963
or
6064
```java
6165
@AttachClaims(value = {
62-
@Claim(name = "user_id", value = "6", type = Long.class),
63-
@Claim(name = "role_id", value = "1"),
64-
@Claim(name = "is_social_user", value = "false")
65-
}, claims = {ROLE_NAME, "ADMIN"})
66+
@Claim(name = "user_id", value = "6", type = Long.class),
67+
@Claim(name = "role_id", value = "1"),
68+
@Claim(name = "is_social_user", value = "false")
69+
}, claims = {"role_name:ADMIN", "user_name=ahunigel"})
70+
@WithMockUser()
71+
```
72+
or
73+
```java
74+
@WithMockUserAndClaims(
75+
@AttachClaims(value = {
76+
@Claim(name = "user_id", value = "6", type = Long.class),
77+
@Claim(name = "role_id", value = "1"),
78+
@Claim(name = "is_social_user", value = "false")},
79+
claims = {"role_name:ADMIN", "user_name=ahunigel"})
80+
)
6681
```
67-
Refer to https://jitpack.io/#ahunigel/spring-security-oauth2-test for details.
6882

6983
## TODOs
7084

7185
- For oauth2 request, add ability to set ResourceServerSecurityConfigurer.stateless to false, maybe add an
72-
annotation like `@ResourceStateLess(false)`
86+
annotation like `@ResourceStateless(false)`
7387

7488
- Add support for `RestTemplate`

src/main/java/com/github/ahunigel/test/security/AttachClaims.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
Claim[] value();
2323

2424
/**
25-
* key-value paired string array, redundant value will be ignored
25+
* key-value paired string array, separated by <code>:</code> or <code>=</code>
2626
* <p>
2727
* would merge with #value() if key is absent
2828
*

src/main/java/com/github/ahunigel/test/security/AttachClaimsTestExecutionListener.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import org.springframework.test.context.support.AbstractTestExecutionListener;
1212

1313
import java.lang.reflect.AnnotatedElement;
14-
import java.util.HashMap;
1514
import java.util.Map;
1615

1716
/**
@@ -47,9 +46,7 @@ private AttachClaims findAnnotation(AnnotatedElement annotated) {
4746
public void attachClaimsToAuthentication(AttachClaims annotation) {
4847
Authentication authentication = TestSecurityContextHolder.getContext().getAuthentication();
4948
if (authentication != null && authentication instanceof AbstractAuthenticationToken) {
50-
Map<String, Object> claims = ClaimUtils.getClaims(annotation.value());
51-
Map<String, String> stringMap = toMap(annotation.claims());
52-
stringMap.entrySet().stream().forEach(entry -> claims.putIfAbsent(entry.getKey(), entry.getValue()));
49+
Map<String, Object> claims = ClaimUtils.extractClaims(annotation);
5350
if (!claims.isEmpty()) {
5451
((AbstractAuthenticationToken) authentication).setDetails(claims);
5552
}
@@ -58,11 +55,4 @@ public void attachClaimsToAuthentication(AttachClaims annotation) {
5855
}
5956
}
6057

61-
private Map<String, String> toMap(String[] claims) {
62-
final Map<String, String> map = new HashMap<>();
63-
for (int i = 0; i + 1 < claims.length; i += 2) {
64-
map.put(claims[i], claims[i + 1]);
65-
}
66-
return map;
67-
}
6858
}

src/main/java/com/github/ahunigel/test/security/WithMockUserAndClaims.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@
2828
@WithSecurityContext(factory = WithMockUserAndClaims.WithMockUserWithClaimsSecurityContextFactory.class)
2929
public @interface WithMockUserAndClaims {
3030
/**
31-
* Return the contained {@link Claim} annotations.
31+
* Return the contained {@link AttachClaims} annotations.
3232
*
3333
* @return the claims
3434
*/
3535
@AliasFor("claims")
36-
Claim[] value();
36+
AttachClaims value();
3737

3838
@AliasFor("value")
39-
Claim[] claims();
39+
AttachClaims claims();
4040

4141
WithMockUser user() default @WithMockUser();
4242

@@ -45,7 +45,7 @@ class WithMockUserWithClaimsSecurityContextFactory implements WithSecurityContex
4545
public SecurityContext createSecurityContext(WithMockUserAndClaims annotation) {
4646
SecurityContext context = MockUserUtils.getSecurityContext(annotation.user());
4747
Authentication authentication = context.getAuthentication();
48-
Map<String, Object> claims = ClaimUtils.getClaims(annotation.value());
48+
Map<String, Object> claims = ClaimUtils.extractClaims(annotation.value());
4949
if (!claims.isEmpty() && authentication instanceof AbstractAuthenticationToken) {
5050
((AbstractAuthenticationToken) authentication).setDetails(claims);
5151
}

src/main/java/com/github/ahunigel/test/security/oauth2/WithMockOAuth2User.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.github.ahunigel.test.security.oauth2;
22

3-
import com.github.ahunigel.test.security.Claim;
3+
import com.github.ahunigel.test.security.AttachClaims;
44
import com.github.ahunigel.test.security.util.ClaimUtils;
55
import com.github.ahunigel.test.security.util.MockUserUtils;
66
import org.springframework.security.core.context.SecurityContext;
@@ -29,11 +29,11 @@
2929
WithMockUser user() default @WithMockUser();
3030

3131
/**
32-
* Return the contained {@link Claim} annotations.
32+
* Return the contained {@link AttachClaims} annotations.
3333
*
3434
* @return the claims
3535
*/
36-
Claim[] claims();
36+
AttachClaims claims() default @AttachClaims({});
3737

3838
class WithMockOAuth2UserSecurityContextFactory implements WithSecurityContextFactory<WithMockOAuth2User> {
3939

@@ -43,7 +43,7 @@ public SecurityContext createSecurityContext(final WithMockOAuth2User annotation
4343
OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(
4444
WithMockOAuth2Client.WithMockOAuth2ClientSecurityContextFactory.getOAuth2Request(annotation.client()),
4545
MockUserUtils.getAuthentication(annotation.user()));
46-
Map<String, Object> claims = ClaimUtils.getClaims(annotation.claims());
46+
Map<String, Object> claims = ClaimUtils.extractClaims(annotation.claims());
4747
if (!claims.isEmpty()) {
4848
oAuth2Authentication.setDetails(claims);
4949
}

src/main/java/com/github/ahunigel/test/security/util/ClaimUtils.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package com.github.ahunigel.test.security.util;
22

3+
import com.github.ahunigel.test.security.AttachClaims;
34
import com.github.ahunigel.test.security.Claim;
45
import org.apache.commons.beanutils.ConvertUtils;
56

67
import java.util.Arrays;
8+
import java.util.HashMap;
79
import java.util.Map;
810
import java.util.stream.Collectors;
911

@@ -17,10 +19,32 @@ private ClaimUtils() {
1719
throw new InstantiationError();
1820
}
1921

20-
public static Map<String, Object> getClaims(Claim[] claims) {
22+
public static Map<String, Object> extractClaims(AttachClaims annotation) {
23+
Map<String, Object> claims = extractClaims(annotation.value());
24+
Map<String, String> pairs = extractClaims(annotation.claims());
25+
pairs.entrySet().stream().forEach(entry -> claims.putIfAbsent(entry.getKey(), entry.getValue()));
26+
return claims;
27+
}
28+
29+
public static Map<String, Object> extractClaims(Claim[] claims) {
2130
return Arrays.stream(claims)
2231
.collect(Collectors.toMap(Claim::name, claim ->
2332
ConvertUtils.convert(claim.value(), claim.type())
2433
));
2534
}
35+
36+
public static Map<String, String> extractClaims(String... pairs) {
37+
final Map<String, String> map = new HashMap<>();
38+
for (String pair : pairs) {
39+
String separator = ":";
40+
if (!pair.contains(separator) && pair.contains("=")) {
41+
separator = "=";
42+
}
43+
int index = pair.indexOf(separator);
44+
String key = pair.substring(0, index > 0 ? index : pair.length());
45+
String value = index > 0 ? pair.substring(index + 1) : null;
46+
map.put(key, value);
47+
}
48+
return map;
49+
}
2650
}

0 commit comments

Comments
 (0)