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:
Torsten Brendgen
2026-07-09 14:44:38 +02:00
parent 1aa2adac08
commit dc93ea0813
72 changed files with 32906 additions and 516 deletions

View File

@@ -55,13 +55,8 @@ namespace Microsoft.SelfService.Portal.Core.API.Services
return queueJob.Id;
}
public Guid EnqueueDeploymentRequest(Guid deploymentGroupId, ICollection<Guid> targetIds, string jsonData)
public Guid EnqueueDeploymentRequest(Guid deploymentGroupId, ICollection<Guid> targetIds, string jsonData, Guid? deploymentArtifactId = null)
{
var deploymentDocument = ConfigurationDocumentValidator.NormalizeAndValidate(
jsonData,
ConfigurationDocumentKind.DeploymentOverride);
jsonData = deploymentDocument.JsonData;
var deploymentGroup = _context.DeploymentGroups
.AsNoTracking()
.Include(group => group.Template)
@@ -80,6 +75,39 @@ namespace Microsoft.SelfService.Portal.Core.API.Services
throw new InvalidOperationException("DeploymentGroup does not exist.");
}
var currentArtifact = deploymentArtifactId.HasValue
? _context.DeploymentArtifacts
.AsNoTracking()
.FirstOrDefault(artifact =>
artifact.Id == deploymentArtifactId.Value
&& artifact.DeploymentGroupId == deploymentGroupId
&& !artifact.IsStale)
: _context.DeploymentArtifacts
.AsNoTracking()
.Where(artifact =>
artifact.DeploymentGroupId == deploymentGroupId
&& artifact.ArtifactType == DeploymentArtifactTypes.ResolvedConfigurationData
&& !artifact.IsStale)
.OrderByDescending(artifact => artifact.Created)
.FirstOrDefault();
if (deploymentArtifactId.HasValue && currentArtifact == null)
{
throw new InvalidOperationException("Deployment artifact does not exist or is stale.");
}
if (currentArtifact != null)
{
jsonData = currentArtifact.DeploymentJson;
}
else
{
var deploymentDocument = ConfigurationDocumentValidator.NormalizeAndValidate(
jsonData,
ConfigurationDocumentKind.DeploymentOverride);
jsonData = deploymentDocument.JsonData;
}
var primaryTemplateSelection = deploymentGroup.TemplateSelections
.OrderBy(selection => selection.SortOrder)
.FirstOrDefault();
@@ -156,6 +184,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Services
{
selection.Id,
selection.TemplateVersionId,
selection.TemplateRevisionId,
TemplateId = selection.TemplateVersion.TemplateId,
TemplateName = selection.TemplateVersion.Template.Name,
selection.TemplateVersion.Version,
@@ -176,6 +205,8 @@ namespace Microsoft.SelfService.Portal.Core.API.Services
assignment.NodeDataJson
}),
TargetIds = resolvedTargetIds,
DeploymentArtifactId = currentArtifact?.Id,
DeploymentJson = currentArtifact?.DeploymentJson,
JsonData = jsonData,
TargetCount = resolvedTargetIds.Count,
Created = DateTime.UtcNow