Skip to content

Commit e7f21d8

Browse files
committed
Clean up callbacks and web hooks
1 parent 6a7ae3e commit e7f21d8

3 files changed

Lines changed: 174 additions & 20 deletions

File tree

modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,7 @@ private void cleanupSecuritySchemeReferences(Iterable<String> schemesToClean) {
679679
return;
680680
}
681681

682-
// clean up global security requirements
682+
// Global security requirements
683683
if (openAPI.getSecurity() != null) {
684684
List<SecurityRequirement> cleanRequirements = cleanupSecurityRequirements(openAPI.getSecurity(),
685685
schemesToClean);
@@ -688,24 +688,58 @@ private void cleanupSecuritySchemeReferences(Iterable<String> schemesToClean) {
688688
}
689689
}
690690

691-
// loop through all the paths and operations to clean up the references
691+
// Paths
692692
if (openAPI.getPaths() != null) {
693693
for (PathItem path : openAPI.getPaths().values()) {
694-
List<Operation> operations = new ArrayList<>(path.readOperations());
695-
for (Operation operation : operations) {
696-
if (operation.getSecurity() == null) {
697-
continue;
698-
}
694+
cleanupPathItemSecuritySchemes(path, schemesToClean);
695+
}
696+
}
699697

700-
List<SecurityRequirement> cleanRequirements = cleanupSecurityRequirements(operation.getSecurity(), schemesToClean);
701-
if (cleanRequirements.size() != operation.getSecurity().size()) {
702-
operation.setSecurity(cleanRequirements);
703-
}
698+
// Webhooks
699+
if (openAPI.getWebhooks() != null) {
700+
for (PathItem path : openAPI.getWebhooks().values()) {
701+
cleanupPathItemSecuritySchemes(path, schemesToClean);
702+
}
703+
}
704+
705+
// Callbacks
706+
if (openAPI.getComponents() != null && openAPI.getComponents().getCallbacks() != null) {
707+
Map<String, Callback> callbacks = openAPI.getComponents().getCallbacks();
708+
for (Callback callback : callbacks.values()) {
709+
if (callback == null)
710+
continue;
711+
712+
for (PathItem path : callback.values()) {
713+
cleanupPathItemSecuritySchemes(path, schemesToClean);
704714
}
705715
}
706716
}
707717
}
708718

719+
/**
720+
* Cleans up the references to the security schemes that are removed by the filter in a given PathItem.
721+
* @param path the PathItem to clean up
722+
* @param schemesToClean the security schemes keys to remove
723+
*/
724+
private void cleanupPathItemSecuritySchemes(PathItem path, Iterable<String> schemesToClean) {
725+
if (path == null || schemesToClean == null) {
726+
return;
727+
}
728+
729+
List<Operation> operations = new ArrayList<>(path.readOperations());
730+
for (Operation operation : operations) {
731+
if (operation.getSecurity() == null) {
732+
continue;
733+
}
734+
735+
List<SecurityRequirement> cleanRequirements = cleanupSecurityRequirements(operation.getSecurity(),
736+
schemesToClean);
737+
if (cleanRequirements.size() != operation.getSecurity().size()) {
738+
operation.setSecurity(cleanRequirements);
739+
}
740+
}
741+
}
742+
709743
/**
710744
* Removes given security schemes from the list of security requirements and remove the requirement if it becomes empty after the cleanup.
711745
*

modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenAPINormalizerTest.java

Lines changed: 76 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -948,8 +948,8 @@ public void testSecuritySchemesFilter() {
948948
assertEquals(openAPI.getComponents().getSecuritySchemes().containsKey("openIdConnect1"), false);
949949
assertEquals(openAPI.getComponents().getSecuritySchemes().containsKey("openIdConnect2"), false);
950950

951-
// Check how we clean up the references to the removed security schemes in the
952-
// global security requirement
951+
// Check how we clean up the references to the removed security schemes
952+
// Global security requirements
953953
assertTrue(openAPI.getSecurity().stream().anyMatch(map -> map.containsKey("api_key1")));
954954
assertFalse(openAPI.getSecurity().stream().anyMatch(map -> map.containsKey("api_key2")));
955955
assertFalse(openAPI.getSecurity().stream().anyMatch(map -> map.containsKey("http1")));
@@ -963,8 +963,7 @@ public void testSecuritySchemesFilter() {
963963
// We should leave only one (the original one) empty security requirement object
964964
assertEquals(openAPI.getSecurity().stream().filter(map -> map.isEmpty()).count(), 1);
965965

966-
// Check how we clean up the references to the removed security schemes in the
967-
// paths
966+
// Paths
968967
assertTrue(openAPI.getPaths().get("/api_keys").getGet().getSecurity().stream()
969968
.anyMatch(map -> map.containsKey("api_key1")));
970969
assertFalse(openAPI.getPaths().get("/api_keys").getGet().getSecurity().stream()
@@ -1005,14 +1004,82 @@ public void testSecuritySchemesFilter() {
10051004
.anyMatch(map -> map.containsKey("openIdConnect1")));
10061005
assertFalse(openAPI.getPaths().get("/openIdConnect2").getPost().getSecurity().stream()
10071006
.anyMatch(map -> map.containsKey("openIdConnect2")));
1008-
// One of security requirements becomes empty after clean up - we should remove it
1007+
// One of security requirements becomes empty after clean up - we should remove
1008+
// it
10091009
assertEquals(openAPI.getPaths().get("/multipleSecuritySchemes").getGet().getSecurity().size(), 1);
10101010
// Another requirement should contain only api_key1 and oauth2_1 schemes
10111011
assertEquals(openAPI.getPaths().get("/multipleSecuritySchemes").getGet().getSecurity().get(0).size(), 2);
1012-
assertTrue(openAPI.getPaths().get("/multipleSecuritySchemes").getGet().getSecurity().get(0).containsKey("api_key1"));
1013-
assertTrue(openAPI.getPaths().get("/multipleSecuritySchemes").getGet().getSecurity().get(0).containsKey("oauth2_1"));
1014-
assertEquals(openAPI.getPaths().get("/multipleSecuritySchemes").getGet().getSecurity().get(0).get("oauth2_1").size(), 1);
1015-
assertEquals(openAPI.getPaths().get("/multipleSecuritySchemes").getGet().getSecurity().get(0).get("oauth2_1").get(0), "read:pets");
1012+
assertTrue(openAPI.getPaths().get("/multipleSecuritySchemes").getGet().getSecurity().get(0)
1013+
.containsKey("api_key1"));
1014+
assertTrue(openAPI.getPaths().get("/multipleSecuritySchemes").getGet().getSecurity().get(0)
1015+
.containsKey("oauth2_1"));
1016+
assertEquals(
1017+
openAPI.getPaths().get("/multipleSecuritySchemes").getGet().getSecurity().get(0).get("oauth2_1").size(),
1018+
1);
1019+
assertEquals(
1020+
openAPI.getPaths().get("/multipleSecuritySchemes").getGet().getSecurity().get(0).get("oauth2_1").get(0),
1021+
"read:pets");
1022+
1023+
// Webhooks
1024+
assertTrue(openAPI.getWebhooks().get("webhookAllSecuritySchemes").getPost().getSecurity().stream()
1025+
.anyMatch(map -> map.containsKey("api_key1")));
1026+
assertFalse(openAPI.getWebhooks().get("webhookAllSecuritySchemes").getPost().getSecurity().stream()
1027+
.anyMatch(map -> map.containsKey("api_key2")));
1028+
assertFalse(openAPI.getWebhooks().get("webhookAllSecuritySchemes").getPost().getSecurity().stream()
1029+
.anyMatch(map -> map.containsKey("http1")));
1030+
assertFalse(openAPI.getWebhooks().get("webhookAllSecuritySchemes").getPost().getSecurity().stream()
1031+
.anyMatch(map -> map.containsKey("http2")));
1032+
assertFalse(openAPI.getWebhooks().get("webhookAllSecuritySchemes").getPost().getSecurity().stream()
1033+
.anyMatch(map -> map.containsKey("mutualTLS1")));
1034+
assertFalse(openAPI.getWebhooks().get("webhookAllSecuritySchemes").getPost().getSecurity().stream()
1035+
.anyMatch(map -> map.containsKey("mutualTLS2")));
1036+
assertTrue(openAPI.getWebhooks().get("webhookAllSecuritySchemes").getPost().getSecurity().stream()
1037+
.anyMatch(map -> map.containsKey("oauth2_1")));
1038+
assertTrue(openAPI.getWebhooks().get("webhookAllSecuritySchemes").getPost().getSecurity().stream()
1039+
.anyMatch(map -> map.containsKey("oauth2_2")));
1040+
assertFalse(openAPI.getWebhooks().get("webhookAllSecuritySchemes").getPost().getSecurity().stream()
1041+
.anyMatch(map -> map.containsKey("openIdConnect1")));
1042+
assertFalse(openAPI.getWebhooks().get("webhookAllSecuritySchemes").getPost().getSecurity().stream()
1043+
.anyMatch(map -> map.containsKey("openIdConnect2")));
1044+
// We should leave only one (the original one) empty security requirement object
1045+
assertEquals(openAPI.getWebhooks().get("webhookAllSecuritySchemes").getPost().getSecurity().stream()
1046+
.filter(map -> map.isEmpty()).count(), 1);
1047+
1048+
// Callbacks
1049+
assertTrue(openAPI.getComponents().getCallbacks().get("callbackAllSecuritySchemes")
1050+
.get("{$request.body#/callbackUrl}").getPost().getSecurity().stream()
1051+
.anyMatch(map -> map.containsKey("api_key1")));
1052+
assertFalse(openAPI.getComponents().getCallbacks().get("callbackAllSecuritySchemes")
1053+
.get("{$request.body#/callbackUrl}").getPost().getSecurity().stream()
1054+
.anyMatch(map -> map.containsKey("api_key2")));
1055+
assertFalse(openAPI.getComponents().getCallbacks().get("callbackAllSecuritySchemes")
1056+
.get("{$request.body#/callbackUrl}").getPost().getSecurity().stream()
1057+
.anyMatch(map -> map.containsKey("http1")));
1058+
assertFalse(openAPI.getComponents().getCallbacks().get("callbackAllSecuritySchemes")
1059+
.get("{$request.body#/callbackUrl}").getPost().getSecurity().stream()
1060+
.anyMatch(map -> map.containsKey("http2")));
1061+
assertFalse(openAPI.getComponents().getCallbacks().get("callbackAllSecuritySchemes")
1062+
.get("{$request.body#/callbackUrl}").getPost().getSecurity().stream()
1063+
.anyMatch(map -> map.containsKey("mutualTLS1")));
1064+
assertFalse(openAPI.getComponents().getCallbacks().get("callbackAllSecuritySchemes")
1065+
.get("{$request.body#/callbackUrl}").getPost().getSecurity().stream()
1066+
.anyMatch(map -> map.containsKey("mutualTLS2")));
1067+
assertTrue(openAPI.getComponents().getCallbacks().get("callbackAllSecuritySchemes")
1068+
.get("{$request.body#/callbackUrl}").getPost().getSecurity().stream()
1069+
.anyMatch(map -> map.containsKey("oauth2_1")));
1070+
assertTrue(openAPI.getComponents().getCallbacks().get("callbackAllSecuritySchemes")
1071+
.get("{$request.body#/callbackUrl}").getPost().getSecurity().stream()
1072+
.anyMatch(map -> map.containsKey("oauth2_2")));
1073+
assertFalse(openAPI.getComponents().getCallbacks().get("callbackAllSecuritySchemes")
1074+
.get("{$request.body#/callbackUrl}").getPost().getSecurity().stream()
1075+
.anyMatch(map -> map.containsKey("openIdConnect1")));
1076+
assertFalse(openAPI.getComponents().getCallbacks().get("callbackAllSecuritySchemes")
1077+
.get("{$request.body#/callbackUrl}").getPost().getSecurity().stream()
1078+
.anyMatch(map -> map.containsKey("openIdConnect2")));
1079+
// We should leave only one (the original one) empty security requirement object
1080+
assertEquals(openAPI.getComponents().getCallbacks().get("callbackAllSecuritySchemes")
1081+
.get("{$request.body#/callbackUrl}").getPost().getSecurity().stream().filter(map -> map.isEmpty())
1082+
.count(), 1);
10161083
}
10171084

10181085
@Test

modules/openapi-generator/src/test/resources/3_1/all_security_schemes.yaml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,32 @@ components:
260260
description: OpenID Connect Authentication sample 2
261261
openIdConnectUrl: 'http://petstore.swagger.io/.well-known/openid-configuration2'
262262

263+
callbacks:
264+
callbackAllSecuritySchemes:
265+
'{$request.body#/callbackUrl}':
266+
post:
267+
requestBody:
268+
description: Callback payload
269+
content:
270+
application/json:
271+
schema:
272+
$ref: '#/components/schemas/Dummy'
273+
responses:
274+
'200':
275+
description: successful operation
276+
security:
277+
- {}
278+
- api_key1: []
279+
- api_key2: []
280+
- http1: []
281+
- http2: []
282+
- mutualTLS1: []
283+
- mutualTLS2: []
284+
- oauth2_1: ["read:pets"]
285+
- oauth2_2: ["write:pets", "read:pets"]
286+
- openIdConnect1: []
287+
- openIdConnect2: []
288+
263289
schemas:
264290
Dummy:
265291
title: Dummy schema
@@ -269,3 +295,30 @@ components:
269295
id:
270296
type: integer
271297
format: int64
298+
299+
webhooks:
300+
webhookAllSecuritySchemes:
301+
post:
302+
summary: Dummy webhook endpoint
303+
operationId: dummyWebhook
304+
requestBody:
305+
description: Webhook payload
306+
content:
307+
application/json:
308+
schema:
309+
$ref: '#/components/schemas/Dummy'
310+
responses:
311+
'200':
312+
description: successful operation
313+
security:
314+
- {}
315+
- api_key1: []
316+
- api_key2: []
317+
- http1: []
318+
- http2: []
319+
- mutualTLS1: []
320+
- mutualTLS2: []
321+
- oauth2_1: ["read:pets"]
322+
- oauth2_2: ["write:pets", "read:pets"]
323+
- openIdConnect1: []
324+
- openIdConnect2: []

0 commit comments

Comments
 (0)