Skip to content

Commit c0b97b9

Browse files
author
nigel.zheng
committed
feat: add some general helper classes
1 parent 768b38c commit c0b97b9

File tree

6 files changed

+480
-0
lines changed

6 files changed

+480
-0
lines changed
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
package com.github.ahunigel.test.security.helper;
2+
3+
import org.springframework.beans.factory.ObjectFactory;
4+
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
5+
import org.springframework.http.HttpMethod;
6+
import org.springframework.http.MediaType;
7+
import org.springframework.test.web.servlet.MockMvc;
8+
import org.springframework.test.web.servlet.ResultActions;
9+
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
10+
11+
import java.util.Optional;
12+
13+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request;
14+
15+
/**
16+
* Created by Nigel Zheng on 7/31/2018.
17+
*/
18+
public class MockMvcHelper {
19+
private final MockMvc mockMvc;
20+
21+
private final MediaType defaultMediaType;
22+
23+
protected final SerializationHelper conv;
24+
25+
public MockMvcHelper(MockMvc mockMvc, ObjectFactory<HttpMessageConverters> messageConverters,
26+
MediaType defaultMediaType) {
27+
this.mockMvc = mockMvc;
28+
this.conv = new SerializationHelper(messageConverters);
29+
this.defaultMediaType = defaultMediaType;
30+
}
31+
32+
/**
33+
* Generic request builder which adds relevant "Accept" and "Content-Type" headers
34+
*
35+
* @param contentType should be not-null when issuing request with body (POST, PUT, PATCH), null otherwise
36+
* @param accept should be not-null when issuing response with body (GET, POST, OPTION), null otherwise
37+
* @param method
38+
* @param urlTemplate
39+
* @param uriVars
40+
* @return a request builder with minimal info you can tweak further: add headers, cookies, etc.
41+
*/
42+
public MockHttpServletRequestBuilder requestBuilder(
43+
Optional<MediaType> contentType,
44+
Optional<MediaType> accept,
45+
HttpMethod method,
46+
String urlTemplate,
47+
Object... uriVars) {
48+
final MockHttpServletRequestBuilder builder = request(method, urlTemplate, uriVars);
49+
contentType.ifPresent(builder::contentType);
50+
accept.ifPresent(builder::accept);
51+
return builder;
52+
}
53+
54+
public ResultActions perform(MockHttpServletRequestBuilder request) throws Exception {
55+
return mockMvc.perform(request);
56+
}
57+
58+
/* GET */
59+
public MockHttpServletRequestBuilder getRequestBuilder(MediaType accept, String urlTemplate, Object... uriVars) {
60+
return requestBuilder(Optional.empty(), Optional.of(accept), HttpMethod.GET, urlTemplate, uriVars);
61+
}
62+
63+
public MockHttpServletRequestBuilder getRequestBuilder(String urlTemplate, Object... uriVars) {
64+
return getRequestBuilder(defaultMediaType, urlTemplate, uriVars);
65+
}
66+
67+
public ResultActions get(MediaType accept, String urlTemplate, Object... uriVars) throws Exception {
68+
return mockMvc.perform(getRequestBuilder(accept, urlTemplate, uriVars));
69+
}
70+
71+
public ResultActions get(String urlTemplate, Object... uriVars) throws Exception {
72+
return mockMvc.perform(getRequestBuilder(urlTemplate, uriVars));
73+
}
74+
75+
/* POST */
76+
public <T> MockHttpServletRequestBuilder postRequestBuilder(final T payload, MediaType contentType, MediaType accept,
77+
String urlTemplate, Object... uriVars) {
78+
return feed(
79+
requestBuilder(Optional.of(contentType), Optional.of(accept), HttpMethod.POST, urlTemplate, uriVars),
80+
payload,
81+
contentType);
82+
}
83+
84+
public <T> MockHttpServletRequestBuilder postRequestBuilder(final T payload, String urlTemplate, Object... uriVars) {
85+
return postRequestBuilder(payload, defaultMediaType, defaultMediaType, urlTemplate, uriVars);
86+
}
87+
88+
public <T> ResultActions post(final T payload, MediaType contentType, MediaType accept, String urlTemplate,
89+
Object... uriVars) throws Exception {
90+
return mockMvc.perform(postRequestBuilder(payload, contentType, accept, urlTemplate, uriVars));
91+
}
92+
93+
public <T> ResultActions post(final T payload, String urlTemplate, Object... uriVars) throws Exception {
94+
return mockMvc.perform(postRequestBuilder(payload, urlTemplate, uriVars));
95+
}
96+
97+
98+
/* PUT */
99+
public <T> MockHttpServletRequestBuilder putRequestBuilder(final T payload, MediaType contentType,
100+
String urlTemplate, Object... uriVars) {
101+
return feed(
102+
requestBuilder(Optional.of(contentType), Optional.empty(), HttpMethod.PUT, urlTemplate, uriVars),
103+
payload,
104+
contentType);
105+
}
106+
107+
public <T> MockHttpServletRequestBuilder putRequestBuilder(final T payload, String urlTemplate, Object... uriVars) {
108+
return putRequestBuilder(payload, defaultMediaType, urlTemplate, uriVars);
109+
}
110+
111+
public <T> ResultActions put(final T payload, MediaType contentType, String urlTemplate, Object... uriVars)
112+
throws Exception {
113+
return mockMvc.perform(putRequestBuilder(payload, contentType, urlTemplate, uriVars));
114+
}
115+
116+
public <T> ResultActions put(final T payload, String urlTemplate, Object... uriVars) throws Exception {
117+
return mockMvc.perform(putRequestBuilder(payload, urlTemplate, uriVars));
118+
}
119+
120+
121+
/* PATCH */
122+
public <T> MockHttpServletRequestBuilder patchRequestBuilder(final T payload, MediaType contentType,
123+
String urlTemplate, Object... uriVars) {
124+
return feed(
125+
requestBuilder(Optional.of(contentType), Optional.empty(), HttpMethod.PATCH, urlTemplate, uriVars),
126+
payload,
127+
contentType);
128+
}
129+
130+
public <T> MockHttpServletRequestBuilder patchRequestBuilder(final T payload, String urlTemplate, Object... uriVars) {
131+
return patchRequestBuilder(payload, defaultMediaType, urlTemplate, uriVars);
132+
}
133+
134+
public <T> ResultActions patch(final T payload, MediaType contentType, String urlTemplate, Object... uriVars)
135+
throws Exception {
136+
return mockMvc.perform(patchRequestBuilder(payload, contentType, urlTemplate, uriVars));
137+
}
138+
139+
public <T> ResultActions patch(final T payload, String urlTemplate, Object... uriVars) throws Exception {
140+
return mockMvc.perform(patchRequestBuilder(payload, urlTemplate, uriVars));
141+
}
142+
143+
144+
/* DELETE */
145+
public MockHttpServletRequestBuilder deleteRequestBuilder(String urlTemplate, Object... uriVars) {
146+
return requestBuilder(Optional.empty(), Optional.empty(), HttpMethod.DELETE, urlTemplate, uriVars);
147+
}
148+
149+
public ResultActions delete(String urlTemplate, Object... uriVars) throws Exception {
150+
return mockMvc.perform(deleteRequestBuilder(urlTemplate, uriVars));
151+
}
152+
153+
154+
/* HEAD */
155+
public MockHttpServletRequestBuilder headRequestBuilder(String urlTemplate, Object... uriVars) {
156+
return requestBuilder(Optional.empty(), Optional.empty(), HttpMethod.HEAD, urlTemplate, uriVars);
157+
}
158+
159+
public ResultActions head(String urlTemplate, Object... uriVars) throws Exception {
160+
return mockMvc.perform(headRequestBuilder(urlTemplate, uriVars));
161+
}
162+
163+
164+
/* OPTION */
165+
public MockHttpServletRequestBuilder optionRequestBuilder(MediaType accept, String urlTemplate, Object... uriVars) {
166+
return requestBuilder(Optional.empty(), Optional.of(accept), HttpMethod.OPTIONS, urlTemplate, uriVars);
167+
}
168+
169+
public MockHttpServletRequestBuilder optionRequestBuilder(String urlTemplate, Object... uriVars) {
170+
return requestBuilder(Optional.empty(), Optional.of(defaultMediaType), HttpMethod.OPTIONS, urlTemplate, uriVars);
171+
}
172+
173+
public ResultActions option(MediaType accept, String urlTemplate, Object... uriVars) throws Exception {
174+
return mockMvc.perform(optionRequestBuilder(accept, urlTemplate, uriVars));
175+
}
176+
177+
public ResultActions option(String urlTemplate, Object... uriVars) throws Exception {
178+
return mockMvc.perform(optionRequestBuilder(urlTemplate, uriVars));
179+
}
180+
181+
/**
182+
* Adds serialized payload to request content
183+
*
184+
* @param request
185+
* @param payload
186+
* @param mediaType
187+
* @param <T>
188+
* @return the request with provided payload as content
189+
* @throws Exception if things go wrong (no registered serializer for payload type and asked MediaType, serialization failure, ...)
190+
*/
191+
public <T> MockHttpServletRequestBuilder feed(
192+
MockHttpServletRequestBuilder request,
193+
final T payload,
194+
final MediaType mediaType) {
195+
if (payload == null) {
196+
return request;
197+
}
198+
199+
final SerializationHelper.ByteArrayHttpOutputMessage msg = conv.outputMessage(payload, mediaType);
200+
return request
201+
.headers(msg.headers)
202+
.content(msg.out.toByteArray());
203+
}
204+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.github.ahunigel.test.security.helper;
2+
3+
import org.junit.Before;
4+
import org.junit.runner.RunWith;
5+
import org.springframework.beans.factory.annotation.Autowired;
6+
import org.springframework.boot.test.mock.mockito.MockBean;
7+
import org.springframework.context.annotation.Import;
8+
import org.springframework.security.core.context.SecurityContextHolder;
9+
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
10+
import org.springframework.test.context.junit4.SpringRunner;
11+
12+
import static org.mockito.Mockito.when;
13+
14+
/**
15+
* Created by Nigel.Zheng on 7/31/2018.
16+
*/
17+
@RunWith(SpringRunner.class)
18+
@Import(OAuth2MockMvcConfig.class)
19+
public class OAuth2ControllerTest {
20+
@MockBean
21+
private ResourceServerTokenServices tokenService;
22+
23+
@Autowired
24+
protected OAuth2MockMvcHelper api;
25+
26+
@Autowired
27+
protected SerializationHelper conv;
28+
29+
@Before
30+
public void setUpTokenService() {
31+
when(tokenService.loadAuthentication(api.VALID_TEST_TOKEN_VALUE))
32+
.thenAnswer(invocation -> SecurityContextHolder.getContext().getAuthentication());
33+
}
34+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.github.ahunigel.test.security.helper;
2+
3+
import org.springframework.beans.factory.ObjectFactory;
4+
import org.springframework.beans.factory.annotation.Value;
5+
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
6+
import org.springframework.boot.test.context.TestConfiguration;
7+
import org.springframework.context.annotation.Bean;
8+
import org.springframework.http.MediaType;
9+
import org.springframework.test.web.servlet.MockMvc;
10+
11+
/**
12+
* Created by Nigel Zheng on 7/31/2018.
13+
*/
14+
@TestConfiguration
15+
public class OAuth2MockMvcConfig {
16+
@Bean
17+
public SerializationHelper serializationHelper(ObjectFactory<HttpMessageConverters> messageConverters) {
18+
return new SerializationHelper(messageConverters);
19+
}
20+
21+
@Bean
22+
public OAuth2MockMvcHelper mockMvcHelper(
23+
MockMvc mockMvc,
24+
ObjectFactory<HttpMessageConverters> messageConverters,
25+
@Value("${controllers.default-media-type:application/json;charset=UTF-8}") MediaType defaultMediaType) {
26+
return new OAuth2MockMvcHelper(mockMvc, messageConverters, defaultMediaType);
27+
}
28+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.github.ahunigel.test.security.helper;
2+
3+
import org.springframework.beans.factory.ObjectFactory;
4+
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
5+
import org.springframework.http.HttpMethod;
6+
import org.springframework.http.MediaType;
7+
import org.springframework.security.core.context.SecurityContextHolder;
8+
import org.springframework.security.oauth2.provider.OAuth2Authentication;
9+
import org.springframework.test.web.servlet.MockMvc;
10+
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
11+
12+
import java.util.Optional;
13+
14+
/**
15+
* Created by Nigel Zheng on 7/31/2018.
16+
*/
17+
public class OAuth2MockMvcHelper extends MockMvcHelper {
18+
public static final String VALID_TEST_TOKEN_VALUE = "test.fake.jwt";
19+
20+
public OAuth2MockMvcHelper(
21+
final MockMvc mockMvc,
22+
final ObjectFactory<HttpMessageConverters> messageConverters,
23+
final MediaType defaultMediaType) {
24+
super(mockMvc, messageConverters, defaultMediaType);
25+
}
26+
27+
/**
28+
* Adds OAuth2 support: adds an Authorisation header to all request builders
29+
* if there is an OAuth2Authentication in test security context.
30+
* <p>
31+
* /!\ Make sure your token services recognize this dummy "VALID_TEST_TOKEN_VALUE" token as valid during your tests /!\
32+
*
33+
* @param contentType should be not-null when issuing request with body (POST, PUT, PATCH), null otherwise
34+
* @param accept should be not-null when issuing response with body (GET, POST, OPTION), null otherwise
35+
* @param method
36+
* @param urlTemplate
37+
* @param uriVars
38+
* @return a request builder with minimal info you can tweak further (add headers, cookies, etc.)
39+
*/
40+
@Override
41+
public MockHttpServletRequestBuilder requestBuilder(
42+
Optional<MediaType> contentType,
43+
Optional<MediaType> accept,
44+
HttpMethod method,
45+
String urlTemplate,
46+
Object... uriVars) {
47+
final MockHttpServletRequestBuilder builder = super.requestBuilder(contentType, accept, method, urlTemplate, uriVars);
48+
if (SecurityContextHolder.getContext().getAuthentication() instanceof OAuth2Authentication) {
49+
builder.header("Authorization", "Bearer " + VALID_TEST_TOKEN_VALUE);
50+
}
51+
return builder;
52+
}
53+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.github.ahunigel.test.security.helper;
2+
3+
import org.springframework.boot.test.context.TestComponent;
4+
import org.springframework.security.authentication.TestingAuthenticationToken;
5+
import org.springframework.security.core.Authentication;
6+
import org.springframework.security.core.GrantedAuthority;
7+
import org.springframework.security.core.authority.AuthorityUtils;
8+
import org.springframework.security.core.userdetails.User;
9+
import org.springframework.security.oauth2.client.OAuth2ClientContext;
10+
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
11+
import org.springframework.security.oauth2.provider.OAuth2Authentication;
12+
import org.springframework.security.oauth2.provider.OAuth2Request;
13+
14+
import java.io.Serializable;
15+
import java.util.Collections;
16+
import java.util.List;
17+
import java.util.Map;
18+
import java.util.Set;
19+
20+
import static org.mockito.Mockito.mock;
21+
import static org.mockito.Mockito.when;
22+
23+
/**
24+
* Created by Nigel Zheng on 8/2/2018.
25+
*/
26+
@TestComponent
27+
public class OAuth2TestHelper {
28+
29+
public OAuth2ClientContext getOAuth2ClientContext() {
30+
OAuth2ClientContext mockClient = mock(OAuth2ClientContext.class);
31+
when(mockClient.getAccessToken()).thenReturn(new DefaultOAuth2AccessToken("my-fun-token"));
32+
33+
return mockClient;
34+
}
35+
36+
public Authentication getOAuthTestAuthentication() {
37+
return getOAuthTestAuthentication(Collections.emptyMap());
38+
}
39+
40+
public Authentication getOAuthTestAuthentication(Map<String, Object> claims) {
41+
OAuth2Authentication oauth = new OAuth2Authentication(getOAuth2Request(), getAuthentication(claims));
42+
if (oauth.getDetails() == null) {
43+
oauth.setDetails(oauth.getUserAuthentication().getDetails());
44+
}
45+
return oauth;
46+
}
47+
48+
private OAuth2Request getOAuth2Request() {
49+
String clientId = "oauth-client-id";
50+
Map<String, String> requestParameters = Collections.emptyMap();
51+
boolean approved = true;
52+
String redirectUrl = "http://my-redirect-url.com";
53+
Set<String> responseTypes = Collections.emptySet();
54+
Set<String> scopes = Collections.emptySet();
55+
Set<String> resourceIds = Collections.emptySet();
56+
Map<String, Serializable> extensionProperties = Collections.emptyMap();
57+
List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("Everything");
58+
59+
return new OAuth2Request(requestParameters, clientId, authorities,
60+
approved, scopes, resourceIds, redirectUrl, responseTypes, extensionProperties);
61+
}
62+
63+
private Authentication getAuthentication(Map<String, Object> claims) {
64+
List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("Everything");
65+
66+
User userPrincipal = new User("admin", "", true, true, true, true, authorities);
67+
68+
TestingAuthenticationToken token = new TestingAuthenticationToken(userPrincipal, null, authorities);
69+
token.setAuthenticated(true);
70+
token.setDetails(claims);
71+
return token;
72+
}
73+
74+
}

0 commit comments

Comments
 (0)