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:
143
Controllers/CredentialSecretController.cs
Normal file
143
Controllers/CredentialSecretController.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.SelfService.Portal.Core.API.Context;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.CredentialSecret.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.CredentialSecret.Get;
|
||||
using Microsoft.SelfService.Portal.Core.API.JsonDocuments;
|
||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/credential-secrets")]
|
||||
[ApiController]
|
||||
public class CredentialSecretController : Controller
|
||||
{
|
||||
private readonly DataContext _context;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public CredentialSecretController(DataContext context, IMapper mapper)
|
||||
{
|
||||
_context = context;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesResponseType(200, Type = typeof(IEnumerable<GetCredentialSecretDto>))]
|
||||
public IActionResult GetCredentialSecrets()
|
||||
{
|
||||
var secrets = _context.CredentialSecrets
|
||||
.AsNoTracking()
|
||||
.OrderBy(secret => secret.Name)
|
||||
.ToList();
|
||||
|
||||
return Ok(_mapper.Map<List<GetCredentialSecretDto>>(secrets));
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
[ProducesResponseType(200, Type = typeof(GetCredentialSecretDto))]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult GetCredentialSecretById(Guid id)
|
||||
{
|
||||
var secret = _context.CredentialSecrets
|
||||
.AsNoTracking()
|
||||
.FirstOrDefault(existing => existing.Id == id);
|
||||
|
||||
if (secret == null)
|
||||
return NotFound();
|
||||
|
||||
return Ok(_mapper.Map<GetCredentialSecretDto>(secret));
|
||||
}
|
||||
|
||||
[HttpGet("resolve")]
|
||||
[ProducesResponseType(200, Type = typeof(GetCredentialSecretValueDto))]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult ResolveCredentialSecret([FromQuery] string name)
|
||||
{
|
||||
var secret = _context.CredentialSecrets
|
||||
.AsNoTracking()
|
||||
.FirstOrDefault(existing => existing.Name == name && existing.IsEnabled);
|
||||
|
||||
if (secret == null)
|
||||
return NotFound();
|
||||
|
||||
return Ok(_mapper.Map<GetCredentialSecretValueDto>(secret));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult AddCredentialSecret([FromBody] AddCredentialSecretDto credentialSecret)
|
||||
{
|
||||
if (credentialSecret == null)
|
||||
return BadRequest(ModelState);
|
||||
|
||||
if (_context.CredentialSecrets.Any(existing => existing.Name == credentialSecret.Name))
|
||||
{
|
||||
ModelState.AddModelError(nameof(credentialSecret.Name), "Credential secret already exists.");
|
||||
return StatusCode(422, ModelState);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(credentialSecret.MetadataJson))
|
||||
{
|
||||
try
|
||||
{
|
||||
credentialSecret.MetadataJson = ConfigurationDocumentValidator.NormalizeAndValidate(
|
||||
credentialSecret.MetadataJson,
|
||||
ConfigurationDocumentKind.Metadata).JsonData;
|
||||
}
|
||||
catch (ConfigurationDocumentValidationException ex)
|
||||
{
|
||||
ModelState.AddModelError(nameof(credentialSecret.MetadataJson), ex.Message);
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
}
|
||||
|
||||
var model = _mapper.Map<CredentialSecretModel>(credentialSecret);
|
||||
model.Id = Guid.NewGuid();
|
||||
|
||||
_context.CredentialSecrets.Add(model);
|
||||
_context.SaveChanges();
|
||||
|
||||
return Ok(model.Id);
|
||||
}
|
||||
|
||||
[HttpPut("{id}")]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult UpdateCredentialSecret(Guid id, [FromBody] AddCredentialSecretDto credentialSecret)
|
||||
{
|
||||
var existing = _context.CredentialSecrets.FirstOrDefault(secret => secret.Id == id);
|
||||
if (existing == null)
|
||||
return NotFound();
|
||||
|
||||
existing.Name = credentialSecret.Name;
|
||||
existing.UserName = credentialSecret.UserName;
|
||||
existing.SecretValue = credentialSecret.SecretValue;
|
||||
existing.SecretType = credentialSecret.SecretType;
|
||||
existing.MetadataJson = credentialSecret.MetadataJson;
|
||||
existing.IsEnabled = credentialSecret.IsEnabled;
|
||||
existing.Modified = DateTime.UtcNow;
|
||||
existing.ModifiedBy = User?.Identity?.Name ?? "System";
|
||||
|
||||
_context.SaveChanges();
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult DeleteCredentialSecret(Guid id)
|
||||
{
|
||||
var secret = _context.CredentialSecrets.FirstOrDefault(existing => existing.Id == id);
|
||||
if (secret == null)
|
||||
return NotFound();
|
||||
|
||||
_context.CredentialSecrets.Remove(secret);
|
||||
_context.SaveChanges();
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user