- 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.
95 lines
3.3 KiB
C#
95 lines
3.3 KiB
C#
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.SelfService.Portal.Core.API.Context;
|
|
using Microsoft.SelfService.Portal.Core.API.Dto.Auth;
|
|
using Microsoft.SelfService.Portal.Core.API.Models;
|
|
using Microsoft.SelfService.Portal.Core.API.Services;
|
|
using System.Text.Json;
|
|
|
|
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|
{
|
|
[Route("api/auth")]
|
|
[ApiController]
|
|
public class AuthController : Controller
|
|
{
|
|
private readonly DataContext _context;
|
|
private readonly ApiTokenService _tokenService;
|
|
|
|
public AuthController(DataContext context, ApiTokenService tokenService)
|
|
{
|
|
_context = context;
|
|
_tokenService = tokenService;
|
|
}
|
|
|
|
[HttpPost("token")]
|
|
[AllowAnonymous]
|
|
[ProducesResponseType(200, Type = typeof(TokenResponseDto))]
|
|
[ProducesResponseType(400)]
|
|
[ProducesResponseType(401)]
|
|
public IActionResult CreateToken([FromBody] TokenRequestDto request)
|
|
{
|
|
if (request == null
|
|
|| string.IsNullOrWhiteSpace(request.ClientId)
|
|
|| string.IsNullOrWhiteSpace(request.ClientSecret))
|
|
{
|
|
return BadRequest(new { message = "ClientId and ClientSecret are required." });
|
|
}
|
|
|
|
var client = _context.ApiClients
|
|
.FirstOrDefault(existing => existing.ClientId == request.ClientId);
|
|
|
|
if (client == null
|
|
|| !client.IsEnabled
|
|
|| (client.ExpiresAt.HasValue && client.ExpiresAt.Value <= DateTime.UtcNow)
|
|
|| !ApiClientSecretHasher.VerifySecret(request.ClientSecret, client.SecretHash))
|
|
{
|
|
return Unauthorized(new { message = "Invalid client credentials." });
|
|
}
|
|
|
|
IReadOnlyCollection<string> scopes;
|
|
try
|
|
{
|
|
scopes = _tokenService.ResolveRequestedScopes(client, request.Scope);
|
|
}
|
|
catch (InvalidOperationException ex)
|
|
{
|
|
return Unauthorized(new { message = ex.Message });
|
|
}
|
|
|
|
var token = _tokenService.CreateAccessToken(client, scopes);
|
|
var now = DateTime.UtcNow;
|
|
|
|
client.LastUsedAt = now;
|
|
client.Modified = now;
|
|
client.ModifiedBy = client.ClientId;
|
|
|
|
_context.ApiTokens.Add(new ApiTokenModel
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Jti = token.Jti,
|
|
Subject = client.ClientId,
|
|
SubjectType = "ApiClient",
|
|
ApiClientId = client.Id,
|
|
Name = $"Client credentials token for {client.Name}",
|
|
ScopesJson = JsonSerializer.Serialize(scopes),
|
|
IssuedAt = token.IssuedAt,
|
|
ExpiresAt = token.ExpiresAt,
|
|
Created = now,
|
|
CreatedBy = client.ClientId,
|
|
Modified = now,
|
|
ModifiedBy = client.ClientId
|
|
});
|
|
|
|
_context.SaveChanges();
|
|
|
|
return Ok(new TokenResponseDto
|
|
{
|
|
AccessToken = token.AccessToken,
|
|
ExpiresIn = _tokenService.TokenLifetimeSeconds,
|
|
Scope = string.Join(' ', scopes)
|
|
});
|
|
}
|
|
}
|
|
}
|