Skip to content
This repository was archived by the owner on Dec 25, 2024. It is now read-only.

Commit b8a3620

Browse files
authored
v2 improves security code and documentation (#137)
* Adds readme security section * Adds security sample * Adds files for python testing * petstore regenerated to delete unused api path files * Adds security section to the docs * Generates root security requirements objects * Generates security requirement objects * Passes through and uses security_index * Operation docs now show security code from root * Renames auth_info to security_scheme_info * Adds test_endpoint_call_lacks_security * Adds test_endpoint_call_lacks_security, more code * Adds test_endpoint_call_contains_security * Fixes operation response type, remves typing union * Improves multiple response and parameter imports in operation files * Fixes petstore tests * Adds tests of all securities in the endpoints, secuirty_index passed in * Adds ServerIndexInfo to allow configuration of servers by path or operation * Regnerates petstore, fixes petstore test * Adds SecurityIndexInfo * Adds security_index_info to allow users to set a default security index before making an api call * Adds test_endpoint_call_contains_security_index1_from_endpoint_config * Adds CI invocation * Regenerates samples * Sample regen with unit test fix
1 parent 9f635c3 commit b8a3620

File tree

1,022 files changed

+15441
-8856
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,022 files changed

+15441
-8856
lines changed

CI/circle_parallel.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ elif [ "$NODE_INDEX" = "4" ]; then
7070
(cd samples/openapi3/client/petstore/python && make test)
7171
(cd samples/openapi3/client/3_0_3_unit_test/python && make test)
7272
(cd samples/openapi3/client/features/nonCompliantUseDiscriminatorIfCompositionFails/python && make test)
73+
(cd samples/openapi3/client/features/security/python && make test)
7374

7475
else
7576
echo "Running node $NODE_INDEX"

bin/configs/python_security.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
generatorName: python
2+
outputDir: samples/openapi3/client/features/security/python
3+
inputSpec: modules/openapi-json-schema-generator/src/test/resources/3_0/security.yaml
4+
additionalProperties:
5+
packageName: this_package

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/CodegenConfig.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ public interface CodegenConfig {
140140

141141
CodegenTag fromTag(String name, String description);
142142

143+
List<HashMap<String, CodegenSecurityRequirementValue>> fromSecurity(List<SecurityRequirement> security, String jsonPath);
144+
143145
CodegenOperation fromOperation(Operation operation, String jsonPath);
144146

145147
CodegenKey getKey(String key);
@@ -214,6 +216,8 @@ public interface CodegenConfig {
214216

215217
String toServerFilename(String baseName);
216218

219+
String toSecurityRequirementObjectFilename(String baseName);
220+
217221
String getCamelCaseServer(String baseName);
218222

219223
String toModelImport(String refClass);

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/CodegenConstants.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ public class CodegenConstants {
2424
/* System Properties */
2525
// NOTE: We may want to move these to a separate class to avoid confusion or modification.
2626
public static final String SERVERS = "servers";
27+
28+
public static final String SECURITY = "security";
2729
public static final String APIS = "apis";
2830
public static final String MODELS = "models";
2931
public static final String CONTENT = "content";
@@ -243,7 +245,7 @@ public class CodegenConstants {
243245

244246
public static enum PARAM_NAMING_TYPE {camelCase, PascalCase, snake_case, original}
245247

246-
public static enum JSON_PATH_LOCATION_TYPE {SCHEMA, REQUEST_BODY, PARAMETER, RESPONSE, HEADER, CONTENT, CONTENT_TYPE, HEADERS, PARAMETERS, RESPONSES, REQUEST_BODIES, SCHEMAS, PATHS, PATH, COMPONENTS, OPERATION, SECURITY_SCHEMES, SECURITY_SCHEME, SERVERS, SERVER, API_ROOT_FOLDER, API_PATH, API_TAG, API_PATHS, API_TAGS}
248+
public static enum JSON_PATH_LOCATION_TYPE {SCHEMA, REQUEST_BODY, PARAMETER, RESPONSE, HEADER, CONTENT, CONTENT_TYPE, HEADERS, PARAMETERS, RESPONSES, REQUEST_BODIES, SCHEMAS, PATHS, PATH, COMPONENTS, OPERATION, SECURITY_SCHEMES, SECURITY_SCHEME, SERVERS, SERVER, API_ROOT_FOLDER, API_PATH, API_TAG, API_PATHS, API_TAGS, SECURITY, SECURITIES}
247249

248250
public static enum MODEL_PROPERTY_NAMING_TYPE {camelCase, PascalCase, snake_case, original}
249251

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/DefaultCodegen.java

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,11 @@ public String toServerFilename(String basename) {
10791079
return toModuleFilename(basename);
10801080
}
10811081

1082+
@Override
1083+
public String toSecurityRequirementObjectFilename(String basename) {
1084+
return toModuleFilename(basename);
1085+
}
1086+
10821087
@Override
10831088
public String getCamelCaseServer(String basename) {
10841089
return toModelName(basename);
@@ -2639,15 +2644,7 @@ else if (one.required)
26392644
return 1;
26402645
});
26412646
}
2642-
List<HashMap<String, CodegenSecurityRequirementValue>> security = null;
2643-
List<SecurityRequirement> securities = operation.getSecurity();
2644-
if (securities != null && !securities.isEmpty()) {
2645-
security = new ArrayList<>();
2646-
for (SecurityRequirement originalSecurityRequirement: securities) {
2647-
HashMap<String, CodegenSecurityRequirementValue> securityRequirement = fromSecurityRequirement(originalSecurityRequirement, jsonPath + "/security");
2648-
security.add(securityRequirement);
2649-
}
2650-
}
2647+
List<HashMap<String, CodegenSecurityRequirementValue>> security = fromSecurity(operation.getSecurity(), jsonPath + "/security");
26512648

26522649
ExternalDocumentation externalDocs = operation.getExternalDocs();
26532650
CodegenKey jsonPathPiece = getKey(pathPieces[pathPieces.length-1]);
@@ -2681,12 +2678,28 @@ else if (one.required)
26812678
jsonPathPiece);
26822679
}
26832680

2681+
@Override
2682+
public List<HashMap<String, CodegenSecurityRequirementValue>> fromSecurity(List<SecurityRequirement> security, String jsonPath) {
2683+
if (security == null) {
2684+
return null;
2685+
}
2686+
List securityRequirements = new ArrayList<>();
2687+
int i = 0;
2688+
for (SecurityRequirement specSecurityRequirement: security) {
2689+
HashMap<String, CodegenSecurityRequirementValue> securityRequirement = fromSecurityRequirement(specSecurityRequirement, jsonPath+ "/" + i);
2690+
securityRequirements.add(securityRequirement);
2691+
i++;
2692+
}
2693+
return securityRequirements;
2694+
}
2695+
26842696
/**
26852697
* Convert OAS Response object to Codegen Response object
26862698
*
26872699
* @param response OAS Response object
26882700
* @return Codegen Response object
26892701
*/
2702+
@Override
26902703
public CodegenResponse fromResponse(ApiResponse response, String sourceJsonPath) {
26912704
if (response == null) {
26922705
String msg = "response in fromResponse cannot be null!";
@@ -3453,6 +3466,9 @@ private void updatePathsFilepath(String[] pathPieces) {
34533466
if (pathPieces[4].equals("servers")) {
34543467
// #/paths/somePath/get/servers/someServer
34553468
pathPieces[5] = toServerFilename(pathPieces[5]);
3469+
} else if (pathPieces[4].equals("security")) {
3470+
// #/paths/somePath/get/security/0
3471+
pathPieces[5] = toSecurityRequirementObjectFilename(pathPieces[5]);
34563472
} else if (pathPieces[4].equals("responses")) {
34573473
// #/paths/user_login/get/responses/200 -> 200 -> response_200 -> length 6
34583474
pathPieces[5] = toResponseModuleName(pathPieces[5]);
@@ -3499,6 +3515,13 @@ private void updateServersFilepath(String[] pathPieces) {
34993515
pathPieces[2] = toServerFilename(pathPieces[2]);
35003516
}
35013517

3518+
private void updateSecurityFilepath(String[] pathPieces) {
3519+
if (pathPieces.length < 3) {
3520+
return;
3521+
}
3522+
pathPieces[2] = toSecurityRequirementObjectFilename(pathPieces[2]);
3523+
}
3524+
35023525
private void updateApisFilepath(String[] pathPieces) {
35033526
// #/apis
35043527
// #/apis/tags
@@ -3526,6 +3549,8 @@ public String getFilepath(String jsonPath) {
35263549
updatePathsFilepath(pathPieces);
35273550
} else if (jsonPath.startsWith("#/servers")) {
35283551
updateServersFilepath(pathPieces);
3552+
} else if (jsonPath.startsWith("#/security")) {
3553+
updateSecurityFilepath(pathPieces);
35293554
} else if (jsonPath.startsWith("#/apis")) {
35303555
// this is a fake json path that the code generates and uses to generate apis
35313556
updateApisFilepath(pathPieces);

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/DefaultGenerator.java

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.openapijsonschematools.codegen.model.CodegenRequestBody;
4444
import org.openapijsonschematools.codegen.model.CodegenResponse;
4545
import org.openapijsonschematools.codegen.model.CodegenSchema;
46+
import org.openapijsonschematools.codegen.model.CodegenSecurityRequirementValue;
4647
import org.openapijsonschematools.codegen.model.CodegenSecurityScheme;
4748
import org.openapijsonschematools.codegen.model.CodegenServer;
4849
import org.openapijsonschematools.codegen.model.CodegenTag;
@@ -437,7 +438,7 @@ private void generateFiles(List<List<Object>> processTemplateToFileInfos, boolea
437438
}
438439
}
439440

440-
private void generatePathItem(List<File> files, CodegenKey pathKey, CodegenPathItem pathItem, String jsonPath, List<CodegenServer> servers) {
441+
private void generatePathItem(List<File> files, CodegenKey pathKey, CodegenPathItem pathItem, String jsonPath, List<CodegenServer> servers, List<HashMap<String, CodegenSecurityRequirementValue>> security) {
441442
Map<String, Object> pathTemplateInfo = new HashMap<>();
442443
pathTemplateInfo.put("pathModule", pathKey.snakeCase);
443444
pathTemplateInfo.put("apiClassName", pathKey.camelCase);
@@ -458,6 +459,7 @@ private void generatePathItem(List<File> files, CodegenKey pathKey, CodegenPathI
458459
endpointMap.put("operation", operation);
459460
endpointMap.put("pathItem", pathItem);
460461
endpointMap.put("httpMethod", httpMethod);
462+
endpointMap.put("security", security);
461463
generateXs(files, operationJsonPath, CodegenConstants.JSON_PATH_LOCATION_TYPE.OPERATION, CodegenConstants.APIS, endpointMap, true);
462464

463465
// operation docs
@@ -474,6 +476,7 @@ private void generatePathItem(List<File> files, CodegenKey pathKey, CodegenPathI
474476
endpointInfo.put("path", pathKey);
475477
endpointInfo.put("pathItem", pathItem);
476478
endpointInfo.put("servers", servers);
479+
endpointInfo.put("security", security);
477480
endpointInfo.put("packageName", config.packageName());
478481
endpointInfo.put("apiPackage", config.apiPackage());
479482
endpointInfo.put("tag", tag);
@@ -487,6 +490,12 @@ private void generatePathItem(List<File> files, CodegenKey pathKey, CodegenPathI
487490
}
488491
}
489492

493+
// paths.some_path.security.security_requirement_0.py
494+
if (operation.security != null) {
495+
String securityJsonPath = operationJsonPath + "/security";
496+
generateSecurity(files, operation.security, securityJsonPath);
497+
}
498+
490499
// paths.some_path.post.request_body.py, only written if there is no refModule
491500
if (operation.requestBody != null) {
492501
String requestBodyJsonPath = operationJsonPath + "/requestBody";
@@ -545,7 +554,7 @@ private void generatePathItem(List<File> files, CodegenKey pathKey, CodegenPathI
545554
}
546555
}
547556

548-
private void generatePaths(List<File> files, TreeMap<CodegenKey, CodegenPathItem> paths, List<CodegenServer> servers) {
557+
private void generatePaths(List<File> files, TreeMap<CodegenKey, CodegenPathItem> paths, List<CodegenServer> servers, List<HashMap<String, CodegenSecurityRequirementValue>> security) {
549558
if (paths == null || paths.isEmpty()) {
550559
LOGGER.info("Skipping generation of paths because the specification document lacks them.");
551560
return;
@@ -558,13 +567,12 @@ private void generatePaths(List<File> files, TreeMap<CodegenKey, CodegenPathItem
558567
String pathsJsonPath = "#/paths";
559568
generateXs(files, pathsJsonPath, CodegenConstants.JSON_PATH_LOCATION_TYPE.PATHS, CodegenConstants.APIS, null, true);
560569

561-
TreeMap<CodegenKey, CodegenPathItem> codegenPaths = new TreeMap<>();
562570
for (Map.Entry<CodegenKey, CodegenPathItem> entry: paths.entrySet()) {
563571
CodegenKey pathKey = entry.getKey();
564572
CodegenPathItem pathItem = entry.getValue();
565573
String jsonPath = "#/paths/" + ModelUtils.encodeSlashes(pathKey.original);
566574

567-
generatePathItem(files, pathKey, pathItem, jsonPath, servers);
575+
generatePathItem(files, pathKey, pathItem, jsonPath, servers, security);
568576
}
569577
}
570578

@@ -1251,7 +1259,8 @@ Map<String, Object> buildSupportFileBundle(
12511259
TreeMap<String, CodegenParameter> parameters,
12521260
TreeMap<String, CodegenSecurityScheme> securitySchemes,
12531261
List<CodegenServer> servers,
1254-
TreeMap<CodegenKey, CodegenPathItem> paths) {
1262+
TreeMap<CodegenKey, CodegenPathItem> paths,
1263+
List<HashMap<String, CodegenSecurityRequirementValue>> security) {
12551264

12561265
Map<String, Object> bundle = new HashMap<>(config.additionalProperties());
12571266
bundle.put("apiPackage", config.apiPackage());
@@ -1292,6 +1301,7 @@ Map<String, Object> buildSupportFileBundle(
12921301
bundle.put("servers", servers);
12931302
bundle.put("hasServers", hasServers); // also true if there are no root servers but there are pathItem/operation servers
12941303
bundle.put("paths", paths);
1304+
bundle.put("security", security);
12951305
bundle.put("apiFolder", config.apiPackage().replace('.', File.separatorChar));
12961306
bundle.put("modelPackage", config.modelPackage());
12971307
bundle.put("library", config.getLibrary());
@@ -1345,7 +1355,7 @@ private void generateServers(List<File> files, List<CodegenServer> servers, Stri
13451355
}
13461356
}
13471357

1348-
private TreeMap<String, CodegenTag> generateTags() {
1358+
private TreeMap<String, CodegenTag> getTags() {
13491359
List<Tag> specTags = openAPI.getTags();
13501360
if (specTags == null) {
13511361
return null;
@@ -1360,6 +1370,27 @@ private TreeMap<String, CodegenTag> generateTags() {
13601370
return tags;
13611371
}
13621372

1373+
private void generateSecurity(List<File> files, List<HashMap<String, CodegenSecurityRequirementValue>> security, String jsonPath) {
1374+
if (security == null || security.isEmpty()) {
1375+
return;
1376+
}
1377+
if (!generateApis) {
1378+
LOGGER.info("Skipping generation of security because generateApis is set to false.");
1379+
return;
1380+
}
1381+
generateXs(files, jsonPath, CodegenConstants.JSON_PATH_LOCATION_TYPE.SECURITIES, CodegenConstants.SECURITY, null, true);
1382+
1383+
int i = 0;
1384+
for (HashMap<String, CodegenSecurityRequirementValue> securityRequirementObject: security) {
1385+
Map<String, Object> templateData = new HashMap<>();
1386+
templateData.put("packageName", config.packageName());
1387+
templateData.put("securityRequirementObject", securityRequirementObject);
1388+
String serverJsonPath = jsonPath + "/" + i;
1389+
generateXs(files, serverJsonPath, CodegenConstants.JSON_PATH_LOCATION_TYPE.SECURITY, CodegenConstants.SECURITY, templateData, true);
1390+
i++;
1391+
}
1392+
}
1393+
13631394
@Override
13641395
public List<File> generate() {
13651396
if (openAPI == null) {
@@ -1396,7 +1427,7 @@ public List<File> generate() {
13961427

13971428
List<File> files = new ArrayList<>();
13981429
// tags
1399-
TreeMap<String, CodegenTag> tags = generateTags();
1430+
TreeMap<String, CodegenTag> tags = getTags();
14001431
// components.schemas / models
14011432
TreeMap<String, CodegenSchema> schemas = generateSchemas(files);
14021433
// components.requestBodies
@@ -1409,6 +1440,9 @@ public List<File> generate() {
14091440
TreeMap<String, CodegenParameter> parameters = generateParameters(files);
14101441
// components.securitySchemes
14111442
TreeMap<String, CodegenSecurityScheme> securitySchemes = generateSecuritySchemes(files);
1443+
// security
1444+
List<HashMap<String, CodegenSecurityRequirementValue>> security = config.fromSecurity(openAPI.getSecurity(), "#/security");
1445+
generateSecurity(files, security, "#/security");
14121446

14131447
boolean schemasExist = (schemas != null && !schemas.isEmpty());
14141448
boolean requestBodiesExist = (requestBodies != null && !requestBodies.isEmpty());
@@ -1424,13 +1458,13 @@ public List<File> generate() {
14241458
List<CodegenServer> servers = config.fromServers(openAPI.getServers(), serversJsonPath);
14251459
// paths
14261460
TreeMap<CodegenKey, CodegenPathItem> paths = config.fromPaths(openAPI.getPaths());
1427-
generatePaths(files, paths, servers);
1461+
generatePaths(files, paths, servers, security);
14281462
generateServers(files, servers, serversJsonPath);
14291463
// apis
14301464
generateApis(files, paths);
14311465

14321466
// supporting files
1433-
Map<String, Object> bundle = buildSupportFileBundle(schemas, requestBodies, responses, headers, parameters, securitySchemes, servers, paths);
1467+
Map<String, Object> bundle = buildSupportFileBundle(schemas, requestBodies, responses, headers, parameters, securitySchemes, servers, paths, security);
14341468
generateSupportingFiles(files, bundle);
14351469

14361470
if (dryRun) {

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/languages/PythonClientCodegen.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,19 @@ public void processOpts() {
475475
put("components/schemas/__init__schema.hbs", File.separatorChar + "__init__.py");
476476
}}
477477
);
478+
jsonPathTemplateFiles.put(
479+
CodegenConstants.JSON_PATH_LOCATION_TYPE.SECURITIES,
480+
new HashMap<String, String>() {{
481+
put("__init__.hbs", File.separatorChar + "__init__.py");
482+
}}
483+
);
484+
jsonPathTemplateFiles.put(
485+
CodegenConstants.JSON_PATH_LOCATION_TYPE.SECURITY,
486+
new HashMap<String, String>() {{
487+
put("security/security.hbs", ".py");
488+
}}
489+
);
490+
478491
jsonPathTemplateFiles.put(
479492
CodegenConstants.JSON_PATH_LOCATION_TYPE.PATHS,
480493
new HashMap<String, String>() {{
@@ -1732,6 +1745,11 @@ public String toServerFilename(String basename) {
17321745
return "server_" + basename;
17331746
}
17341747

1748+
@Override
1749+
public String toSecurityRequirementObjectFilename(String basename) {
1750+
return "security_requirement_object_" + basename;
1751+
}
1752+
17351753
@Override
17361754
public String getCamelCaseServer(String basename) {
17371755
return "Server" + basename;

modules/openapi-json-schema-generator/src/main/resources/python/_helper_readme_common.hbs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,20 @@ server_index | Class | Description
1616
{{@key}} | [{{jsonPathPiece.camelCase}}](docs/servers/{{jsonPathPiece.snakeCase}}.md) |{{#if description}} {{description}}{{/if}}
1717
{{/each}}
1818
{{/if}}
19+
{{#if security}}
20+
21+
## Security
22+
23+
Set auth info by setting ApiConfiguration.security_scheme_info to a dict where the
24+
key is the below security scheme quoted name, and the value is an instance of the linked
25+
component security scheme class. See how to do this in the endpoint code sample.
26+
27+
| Security Index | Security Scheme to Scope Names |
28+
| -------------- | ------------------------------ |
29+
{{#each security}}
30+
| {{@key}} | {{#eq this.size 0}}no security{{else}}{{#each this}}["{{{@key}}}"](docs/components/security_schemes/{{this.refInfo.refModule}}.md) {{this.scopeNames}}<br>{{/each}}{{/eq}} |
31+
{{/each}}
32+
{{/if}}
1933
{{#if paths}}
2034
2135
## Endpoints

0 commit comments

Comments
 (0)