Skip to content

Commit 84b3bca

Browse files
author
bnasslahsen
committed
Disable security for one operation using @SecurityRequirements. Fixes #259
1 parent ae79660 commit 84b3bca

File tree

6 files changed

+191
-14
lines changed

6 files changed

+191
-14
lines changed

Diff for: CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [UnReleased] -
8+
79
## [1.2.28] -
810
## Changed
911
- Upgrade to spring-boot to 2.2.4.RELEASE

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

+8-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
package org.springdoc.core;
2020

2121
import java.util.ArrayList;
22+
import java.util.Collections;
2223
import java.util.HashMap;
2324
import java.util.HashSet;
2425
import java.util.List;
@@ -191,9 +192,14 @@ public Operation buildTags(HandlerMethod handlerMethod, Operation operation, Ope
191192
}
192193

193194
// Handle SecurityRequirement at operation level
194-
Optional<io.swagger.v3.oas.annotations.security.SecurityRequirement[]> securityRequirement = securityParser
195+
io.swagger.v3.oas.annotations.security.SecurityRequirement[] securityRequirements = securityParser
195196
.getSecurityRequirements(handlerMethod);
196-
securityRequirement.ifPresent(securityRequirements -> securityParser.buildSecurityRequirement(securityRequirements, operation));
197+
if (securityRequirements != null) {
198+
if (securityRequirements.length == 0)
199+
operation.setSecurity(Collections.emptyList());
200+
else
201+
securityParser.buildSecurityRequirement(securityRequirements, operation);
202+
}
197203

198204
if (!CollectionUtils.isEmpty(tagsStr)) {
199205
operation.setTags(new ArrayList<>(tagsStr));

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

+14-12
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ private static boolean isEmpty(OAuthScope[] scopes) {
8181
return result;
8282
}
8383

84-
public Optional<io.swagger.v3.oas.annotations.security.SecurityRequirement[]> getSecurityRequirements(
84+
public io.swagger.v3.oas.annotations.security.SecurityRequirement[] getSecurityRequirements(
8585
HandlerMethod method) {
8686
// class SecurityRequirements
8787
io.swagger.v3.oas.annotations.security.SecurityRequirements classSecurity = ReflectionUtils
@@ -90,16 +90,16 @@ public Optional<io.swagger.v3.oas.annotations.security.SecurityRequirement[]> ge
9090
io.swagger.v3.oas.annotations.security.SecurityRequirements methodSecurity = ReflectionUtils
9191
.getAnnotation(method.getMethod(), io.swagger.v3.oas.annotations.security.SecurityRequirements.class);
9292

93-
Set<io.swagger.v3.oas.annotations.security.SecurityRequirement> allSecurityTags = new HashSet<>();
93+
Set<io.swagger.v3.oas.annotations.security.SecurityRequirement> allSecurityTags = null;
9494

9595
if (classSecurity != null) {
96-
allSecurityTags.addAll(Arrays.asList(classSecurity.value()));
96+
allSecurityTags = new HashSet<>(Arrays.asList(classSecurity.value()));
9797
}
9898
if (methodSecurity != null) {
99-
allSecurityTags.addAll(Arrays.asList(methodSecurity.value()));
99+
allSecurityTags = addSecurityRequirements(allSecurityTags, Arrays.asList(methodSecurity.value()));
100100
}
101101

102-
if (allSecurityTags.isEmpty()) {
102+
if (CollectionUtils.isEmpty(allSecurityTags)) {
103103
// class SecurityRequirement
104104
List<io.swagger.v3.oas.annotations.security.SecurityRequirement> securityRequirementsClassList = ReflectionUtils
105105
.getRepeatableAnnotations(method.getBeanType(),
@@ -109,19 +109,21 @@ public Optional<io.swagger.v3.oas.annotations.security.SecurityRequirement[]> ge
109109
.getRepeatableAnnotations(method.getMethod(),
110110
io.swagger.v3.oas.annotations.security.SecurityRequirement.class);
111111
if (!CollectionUtils.isEmpty(securityRequirementsClassList)) {
112-
allSecurityTags.addAll(securityRequirementsClassList);
112+
allSecurityTags = addSecurityRequirements(allSecurityTags, securityRequirementsClassList);
113113
}
114114
if (!CollectionUtils.isEmpty(securityRequirementsMethodList)) {
115-
allSecurityTags.addAll(securityRequirementsMethodList);
115+
allSecurityTags = addSecurityRequirements(allSecurityTags, securityRequirementsMethodList);
116116
}
117117
}
118118

119-
if (allSecurityTags.isEmpty()) {
120-
return Optional.empty();
121-
}
119+
return (allSecurityTags != null) ? allSecurityTags.toArray(new io.swagger.v3.oas.annotations.security.SecurityRequirement[0]) : null;
120+
}
122121

123-
return Optional.of(
124-
allSecurityTags.toArray(new io.swagger.v3.oas.annotations.security.SecurityRequirement[0]));
122+
private Set<io.swagger.v3.oas.annotations.security.SecurityRequirement> addSecurityRequirements(Set<io.swagger.v3.oas.annotations.security.SecurityRequirement> allSecurityTags, List<io.swagger.v3.oas.annotations.security.SecurityRequirement> securityRequirementsClassList) {
123+
if (allSecurityTags == null)
124+
allSecurityTags = new HashSet<>();
125+
allSecurityTags.addAll(securityRequirementsClassList);
126+
return allSecurityTags;
125127
}
126128

127129
public Optional<List<SecurityRequirement>> getSecurityRequirements(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
*
3+
* * Copyright 2019-2020 the original author or authors.
4+
* *
5+
* * Licensed under the Apache License, Version 2.0 (the "License");
6+
* * you may not use this file except in compliance with the License.
7+
* * You may obtain a copy of the License at
8+
* *
9+
* * https://www.apache.org/licenses/LICENSE-2.0
10+
* *
11+
* * Unless required by applicable law or agreed to in writing, software
12+
* * distributed under the License is distributed on an "AS IS" BASIS,
13+
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* * See the License for the specific language governing permissions and
15+
* * limitations under the License.
16+
*
17+
*/
18+
19+
package test.org.springdoc.api.app76;
20+
21+
import io.swagger.v3.oas.annotations.security.SecurityRequirements;
22+
23+
import org.springframework.web.bind.annotation.GetMapping;
24+
import org.springframework.web.bind.annotation.ResponseBody;
25+
import org.springframework.web.bind.annotation.RestController;
26+
27+
28+
@RestController
29+
public class HelloController {
30+
31+
@GetMapping("/secure")
32+
@ResponseBody
33+
public String secured() {
34+
return "It works!";
35+
}
36+
37+
@GetMapping("/open")
38+
@ResponseBody
39+
@SecurityRequirements
40+
public String open() {
41+
return "It works!";
42+
}
43+
44+
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
*
3+
* * Copyright 2019-2020 the original author or authors.
4+
* *
5+
* * Licensed under the Apache License, Version 2.0 (the "License");
6+
* * you may not use this file except in compliance with the License.
7+
* * You may obtain a copy of the License at
8+
* *
9+
* * https://www.apache.org/licenses/LICENSE-2.0
10+
* *
11+
* * Unless required by applicable law or agreed to in writing, software
12+
* * distributed under the License is distributed on an "AS IS" BASIS,
13+
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* * See the License for the specific language governing permissions and
15+
* * limitations under the License.
16+
*
17+
*/
18+
19+
package test.org.springdoc.api.app76;
20+
21+
import java.util.Arrays;
22+
23+
import io.swagger.v3.oas.models.Components;
24+
import io.swagger.v3.oas.models.OpenAPI;
25+
import io.swagger.v3.oas.models.security.SecurityRequirement;
26+
import io.swagger.v3.oas.models.security.SecurityScheme;
27+
import test.org.springdoc.api.AbstractSpringDocTest;
28+
29+
import org.springframework.boot.autoconfigure.SpringBootApplication;
30+
import org.springframework.context.annotation.Bean;
31+
32+
public class SpringDocApp76Test extends AbstractSpringDocTest {
33+
34+
@SpringBootApplication
35+
static class SpringDocTestApp {
36+
@Bean
37+
public OpenAPI openAPI() {
38+
return new OpenAPI()
39+
.components(new Components().addSecuritySchemes("bearer-jwt",
40+
new SecurityScheme()
41+
.type(SecurityScheme.Type.HTTP)
42+
.scheme("bearer")
43+
.bearerFormat("JWT"))
44+
)
45+
.addSecurityItem(
46+
new SecurityRequirement().addList("bearer-jwt", Arrays.asList("read", "write")));
47+
}
48+
}
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
{
2+
"openapi": "3.0.1",
3+
"info": {
4+
"title": "OpenAPI definition",
5+
"version": "v0"
6+
},
7+
"servers": [
8+
{
9+
"url": "http://localhost",
10+
"description": "Generated server url"
11+
}
12+
],
13+
"security": [
14+
{
15+
"bearer-jwt": [
16+
"read",
17+
"write"
18+
]
19+
}
20+
],
21+
"paths": {
22+
"/open": {
23+
"get": {
24+
"tags": [
25+
"hello-controller"
26+
],
27+
"operationId": "open",
28+
"responses": {
29+
"200": {
30+
"description": "default response",
31+
"content": {
32+
"*/*": {
33+
"schema": {
34+
"type": "string"
35+
}
36+
}
37+
}
38+
}
39+
},
40+
"security": []
41+
}
42+
},
43+
"/secure": {
44+
"get": {
45+
"tags": [
46+
"hello-controller"
47+
],
48+
"operationId": "secured",
49+
"responses": {
50+
"200": {
51+
"description": "default response",
52+
"content": {
53+
"*/*": {
54+
"schema": {
55+
"type": "string"
56+
}
57+
}
58+
}
59+
}
60+
}
61+
}
62+
}
63+
},
64+
"components": {
65+
"securitySchemes": {
66+
"bearer-jwt": {
67+
"type": "http",
68+
"scheme": "bearer",
69+
"bearerFormat": "JWT"
70+
}
71+
}
72+
}
73+
}

0 commit comments

Comments
 (0)