feat: Implement API client and token models with hashing and JWT authentication
- Added ApiClientModel and ApiTokenModel for managing API clients and tokens. - Introduced ConfigurationDefinitionModel and ConfigurationValueModel for configuration management. - Created CredentialSecretModel for storing credential secrets. - Developed DeploymentArtifactModel and DeploymentBatchModel for deployment management. - Enhanced DeploymentTargetModel and DeploymentTemplateSelectionModel to support template revisions. - Added TemplateRevisionModel and TemplateVersionModel for versioning templates. - Implemented ApiClientSecretHasher for secure secret hashing. - Created ApiTokenService for generating and validating JWT tokens. - Updated QueueJobService to handle deployment requests with artifacts. - Configured authentication settings in appsettings.json for JWT and Negotiate authentication.
This commit is contained in:
85
Program.cs
85
Program.cs
@@ -1,11 +1,14 @@
|
||||
using Microsoft.AspNetCore.Authentication.Negotiate;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authentication.Negotiate;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.SelfService.Portal.Core.API.Context;
|
||||
using Microsoft.SelfService.Portal.Core.API.Interfaces;
|
||||
using Microsoft.SelfService.Portal.Core.API.Repository;
|
||||
using Microsoft.SelfService.Portal.Core.API.Services;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
|
||||
@@ -27,6 +30,7 @@ builder.Services.AddScoped<IDeploymentInterface, DeploymentRepository>();
|
||||
builder.Services.AddScoped<ITemplateInterface, TemplateRepository>();
|
||||
builder.Services.AddScoped<ITemplateCategoryInterface, TemplateCategoryRepository>();
|
||||
builder.Services.AddScoped<IQueueJobService, QueueJobService>();
|
||||
builder.Services.AddScoped<ApiTokenService>();
|
||||
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
@@ -36,8 +40,72 @@ builder.Services.AddAutoMapper(_ => { }, AppDomain.CurrentDomain.GetAssemblies()
|
||||
builder.Services.AddDbContext<DataContext>(options =>
|
||||
options.UseSqlServer(builder.Configuration.GetConnectionString("Context") ?? throw new InvalidOperationException("Connection string 'Context' not found.")));
|
||||
|
||||
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
|
||||
.AddNegotiate();
|
||||
var tokenService = new ApiTokenService(builder.Configuration);
|
||||
|
||||
builder.Services.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultScheme = "Smart";
|
||||
options.DefaultChallengeScheme = "Smart";
|
||||
})
|
||||
.AddPolicyScheme("Smart", "Negotiate or Bearer", options =>
|
||||
{
|
||||
options.ForwardDefaultSelector = context =>
|
||||
{
|
||||
var authorization = context.Request.Headers.Authorization.ToString();
|
||||
return authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)
|
||||
? JwtBearerDefaults.AuthenticationScheme
|
||||
: NegotiateDefaults.AuthenticationScheme;
|
||||
};
|
||||
})
|
||||
.AddNegotiate()
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = true,
|
||||
ValidIssuer = tokenService.Issuer,
|
||||
ValidateAudience = true,
|
||||
ValidAudience = tokenService.Audience,
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = tokenService.GetSigningKey(),
|
||||
ValidateLifetime = true,
|
||||
ClockSkew = TimeSpan.FromMinutes(2)
|
||||
};
|
||||
|
||||
options.Events = new JwtBearerEvents
|
||||
{
|
||||
OnTokenValidated = context =>
|
||||
{
|
||||
var jti = context.Principal?.FindFirst(JwtRegisteredClaimNames.Jti)?.Value;
|
||||
if (string.IsNullOrWhiteSpace(jti))
|
||||
{
|
||||
context.Fail("Token does not contain a token id.");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
var dataContext = context.HttpContext.RequestServices.GetRequiredService<DataContext>();
|
||||
var token = dataContext.ApiTokens.FirstOrDefault(existing => existing.Jti == jti);
|
||||
if (token == null)
|
||||
{
|
||||
context.Fail("Token is not registered.");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
if (token.RevokedAt.HasValue || token.ExpiresAt <= DateTime.UtcNow)
|
||||
{
|
||||
context.Fail("Token is revoked or expired.");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
token.LastUsedAt = DateTime.UtcNow;
|
||||
token.Modified = DateTime.UtcNow;
|
||||
token.ModifiedBy = "BearerToken";
|
||||
dataContext.SaveChanges();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
|
||||
@@ -45,6 +113,15 @@ builder.Services.AddAuthorization(options =>
|
||||
{
|
||||
// By default, all incoming requests will be authorized according to the default policy.
|
||||
options.FallbackPolicy = options.DefaultPolicy;
|
||||
options.AddPolicy("QueueProcess", policy => policy.RequireClaim("scope", "queue.process"));
|
||||
options.AddPolicy("DeploymentRead", policy => policy.RequireClaim("scope", "deployment.read"));
|
||||
options.AddPolicy("CredentialResolve", policy => policy.RequireClaim("scope", "credential.resolve"));
|
||||
options.AddPolicy("TokenManage", policy => policy.RequireAssertion(context =>
|
||||
context.User.HasClaim("scope", "token.manage")
|
||||
|| context.User.Identity?.AuthenticationType == NegotiateDefaults.AuthenticationScheme));
|
||||
options.AddPolicy("TokenAdmin", policy => policy.RequireAssertion(context =>
|
||||
context.User.HasClaim("scope", "token.admin")
|
||||
|| context.User.Identity?.AuthenticationType == NegotiateDefaults.AuthenticationScheme));
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
@@ -101,3 +178,5 @@ if (Directory.Exists(frontendDistPath))
|
||||
|
||||
app.Run();
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user