Skip to content

Commit 0e94356

Browse files
authored
Merge pull request quarkusio#47933 from phillip-kruger/openapi-auto-security-fix
OpenAPI Auto security works with enabled-in-dev config from security
2 parents bcd0cb5 + 59bf81c commit 0e94356

File tree

3 files changed

+117
-7
lines changed

3 files changed

+117
-7
lines changed

extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -206,13 +206,14 @@ void registerAutoSecurityFilter(BuildProducer<SyntheticBeanBuildItem> syntheticB
206206
SmallRyeOpenApiConfig openApiConfig,
207207
OpenApiFilteredIndexViewBuildItem apiFilteredIndexViewBuildItem,
208208
List<SecurityInformationBuildItem> securityInformationBuildItems,
209-
OpenApiRecorder recorder) {
209+
OpenApiRecorder recorder,
210+
LaunchModeBuildItem launchMode) {
210211
AutoSecurityFilter autoSecurityFilter = null;
211212

212-
if (openApiConfig.autoAddSecurity()) {
213+
if (securityConfig(launchMode, openApiConfig::autoAddSecurity)) {
213214
autoSecurityFilter = getAutoSecurityFilter(securityInformationBuildItems, openApiConfig)
214215
.filter(securityFilter -> autoSecurityRuntimeEnabled(securityFilter,
215-
() -> hasAutoEndpointSecurity(apiFilteredIndexViewBuildItem, openApiConfig)))
216+
() -> hasAutoEndpointSecurity(apiFilteredIndexViewBuildItem, launchMode, openApiConfig)))
216217
.orElse(null);
217218
}
218219

@@ -339,6 +340,21 @@ void handler(LaunchModeBuildItem launch,
339340
}
340341
}
341342

343+
private boolean securityConfig(
344+
LaunchModeBuildItem launchMode,
345+
Supplier<Boolean> securitySetting) {
346+
347+
if (launchMode.getLaunchMode().equals(LaunchMode.DEVELOPMENT)) {
348+
Config config = ConfigProvider.getConfig();
349+
boolean authEnabled = config.getValue("quarkus.security.auth.enabled-in-dev-mode", Boolean.class);
350+
if (authEnabled)
351+
return securitySetting.get();
352+
return false;
353+
} else {
354+
return securitySetting.get();
355+
}
356+
}
357+
342358
private String getManagementRoot(LaunchModeBuildItem launch,
343359
NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem,
344360
SmallRyeOpenApiConfig openApiConfig,
@@ -399,14 +415,14 @@ void addAutoFilters(BuildProducer<AddToOpenAPIDefinitionBuildItem> addToOpenAPID
399415
addToOpenAPIDefinitionProducer
400416
.produce(new AddToOpenAPIDefinitionBuildItem(
401417
new SecurityConfigFilter(config)));
402-
} else if (config.autoAddSecurity()) {
418+
} else if (securityConfig(launchModeBuildItem, config::autoAddSecurity)) {
403419
getAutoSecurityFilter(securityInformationBuildItems, config)
404420
.map(AddToOpenAPIDefinitionBuildItem::new)
405421
.ifPresent(addToOpenAPIDefinitionProducer::produce);
406422
}
407423

408424
// Add operation filter to add tags/descriptions/security requirements
409-
OASFilter operationFilter = getOperationFilter(apiFilteredIndexViewBuildItem, config);
425+
OASFilter operationFilter = getOperationFilter(apiFilteredIndexViewBuildItem, launchModeBuildItem, config);
410426

411427
if (operationFilter != null) {
412428
addToOpenAPIDefinitionProducer.produce(new AddToOpenAPIDefinitionBuildItem(operationFilter));
@@ -517,9 +533,10 @@ private Optional<AutoSecurityFilter> getAutoSecurityFilter(List<SecurityInformat
517533

518534
private boolean hasAutoEndpointSecurity(
519535
OpenApiFilteredIndexViewBuildItem indexViewBuildItem,
536+
LaunchModeBuildItem launchMode,
520537
SmallRyeOpenApiConfig config) {
521538

522-
if (config.autoAddSecurityRequirement()) {
539+
if (securityConfig(launchMode, config::autoAddSecurityRequirement)) {
523540
Map<String, List<String>> rolesAllowedMethods = Collections.emptyMap();
524541
List<String> authenticatedMethods = Collections.emptyList();
525542

@@ -538,6 +555,7 @@ private boolean hasAutoEndpointSecurity(
538555
}
539556

540557
private OASFilter getOperationFilter(OpenApiFilteredIndexViewBuildItem indexViewBuildItem,
558+
LaunchModeBuildItem launchMode,
541559
SmallRyeOpenApiConfig config) {
542560

543561
Map<String, ClassAndMethod> classNamesMethods = Collections.emptyMap();
@@ -548,7 +566,7 @@ private OASFilter getOperationFilter(OpenApiFilteredIndexViewBuildItem indexView
548566
classNamesMethods = getClassNamesMethodReferences(indexViewBuildItem);
549567
}
550568

551-
if (config.autoAddSecurityRequirement()) {
569+
if (securityConfig(launchMode, config::autoAddSecurityRequirement)) {
552570
rolesAllowedMethods = getRolesAllowedMethodReferences(indexViewBuildItem);
553571

554572
for (String methodRef : getPermissionsAllowedMethodReferences(indexViewBuildItem)) {
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package io.quarkus.smallrye.openapi.test.jaxrs;
2+
3+
import static org.hamcrest.Matchers.equalTo;
4+
import static org.hamcrest.Matchers.notNullValue;
5+
import static org.hamcrest.Matchers.nullValue;
6+
7+
import org.jboss.shrinkwrap.api.asset.StringAsset;
8+
import org.junit.jupiter.api.Test;
9+
import org.junit.jupiter.api.extension.RegisterExtension;
10+
11+
import io.quarkus.test.QuarkusDevModeTest;
12+
import io.restassured.RestAssured;
13+
14+
public class AutoSecurityDisabledTestCase {
15+
16+
@RegisterExtension
17+
final static QuarkusDevModeTest TEST = new QuarkusDevModeTest()
18+
.withApplicationRoot((jar) -> jar
19+
.addClasses(OpenApiWithSecurity.class)
20+
.addAsResource(
21+
new StringAsset("quarkus.security.auth.enabled-in-dev-mode=false"),
22+
"application.properties"));
23+
24+
@Test
25+
void testAutoSecurityRequirement() {
26+
27+
RestAssured.given()
28+
.header("Accept", "application/json")
29+
.when()
30+
.get("/q/openapi")
31+
.then()
32+
.log().body()
33+
.and()
34+
// Make sure `security` is NOT present
35+
.body("paths.'/openApiWithSecurity/test-security/annotated'.get.security", nullValue())
36+
.body("paths.'/openApiWithSecurity/test-security/annotated2'.get.security", nullValue())
37+
.body("paths.'/openApiWithSecurity/test-security/naked'.get.security", nullValue())
38+
// Make sure only 200 response is present
39+
.body("paths.'/openApiWithSecurity/test-security/annotated'.get.responses.size()", equalTo(1))
40+
.body("paths.'/openApiWithSecurity/test-security/annotated'.get.responses['200']", notNullValue())
41+
.body("paths.'/openApiWithSecurity/test-security/annotated'.get.responses['401']", nullValue())
42+
.body("paths.'/openApiWithSecurity/test-security/annotated'.get.responses['403']", nullValue())
43+
.body("paths.'/openApiWithSecurity/test-security/annotated2'.get.responses.size()", equalTo(1))
44+
.body("paths.'/openApiWithSecurity/test-security/annotated2'.get.responses['200']", notNullValue())
45+
.body("paths.'/openApiWithSecurity/test-security/annotated2'.get.responses['401']", nullValue())
46+
.body("paths.'/openApiWithSecurity/test-security/annotated2'.get.responses['403']", nullValue())
47+
.body("paths.'/openApiWithSecurity/test-security/naked'.get.responses.size()", equalTo(1))
48+
.body("paths.'/openApiWithSecurity/test-security/naked'.get.responses['200']", notNullValue())
49+
.body("paths.'/openApiWithSecurity/test-security/naked'.get.responses['401']", nullValue())
50+
.body("paths.'/openApiWithSecurity/test-security/naked'.get.responses['403']", nullValue());
51+
}
52+
53+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package io.quarkus.smallrye.openapi.test.jaxrs;
2+
3+
import jakarta.annotation.security.RolesAllowed;
4+
import jakarta.ws.rs.GET;
5+
import jakarta.ws.rs.Path;
6+
7+
import io.quarkus.security.Authenticated;
8+
9+
@Path("/openApiWithSecurity")
10+
public class OpenApiWithSecurity {
11+
12+
@GET
13+
@Path("/test-security/naked")
14+
@Authenticated
15+
public String secureEndpointWithoutSecurityAnnotation() {
16+
return "secret";
17+
}
18+
19+
@GET
20+
@Path("/test-security/annotated")
21+
@RolesAllowed("admin")
22+
public String secureEndpointWithRolesAllowedAnnotation() {
23+
return "secret";
24+
}
25+
26+
@GET
27+
@Path("/test-security/annotated2")
28+
@RolesAllowed("user")
29+
public String secureEndpointWithRolesAllowed2Annotation() {
30+
return "secret";
31+
}
32+
33+
@GET
34+
@Path("/test-security/public")
35+
public String publicEndpoint() {
36+
return "boo";
37+
}
38+
39+
}

0 commit comments

Comments
 (0)