Skip to content

Commit 0b789b0

Browse files
committed
spring-projects#2 changes as requested by reviewer
1 parent b63a411 commit 0b789b0

9 files changed

+191
-164
lines changed

.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ target/
1717
.settings
1818
.springBeans
1919
.sts4-cache
20-
bin/
2120

2221
### IntelliJ IDEA ###
2322
.idea

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

+3
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ apply plugin: 'io.spring.convention.spring-sample-boot'
22

33
dependencies {
44
implementation 'org.springframework.boot:spring-boot-starter-web'
5+
implementation 'org.springframework.boot:spring-boot-starter-security'
56

67
implementation 'com.nimbusds:oauth2-oidc-sdk:7.3'
78

89
testImplementation('org.springframework.boot:spring-boot-starter-test') {
910
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
1011
}
1112

13+
testImplementation 'org.springframework.security:spring-security-test'
14+
1215
testRuntime("org.junit.platform:junit-platform-runner")
1316
testRuntime("org.junit.jupiter:junit-jupiter-engine")
1417
}

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

-65
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright 2020 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+
* https://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 sample;
18+
19+
import static java.util.Objects.requireNonNull;
20+
import static org.springframework.http.HttpMethod.GET;
21+
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
22+
23+
import java.io.IOException;
24+
import java.io.Writer;
25+
26+
import javax.servlet.FilterChain;
27+
import javax.servlet.ServletException;
28+
import javax.servlet.http.HttpServletRequest;
29+
import javax.servlet.http.HttpServletResponse;
30+
31+
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
32+
import org.springframework.security.web.util.matcher.RequestMatcher;
33+
import org.springframework.web.filter.OncePerRequestFilter;
34+
import org.springframework.web.util.UrlPathHelper;
35+
36+
import com.nimbusds.jose.jwk.JWKSet;
37+
38+
public class JwkSetEndpointFilter extends OncePerRequestFilter {
39+
40+
static final String WELL_KNOWN_JWK_URIS = "/.well-known/jwk_uris";
41+
private final RequestMatcher requestMatcher = new AntPathRequestMatcher(WELL_KNOWN_JWK_URIS, GET.name(), true,
42+
new UrlPathHelper());
43+
44+
private final JWKSet jwkSet;
45+
46+
public JwkSetEndpointFilter(JWKSet jwkSet) {
47+
this.jwkSet = requireNonNull(jwkSet, "jwkSet should not be null");
48+
}
49+
50+
@Override
51+
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
52+
throws ServletException, IOException {
53+
54+
if (ifRequestMatches(request)) {
55+
respond(response);
56+
} else {
57+
filterChain.doFilter(request, response);
58+
}
59+
}
60+
61+
protected void respond(HttpServletResponse response) throws IOException {
62+
response.setContentType(APPLICATION_JSON_VALUE);
63+
try (Writer writer = response.getWriter()) {
64+
writer.write(jwkSet.toPublicJWKSet().toJSONObject().toJSONString());
65+
}
66+
}
67+
68+
protected boolean ifRequestMatches(HttpServletRequest request) {
69+
return this.requestMatcher.matches(request);
70+
}
71+
72+
}

samples/boot/minimal/src/main/java/sample/Config.java renamed to samples/boot/minimal/src/main/java/sample/SecurityConfig.java

+12-14
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616

1717
package sample;
1818

19-
import org.springframework.boot.web.servlet.FilterRegistrationBean;
20-
import org.springframework.context.annotation.Bean;
2119
import org.springframework.context.annotation.Configuration;
20+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
21+
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
22+
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
2223

2324
import com.nimbusds.jose.JOSEException;
2425
import com.nimbusds.jose.jwk.JWK;
@@ -27,19 +28,16 @@
2728
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
2829

2930
@Configuration
30-
public class Config {
31+
public class SecurityConfig extends WebSecurityConfigurerAdapter {
3132

32-
@Bean
33-
FilterRegistrationBean<JWKSetEndpoint> registerJWKSetEndpoint() throws JOSEException {
34-
FilterRegistrationBean<JWKSetEndpoint> fb = new FilterRegistrationBean<>();
35-
fb.setFilter(new JWKSetEndpoint(generateJwkSet()));
36-
fb.addUrlPatterns("/*");
37-
return fb;
38-
}
33+
@Override
34+
protected void configure(HttpSecurity http) throws Exception {
35+
http.addFilterBefore(new JwkSetEndpointFilter(generateJwkSet()), ChannelProcessingFilter.class);
36+
}
3937

40-
protected JWKSet generateJwkSet() throws JOSEException {
41-
JWK jwk = new RSAKeyGenerator(2048).keyID("minimal-ASA").keyUse(KeyUse.ENCRYPTION).generate();
42-
return new JWKSet(jwk);
43-
}
38+
protected JWKSet generateJwkSet() throws JOSEException {
39+
JWK jwk = new RSAKeyGenerator(2048).keyID("minimal-ASA").keyUse(KeyUse.ENCRYPTION).generate();
40+
return new JWKSet(jwk);
41+
}
4442

4543
}

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
@RestController
2323
public class FakeController {
2424

25-
@RequestMapping("/fake")
26-
public String hello() {
27-
return "fake";
28-
}
25+
@RequestMapping("/fake")
26+
public String hello() {
27+
return "fake";
28+
}
2929
}

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

-75
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright 2020 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+
* https://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 sample;
18+
19+
import static org.junit.jupiter.api.Assertions.assertFalse;
20+
import static org.junit.jupiter.api.Assertions.assertTrue;
21+
import static org.springframework.http.HttpMethod.GET;
22+
import static org.springframework.http.HttpMethod.POST;
23+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
24+
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
25+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
26+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
27+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
28+
import static sample.JwkSetEndpointFilter.WELL_KNOWN_JWK_URIS;
29+
30+
import org.hamcrest.Matchers;
31+
import org.junit.jupiter.api.BeforeAll;
32+
import org.junit.jupiter.api.Test;
33+
import org.junit.jupiter.api.TestInstance;
34+
import org.junit.jupiter.api.TestInstance.Lifecycle;
35+
import org.springframework.mock.web.MockHttpServletRequest;
36+
import org.springframework.test.web.servlet.MockMvc;
37+
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
38+
39+
import com.nimbusds.jose.JOSEException;
40+
import com.nimbusds.jose.jwk.JWK;
41+
import com.nimbusds.jose.jwk.JWKSet;
42+
import com.nimbusds.jose.jwk.KeyUse;
43+
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
44+
45+
@TestInstance(Lifecycle.PER_CLASS)
46+
public class JwkSetEndpointFilterTest {
47+
48+
private MockMvc mvc;
49+
private JWKSet jwkSet;
50+
private JWK jwk;
51+
private JwkSetEndpointFilter filter;
52+
53+
@BeforeAll
54+
void setup() throws JOSEException {
55+
this.jwk = new RSAKeyGenerator(2048).keyID("endpoint-test").keyUse(KeyUse.ENCRYPTION).generate();
56+
this.jwkSet = new JWKSet(jwk);
57+
this.filter = new JwkSetEndpointFilter(jwkSet);
58+
this.mvc = MockMvcBuilders.standaloneSetup(new FakeController()).addFilters(filter)
59+
.alwaysDo(print()).build();
60+
}
61+
62+
@Test
63+
void testRequestMatcher() {
64+
assertTrue(this.filter.ifRequestMatches(new MockHttpServletRequest(GET.name(), WELL_KNOWN_JWK_URIS)));
65+
66+
assertFalse(this.filter.ifRequestMatches(new MockHttpServletRequest(POST.name(), WELL_KNOWN_JWK_URIS)));
67+
assertFalse(this.filter.ifRequestMatches(new MockHttpServletRequest(GET.name(), "/stuff" + WELL_KNOWN_JWK_URIS)));
68+
}
69+
70+
@Test
71+
void testResponseIfRequestMatches() throws Exception {
72+
mvc.perform(get(WELL_KNOWN_JWK_URIS)).andDo(print()).andExpect(status().isOk())
73+
.andExpect(jsonPath("$.keys").isArray()).andExpect(jsonPath("$.keys").isNotEmpty())
74+
.andExpect(jsonPath("$.keys[0].kid").value(jwk.getKeyID()))
75+
.andExpect(jsonPath("$.keys[0].kty").value(jwk.getKeyType().toString()));
76+
}
77+
78+
@Test
79+
void testResponseIfNotRequestMatches() throws Exception {
80+
mvc.perform(get("/fake")).andDo(print()).andExpect(status().isOk())
81+
.andExpect(content().string(Matchers.is("fake")));
82+
}
83+
}

0 commit comments

Comments
 (0)