diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractAdaCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractAdaCodegen.java index b395b739ada..02e193d8f47 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractAdaCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractAdaCodegen.java @@ -24,6 +24,8 @@ import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.responses.ApiResponse; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; import org.openapitools.codegen.CodegenConfig; import org.openapitools.codegen.CodegenConstants; import org.openapitools.codegen.CodegenModel; @@ -414,9 +416,38 @@ abstract public class AbstractAdaCodegen extends DefaultCodegen implements Codeg } } } + + // Add a vendor extension attribute that provides a map of auth methods and the scopes + // which are expected by the operation. This map is then used by postProcessOperationsWithModels + // to build another vendor extension that provides a subset of the auth methods with only + // the scopes required by the operation. + final List securities = operation.getSecurity(); + if (securities != null && securities.size() > 0) { + final Map securitySchemes = openAPI.getComponents() != null ? openAPI.getComponents().getSecuritySchemes() : null; + final List globalSecurities = openAPI.getSecurity(); + + Map> scopes = getAuthScopes(securities, securitySchemes); + if (scopes.isEmpty() && globalSecurities != null) { + scopes = getAuthScopes(globalSecurities, securitySchemes); + } + op.vendorExtensions.put("x-scopes", scopes); + } return op; } + private Map> getAuthScopes(List securities, Map securitySchemes) { + final Map> scopes = new HashMap<>(); + for (SecurityRequirement requirement : securities) { + for (String key : requirement.keySet()) { + SecurityScheme securityScheme = securitySchemes.get(key); + if (securityScheme != null) { + scopes.put(key, requirement.get(key)); + } + } + } + return scopes; + } + @SuppressWarnings("unchecked") @Override public Map postProcessOperationsWithModels(Map objs, List allModels) { @@ -449,7 +480,14 @@ abstract public class AbstractAdaCodegen extends DefaultCodegen implements Codeg p.dataType = "Swagger.File_Part_Type"; } } - postProcessAuthMethod(op1.authMethods); + + // Given the operation scopes and the auth methods, build a list of auth methods that only + // describe the auth methods and scopes required by the operation. + final Map> scopes = (Map>) op1.vendorExtensions.get("x-scopes"); + List opScopes = postProcessAuthMethod(op1.authMethods, scopes); + if (opScopes != null) { + op1.vendorExtensions.put("x-auth-scopes", opScopes); + } /* * Scan the path parameter to construct a x-path-index that tells the index of @@ -584,7 +622,7 @@ abstract public class AbstractAdaCodegen extends DefaultCodegen implements Codeg * Collect the scopes to generate unique identifiers for each of them. */ List authMethods = (List) objs.get("authMethods"); - postProcessAuthMethod(authMethods); + postProcessAuthMethod(authMethods, null); return super.postProcessSupportingFileData(objs); } @@ -593,8 +631,11 @@ abstract public class AbstractAdaCodegen extends DefaultCodegen implements Codeg * Collect the scopes to generate a unique identifier for each of them. * * @param authMethods the auth methods with their scopes. + * @param scopes the optional auth methods and scopes required by an operation + * @return the authMethods to be used by the operation with its required scopes. */ - private void postProcessAuthMethod(List authMethods) { + private List postProcessAuthMethod(List authMethods, Map> scopes) { + List result = (scopes == null) ? null : new ArrayList(); if (authMethods != null) { for (CodegenSecurity authMethod : authMethods) { if (authMethod.scopes != null) { @@ -620,8 +661,39 @@ abstract public class AbstractAdaCodegen extends DefaultCodegen implements Codeg } } } + + // If we have operation scopes, filter the auth method to describe the operation auth + // method with only the scope that it requires. We have to create a new auth method + // instance because the original object must not be modified. + List opScopes = (scopes == null) ? null : scopes.get(authMethod.name); authMethod.name = org.openapitools.codegen.utils.StringUtils.camelize(sanitizeName(authMethod.name), true); + if (opScopes != null) { + CodegenSecurity opSecurity = new CodegenSecurity(); + opSecurity.name = authMethod.name; + opSecurity.type = authMethod.type; + opSecurity.hasMore = false; + opSecurity.isBasic = authMethod.isBasic; + opSecurity.isApiKey = authMethod.isApiKey; + opSecurity.isKeyInCookie = authMethod.isKeyInCookie; + opSecurity.isKeyInHeader = authMethod.isKeyInHeader; + opSecurity.isKeyInQuery = authMethod.isKeyInQuery; + opSecurity.flow = authMethod.flow; + opSecurity.tokenUrl = authMethod.tokenUrl; + List> opAuthScopes = new ArrayList>(); + for (String opScopeName : opScopes) { + for (Map scope : authMethod.scopes) { + String name = (String) scope.get("scope"); + if (opScopeName.equals(name)) { + opAuthScopes.add(scope); + break; + } + } + } + opSecurity.scopes = opAuthScopes; + result.add(opSecurity); + } } } + return result; } } diff --git a/modules/openapi-generator/src/main/resources/Ada/server-skeleton-body.mustache b/modules/openapi-generator/src/main/resources/Ada/server-skeleton-body.mustache index b14dd242d5d..cabae11a17a 100644 --- a/modules/openapi-generator/src/main/resources/Ada/server-skeleton-body.mustache +++ b/modules/openapi-generator/src/main/resources/Ada/server-skeleton-body.mustache @@ -13,7 +13,7 @@ package body {{package}}.Skeletons is package API_{{operationId}} is new Swagger.Servers.Operation (Handler => {{operationId}}, Method => Swagger.Servers.{{httpMethod}}, - URI => "{{path}}"); + URI => URI_Prefix & "{{path}}"); -- {{summary}} procedure {{operationId}} @@ -32,7 +32,7 @@ package body {{package}}.Skeletons is Result : {{returnType}}; {{/returnType}} begin - {{#authMethods}} + {{#vendorExtensions.x-auth-scopes}} if not Context.Is_Authenticated then Context.Set_Error (401, "Not authenticated"); return; @@ -43,7 +43,7 @@ package body {{package}}.Skeletons is return; end if; {{/scopes}} - {{/authMethods}} + {{/vendorExtensions.x-auth-scopes}} {{#queryParams}} Swagger.Servers.Get_Query_Parameter (Req, "{{baseName}}", {{paramName}}); {{/queryParams}} @@ -128,7 +128,7 @@ package body {{package}}.Skeletons is Result : {{returnType}}; {{/returnType}} begin - {{#authMethods}} + {{#vendorExtensions.x-auth-scopes}} if not Context.Is_Authenticated then Context.Set_Error (401, "Not authenticated"); return; @@ -139,7 +139,7 @@ package body {{package}}.Skeletons is return; end if; {{/scopes}} - {{/authMethods}} + {{/vendorExtensions.x-auth-scopes}} {{#queryParams}} Swagger.Servers.Get_Query_Parameter (Req, "{{baseName}}", {{paramName}}); {{/queryParams}} @@ -185,7 +185,7 @@ package body {{package}}.Skeletons is package API_{{operationId}} is new Swagger.Servers.Operation (Handler => {{operationId}}, Method => Swagger.Servers.{{httpMethod}}, - URI => "{{path}}"); + URI => URI_Prefix & "{{path}}"); {{/operation}} {{/operations}} {{/apis}} diff --git a/modules/openapi-generator/src/main/resources/Ada/server-skeleton-spec.mustache b/modules/openapi-generator/src/main/resources/Ada/server-skeleton-spec.mustache index e14600dff7b..dcab9651d93 100644 --- a/modules/openapi-generator/src/main/resources/Ada/server-skeleton-spec.mustache +++ b/modules/openapi-generator/src/main/resources/Ada/server-skeleton-spec.mustache @@ -32,6 +32,7 @@ package {{package}}.Skeletons is generic type Implementation_Type is limited new Server_Type with private; + URI_Prefix : String := ""; package Skeleton is procedure Register (Server : in out Swagger.Servers.Application_Type'Class); @@ -56,6 +57,7 @@ package {{package}}.Skeletons is generic type Implementation_Type is limited new Server_Type with private; + URI_Prefix : String := ""; package Shared_Instance is procedure Register (Server : in out Swagger.Servers.Application_Type'Class);