Skip to content

Commit 7b2c271

Browse files
author
bnasslahsen
committed
Added the support for spring-security-oauth2 authorization server. Fixes #327
1 parent 704f530 commit 7b2c271

23 files changed

+438
-77
lines changed

Diff for: pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
<swagger-api.version>2.1.0</swagger-api.version>
7171
<swagger-ui.version>3.24.0</swagger-ui.version>
7272
<webjars-locator.version>0.38</webjars-locator.version>
73+
<spring-security-oauth2.version>2.3.5.RELEASE</spring-security-oauth2.version>
7374
</properties>
7475

7576
<dependencyManagement>
@@ -101,6 +102,11 @@
101102
<artifactId>webjars-locator</artifactId>
102103
<version>${webjars-locator.version}</version>
103104
</dependency>
105+
<dependency>
106+
<groupId>org.springframework.security.oauth</groupId>
107+
<artifactId>spring-security-oauth2</artifactId>
108+
<version>${spring-security-oauth2.version}</version>
109+
</dependency>
104110
</dependencies>
105111
</dependencyManagement>
106112
<dependencies>

Diff for: springdoc-openapi-common/src/main/java/org/springdoc/core/AbstractRequestBuilder.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ protected Parameter customiseParameter(Parameter parameter, ParameterInfo parame
175175
}
176176

177177
protected boolean isParamToIgnore(java.lang.reflect.Parameter parameter) {
178-
if (parameter.isAnnotationPresent(PathVariable.class)) {
178+
if (parameter.isAnnotationPresent(PathVariable.class) || parameter.isAnnotationPresent(RequestParam.class)) {
179179
return false;
180180
}
181181
return parameterBuilder.isAnnotationToIgnore(parameter) || PARAM_TYPES_TO_IGNORE.contains(parameter.getType()) || (AnnotationUtils.findAnnotation(parameter.getType(), Hidden.class) != null);

Diff for: springdoc-openapi-common/src/main/java/org/springdoc/core/OpenAPIBuilder.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@ public class OpenAPIBuilder {
4242
private final SecurityParser securityParser;
4343
private final Map<HandlerMethod, String> springdocTags = new HashMap<>();
4444
private String serverBaseUrl;
45+
private final Optional<SecurityOAuth2Provider> springSecurityOAuth2Provider;
4546

4647
@SuppressWarnings("WeakerAccess")
47-
OpenAPIBuilder(Optional<OpenAPI> openAPI, ApplicationContext context, SecurityParser securityParser) {
48+
OpenAPIBuilder(Optional<OpenAPI> openAPI, ApplicationContext context, SecurityParser securityParser, Optional<SecurityOAuth2Provider> springSecurityOAuth2Provider) {
4849
if (openAPI.isPresent()) {
4950
this.openAPI = openAPI.get();
5051
if (this.openAPI.getComponents() == null)
@@ -60,6 +61,7 @@ public class OpenAPIBuilder {
6061
}
6162
this.context = context;
6263
this.securityParser = securityParser;
64+
this.springSecurityOAuth2Provider = springSecurityOAuth2Provider;
6365
}
6466

6567
private static String splitCamelCase(String str) {
@@ -308,4 +310,8 @@ public Map<String, Object> getControllerAdviceMap() {
308310
controller -> (AnnotationUtils.findAnnotation(controller.getValue().getClass(), Hidden.class) == null))
309311
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a1, a2) -> a1));
310312
}
313+
314+
public Optional<SecurityOAuth2Provider> getSpringSecurityOAuth2Provider() {
315+
return springSecurityOAuth2Provider;
316+
}
311317
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.springdoc.core;
2+
3+
import java.util.Map;
4+
5+
public interface SecurityOAuth2Provider {
6+
7+
Map getHandlerMethods();
8+
9+
Map<String, Object> getFrameworkEndpoints();
10+
}

Diff for: springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfiguration.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ IgnoredParameterAnnotationsDefault ignoredParameterAnnotationsDefault() {
4646
}
4747

4848
@Bean
49-
public OpenAPIBuilder openAPIBuilder(Optional<OpenAPI> openAPI, ApplicationContext context, SecurityParser securityParser) {
50-
return new OpenAPIBuilder(openAPI, context, securityParser);
49+
public OpenAPIBuilder openAPIBuilder(Optional<OpenAPI> openAPI, ApplicationContext context, SecurityParser securityParser,Optional<SecurityOAuth2Provider> springSecurityOAuth2Provider) {
50+
return new OpenAPIBuilder(openAPI, context, securityParser,springSecurityOAuth2Provider);
5151
}
5252

5353
@Bean

Diff for: springdoc-openapi-security/pom.xml

+11-1
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,22 @@
2020
<groupId>org.springframework.security</groupId>
2121
<artifactId>spring-security-core</artifactId>
2222
</dependency>
23+
<dependency>
24+
<groupId>org.springframework.security.oauth</groupId>
25+
<artifactId>spring-security-oauth2</artifactId>
26+
<optional>true</optional>
27+
</dependency>
2328
<dependency>
2429
<groupId>org.springdoc</groupId>
25-
<artifactId>springdoc-openapi-webflux-core</artifactId>
30+
<artifactId>springdoc-openapi-webmvc-core</artifactId>
2631
<version>${project.version}</version>
2732
<scope>test</scope>
2833
</dependency>
34+
<dependency>
35+
<groupId>javax.servlet</groupId>
36+
<artifactId>javax.servlet-api</artifactId>
37+
<scope>provided</scope>
38+
</dependency>
2939
<dependency>
3040
<groupId>org.hibernate.validator</groupId>
3141
<artifactId>hibernate-validator</artifactId>

Diff for: springdoc-openapi-security/src/main/java/org/springdoc/core/SpringDocSecurityConfiguration.java

+7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package org.springdoc.core;
22

3+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
34
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
45
import org.springframework.context.annotation.Bean;
56
import org.springframework.context.annotation.Configuration;
67
import org.springframework.context.annotation.Primary;
8+
import org.springframework.security.oauth2.provider.endpoint.FrameworkEndpointHandlerMapping;
79

810
import static org.springdoc.core.Constants.SPRINGDOC_ENABLED;
911

@@ -22,4 +24,9 @@ IgnoredParameterTypes ignoredParameterTypes() {
2224
return new IgnoredParameterTypes();
2325
}
2426

27+
@Bean
28+
@ConditionalOnBean(FrameworkEndpointHandlerMapping.class)
29+
public SpringSecurityOAuth2Provider springSecurityOAuth2Provider(FrameworkEndpointHandlerMapping oauth2EndpointHandlerMapping) {
30+
return new SpringSecurityOAuth2Provider(oauth2EndpointHandlerMapping);
31+
}
2532
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.springdoc.core;
2+
3+
import org.springframework.security.oauth2.provider.endpoint.FrameworkEndpoint;
4+
import org.springframework.security.oauth2.provider.endpoint.FrameworkEndpointHandlerMapping;
5+
import org.springframework.web.method.HandlerMethod;
6+
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
7+
8+
import java.util.Map;
9+
10+
public class SpringSecurityOAuth2Provider implements SecurityOAuth2Provider {
11+
12+
private FrameworkEndpointHandlerMapping oauth2EndpointHandlerMapping;
13+
14+
public SpringSecurityOAuth2Provider(FrameworkEndpointHandlerMapping oauth2EndpointHandlerMapping) {
15+
this.oauth2EndpointHandlerMapping = oauth2EndpointHandlerMapping;
16+
}
17+
18+
public FrameworkEndpointHandlerMapping getOauth2EndpointHandlerMapping() {
19+
return oauth2EndpointHandlerMapping;
20+
}
21+
22+
@Override
23+
public Map<RequestMappingInfo, HandlerMethod> getHandlerMethods() {
24+
return oauth2EndpointHandlerMapping.getHandlerMethods();
25+
}
26+
27+
@Override
28+
public Map getFrameworkEndpoints(){
29+
return oauth2EndpointHandlerMapping.getApplicationContext().getBeansWithAnnotation(FrameworkEndpoint.class);
30+
}
31+
32+
}

Diff for: springdoc-openapi-security/src/test/java/test/org/springdoc/api/AbstractSpringDocTest.java

+27-14
Original file line numberDiff line numberDiff line change
@@ -3,45 +3,58 @@
33
import com.fasterxml.jackson.databind.ObjectMapper;
44
import org.junit.Test;
55
import org.junit.runner.RunWith;
6+
import org.skyscreamer.jsonassert.JSONAssert;
67
import org.springdoc.core.Constants;
78
import org.springframework.beans.factory.annotation.Autowired;
8-
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
9+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
10+
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
11+
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
12+
import org.springframework.boot.test.context.SpringBootTest;
13+
import org.springframework.context.annotation.Configuration;
914
import org.springframework.test.context.ActiveProfiles;
1015
import org.springframework.test.context.junit4.SpringRunner;
11-
import org.springframework.test.web.reactive.server.EntityExchangeResult;
12-
import org.springframework.test.web.reactive.server.WebTestClient;
16+
import org.springframework.test.web.servlet.MockMvc;
17+
import org.springframework.test.web.servlet.MvcResult;
1318

1419
import java.nio.file.Files;
1520
import java.nio.file.Path;
1621
import java.nio.file.Paths;
1722

18-
import static org.junit.Assert.assertEquals;
23+
import static org.hamcrest.Matchers.is;
24+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
25+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
26+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
1927

2028
@RunWith(SpringRunner.class)
21-
@WebFluxTest
29+
@SpringBootTest
2230
@ActiveProfiles("test")
31+
@AutoConfigureMockMvc
2332
public abstract class AbstractSpringDocTest {
2433

34+
public static String className;
35+
2536
@Autowired
26-
private WebTestClient webTestClient;
37+
protected MockMvc mockMvc;
2738

2839
@Autowired
2940
private ObjectMapper objectMapper;
3041

42+
@Configuration
43+
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class})
44+
static class ContextConfiguration { }
45+
3146
@Test
3247
public void testApp() throws Exception {
33-
EntityExchangeResult<byte[]> getResult = webTestClient.get().uri(Constants.DEFAULT_API_DOCS_URL).exchange()
34-
.expectStatus().isOk().expectBody().returnResult();
35-
36-
String result = new String(getResult.getResponseBody());
37-
String className = getClass().getSimpleName();
48+
className = getClass().getSimpleName();
3849
String testNumber = className.replaceAll("[^0-9]", "");
39-
50+
MvcResult mockMvcResult = mockMvc.perform(get(Constants.DEFAULT_API_DOCS_URL)).andExpect(status().isOk())
51+
.andExpect(jsonPath("$.openapi", is("3.0.1"))).andReturn();
52+
String result = mockMvcResult.getResponse().getContentAsString();
4053
Path path = Paths.get(getClass().getClassLoader().getResource("results/app" + testNumber + ".json").toURI());
4154
byte[] fileBytes = Files.readAllBytes(path);
4255
String expected = new String(fileBytes);
43-
44-
assertEquals(objectMapper.readTree(expected), objectMapper.readTree(result));
56+
JSONAssert.assertEquals(expected, result, true);
4557
}
4658

59+
4760
}
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
11
package test.org.springdoc.api.app1;
22

3+
import io.swagger.v3.oas.models.OpenAPI;
4+
import io.swagger.v3.oas.models.info.Info;
5+
import io.swagger.v3.oas.models.info.License;
6+
import org.springframework.boot.autoconfigure.SpringBootApplication;
7+
import org.springframework.context.annotation.Bean;
38
import test.org.springdoc.api.AbstractSpringDocTest;
49

510
public class SpringDocApp1Test extends AbstractSpringDocTest {
611

12+
@SpringBootApplication(scanBasePackages = {"test.org.springdoc.api.configuration,test.org.springdoc.api.app1"})
13+
static class SpringDocTestApp {
14+
@Bean
15+
public OpenAPI customOpenAPI() {
16+
return new OpenAPI()
17+
.info(new Info().title("Security API").version("v1")
18+
.license(new License().name("Apache 2.0").url("http://springdoc.org")));
19+
}
20+
}
721
}

Diff for: springdoc-openapi-security/src/test/java/test/org/springdoc/api/app1/SpringDocTestApp.java

-24
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
11
package test.org.springdoc.api.app2;
22

3+
import io.swagger.v3.oas.models.OpenAPI;
4+
import io.swagger.v3.oas.models.info.Info;
5+
import io.swagger.v3.oas.models.info.License;
6+
import org.springframework.boot.autoconfigure.SpringBootApplication;
7+
import org.springframework.context.annotation.Bean;
38
import test.org.springdoc.api.AbstractSpringDocTest;
49

510
public class SpringDocApp2Test extends AbstractSpringDocTest {
611

12+
@SpringBootApplication(scanBasePackages = {"test.org.springdoc.api.configuration,test.org.springdoc.api.app2"})
13+
static class SpringDocTestApp {
14+
@Bean
15+
public OpenAPI customOpenAPI() {
16+
return new OpenAPI()
17+
.info(new Info().title("Security API").version("v1")
18+
.license(new License().name("Apache 2.0").url("http://springdoc.org")));
19+
}
20+
}
21+
722
}

Diff for: springdoc-openapi-security/src/test/java/test/org/springdoc/api/app2/SpringDocTestApp.java

-24
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package test.org.springdoc.api.app3;
2+
3+
import org.junit.Test;
4+
import org.springframework.boot.SpringBootConfiguration;
5+
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
6+
7+
import static org.assertj.core.api.Assertions.assertThat;
8+
9+
public class SpringOauth2Test {
10+
11+
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
12+
.withUserConfiguration(TestApp.class);
13+
14+
@Test
15+
public void configurations_successfully_loaded() {
16+
contextRunner
17+
.run(context -> assertThat(context)
18+
.hasNotFailed()
19+
.doesNotHaveBean("springSecurityOAuth2Provider")
20+
);
21+
}
22+
23+
@SpringBootConfiguration
24+
static class TestApp {
25+
}
26+
27+
}

0 commit comments

Comments
 (0)