Skip to content

Commit 26c3941

Browse files
committed
Polish gh-31
1 parent fa5c351 commit 26c3941

6 files changed

+81
-102
lines changed

build.gradle

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ group = 'org.springframework.security.experimental'
1616
description = 'Spring Authorization Server'
1717
version = '0.0.1-SNAPSHOT'
1818

19-
ext['junit-jupiter.version'] = '5.4.0'
20-
2119
repositories {
2220
mavenCentral()
2321
}

samples/boot/minimal/spring-authorization-server-samples-boot-minimal.gradle

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,11 @@ apply plugin: 'io.spring.convention.spring-sample-boot'
33
dependencies {
44
implementation 'org.springframework.boot:spring-boot-starter-web'
55
implementation 'org.springframework.boot:spring-boot-starter-security'
6-
76
implementation 'com.nimbusds:oauth2-oidc-sdk'
87

98
testImplementation('org.springframework.boot:spring-boot-starter-test') {
109
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
1110
}
12-
13-
testImplementation 'org.springframework.security:spring-security-test'
14-
15-
testRuntime("org.junit.platform:junit-platform-runner")
16-
testRuntime("org.junit.jupiter:junit-jupiter-engine")
1711
}
1812

1913
test {

samples/boot/minimal/src/main/java/sample/JwkSetEndpointFilter.java

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,35 +13,27 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
1716
package sample;
1817

19-
import static org.springframework.http.HttpMethod.GET;
20-
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
21-
22-
import java.io.IOException;
23-
import java.io.Writer;
18+
import com.nimbusds.jose.jwk.JWKSet;
19+
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
20+
import org.springframework.security.web.util.matcher.RequestMatcher;
21+
import org.springframework.util.Assert;
22+
import org.springframework.web.filter.OncePerRequestFilter;
2423

2524
import javax.servlet.FilterChain;
2625
import javax.servlet.ServletException;
2726
import javax.servlet.http.HttpServletRequest;
2827
import javax.servlet.http.HttpServletResponse;
28+
import java.io.IOException;
29+
import java.io.Writer;
2930

30-
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
31-
import org.springframework.security.web.util.matcher.RequestMatcher;
32-
import org.springframework.util.Assert;
33-
import org.springframework.web.filter.OncePerRequestFilter;
34-
import org.springframework.web.util.UrlPathHelper;
35-
36-
import com.nimbusds.jose.jwk.JWKSet;
31+
import static org.springframework.http.HttpMethod.GET;
32+
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
3733

3834
public class JwkSetEndpointFilter extends OncePerRequestFilter {
39-
40-
static final String WELL_KNOWN_JWK_URIS = "/.well-known/jwk_uris";
41-
42-
private final RequestMatcher requestMatcher = new AntPathRequestMatcher(WELL_KNOWN_JWK_URIS, GET.name(), true,
43-
new UrlPathHelper());
44-
35+
static final String DEFAULT_JWK_SET_URI = "/oauth2/jwks";
36+
private final RequestMatcher requestMatcher = new AntPathRequestMatcher(DEFAULT_JWK_SET_URI, GET.name());
4537
private final JWKSet jwkSet;
4638

4739
public JwkSetEndpointFilter(JWKSet jwkSet) {
@@ -53,7 +45,7 @@ public JwkSetEndpointFilter(JWKSet jwkSet) {
5345
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
5446
throws ServletException, IOException {
5547

56-
if (ifRequestMatches(request)) {
48+
if (matchesRequest(request)) {
5749
respond(response);
5850
} else {
5951
filterChain.doFilter(request, response);
@@ -63,12 +55,11 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
6355
private void respond(HttpServletResponse response) throws IOException {
6456
response.setContentType(APPLICATION_JSON_VALUE);
6557
try (Writer writer = response.getWriter()) {
66-
writer.write(jwkSet.toPublicJWKSet().toJSONObject().toJSONString());
58+
writer.write(this.jwkSet.toPublicJWKSet().toJSONObject().toJSONString());
6759
}
6860
}
6961

70-
private boolean ifRequestMatches(HttpServletRequest request) {
62+
private boolean matchesRequest(HttpServletRequest request) {
7163
return this.requestMatcher.matches(request);
7264
}
73-
7465
}

samples/boot/minimal/src/main/java/sample/SecurityConfig.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,28 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
1716
package sample;
1817

19-
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
20-
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
21-
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
22-
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
23-
2418
import com.nimbusds.jose.JOSEException;
2519
import com.nimbusds.jose.jwk.JWK;
2620
import com.nimbusds.jose.jwk.JWKSet;
2721
import com.nimbusds.jose.jwk.KeyUse;
2822
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
23+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
24+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
25+
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
26+
import org.springframework.security.web.authentication.logout.LogoutFilter;
2927

3028
@EnableWebSecurity
3129
public class SecurityConfig extends WebSecurityConfigurerAdapter {
3230

3331
@Override
3432
protected void configure(HttpSecurity http) throws Exception {
35-
http.addFilterBefore(new JwkSetEndpointFilter(generateJwkSet()), ChannelProcessingFilter.class);
33+
http.addFilterBefore(new JwkSetEndpointFilter(generateJwkSet()), LogoutFilter.class);
3634
}
3735

38-
protected JWKSet generateJwkSet() throws JOSEException {
36+
private JWKSet generateJwkSet() throws JOSEException {
3937
JWK jwk = new RSAKeyGenerator(2048).keyID("minimal-ASA").keyUse(KeyUse.SIGNATURE).generate();
4038
return new JWKSet(jwk);
4139
}
42-
4340
}

samples/boot/minimal/src/test/java/sample/JwkSetEndpointFilterTest.java renamed to samples/boot/minimal/src/test/java/sample/JwkSetEndpointFilterTests.java

Lines changed: 54 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -13,68 +13,66 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
1716
package sample;
1817

19-
import static org.assertj.core.api.Assertions.assertThatThrownBy;
20-
import static org.hamcrest.Matchers.is;
21-
import static org.mockito.Mockito.mock;
22-
import static org.mockito.Mockito.never;
23-
import static org.mockito.Mockito.only;
24-
import static org.mockito.Mockito.verify;
25-
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
26-
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
27-
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
28-
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
29-
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
30-
import static sample.JwkSetEndpointFilter.WELL_KNOWN_JWK_URIS;
31-
32-
import javax.servlet.FilterChain;
33-
import javax.servlet.http.HttpServletRequest;
34-
import javax.servlet.http.HttpServletResponse;
35-
18+
import com.nimbusds.jose.JOSEException;
19+
import com.nimbusds.jose.jwk.JWK;
20+
import com.nimbusds.jose.jwk.JWKSet;
21+
import com.nimbusds.jose.jwk.KeyUse;
22+
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
3623
import org.junit.jupiter.api.BeforeAll;
3724
import org.junit.jupiter.api.Test;
3825
import org.junit.jupiter.api.TestInstance;
3926
import org.junit.jupiter.api.TestInstance.Lifecycle;
40-
import org.mockito.Mockito;
4127
import org.springframework.mock.web.MockHttpServletRequest;
4228
import org.springframework.mock.web.MockHttpServletResponse;
4329
import org.springframework.test.web.servlet.MockMvc;
4430
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
4531
import org.springframework.web.bind.annotation.RequestMapping;
4632
import org.springframework.web.bind.annotation.RestController;
4733

48-
import com.nimbusds.jose.JOSEException;
49-
import com.nimbusds.jose.jwk.JWK;
50-
import com.nimbusds.jose.jwk.JWKSet;
51-
import com.nimbusds.jose.jwk.KeyUse;
52-
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
34+
import javax.servlet.FilterChain;
35+
import javax.servlet.http.HttpServletRequest;
36+
import javax.servlet.http.HttpServletResponse;
5337

54-
@TestInstance(Lifecycle.PER_CLASS)
55-
public class JwkSetEndpointFilterTest {
38+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
39+
import static org.hamcrest.Matchers.is;
40+
import static org.mockito.ArgumentMatchers.any;
41+
import static org.mockito.Mockito.mock;
42+
import static org.mockito.Mockito.only;
43+
import static org.mockito.Mockito.verify;
44+
import static org.mockito.Mockito.verifyNoInteractions;
45+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
46+
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
47+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
48+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
49+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
50+
import static sample.JwkSetEndpointFilter.DEFAULT_JWK_SET_URI;
5651

57-
private MockMvc mvc;
58-
private JWKSet jwkSet;
52+
@TestInstance(Lifecycle.PER_CLASS)
53+
public class JwkSetEndpointFilterTests {
5954
private JWK jwk;
55+
private JWKSet jwkSet;
6056
private JwkSetEndpointFilter filter;
57+
private MockMvc mvc;
6158

6259
@BeforeAll
6360
void setup() throws JOSEException {
6461
this.jwk = new RSAKeyGenerator(2048).keyID("endpoint-test").keyUse(KeyUse.SIGNATURE).generate();
65-
this.jwkSet = new JWKSet(jwk);
66-
this.filter = new JwkSetEndpointFilter(jwkSet);
67-
this.mvc = MockMvcBuilders.standaloneSetup(new FakeController()).addFilters(filter).alwaysDo(print()).build();
62+
this.jwkSet = new JWKSet(this.jwk);
63+
this.filter = new JwkSetEndpointFilter(this.jwkSet);
64+
this.mvc = MockMvcBuilders.standaloneSetup(new HelloController()).addFilters(this.filter).alwaysDo(print()).build();
6865
}
6966

7067
@Test
71-
void constructorWhenJsonWebKeySetIsNullThrowIllegalArgumentException() {
72-
assertThatThrownBy(() -> new JwkSetEndpointFilter(null)).isInstanceOf(IllegalArgumentException.class);
68+
void constructorWhenJWKSetNullThenThrowIllegalArgumentException() {
69+
assertThatThrownBy(() -> new JwkSetEndpointFilter(null))
70+
.isInstanceOf(IllegalArgumentException.class);
7371
}
7472

7573
@Test
76-
void doFilterWhenPathMatches() throws Exception {
77-
String requestUri = WELL_KNOWN_JWK_URIS;
74+
void doFilterWhenRequestMatchesThenProcess() throws Exception {
75+
String requestUri = DEFAULT_JWK_SET_URI;
7876
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
7977
request.setServletPath(requestUri);
8078

@@ -83,13 +81,12 @@ void doFilterWhenPathMatches() throws Exception {
8381

8482
this.filter.doFilter(request, response, filterChain);
8583

86-
verify(filterChain, never()).doFilter(Mockito.any(HttpServletRequest.class),
87-
Mockito.any(HttpServletResponse.class));
84+
verifyNoInteractions(filterChain);
8885
}
8986

9087
@Test
91-
void doFilterWhenPathDoesNotMatch() throws Exception {
92-
String requestUri = "/stuff/" + WELL_KNOWN_JWK_URIS;
88+
void doFilterWhenRequestDoesNotMatchThenContinueChain() throws Exception {
89+
String requestUri = "/path";
9390
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
9491
request.setServletPath(requestUri);
9592

@@ -98,30 +95,34 @@ void doFilterWhenPathDoesNotMatch() throws Exception {
9895

9996
this.filter.doFilter(request, response, filterChain);
10097

101-
verify(filterChain, only()).doFilter(Mockito.any(HttpServletRequest.class),
102-
Mockito.any(HttpServletResponse.class));
98+
verify(filterChain, only()).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
10399
}
104100

105101
@Test
106-
void testResponseIfRequestMatches() throws Exception {
107-
mvc.perform(get(WELL_KNOWN_JWK_URIS)).andDo(print()).andExpect(status().isOk())
108-
.andExpect(jsonPath("$.keys").isArray()).andExpect(jsonPath("$.keys").isNotEmpty())
109-
.andExpect(jsonPath("$.keys[0].kid").value(jwk.getKeyID()))
110-
.andExpect(jsonPath("$.keys[0].kty").value(jwk.getKeyType().toString()));
102+
void requestWhenMatchesThenResponseContainsKeys() throws Exception {
103+
this.mvc.perform(get(DEFAULT_JWK_SET_URI))
104+
.andDo(print())
105+
.andExpect(status().isOk())
106+
.andExpect(jsonPath("$.keys").isArray())
107+
.andExpect(jsonPath("$.keys").isNotEmpty())
108+
.andExpect(jsonPath("$.keys[0].kid").value(this.jwk.getKeyID()))
109+
.andExpect(jsonPath("$.keys[0].kty").value(this.jwk.getKeyType().toString()));
111110
}
112111

113112
@Test
114-
void testResponseIfNotRequestMatches() throws Exception {
115-
mvc.perform(get("/fake")).andDo(print()).andExpect(status().isOk())
116-
.andExpect(content().string(is("fake")));
113+
void requestWhenDoesNotMatchThenResponseContainsOther() throws Exception {
114+
this.mvc.perform(get("/hello"))
115+
.andDo(print())
116+
.andExpect(status().isOk())
117+
.andExpect(content().string(is("hello")));
117118
}
118119

119120
@RestController
120-
class FakeController {
121+
static class HelloController {
121122

122-
@RequestMapping("/fake")
123-
public String hello() {
124-
return "fake";
123+
@RequestMapping("/hello")
124+
String hello() {
125+
return "hello";
125126
}
126127
}
127128
}

samples/boot/minimal/src/test/java/sample/MinimalAuthorizationServerApplicationTests.java

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,27 @@
1515
*/
1616
package sample;
1717

18-
import static org.assertj.core.api.Assertions.assertThat;
19-
import static org.springframework.http.HttpStatus.OK;
20-
2118
import org.junit.jupiter.api.Test;
2219
import org.springframework.boot.test.context.SpringBootTest;
2320
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
2421
import org.springframework.boot.web.server.LocalServerPort;
22+
import org.springframework.http.HttpStatus;
2523
import org.springframework.http.ResponseEntity;
2624
import org.springframework.web.client.RestTemplate;
2725

26+
import static org.assertj.core.api.Assertions.assertThat;
27+
2828
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
2929
public class MinimalAuthorizationServerApplicationTests {
30-
3130
private RestTemplate rest = new RestTemplate();
3231

3332
@LocalServerPort
3433
private int serverPort;
3534

3635
@Test
37-
void verifyJwkSetEndpointFilterAccessibleWithoutAuthentication() {
38-
ResponseEntity<String> responseEntity = rest.getForEntity(
39-
"http://localhost:" + serverPort + JwkSetEndpointFilter.WELL_KNOWN_JWK_URIS, String.class);
40-
assertThat(responseEntity.getStatusCode()).isEqualTo(OK);
36+
void requestWhenNotAuthenticatedThenJwkSetEndpointStillAccessible() {
37+
ResponseEntity<String> responseEntity = this.rest.getForEntity(
38+
"http://localhost:" + this.serverPort + JwkSetEndpointFilter.DEFAULT_JWK_SET_URI, String.class);
39+
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
4140
}
42-
4341
}

0 commit comments

Comments
 (0)