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

Add API key authentication support to aspnetcore server #3089

Merged
merged 3 commits into from
Jun 21, 2019
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 @@ -309,6 +309,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"));
}

public void setPackageGuid(String packageGuid) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<string> ApiKeys { get; set; }

public string PolicyName { get; set; }

public ApiKeyRequirement(IEnumerable<string> apiKeys, string policyName)
{
ApiKeys = apiKeys?.ToList() ?? new List<string>();
PolicyName = policyName;
}
}

public class ApiKeyRequirementHandler : AuthorizationHandler<ApiKeyRequirement>
{

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}}
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -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}}
{
Expand Down Expand Up @@ -40,6 +42,22 @@ namespace {{packageName}}
/// <param name="services"></param>
public void ConfigureServices(IServiceCollection services)
{
{{#authMethods}}
{{#isApiKey}}
{{#-first}}
services.AddTransient<IAuthorizationHandler, ApiKeyRequirementHandler>();
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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ namespace {{apiPackage}}
/// <param name="{{paramName}}">{{description}}</param>{{/allParams}}{{#responses}}
/// <response code="{{code}}">{{message}}</response>{{/responses}}
[{{httpMethod}}]
[Route("{{{basePathWithoutHost}}}{{{path}}}")]{{#hasAuthMethods}}{{#authMethods}}{{#isBasicBearer}}
[Route("{{{basePathWithoutHost}}}{{{path}}}")]{{#hasAuthMethods}}{{#authMethods}}{{#isApiKey}}
[Authorize(Policy = "{{name}}")]{{/isApiKey}}{{#isBasicBearer}}
[Authorize{{#hasScopes}}(Roles = "{{#scopes}}{{scope}}{{#hasMore}},{{/hasMore}}{{/scopes}}"){{/hasScopes}}]{{/isBasicBearer}}{{/authMethods}}{{/hasAuthMethods}}
[ValidateModelState]{{#useSwashbuckle}}
[SwaggerOperation("{{operationId}}")]{{#responses}}{{#dataType}}
Expand Down
Original file line number Diff line number Diff line change
@@ -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<string> ApiKeys { get; set; }

public string PolicyName { get; set; }

public ApiKeyRequirement(IEnumerable<string> apiKeys, string policyName)
{
ApiKeys = apiKeys?.ToList() ?? new List<string>();
PolicyName = policyName;
}
}

public class ApiKeyRequirementHandler : AuthorizationHandler<ApiKeyRequirement>
{

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);
}

}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ public virtual IActionResult FindPetsByTags([FromQuery][Required()]List<string>
/// <response code="404">Pet not found</response>
[HttpGet]
[Route("/v2/pet/{petId}")]
[Authorize(Policy = "api_key")]
[ValidateModelState]
[SwaggerOperation("GetPetById")]
[SwaggerResponse(statusCode: 200, type: typeof(Pet), description: "successful operation")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public virtual IActionResult DeleteOrder([FromRoute][Required]string orderId)
/// <response code="200">successful operation</response>
[HttpGet]
[Route("/v2/store/inventory")]
[Authorize(Policy = "api_key")]
[ValidateModelState]
[SwaggerOperation("GetInventory")]
[SwaggerResponse(statusCode: 200, type: typeof(Dictionary<string, int?>), description: "successful operation")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -49,6 +51,13 @@ public Startup(IConfiguration configuration)
/// <param name="services"></param>
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IAuthorizationHandler, ApiKeyRequirementHandler>();
services.AddAuthorization(authConfig =>
{
authConfig.AddPolicy("api_key",
policyBuilder => policyBuilder
.AddRequirements(new ApiKeyRequirement(new[] { "my-secret-key" },"api_key")));

// Add framework services.
services
.AddMvc()
Expand Down