Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Ada] Operation security scopes are ignored when generating the server #1044

Merged
merged 2 commits into from
Sep 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
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;
Expand Down Expand Up @@ -414,9 +416,38 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation
}
}
}

// 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<SecurityRequirement> securities = operation.getSecurity();
if (securities != null && securities.size() > 0) {
final Map<String, SecurityScheme> securitySchemes = openAPI.getComponents() != null ? openAPI.getComponents().getSecuritySchemes() : null;
final List<SecurityRequirement> globalSecurities = openAPI.getSecurity();

Map<String, List<String>> scopes = getAuthScopes(securities, securitySchemes);
if (scopes.isEmpty() && globalSecurities != null) {
scopes = getAuthScopes(globalSecurities, securitySchemes);
}
op.vendorExtensions.put("x-scopes", scopes);
}
return op;
}

private Map<String, List<String>> getAuthScopes(List<SecurityRequirement> securities, Map<String, SecurityScheme> securitySchemes) {
final Map<String, List<String>> 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<String, Object> postProcessOperationsWithModels(Map<String, Object> objs, List<Object> allModels) {
Expand Down Expand Up @@ -449,7 +480,14 @@ public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> o
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<String, List<String>> scopes = (Map<String, List<String>>) op1.vendorExtensions.get("x-scopes");
List<CodegenSecurity> 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
Expand Down Expand Up @@ -584,7 +622,7 @@ public Map<String, Object> postProcessSupportingFileData(Map<String, Object> obj
* Collect the scopes to generate unique identifiers for each of them.
*/
List<CodegenSecurity> authMethods = (List<CodegenSecurity>) objs.get("authMethods");
postProcessAuthMethod(authMethods);
postProcessAuthMethod(authMethods, null);

return super.postProcessSupportingFileData(objs);
}
Expand All @@ -593,8 +631,11 @@ public Map<String, Object> postProcessSupportingFileData(Map<String, Object> obj
* 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<CodegenSecurity> authMethods) {
private List<CodegenSecurity> postProcessAuthMethod(List<CodegenSecurity> authMethods, Map<String, List<String>> scopes) {
List<CodegenSecurity> result = (scopes == null) ? null : new ArrayList<CodegenSecurity>();
if (authMethods != null) {
for (CodegenSecurity authMethod : authMethods) {
if (authMethod.scopes != null) {
Expand All @@ -620,8 +661,39 @@ private void postProcessAuthMethod(List<CodegenSecurity> authMethods) {
}
}
}

// 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<String> 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<Map<String, Object>> opAuthScopes = new ArrayList<Map<String, Object>>();
for (String opScopeName : opScopes) {
for (Map<String, Object> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
Expand All @@ -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;
Expand All @@ -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}}
Expand Down Expand Up @@ -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;
Expand All @@ -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}}
Expand Down Expand Up @@ -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}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down