Skip to content

Commit

Permalink
Added Authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
arumie committed Mar 2, 2024
1 parent 73c54c1 commit 300425e
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 2 deletions.
1 change: 1 addition & 0 deletions .github/workflows/google-cloudrun-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ jobs:
image: ${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{env.GAR_REPO}}/${{ env.SERVICE }}:${{ github.sha }}
secrets: |
AiTestimonials__PostgresConnectionString=vercel-postgres-secret:latest
API_KEY=dzachdev-api-key-secret:latest
# If required, use the Cloud Run url output in later steps
- name: Show Output
Expand Down
42 changes: 42 additions & 0 deletions AiTestimonials/Authorization/ApiKeyMiddleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System.Net;

namespace AiTestimonials.Authorization;

public class ApiKeyMiddleware
{
private readonly RequestDelegate _next;
private readonly IApiKeyValidation _apiKeyValidation;

private readonly List<string> _utilityEndpoints =
[
"/health/ready",
"/health/live"
];

public ApiKeyMiddleware(RequestDelegate next, IApiKeyValidation apiKeyValidation)
{
_next = next;
_apiKeyValidation = apiKeyValidation;
}
public async Task InvokeAsync(HttpContext context)
{
if (_utilityEndpoints.Contains(context.Request.Path))
{
await _next(context);
return;
}

if (string.IsNullOrWhiteSpace(context.Request.Headers[AuthConstants.ApiKeyHeaderName]))
{
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
return;
}
string? userApiKey = context.Request.Headers[AuthConstants.ApiKeyHeaderName];
if (!_apiKeyValidation.IsValidApiKey(userApiKey!))
{
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
return;
}
await _next(context);
}
}
15 changes: 15 additions & 0 deletions AiTestimonials/Authorization/ApiKeyValidation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace AiTestimonials.Authorization;

internal sealed class ApiKeyValidation(IConfiguration configuration) : IApiKeyValidation
{
public bool IsValidApiKey(string userApiKey)
{
if (string.IsNullOrWhiteSpace(userApiKey))
{
return false;
}

var apiKey = configuration.GetValue<string>(AuthConstants.ApiKeyName);
return apiKey != null && apiKey == userApiKey;
}
}
7 changes: 7 additions & 0 deletions AiTestimonials/Authorization/AuthConstants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace AiTestimonials.Authorization;

public static class AuthConstants
{
public const string ApiKeyHeaderName = "x-api-key";
public const string ApiKeyName = "API_KEY";
}
6 changes: 6 additions & 0 deletions AiTestimonials/Authorization/IApiKeyValidation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace AiTestimonials.Authorization;

public interface IApiKeyValidation
{
bool IsValidApiKey(string userApiKey);
}
38 changes: 37 additions & 1 deletion AiTestimonials/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
using AiTestimonials.Options;
using AiTestimonials.Repository;
using AiTestimonials.Services;
using AiTestimonials.Authorization;
using Swashbuckle.AspNetCore.Swagger;
using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder(args);

Expand All @@ -13,20 +16,53 @@
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddTransient<IApiKeyValidation, ApiKeyValidation>();
builder.Services.AddScoped<AiTestimonialsService>();
builder.Services.AddScoped<VercelPostgresRepository>();

builder.Services.AddAuthorization();
builder.Services.AddAuthentication();
builder.Services.AddSwaggerGen(c =>
{
c.AddSecurityDefinition(AuthConstants.ApiKeyName, new OpenApiSecurityScheme
{
Description = "ApiKey must appear in header",
Type = SecuritySchemeType.ApiKey,
Name = AuthConstants.ApiKeyHeaderName,
In = ParameterLocation.Header,
Scheme = "ApiKeyScheme"
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme()
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = AuthConstants.ApiKeyName
},
In = ParameterLocation.Header
},
new List<string>()
}
});
});

var app = builder.Build();

app.RegisterAiTestimonialsEndpoints();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwagger(new SwaggerOptions() { SerializeAsV2 = true, RouteTemplate = "swagger/{documentName}/swaggerV2.{json|yaml}" });
app.UseSwagger(new SwaggerOptions() );
app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseMiddleware<ApiKeyMiddleware>();
app.UseAuthorization();

app.Run();
3 changes: 2 additions & 1 deletion AiTestimonials/appsettings.Development.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
"PostgresDatabase": "",
"PostgresUser": "",
"PostgresHost": ""
}
},
"API_KEY": "developer"
}

0 comments on commit 300425e

Please sign in to comment.