From 1553e062fc217ff97c1d7da08e897652afb3cfe7 Mon Sep 17 00:00:00 2001 From: MBcom <27956078+MBcom@users.noreply.github.com> Date: Tue, 4 Jun 2019 13:22:35 +0200 Subject: [PATCH] added api key authentication to aspnetcore 2.1 updated samples --- .../languages/AspNetCoreServerCodegen.java | 2 + .../Authentication/ApiAuthentication.mustache | 60 +++++++++++++++++++ .../resources/aspnetcore/2.1/Startup.mustache | 18 ++++++ .../aspnetcore/2.1/controller.mustache | 4 +- .../aspnetcore/.openapi-generator/VERSION | 2 +- .../Authentication/ApiAuthentication.cs | 47 +++++++++++++++ .../Org.OpenAPITools/Controllers/PetApi.cs | 10 ++-- .../Org.OpenAPITools/Controllers/StoreApi.cs | 6 +- .../Org.OpenAPITools/Controllers/UserApi.cs | 17 +++--- .../src/Org.OpenAPITools/Startup.cs | 9 +++ .../wwwroot/openapi-original.json | 21 ++++--- 11 files changed, 173 insertions(+), 23 deletions(-) create mode 100644 modules/openapi-generator/src/main/resources/aspnetcore/2.1/Authentication/ApiAuthentication.mustache create mode 100644 samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Authentication/ApiAuthentication.cs diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AspNetCoreServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AspNetCoreServerCodegen.java index cd9466e208b7..23b57dacd098 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AspNetCoreServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AspNetCoreServerCodegen.java @@ -196,6 +196,8 @@ public void processOpts() { supportingFiles.add(new SupportingFile("Filters" + File.separator + "GeneratePathParamsValidationFilter.mustache", packageFolder + File.separator + "Filters", "GeneratePathParamsValidationFilter.cs")); } + + supportingFiles.add(new SupportingFile("Authentication" + File.separator + "ApiAuthentication.mustache",packageFolder + File.separator + "Authentication", "ApiAuthentication.cs")); supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "README.md", packageFolder + File.separator + "wwwroot", "README.md")); supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "index.html", packageFolder + File.separator + "wwwroot", "index.html")); diff --git a/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Authentication/ApiAuthentication.mustache b/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Authentication/ApiAuthentication.mustache new file mode 100644 index 000000000000..8f266775e131 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Authentication/ApiAuthentication.mustache @@ -0,0 +1,60 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc.Filters; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace {{packageName}}.Authentication +{ + public class ApiKeyRequirement : IAuthorizationRequirement + { + public IReadOnlyList ApiKeys { get; set; } + + public string PolicyName { get; set; } + + public ApiKeyRequirement(IEnumerable apiKeys, string policyName) + { + ApiKeys = apiKeys?.ToList() ?? new List(); + PolicyName = policyName; + } + } + + public class ApiKeyRequirementHandler : AuthorizationHandler + { + + protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ApiKeyRequirement requirement) + { + SucceedRequirementIfApiKeyPresentAndValid(context, requirement); + return Task.CompletedTask; + } + + private void SucceedRequirementIfApiKeyPresentAndValid(AuthorizationHandlerContext context, ApiKeyRequirement requirement) + { +{{#authMethods}}{{#isApiKey}} +{{#-first}} + if (context.Resource is AuthorizationFilterContext authorizationFilterContext) + { + var apiKey = ""; +{{/-first}} +{{#isKeyInHeader}} + apiKey = authorizationFilterContext.HttpContext.Request.Headers["{{keyParamName}}"].FirstOrDefault(); +{{/isKeyInHeader}} +{{#isKeyInQuery}} + apiKey = authorizationFilterContext.HttpContext.Request.Query["{{keyParamName}}"].FirstOrDefault(); +{{/isKeyInQuery}} +{{#isKeyInCookie}} + apiKey = authorizationFilterContext.HttpContext.Request.Cookies["{{keyParamName}}"] ?? null; +{{/isKeyInCookie}} + if (requirement.PolicyName == "{{name}}" && apiKey != null && requirement.ApiKeys.Any(requiredApiKey => apiKey == requiredApiKey)) + { + context.Succeed(requirement); + } +{{#-last}} + } +{{/-last}} +{{/isApiKey}}{{/authMethods}} + } + } +} + diff --git a/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Startup.mustache b/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Startup.mustache index 7a488bfcf170..59d1df70eea1 100644 --- a/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Startup.mustache +++ b/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Startup.mustache @@ -12,6 +12,8 @@ using Newtonsoft.Json.Serialization;{{#useSwashbuckle}} using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.SwaggerGen; using {{packageName}}.Filters;{{/useSwashbuckle}} +using {{packageName}}.Authentication; +using Microsoft.AspNetCore.Authorization; namespace {{packageName}} { @@ -40,6 +42,22 @@ namespace {{packageName}} /// public void ConfigureServices(IServiceCollection services) { +{{#authMethods}} +{{#isApiKey}} +{{#-first}} + services.AddTransient(); + services.AddAuthorization(authConfig => + { +{{/-first}} + authConfig.AddPolicy("{{name}}", + policyBuilder => policyBuilder + .AddRequirements(new ApiKeyRequirement(new[] { "my-secret-key" },"{{name}}"))); +{{#-last}} + }); +{{/-last}} +{{/isApiKey}} +{{/authMethods}} + // Add framework services. services .AddMvc() diff --git a/modules/openapi-generator/src/main/resources/aspnetcore/2.1/controller.mustache b/modules/openapi-generator/src/main/resources/aspnetcore/2.1/controller.mustache index 1805b7d2cc6e..5a606b665f36 100644 --- a/modules/openapi-generator/src/main/resources/aspnetcore/2.1/controller.mustache +++ b/modules/openapi-generator/src/main/resources/aspnetcore/2.1/controller.mustache @@ -8,6 +8,7 @@ using Newtonsoft.Json; using System.ComponentModel.DataAnnotations; using {{packageName}}.Attributes; using {{packageName}}.Models; +using Microsoft.AspNetCore.Authorization; namespace {{packageName}}.Controllers { {{#operations}} @@ -24,7 +25,8 @@ namespace {{packageName}}.Controllers /// {{description}}{{/allParams}}{{#responses}} /// {{message}}{{/responses}} [{{httpMethod}}] - [Route("{{{basePathWithoutHost}}}{{{path}}}")] + [Route("{{{basePathWithoutHost}}}{{{path}}}")]{{#hasAuthMethods}}{{#authMethods}}{{#isApiKey}} + [Authorize(Policy = "{{name}}")]{{/isApiKey}}{{/authMethods}}{{/hasAuthMethods}} [ValidateModelState]{{#useSwashbuckle}} [SwaggerOperation("{{operationId}}")]{{#responses}}{{#dataType}} [SwaggerResponse(statusCode: {{code}}, type: typeof({{&dataType}}), description: "{{message}}")]{{/dataType}}{{^dataType}}{{/dataType}}{{/responses}}{{/useSwashbuckle}} diff --git a/samples/server/petstore/aspnetcore/.openapi-generator/VERSION b/samples/server/petstore/aspnetcore/.openapi-generator/VERSION index e24c1f857e01..afa636560641 100644 --- a/samples/server/petstore/aspnetcore/.openapi-generator/VERSION +++ b/samples/server/petstore/aspnetcore/.openapi-generator/VERSION @@ -1 +1 @@ -3.3.3-SNAPSHOT \ No newline at end of file +4.0.0-SNAPSHOT \ No newline at end of file diff --git a/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Authentication/ApiAuthentication.cs b/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Authentication/ApiAuthentication.cs new file mode 100644 index 000000000000..bde72d78080b --- /dev/null +++ b/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Authentication/ApiAuthentication.cs @@ -0,0 +1,47 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc.Filters; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Org.OpenAPITools.Authentication +{ + public class ApiKeyRequirement : IAuthorizationRequirement + { + public IReadOnlyList ApiKeys { get; set; } + + public string PolicyName { get; set; } + + public ApiKeyRequirement(IEnumerable apiKeys, string policyName) + { + ApiKeys = apiKeys?.ToList() ?? new List(); + PolicyName = policyName; + } + } + + public class ApiKeyRequirementHandler : AuthorizationHandler + { + + protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ApiKeyRequirement requirement) + { + SucceedRequirementIfApiKeyPresentAndValid(context, requirement); + return Task.CompletedTask; + } + + private void SucceedRequirementIfApiKeyPresentAndValid(AuthorizationHandlerContext context, ApiKeyRequirement requirement) + { + + if (context.Resource is AuthorizationFilterContext authorizationFilterContext) + { + var apiKey = ""; + apiKey = authorizationFilterContext.HttpContext.Request.Headers["api_key"].FirstOrDefault(); + if (requirement.PolicyName == "api_key" && apiKey != null && requirement.ApiKeys.Any(requiredApiKey => apiKey == requiredApiKey)) + { + context.Succeed(requirement); + } + + } + } +} + diff --git a/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Controllers/PetApi.cs b/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Controllers/PetApi.cs index 9ea99af7cdf6..b9d25b58b01b 100644 --- a/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Controllers/PetApi.cs +++ b/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Controllers/PetApi.cs @@ -17,6 +17,7 @@ using System.ComponentModel.DataAnnotations; using Org.OpenAPITools.Attributes; using Org.OpenAPITools.Models; +using Microsoft.AspNetCore.Authorization; namespace Org.OpenAPITools.Controllers { @@ -28,13 +29,13 @@ public class PetApiController : ControllerBase /// /// Add a new pet to the store /// - /// Pet object that needs to be added to the store + /// Pet object that needs to be added to the store /// Invalid input [HttpPost] [Route("/v2/pet")] [ValidateModelState] [SwaggerOperation("AddPet")] - public virtual IActionResult AddPet([FromBody]Pet pet) + public virtual IActionResult AddPet([FromBody]Pet body) { //TODO: Uncomment the next line to return response 405 or use other options such as return this.NotFound(), return this.BadRequest(..), ... // return StatusCode(405); @@ -134,6 +135,7 @@ public virtual IActionResult FindPetsByTags([FromQuery][Required()]List /// Pet not found [HttpGet] [Route("/v2/pet/{petId}")] + [Authorize(Policy = "api_key")] [ValidateModelState] [SwaggerOperation("GetPetById")] [SwaggerResponse(statusCode: 200, type: typeof(Pet), description: "successful operation")] @@ -162,7 +164,7 @@ public virtual IActionResult GetPetById([FromRoute][Required]long? petId) /// /// Update an existing pet /// - /// Pet object that needs to be added to the store + /// Pet object that needs to be added to the store /// Invalid ID supplied /// Pet not found /// Validation exception @@ -170,7 +172,7 @@ public virtual IActionResult GetPetById([FromRoute][Required]long? petId) [Route("/v2/pet")] [ValidateModelState] [SwaggerOperation("UpdatePet")] - public virtual IActionResult UpdatePet([FromBody]Pet pet) + public virtual IActionResult UpdatePet([FromBody]Pet body) { //TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ... // return StatusCode(400); diff --git a/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Controllers/StoreApi.cs b/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Controllers/StoreApi.cs index 2b46191a7925..22aad18fea6f 100644 --- a/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Controllers/StoreApi.cs +++ b/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Controllers/StoreApi.cs @@ -17,6 +17,7 @@ using System.ComponentModel.DataAnnotations; using Org.OpenAPITools.Attributes; using Org.OpenAPITools.Models; +using Microsoft.AspNetCore.Authorization; namespace Org.OpenAPITools.Controllers { @@ -55,6 +56,7 @@ public virtual IActionResult DeleteOrder([FromRoute][Required]string orderId) /// successful operation [HttpGet] [Route("/v2/store/inventory")] + [Authorize(Policy = "api_key")] [ValidateModelState] [SwaggerOperation("GetInventory")] [SwaggerResponse(statusCode: 200, type: typeof(Dictionary), description: "successful operation")] @@ -110,7 +112,7 @@ public virtual IActionResult GetOrderById([FromRoute][Required][Range(1, 5)]long /// /// Place an order for a pet /// - /// order placed for purchasing the pet + /// order placed for purchasing the pet /// successful operation /// Invalid Order [HttpPost] @@ -118,7 +120,7 @@ public virtual IActionResult GetOrderById([FromRoute][Required][Range(1, 5)]long [ValidateModelState] [SwaggerOperation("PlaceOrder")] [SwaggerResponse(statusCode: 200, type: typeof(Order), description: "successful operation")] - public virtual IActionResult PlaceOrder([FromBody]Order order) + public virtual IActionResult PlaceOrder([FromBody]Order body) { //TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ... // return StatusCode(200, default(Order)); diff --git a/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Controllers/UserApi.cs b/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Controllers/UserApi.cs index 99fc6e4ea243..7360b23a75af 100644 --- a/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Controllers/UserApi.cs +++ b/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Controllers/UserApi.cs @@ -17,6 +17,7 @@ using System.ComponentModel.DataAnnotations; using Org.OpenAPITools.Attributes; using Org.OpenAPITools.Models; +using Microsoft.AspNetCore.Authorization; namespace Org.OpenAPITools.Controllers { @@ -29,13 +30,13 @@ public class UserApiController : ControllerBase /// Create user /// /// This can only be done by the logged in user. - /// Created user object + /// Created user object /// successful operation [HttpPost] [Route("/v2/user")] [ValidateModelState] [SwaggerOperation("CreateUser")] - public virtual IActionResult CreateUser([FromBody]User user) + public virtual IActionResult CreateUser([FromBody]User body) { //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... // return StatusCode(0); @@ -47,13 +48,13 @@ public virtual IActionResult CreateUser([FromBody]User user) /// /// Creates list of users with given input array /// - /// List of user object + /// List of user object /// successful operation [HttpPost] [Route("/v2/user/createWithArray")] [ValidateModelState] [SwaggerOperation("CreateUsersWithArrayInput")] - public virtual IActionResult CreateUsersWithArrayInput([FromBody]List user) + public virtual IActionResult CreateUsersWithArrayInput([FromBody]List body) { //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... // return StatusCode(0); @@ -65,13 +66,13 @@ public virtual IActionResult CreateUsersWithArrayInput([FromBody]List user /// /// Creates list of users with given input array /// - /// List of user object + /// List of user object /// successful operation [HttpPost] [Route("/v2/user/createWithList")] [ValidateModelState] [SwaggerOperation("CreateUsersWithListInput")] - public virtual IActionResult CreateUsersWithListInput([FromBody]List user) + public virtual IActionResult CreateUsersWithListInput([FromBody]List body) { //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... // return StatusCode(0); @@ -188,14 +189,14 @@ public virtual IActionResult LogoutUser() /// /// This can only be done by the logged in user. /// name that need to be deleted - /// Updated user object + /// Updated user object /// Invalid user supplied /// User not found [HttpPut] [Route("/v2/user/{username}")] [ValidateModelState] [SwaggerOperation("UpdateUser")] - public virtual IActionResult UpdateUser([FromRoute][Required]string username, [FromBody]User user) + public virtual IActionResult UpdateUser([FromRoute][Required]string username, [FromBody]User body) { //TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ... // return StatusCode(400); diff --git a/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Startup.cs b/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Startup.cs index 0df10a0b0cb7..8fdbadfc4d87 100644 --- a/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Startup.cs +++ b/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/Startup.cs @@ -21,6 +21,8 @@ using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.SwaggerGen; using Org.OpenAPITools.Filters; +using Org.OpenAPITools.Authentication; +using Microsoft.AspNetCore.Authorization; namespace Org.OpenAPITools { @@ -49,6 +51,13 @@ public Startup(IConfiguration configuration) /// public void ConfigureServices(IServiceCollection services) { + services.AddTransient(); + services.AddAuthorization(authConfig => + { + authConfig.AddPolicy("api_key", + policyBuilder => policyBuilder + .AddRequirements(new ApiKeyRequirement(new[] { "my-secret-key" },"api_key"))); + // Add framework services. services .AddMvc() diff --git a/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/wwwroot/openapi-original.json b/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/wwwroot/openapi-original.json index 82d674b55753..a0a4803cd077 100644 --- a/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/wwwroot/openapi-original.json +++ b/samples/server/petstore/aspnetcore/src/Org.OpenAPITools/wwwroot/openapi-original.json @@ -60,7 +60,8 @@ }, "security" : [ { "petstore_auth" : [ "write:pets", "read:pets" ] - } ] + } ], + "x-codegen-request-body-name" : "body" }, "post" : { "tags" : [ "pet" ], @@ -90,7 +91,8 @@ }, "security" : [ { "petstore_auth" : [ "write:pets", "read:pets" ] - } ] + } ], + "x-codegen-request-body-name" : "body" } }, "/pet/findByStatus" : { @@ -432,7 +434,8 @@ "description" : "Invalid Order", "content" : { } } - } + }, + "x-codegen-request-body-name" : "body" } }, "/store/order/{orderId}" : { @@ -527,7 +530,8 @@ "description" : "successful operation", "content" : { } } - } + }, + "x-codegen-request-body-name" : "body" } }, "/user/createWithArray" : { @@ -554,7 +558,8 @@ "description" : "successful operation", "content" : { } } - } + }, + "x-codegen-request-body-name" : "body" } }, "/user/createWithList" : { @@ -581,7 +586,8 @@ "description" : "successful operation", "content" : { } } - } + }, + "x-codegen-request-body-name" : "body" } }, "/user/login" : { @@ -732,7 +738,8 @@ "description" : "User not found", "content" : { } } - } + }, + "x-codegen-request-body-name" : "body" }, "delete" : { "tags" : [ "user" ],