Add migration to update ApiClients with centralized authorization scopes
This migration updates the ScopesJson for the ApiClient with Id 91000000-0000-0000-0000-000000000001 to include additional authorization scopes for improved API access control. The Down method reverts the changes if necessary.
This commit is contained in:
422
.tests/Api.Workflow.Tests.ps1
Normal file
422
.tests/Api.Workflow.Tests.ps1
Normal file
@@ -0,0 +1,422 @@
|
||||
param(
|
||||
[string]$ApiBaseUrl = 'http://localhost:5286/api',
|
||||
|
||||
[string]$ClientId = 'ssp-demo-worker',
|
||||
|
||||
[string]$ClientSecret = 'DemoOnly-DoNotUseInProduction!',
|
||||
|
||||
[int]$ApiTimeoutSec = 30
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Invoke-Api {
|
||||
param(
|
||||
[ValidateSet('GET', 'POST', 'PUT', 'DELETE')]
|
||||
[string]$Method,
|
||||
|
||||
[string]$Path,
|
||||
|
||||
[object]$Body,
|
||||
|
||||
[string]$BearerToken,
|
||||
|
||||
[switch]$AllowNotFound
|
||||
)
|
||||
|
||||
$uri = ('{0}/{1}' -f $ApiBaseUrl.TrimEnd('/'), $Path.TrimStart('/'))
|
||||
$parameters = @{
|
||||
Method = $Method
|
||||
Uri = $uri
|
||||
TimeoutSec = $ApiTimeoutSec
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
|
||||
if ($Body) {
|
||||
$parameters.Body = ($Body | ConvertTo-Json -Depth 20)
|
||||
$parameters.ContentType = 'application/json'
|
||||
}
|
||||
|
||||
if ($BearerToken) {
|
||||
$parameters.Headers = @{
|
||||
Authorization = "Bearer $BearerToken"
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Invoke-RestMethod @parameters
|
||||
}
|
||||
catch {
|
||||
$statusCode = $null
|
||||
if ($_.Exception.Response -and $_.Exception.Response.StatusCode) {
|
||||
$statusCode = [int]$_.Exception.Response.StatusCode
|
||||
}
|
||||
|
||||
if ($AllowNotFound -and $statusCode -eq 404) {
|
||||
return $null
|
||||
}
|
||||
|
||||
$responseBody = '<empty response body>'
|
||||
if ($_.Exception.Response) {
|
||||
try {
|
||||
$stream = $_.Exception.Response.GetResponseStream()
|
||||
if ($stream) {
|
||||
$reader = [System.IO.StreamReader]::new($stream)
|
||||
$text = $reader.ReadToEnd()
|
||||
if (-not [string]::IsNullOrWhiteSpace($text)) {
|
||||
$responseBody = $text
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
$responseBody = '<could not read response body>'
|
||||
}
|
||||
}
|
||||
|
||||
throw "API request failed. Method=[$Method], Uri=[$uri], Response=[$responseBody]. $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
function Get-AuthToken {
|
||||
param([string]$Scope)
|
||||
|
||||
$token = Invoke-Api -Method POST -Path 'auth/token' -Body @{
|
||||
clientId = $ClientId
|
||||
clientSecret = $ClientSecret
|
||||
scope = $Scope
|
||||
}
|
||||
|
||||
return $token.accessToken
|
||||
}
|
||||
|
||||
function Find-ByName {
|
||||
param(
|
||||
[object[]]$Items,
|
||||
[string]$Name
|
||||
)
|
||||
|
||||
return @($Items | Where-Object { $_.name -eq $Name })[0]
|
||||
}
|
||||
|
||||
function ConvertTo-GuidValue {
|
||||
param([object]$Value)
|
||||
|
||||
return [guid]@($Value)[0]
|
||||
}
|
||||
|
||||
function ConvertTo-ApiItems {
|
||||
param([object]$Value)
|
||||
|
||||
if ($null -eq $Value) {
|
||||
return @()
|
||||
}
|
||||
|
||||
$items = @($Value)
|
||||
if ($items.Count -eq 1 -and $items[0] -is [array]) {
|
||||
return @($items[0])
|
||||
}
|
||||
|
||||
if ($items.Count -eq 1 -and $items[0].PSObject.Properties['value']) {
|
||||
return @($items[0].value)
|
||||
}
|
||||
|
||||
return $items
|
||||
}
|
||||
|
||||
function Write-TestSection {
|
||||
param([string]$Name)
|
||||
|
||||
Write-Host ""
|
||||
Write-Host ("=== {0} ===" -f $Name) -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
function Write-TestInfo {
|
||||
param(
|
||||
[string]$Label,
|
||||
[object]$Value
|
||||
)
|
||||
|
||||
Write-Host (" - {0}: {1}" -f $Label, $Value)
|
||||
}
|
||||
|
||||
Describe 'API controller workflow smoke test' {
|
||||
$script:token = $null
|
||||
$script:environmentId = $null
|
||||
$script:domainIds = @()
|
||||
$script:targetIds = @()
|
||||
$script:deploymentBatchId = $null
|
||||
$script:templateSelectionIds = @()
|
||||
$script:targetAssignmentIds = @()
|
||||
$script:configurationValueId = $null
|
||||
$script:credentialSecretId = $null
|
||||
$script:testRunId = ([guid]::NewGuid().ToString('N')).Substring(0, 8)
|
||||
$script:environmentName = "Pester Environment $script:testRunId"
|
||||
$script:domainName1 = "Pester Domain A $script:testRunId"
|
||||
$script:domainName2 = "Pester Domain B $script:testRunId"
|
||||
$script:targetName1 = "PST-$script:testRunId-01"
|
||||
$script:targetName2 = "PST-$script:testRunId-02"
|
||||
$script:targetName3 = "PST-$script:testRunId-03"
|
||||
$script:credentialSecretName = "Pester/Workflow/$script:testRunId"
|
||||
|
||||
try {
|
||||
It 'creates an environment, links two domains, creates targets and composes a deployment batch' {
|
||||
Write-TestSection -Name 'test run'
|
||||
Write-TestInfo -Label 'API base URL' -Value $ApiBaseUrl
|
||||
Write-TestInfo -Label 'Run id' -Value $script:testRunId
|
||||
|
||||
Write-TestSection -Name 'auth and inventory'
|
||||
$script:token = Get-AuthToken -Scope 'configuration.read configuration.write credential.read credential.write credential.resolve deployment.read deployment.write queue.read template.read token.manage token.admin'
|
||||
Write-TestInfo -Label 'Bearer token' -Value 'issued'
|
||||
|
||||
$allowedScopesResponse = Invoke-Api -Method GET -Path 'tokens/scopes' -BearerToken $script:token
|
||||
$allowedScopes = @($allowedScopesResponse)
|
||||
if ($allowedScopesResponse.PSObject.Properties['value']) {
|
||||
$allowedScopes = @($allowedScopesResponse.value)
|
||||
}
|
||||
|
||||
$allowedScopes -contains 'deployment.write' | Should Be $true
|
||||
Write-TestInfo -Label 'Allowed scopes' -Value @($allowedScopes).Count
|
||||
|
||||
$myTokens = @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path 'tokens/my' -BearerToken $script:token))
|
||||
$myTokens.Count | Should BeGreaterThan 0
|
||||
Write-TestInfo -Label 'Managed tokens visible' -Value $myTokens.Count
|
||||
|
||||
$services = @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path 'Service' -BearerToken $script:token))
|
||||
$services.Count | Should BeGreaterThan 0
|
||||
Write-TestInfo -Label 'Services' -Value $services.Count
|
||||
$service = $services | Select-Object -First 1
|
||||
Invoke-Api -Method GET -Path ("Service/{0}" -f $service.id) -BearerToken $script:token | Should Not BeNullOrEmpty
|
||||
Invoke-Api -Method GET -Path ("Service/{0}/RoleDefinitions" -f $service.id) -BearerToken $script:token | Out-Null
|
||||
|
||||
$templateCategories = @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path 'TemplateCategory' -BearerToken $script:token))
|
||||
$templateCategories.Count | Should BeGreaterThan 0
|
||||
Write-TestInfo -Label 'Template categories' -Value $templateCategories.Count
|
||||
Invoke-Api -Method GET -Path ("TemplateCategory/{0}" -f $templateCategories[0].id) -BearerToken $script:token | Should Not BeNullOrEmpty
|
||||
|
||||
$deploymentRules = @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path 'deployment-rules' -BearerToken $script:token))
|
||||
$deploymentRules.Count | Should BeGreaterThan 0
|
||||
Write-TestInfo -Label 'Deployment rules' -Value $deploymentRules.Count
|
||||
Invoke-Api -Method GET -Path ("deployment-rules/{0}" -f $deploymentRules[0].id) -BearerToken $script:token | Should Not BeNullOrEmpty
|
||||
|
||||
$configurationDefinitions = @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path 'configuration-definitions' -BearerToken $script:token))
|
||||
$configurationDefinitions.Count | Should BeGreaterThan 0
|
||||
Write-TestInfo -Label 'Configuration definitions' -Value $configurationDefinitions.Count
|
||||
$configurationDefinition = $configurationDefinitions | Select-Object -First 1
|
||||
Invoke-Api -Method GET -Path ("configuration-definitions/{0}" -f $configurationDefinition.id) -BearerToken $script:token | Should Not BeNullOrEmpty
|
||||
Invoke-Api -Method GET -Path ("configuration-definitions/{0}/values" -f $configurationDefinition.id) -BearerToken $script:token | Out-Null
|
||||
|
||||
Write-TestSection -Name 'credential secret'
|
||||
$script:credentialSecretId = ConvertTo-GuidValue -Value (Invoke-Api -Method POST -Path 'credential-secrets' -BearerToken $script:token -Body @{
|
||||
name = $script:credentialSecretName
|
||||
userName = "CONTOSO\svc-pester-$script:testRunId"
|
||||
secretValue = 'PesterSecret!'
|
||||
secretType = 'Credential'
|
||||
metadataJson = (@{ source = 'Api.Workflow.Tests.ps1'; runId = $script:testRunId } | ConvertTo-Json -Compress)
|
||||
isEnabled = $true
|
||||
})
|
||||
Write-TestInfo -Label 'Created credential secret' -Value $script:credentialSecretId
|
||||
Invoke-Api -Method GET -Path ("credential-secrets/{0}" -f $script:credentialSecretId) -BearerToken $script:token | Should Not BeNullOrEmpty
|
||||
$resolvedSecret = Invoke-Api -Method GET -Path ("credential-secrets/resolve?name={0}" -f [uri]::EscapeDataString($script:credentialSecretName)) -BearerToken $script:token
|
||||
$resolvedSecret.userName | Should Be "CONTOSO\svc-pester-$script:testRunId"
|
||||
Write-TestInfo -Label 'Resolved credential user' -Value $resolvedSecret.userName
|
||||
|
||||
Write-TestSection -Name 'environment and domains'
|
||||
Invoke-Api -Method POST -Path 'Environment' -BearerToken $script:token -Body @{
|
||||
name = $script:environmentName
|
||||
environmentType = 'Test'
|
||||
hostingType = 'OnPrem'
|
||||
providerType = 'Pester'
|
||||
metadataJson = (@{ source = 'Api.Workflow.Tests.ps1'; runId = $script:testRunId } | ConvertTo-Json -Compress)
|
||||
} | Out-Null
|
||||
|
||||
$environment = Find-ByName -Items @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path 'Environment' -BearerToken $script:token)) -Name $script:environmentName
|
||||
$environment | Should Not BeNullOrEmpty
|
||||
$script:environmentId = ConvertTo-GuidValue -Value $environment.id
|
||||
Write-TestInfo -Label 'Created environment' -Value ("{0} ({1})" -f $script:environmentName, $script:environmentId)
|
||||
|
||||
$script:configurationValueId = ConvertTo-GuidValue -Value (Invoke-Api -Method POST -Path 'configuration-values' -BearerToken $script:token -Body @{
|
||||
configurationDefinitionId = [string](ConvertTo-GuidValue -Value $configurationDefinition.id)
|
||||
scopeType = 'Environment'
|
||||
scopeId = [string]$script:environmentId
|
||||
valueSourceType = 'Static'
|
||||
valueJson = (@{ value = "Pester-$script:testRunId" } | ConvertTo-Json -Compress)
|
||||
sortOrder = 999
|
||||
})
|
||||
@(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path ("configuration-values?scopeType=Environment&scopeId={0}" -f $script:environmentId) -BearerToken $script:token)).Count | Should BeGreaterThan 0
|
||||
Write-TestInfo -Label 'Created configuration value' -Value $script:configurationValueId
|
||||
|
||||
$domainId1 = Invoke-Api -Method POST -Path 'Domain' -BearerToken $script:token -Body @{
|
||||
name = $script:domainName1
|
||||
fqdn = "pester-a-$script:testRunId.contoso.local"
|
||||
netBIOS = "PSTA$($script:testRunId.Substring(0, 4))".ToUpper()
|
||||
}
|
||||
|
||||
$domainId2 = Invoke-Api -Method POST -Path 'Domain' -BearerToken $script:token -Body @{
|
||||
name = $script:domainName2
|
||||
fqdn = "pester-b-$script:testRunId.contoso.local"
|
||||
netBIOS = "PSTB$($script:testRunId.Substring(0, 4))".ToUpper()
|
||||
}
|
||||
|
||||
$script:domainIds = @(
|
||||
(ConvertTo-GuidValue -Value $domainId1),
|
||||
(ConvertTo-GuidValue -Value $domainId2)
|
||||
)
|
||||
Write-TestInfo -Label 'Created domains' -Value ($script:domainIds -join ', ')
|
||||
|
||||
foreach ($domainId in $script:domainIds) {
|
||||
Invoke-Api -Method POST -Path ("Domain/{0}/Environment/{1}" -f $domainId, $script:environmentId) -BearerToken $script:token | Out-Null
|
||||
}
|
||||
Write-TestInfo -Label 'Linked domains to environment' -Value $script:domainIds.Count
|
||||
|
||||
Write-TestSection -Name 'targets'
|
||||
$targetDefinitions = @(
|
||||
@{ name = $script:targetName1; domainId = $script:domainIds[0]; role = 'WebFrontEnd'; order = 10 },
|
||||
@{ name = $script:targetName2; domainId = $script:domainIds[0]; role = 'Application'; order = 20 },
|
||||
@{ name = $script:targetName3; domainId = $script:domainIds[1]; role = 'Search'; order = 30 }
|
||||
)
|
||||
|
||||
foreach ($targetDefinition in $targetDefinitions) {
|
||||
$targetId = Invoke-Api -Method POST -Path 'Target' -BearerToken $script:token -Body @{
|
||||
domainID = $targetDefinition.domainId
|
||||
name = $targetDefinition.name
|
||||
targetType = 'VirtualMachine'
|
||||
providerType = 'OnPrem'
|
||||
externalId = $targetDefinition.name
|
||||
metadataJson = (@{ source = 'Api.Workflow.Tests.ps1'; role = $targetDefinition.role } | ConvertTo-Json -Compress)
|
||||
}
|
||||
|
||||
$script:targetIds += ConvertTo-GuidValue -Value $targetId
|
||||
Write-TestInfo -Label 'Created target' -Value ("{0} / {1} ({2})" -f $targetDefinition.name, $targetDefinition.role, $targetId)
|
||||
}
|
||||
|
||||
@($script:targetIds).Count | Should Be 3
|
||||
|
||||
Write-TestSection -Name 'template selection'
|
||||
$templates = @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path 'Template' -BearerToken $script:token))
|
||||
$onPremServiceIds = @(
|
||||
$services |
|
||||
Where-Object { -not $_.isCloudService } |
|
||||
ForEach-Object { [string]$_.id }
|
||||
)
|
||||
$onPremCategoryIds = @(
|
||||
$templateCategories |
|
||||
Where-Object { $onPremServiceIds -contains [string]$_.serviceId } |
|
||||
ForEach-Object { [string]$_.id }
|
||||
)
|
||||
$selectedTemplates = @(
|
||||
$templates |
|
||||
Where-Object { $onPremCategoryIds -contains [string]$_.templateCategoryId } |
|
||||
Select-Object -First 2
|
||||
)
|
||||
@($selectedTemplates).Count | Should BeGreaterThan 0
|
||||
Write-TestInfo -Label 'Available templates' -Value $templates.Count
|
||||
Write-TestInfo -Label 'Selected templates' -Value (($selectedTemplates | ForEach-Object { $_.name }) -join ', ')
|
||||
|
||||
$templateSelections = @()
|
||||
$sortOrder = 10
|
||||
foreach ($template in $selectedTemplates) {
|
||||
$versions = @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path ("Template/{0}/Versions" -f $template.id) -BearerToken $script:token))
|
||||
$version = $versions | Select-Object -First 1
|
||||
$version | Should Not BeNullOrEmpty
|
||||
|
||||
$templateSelections += @{
|
||||
templateVersionId = [string](ConvertTo-GuidValue -Value $version.id)
|
||||
templateRole = 'Service'
|
||||
sortOrder = $sortOrder
|
||||
alias = "Pester-$sortOrder"
|
||||
}
|
||||
|
||||
Write-TestInfo -Label 'Pinned template version' -Value ("{0} -> {1}" -f $template.name, $version.id)
|
||||
$sortOrder += 10
|
||||
}
|
||||
|
||||
$targetAssignments = @()
|
||||
foreach ($targetDefinition in $targetDefinitions) {
|
||||
$targetId = $script:targetIds[$targetDefinitions.IndexOf($targetDefinition)]
|
||||
$targetAssignments += @{
|
||||
targetId = [string]$targetId
|
||||
roleKey = $targetDefinition.role
|
||||
sortOrder = $targetDefinition.order
|
||||
nodeDataJson = (@{ nodeName = $targetDefinition.name; pester = $true } | ConvertTo-Json -Compress)
|
||||
}
|
||||
}
|
||||
|
||||
Write-TestSection -Name 'deployment batch'
|
||||
$script:deploymentBatchId = ConvertTo-GuidValue -Value (Invoke-Api -Method POST -Path 'deployment-batches' -BearerToken $script:token -Body @{
|
||||
status = 'Pending'
|
||||
targetIds = @()
|
||||
templateSelections = $templateSelections
|
||||
targetAssignments = $targetAssignments
|
||||
})
|
||||
|
||||
$script:deploymentBatchId | Should Not BeNullOrEmpty
|
||||
Write-TestInfo -Label 'Created deployment batch' -Value $script:deploymentBatchId
|
||||
|
||||
$composition = Invoke-Api -Method GET -Path ("deployment-batches/{0}/composition" -f $script:deploymentBatchId) -BearerToken $script:token
|
||||
@($composition.templateSelections).Count | Should Be @($templateSelections).Count
|
||||
|
||||
$composition = Invoke-Api -Method GET -Path ("deployment-batches/{0}/composition" -f $script:deploymentBatchId) -BearerToken $script:token
|
||||
@($composition.targetAssignments).Count | Should Be 3
|
||||
$script:targetAssignmentIds = @($composition.targetAssignments | ForEach-Object { ConvertTo-GuidValue -Value $_.id })
|
||||
Write-TestInfo -Label 'Composition template selections' -Value @($composition.templateSelections).Count
|
||||
Write-TestInfo -Label 'Composition target assignments' -Value @($composition.targetAssignments).Count
|
||||
|
||||
$deployments = @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path 'Deployment' -BearerToken $script:token) | Where-Object { [string]$_.deploymentGroupId -eq [string]$script:deploymentBatchId })
|
||||
$deployments.Count | Should Be 3
|
||||
Write-TestInfo -Label 'Deployment rows' -Value $deployments.Count
|
||||
Invoke-Api -Method GET -Path ("Deployment/{0}" -f $deployments[0].id) -BearerToken $script:token | Should Not BeNullOrEmpty
|
||||
|
||||
Invoke-Api -Method GET -Path ("deployment-artifacts?deploymentGroupId={0}" -f $script:deploymentBatchId) -BearerToken $script:token | Out-Null
|
||||
Invoke-Api -Method GET -Path 'Deployment/QueueJobs' -BearerToken $script:token | Out-Null
|
||||
Write-TestInfo -Label 'Artifact and queue endpoints' -Value 'reachable'
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if ($script:token) {
|
||||
Write-TestSection -Name 'cleanup'
|
||||
if ($script:credentialSecretId) {
|
||||
Invoke-Api -Method DELETE -Path ("credential-secrets/{0}" -f $script:credentialSecretId) -BearerToken $script:token -AllowNotFound | Out-Null
|
||||
Write-TestInfo -Label 'Deleted credential secret' -Value $script:credentialSecretId
|
||||
}
|
||||
|
||||
if ($script:configurationValueId) {
|
||||
Invoke-Api -Method DELETE -Path ("configuration-values/{0}" -f $script:configurationValueId) -BearerToken $script:token -AllowNotFound | Out-Null
|
||||
Write-TestInfo -Label 'Deleted configuration value' -Value $script:configurationValueId
|
||||
}
|
||||
|
||||
foreach ($assignmentId in @($script:targetAssignmentIds)) {
|
||||
if ($script:deploymentBatchId) {
|
||||
Invoke-Api -Method DELETE -Path ("deployment-batches/{0}/target-assignments/{1}" -f $script:deploymentBatchId, $assignmentId) -BearerToken $script:token -AllowNotFound | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
if ($script:deploymentBatchId) {
|
||||
Invoke-Api -Method DELETE -Path ("deployment-batches/{0}" -f $script:deploymentBatchId) -BearerToken $script:token -AllowNotFound | Out-Null
|
||||
Write-TestInfo -Label 'Deleted deployment batch' -Value $script:deploymentBatchId
|
||||
}
|
||||
|
||||
foreach ($targetId in @($script:targetIds)) {
|
||||
Invoke-Api -Method DELETE -Path ("Target/{0}" -f $targetId) -BearerToken $script:token -AllowNotFound | Out-Null
|
||||
}
|
||||
if (@($script:targetIds).Count -gt 0) {
|
||||
Write-TestInfo -Label 'Deleted targets' -Value @($script:targetIds).Count
|
||||
}
|
||||
|
||||
foreach ($domainId in @($script:domainIds)) {
|
||||
if ($script:environmentId) {
|
||||
Invoke-Api -Method DELETE -Path ("Domain/{0}/Environment/{1}" -f $domainId, $script:environmentId) -BearerToken $script:token -AllowNotFound | Out-Null
|
||||
}
|
||||
|
||||
Invoke-Api -Method DELETE -Path ("Domain/{0}" -f $domainId) -BearerToken $script:token -AllowNotFound | Out-Null
|
||||
}
|
||||
if (@($script:domainIds).Count -gt 0) {
|
||||
Write-TestInfo -Label 'Deleted domains' -Value @($script:domainIds).Count
|
||||
}
|
||||
|
||||
if ($script:environmentId) {
|
||||
Invoke-Api -Method DELETE -Path ("Environment/{0}" -f $script:environmentId) -BearerToken $script:token -AllowNotFound | Out-Null
|
||||
Write-TestInfo -Label 'Deleted environment' -Value $script:environmentId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,25 +66,69 @@ function Invoke-TestApi {
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-TestApiExpectFailure {
|
||||
param(
|
||||
[ValidateSet('GET', 'POST', 'DELETE')]
|
||||
[string]$Method,
|
||||
|
||||
[string]$Path,
|
||||
|
||||
[object]$Body,
|
||||
|
||||
[string]$BearerToken
|
||||
)
|
||||
|
||||
$uri = ('{0}/{1}' -f $ApiBaseUrl.TrimEnd('/'), $Path.TrimStart('/'))
|
||||
$parameters = @{
|
||||
Method = $Method
|
||||
Uri = $uri
|
||||
TimeoutSec = $ApiTimeoutSec
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
|
||||
if ($Body) {
|
||||
$parameters.Body = ($Body | ConvertTo-Json -Depth 10)
|
||||
$parameters.ContentType = 'application/json'
|
||||
}
|
||||
|
||||
if ($BearerToken) {
|
||||
$parameters.Headers = @{
|
||||
Authorization = "Bearer $BearerToken"
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Invoke-RestMethod @parameters | Out-Null
|
||||
throw "API request was expected to fail but succeeded. Method=[$Method], Uri=[$uri]."
|
||||
}
|
||||
catch {
|
||||
if ($_.Exception.Response -and $_.Exception.Response.StatusCode) {
|
||||
return [int]$_.Exception.Response.StatusCode
|
||||
}
|
||||
|
||||
throw
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'On-prem client credentials API authentication' {
|
||||
It 'issues a bearer token for the seeded demo worker client' {
|
||||
$token = Invoke-TestApi -Method POST -Path 'auth/token' -Body @{
|
||||
clientId = $ClientId
|
||||
clientSecret = $ClientSecret
|
||||
scope = 'deployment.read template.read'
|
||||
scope = 'configuration.read'
|
||||
}
|
||||
|
||||
$token.accessToken | Should Not BeNullOrEmpty
|
||||
$token.tokenType | Should Be 'Bearer'
|
||||
$token.expiresIn | Should BeGreaterThan 0
|
||||
$token.scope | Should Be 'deployment.read template.read'
|
||||
$token.scope | Should Be 'configuration.read'
|
||||
}
|
||||
|
||||
It 'allows bearer-token API calls without Windows authentication' {
|
||||
$token = Invoke-TestApi -Method POST -Path 'auth/token' -Body @{
|
||||
clientId = $ClientId
|
||||
clientSecret = $ClientSecret
|
||||
scope = 'deployment.read template.read'
|
||||
scope = 'configuration.read'
|
||||
}
|
||||
|
||||
$definitions = @(Invoke-TestApi -Method GET -Path 'configuration-definitions?kind=Parameter' -BearerToken $token.accessToken)
|
||||
@@ -93,6 +137,18 @@ Describe 'On-prem client credentials API authentication' {
|
||||
@($definitions | Where-Object { $_.kind -ne 'Parameter' }).Count | Should Be 0
|
||||
}
|
||||
|
||||
It 'rejects bearer-token API calls without the required scope' {
|
||||
$token = Invoke-TestApi -Method POST -Path 'auth/token' -Body @{
|
||||
clientId = $ClientId
|
||||
clientSecret = $ClientSecret
|
||||
scope = 'deployment.read'
|
||||
}
|
||||
|
||||
$statusCode = Invoke-TestApiExpectFailure -Method GET -Path 'configuration-definitions?kind=Parameter' -BearerToken $token.accessToken
|
||||
|
||||
@(401, 403) -contains $statusCode | Should Be $true
|
||||
}
|
||||
|
||||
It 'creates, lists and revokes managed tokens through the token API' {
|
||||
$adminToken = Invoke-TestApi -Method POST -Path 'auth/token' -Body @{
|
||||
clientId = $ClientId
|
||||
|
||||
19
Authorization/ApiPolicies.cs
Normal file
19
Authorization/ApiPolicies.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Authorization
|
||||
{
|
||||
public static class ApiPolicies
|
||||
{
|
||||
public const string ConfigurationRead = "ConfigurationRead";
|
||||
public const string ConfigurationWrite = "ConfigurationWrite";
|
||||
public const string CredentialRead = "CredentialRead";
|
||||
public const string CredentialWrite = "CredentialWrite";
|
||||
public const string CredentialResolve = "CredentialResolve";
|
||||
public const string DeploymentRead = "DeploymentRead";
|
||||
public const string DeploymentWrite = "DeploymentWrite";
|
||||
public const string QueueRead = "QueueRead";
|
||||
public const string QueueProcess = "QueueProcess";
|
||||
public const string TemplateRead = "TemplateRead";
|
||||
public const string TemplateWrite = "TemplateWrite";
|
||||
public const string TokenManage = "TokenManage";
|
||||
public const string TokenAdmin = "TokenAdmin";
|
||||
}
|
||||
}
|
||||
19
Authorization/ApiScopes.cs
Normal file
19
Authorization/ApiScopes.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Authorization
|
||||
{
|
||||
public static class ApiScopes
|
||||
{
|
||||
public const string ConfigurationRead = "configuration.read";
|
||||
public const string ConfigurationWrite = "configuration.write";
|
||||
public const string CredentialRead = "credential.read";
|
||||
public const string CredentialWrite = "credential.write";
|
||||
public const string CredentialResolve = "credential.resolve";
|
||||
public const string DeploymentRead = "deployment.read";
|
||||
public const string DeploymentWrite = "deployment.write";
|
||||
public const string QueueRead = "queue.read";
|
||||
public const string QueueProcess = "queue.process";
|
||||
public const string TemplateRead = "template.read";
|
||||
public const string TemplateWrite = "template.write";
|
||||
public const string TokenManage = "token.manage";
|
||||
public const string TokenAdmin = "token.admin";
|
||||
}
|
||||
}
|
||||
50
Authorization/AuthorizationServiceCollectionExtensions.cs
Normal file
50
Authorization/AuthorizationServiceCollectionExtensions.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Authorization
|
||||
{
|
||||
public static class AuthorizationServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddSelfServicePortalAuthorization(this IServiceCollection services)
|
||||
{
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
options.FallbackPolicy = options.DefaultPolicy;
|
||||
|
||||
AddScopePolicy(options, ApiPolicies.ConfigurationRead, ApiScopes.ConfigurationRead, ApiScopes.ConfigurationWrite);
|
||||
AddScopePolicy(options, ApiPolicies.ConfigurationWrite, ApiScopes.ConfigurationWrite);
|
||||
AddScopePolicy(options, ApiPolicies.CredentialRead, ApiScopes.CredentialRead, ApiScopes.CredentialWrite, ApiScopes.CredentialResolve);
|
||||
AddScopePolicy(options, ApiPolicies.CredentialWrite, ApiScopes.CredentialWrite);
|
||||
AddScopePolicy(options, ApiPolicies.CredentialResolve, ApiScopes.CredentialResolve);
|
||||
AddScopePolicy(options, ApiPolicies.DeploymentRead, ApiScopes.DeploymentRead, ApiScopes.DeploymentWrite);
|
||||
AddScopePolicy(options, ApiPolicies.DeploymentWrite, ApiScopes.DeploymentWrite);
|
||||
AddScopePolicy(options, ApiPolicies.QueueRead, ApiScopes.QueueRead, ApiScopes.QueueProcess);
|
||||
AddScopePolicy(options, ApiPolicies.QueueProcess, ApiScopes.QueueProcess);
|
||||
AddScopePolicy(options, ApiPolicies.TemplateRead, ApiScopes.TemplateRead, ApiScopes.TemplateWrite);
|
||||
AddScopePolicy(options, ApiPolicies.TemplateWrite, ApiScopes.TemplateWrite);
|
||||
AddScopePolicy(options, ApiPolicies.TokenManage, ApiScopes.TokenManage, ApiScopes.TokenAdmin);
|
||||
AddScopePolicy(options, ApiPolicies.TokenAdmin, ApiScopes.TokenAdmin);
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
private static void AddScopePolicy(AuthorizationOptions options, string policyName, params string[] acceptedScopes)
|
||||
{
|
||||
options.AddPolicy(policyName, policy => policy.RequireAssertion(context =>
|
||||
{
|
||||
if (context.User.Identity?.IsAuthenticated != true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var tokenScopes = context.User.FindAll("scope").Select(claim => claim.Value).ToList();
|
||||
if (tokenScopes.Count == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return acceptedScopes.Any(scope => tokenScopes.Contains(scope, StringComparer.OrdinalIgnoreCase));
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -364,7 +364,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Context
|
||||
ClientId = "ssp-demo-worker",
|
||||
Name = "Demo Worker Client",
|
||||
SecretHash = ApiClientSecretHasher.HashSecretForDemoData("DemoOnly-DoNotUseInProduction!", "ssp-demo-worker"),
|
||||
ScopesJson = "[\"deployment.read\",\"deployment.write\",\"queue.process\",\"template.read\",\"credential.resolve\",\"token.manage\",\"token.admin\"]",
|
||||
ScopesJson = "[\"configuration.read\",\"configuration.write\",\"credential.read\",\"credential.write\",\"credential.resolve\",\"deployment.read\",\"deployment.write\",\"queue.read\",\"queue.process\",\"template.read\",\"template.write\",\"token.manage\",\"token.admin\"]",
|
||||
IsEnabled = true
|
||||
})
|
||||
];
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.SelfService.Portal.Core.API.Authorization;
|
||||
using Microsoft.SelfService.Portal.Core.API.Context;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Auth;
|
||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||
@@ -24,7 +25,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpGet("my")]
|
||||
[Authorize(Policy = "TokenManage")]
|
||||
[Authorize(Policy = ApiPolicies.TokenManage)]
|
||||
[ProducesResponseType(200, Type = typeof(IEnumerable<GetManagedTokenDto>))]
|
||||
public IActionResult GetMyTokens()
|
||||
{
|
||||
@@ -41,7 +42,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost("my")]
|
||||
[Authorize(Policy = "TokenManage")]
|
||||
[Authorize(Policy = ApiPolicies.TokenManage)]
|
||||
[ProducesResponseType(200, Type = typeof(CreateManagedTokenResponseDto))]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult CreateMyToken([FromBody] CreateManagedTokenRequestDto request)
|
||||
@@ -111,7 +112,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("my/{id}")]
|
||||
[Authorize(Policy = "TokenManage")]
|
||||
[Authorize(Policy = ApiPolicies.TokenManage)]
|
||||
[ProducesResponseType(200, Type = typeof(GetManagedTokenDto))]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult RevokeMyToken(Guid id)
|
||||
@@ -135,7 +136,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpGet("admin")]
|
||||
[Authorize(Policy = "TokenAdmin")]
|
||||
[Authorize(Policy = ApiPolicies.TokenAdmin)]
|
||||
[ProducesResponseType(200, Type = typeof(IEnumerable<GetManagedTokenDto>))]
|
||||
public IActionResult GetAllTokens()
|
||||
{
|
||||
@@ -148,7 +149,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("admin/{id}")]
|
||||
[Authorize(Policy = "TokenAdmin")]
|
||||
[Authorize(Policy = ApiPolicies.TokenAdmin)]
|
||||
[ProducesResponseType(200, Type = typeof(GetManagedTokenDto))]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult RevokeTokenAsAdmin(Guid id)
|
||||
@@ -166,7 +167,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpGet("scopes")]
|
||||
[Authorize(Policy = "TokenManage")]
|
||||
[Authorize(Policy = ApiPolicies.TokenManage)]
|
||||
[ProducesResponseType(200, Type = typeof(IEnumerable<string>))]
|
||||
public IActionResult GetAllowedScopes()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.SelfService.Portal.Core.API.Authorization;
|
||||
using Microsoft.SelfService.Portal.Core.API.Context;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationDefinition.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationDefinition.Edit;
|
||||
@@ -13,6 +15,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/configuration-definitions")]
|
||||
[ApiController]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationRead)]
|
||||
public class ConfigurationDefinitionController : Controller
|
||||
{
|
||||
private readonly DataContext _context;
|
||||
@@ -84,6 +87,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(422)]
|
||||
@@ -126,6 +130,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPut("{id}")]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -173,6 +178,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
[ProducesResponseType(409)]
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.SelfService.Portal.Core.API.Authorization;
|
||||
using Microsoft.SelfService.Portal.Core.API.Context;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationValue.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationValue.Get;
|
||||
@@ -11,6 +13,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/configuration-values")]
|
||||
[ApiController]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationRead)]
|
||||
public class ConfigurationValueController : Controller
|
||||
{
|
||||
private readonly DataContext _context;
|
||||
@@ -50,6 +53,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult AddConfigurationValue([FromBody] AddConfigurationValueDto configurationValue)
|
||||
@@ -89,6 +93,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult DeleteConfigurationValue(Guid id)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.SelfService.Portal.Core.API.Authorization;
|
||||
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;
|
||||
@@ -11,6 +13,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/credential-secrets")]
|
||||
[ApiController]
|
||||
[Authorize(Policy = ApiPolicies.CredentialRead)]
|
||||
public class CredentialSecretController : Controller
|
||||
{
|
||||
private readonly DataContext _context;
|
||||
@@ -50,6 +53,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpGet("resolve")]
|
||||
[Authorize(Policy = ApiPolicies.CredentialResolve)]
|
||||
[ProducesResponseType(200, Type = typeof(GetCredentialSecretValueDto))]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult ResolveCredentialSecret([FromQuery] string name)
|
||||
@@ -65,6 +69,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Policy = ApiPolicies.CredentialWrite)]
|
||||
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult AddCredentialSecret([FromBody] AddCredentialSecretDto credentialSecret)
|
||||
@@ -103,6 +108,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPut("{id}")]
|
||||
[Authorize(Policy = ApiPolicies.CredentialWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult UpdateCredentialSecret(Guid id, [FromBody] AddCredentialSecretDto credentialSecret)
|
||||
@@ -126,6 +132,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
[Authorize(Policy = ApiPolicies.CredentialWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult DeleteCredentialSecret(Guid id)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.SelfService.Portal.Core.API.Authorization;
|
||||
using Microsoft.SelfService.Portal.Core.API.Context;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentArtifact.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentArtifact.Get;
|
||||
@@ -12,6 +14,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/deployment-artifacts")]
|
||||
[ApiController]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentRead)]
|
||||
public class DeploymentArtifactController : Controller
|
||||
{
|
||||
private readonly DataContext _context;
|
||||
@@ -60,6 +63,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult AddDeploymentArtifact([FromBody] AddDeploymentArtifactDto deploymentArtifact)
|
||||
@@ -120,6 +124,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost("{id}/stale-check")]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(200, Type = typeof(GetDeploymentArtifactDto))]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult CheckDeploymentArtifactStale(Guid id)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.SelfService.Portal.Core.API.Authorization;
|
||||
using Microsoft.SelfService.Portal.Core.API.Context;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentBatch.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentBatch.Edit;
|
||||
@@ -15,6 +17,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/deployment-batches")]
|
||||
[ApiController]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentRead)]
|
||||
public class DeploymentBatchController : Controller
|
||||
{
|
||||
private readonly IDeploymentBatchInterface _deploymentBatchInterface;
|
||||
@@ -82,6 +85,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult AddDeploymentBatch([FromBody] AddDeploymentBatchDto deploymentBatch)
|
||||
@@ -118,6 +122,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -144,6 +149,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPut("{id}")]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -182,6 +188,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost("{id}/template-selections")]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -233,6 +240,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{id}/template-selections/{selectionId}")]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult DeleteTemplateSelection(Guid id, Guid selectionId)
|
||||
@@ -250,6 +258,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost("{id}/parameter-values")]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -299,6 +308,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{id}/parameter-values/{parameterValueId}")]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult DeleteParameterValue(Guid id, Guid parameterValueId)
|
||||
@@ -316,6 +326,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost("{id}/target-assignments")]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -367,6 +378,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{id}/target-assignments/{targetAssignmentId}")]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult DeleteTargetAssignment(Guid id, Guid targetAssignmentId)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.SelfService.Portal.Core.API.Authorization;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Edit;
|
||||
@@ -13,6 +15,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentRead)]
|
||||
public class DeploymentController : Controller
|
||||
{
|
||||
private readonly IDeploymentInterface _deploymentInterface;
|
||||
@@ -62,6 +65,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult AddDeploymentById([FromBody] AddDeploymentDto deployment)
|
||||
@@ -93,6 +97,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost("Request")]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult AddDeploymentRequest([FromBody] AddDeploymentRequestDto request)
|
||||
@@ -234,6 +239,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost("QueueJobs/{Id}/Retry")]
|
||||
[Authorize(Policy = ApiPolicies.QueueProcess)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult RetryQueueJob(Guid Id)
|
||||
@@ -245,6 +251,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost("QueueJobs/Steps/{stepId}/Approve")]
|
||||
[Authorize(Policy = ApiPolicies.QueueProcess)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult ApproveQueueJobStep(Guid stepId, [FromBody] QueueJobStepApprovalDto? payload)
|
||||
@@ -257,6 +264,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost("QueueJobs/Steps/{stepId}/Reject")]
|
||||
[Authorize(Policy = ApiPolicies.QueueProcess)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult RejectQueueJobStep(Guid stepId, [FromBody] QueueJobStepApprovalDto? payload)
|
||||
@@ -269,6 +277,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{Id}")]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -291,6 +300,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("Batch/{deploymentBatchId}/Target/{targetId}")]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -317,6 +327,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPut("{Id}")]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.SelfService.Portal.Core.API.Authorization;
|
||||
using Microsoft.SelfService.Portal.Core.API.Context;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentRule.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentRule.Get;
|
||||
@@ -9,6 +11,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/deployment-rules")]
|
||||
[ApiController]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentRead)]
|
||||
public class DeploymentRuleController : Controller
|
||||
{
|
||||
private readonly DataContext _context;
|
||||
@@ -49,6 +52,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult AddDeploymentRule([FromBody] AddDeploymentRuleDto deploymentRule)
|
||||
@@ -84,6 +88,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPut("{id}")]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult EditDeploymentRule(Guid id, [FromBody] AddDeploymentRuleDto deploymentRule)
|
||||
@@ -123,6 +128,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
[Authorize(Policy = ApiPolicies.DeploymentWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult DeleteDeploymentRule(Guid id)
|
||||
@@ -181,4 +187,3 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.SelfService.Portal.Core.API.Authorization;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Domain.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Domain.Edit;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Domain.Get;
|
||||
@@ -10,6 +12,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationRead)]
|
||||
public class DomainController : Controller
|
||||
{
|
||||
private readonly IDomainInterface _domainInterface;
|
||||
@@ -53,6 +56,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult AddDomainById([FromBody] AddDomainDto domain)
|
||||
@@ -83,6 +87,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{Id}")]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -105,6 +110,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPut("{Id}")]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -149,6 +155,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost("{DomainId}/Environment/{EnvironmentId}")]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(200, Type = typeof(EnvironmentDomainsModel))]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult LinkDomainByIdToEnvironment(Guid DomainId, Guid EnvironmentId)
|
||||
@@ -183,6 +190,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{DomainId}/Environment/{EnvironmentId}")]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(200, Type = typeof(EnvironmentDomainsModel))]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult UnlinkDomainByIdFromEnvironment(Guid DomainId, Guid EnvironmentId)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.SelfService.Portal.Core.API.Authorization;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Environment.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Environment.Edit;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Environment.Get;
|
||||
@@ -12,6 +14,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationRead)]
|
||||
public class EnvironmentController : Controller
|
||||
{
|
||||
private readonly IEnvironmentInterface _environmentInterface;
|
||||
@@ -53,6 +56,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult AddEnvironmentById([FromBody] AddEnvironmentDto environment)
|
||||
@@ -88,6 +92,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{Id}")]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -110,6 +115,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPut("{Id}")]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.SelfService.Portal.Core.API.Authorization;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Service.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Service.Edit;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Service.Get;
|
||||
@@ -11,6 +13,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationRead)]
|
||||
public class ServiceController : Controller
|
||||
{
|
||||
private readonly IMapper _mapper;
|
||||
@@ -51,6 +54,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult AddServiceById([FromBody] AddServiceDto service)
|
||||
@@ -79,6 +83,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPut("{Id}")]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -106,6 +111,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{Id}")]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -141,6 +147,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost("{Id}/RoleDefinitions")]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -177,6 +184,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPut("{Id}/RoleDefinitions/{RoleDefinitionId}")]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -216,6 +224,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{Id}/RoleDefinitions/{RoleDefinitionId}")]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult DeleteRoleDefinition(Guid Id, Guid RoleDefinitionId)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.SelfService.Portal.Core.API.Authorization;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Target.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Target.Edit;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Target.Get;
|
||||
@@ -10,6 +12,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationRead)]
|
||||
public class TargetController : Controller
|
||||
{
|
||||
private readonly ITargetInterface _targetInterface;
|
||||
@@ -52,6 +55,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult AddTargetById([FromBody] AddTargetDto target)
|
||||
@@ -86,6 +90,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPut("{Id}")]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -120,6 +125,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost("{Id}/Domain/{domainId}")]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -151,6 +157,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{Id}/Domain")]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult UnlinkTargetFromDomain(Guid Id)
|
||||
@@ -177,6 +184,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{Id}")]
|
||||
[Authorize(Policy = ApiPolicies.ConfigurationWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.SelfService.Portal.Core.API.Authorization;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Edit;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Get;
|
||||
@@ -10,6 +12,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize(Policy = ApiPolicies.TemplateRead)]
|
||||
public class TemplateCategoryController : Controller
|
||||
{
|
||||
private readonly IMapper _mapper;
|
||||
@@ -50,6 +53,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Policy = ApiPolicies.TemplateWrite)]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult AddTemplateCategoryById([FromBody] AddTemplateCategoryDto templateCategory)
|
||||
@@ -78,6 +82,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPut("{Id}")]
|
||||
[Authorize(Policy = ApiPolicies.TemplateWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -105,6 +110,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{Id}")]
|
||||
[Authorize(Policy = ApiPolicies.TemplateWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.SelfService.Portal.Core.API.Authorization;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Edit;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Get;
|
||||
@@ -16,6 +18,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize(Policy = ApiPolicies.TemplateRead)]
|
||||
public class TemplateController : Controller
|
||||
{
|
||||
private readonly ITemplateInterface _templateInterface;
|
||||
@@ -61,6 +64,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Policy = ApiPolicies.TemplateWrite)]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult AddTemplateById([FromBody] AddTemplateDto template)
|
||||
@@ -97,6 +101,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPut("{Id}")]
|
||||
[Authorize(Policy = ApiPolicies.TemplateWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -139,6 +144,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{Id}")]
|
||||
[Authorize(Policy = ApiPolicies.TemplateWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -186,6 +192,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost("{Id}/Versions")]
|
||||
[Authorize(Policy = ApiPolicies.TemplateWrite)]
|
||||
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -262,6 +269,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost("{Id}/Versions/{VersionId}/Revisions")]
|
||||
[Authorize(Policy = ApiPolicies.TemplateWrite)]
|
||||
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
@@ -298,6 +306,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
}
|
||||
|
||||
[HttpPost("{Id}/Versions/{VersionId}/Publish")]
|
||||
[Authorize(Policy = ApiPolicies.TemplateWrite)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult PublishTemplateVersion(Guid Id, Guid VersionId)
|
||||
|
||||
@@ -160,6 +160,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Helper
|
||||
|
||||
/** Credential Secret Model **/
|
||||
CreateMap<CredentialSecretModel, GetCredentialSecretDto>();
|
||||
CreateMap<CredentialSecretModel, GetCredentialSecretValueDto>();
|
||||
CreateMap<AddCredentialSecretDto, CredentialSecretModel>();
|
||||
|
||||
/** Service Model **/
|
||||
|
||||
4884
Migrations/20260709171904_AddCentralizedAuthorizationScopes.Designer.cs
generated
Normal file
4884
Migrations/20260709171904_AddCentralizedAuthorizationScopes.Designer.cs
generated
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddCentralizedAuthorizationScopes : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.UpdateData(
|
||||
table: "ApiClients",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("91000000-0000-0000-0000-000000000001"),
|
||||
column: "ScopesJson",
|
||||
value: "[\"configuration.read\",\"configuration.write\",\"credential.read\",\"credential.write\",\"credential.resolve\",\"deployment.read\",\"deployment.write\",\"queue.read\",\"queue.process\",\"template.read\",\"template.write\",\"token.manage\",\"token.admin\"]");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.UpdateData(
|
||||
table: "ApiClients",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("91000000-0000-0000-0000-000000000001"),
|
||||
column: "ScopesJson",
|
||||
value: "[\"deployment.read\",\"deployment.write\",\"queue.process\",\"template.read\",\"credential.resolve\",\"token.manage\",\"token.admin\"]");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Migrations
|
||||
Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc),
|
||||
ModifiedBy = "DemoSeed",
|
||||
Name = "Demo Worker Client",
|
||||
ScopesJson = "[\"deployment.read\",\"deployment.write\",\"queue.process\",\"template.read\",\"credential.resolve\",\"token.manage\",\"token.admin\"]",
|
||||
ScopesJson = "[\"configuration.read\",\"configuration.write\",\"credential.read\",\"credential.write\",\"credential.resolve\",\"deployment.read\",\"deployment.write\",\"queue.read\",\"queue.process\",\"template.read\",\"template.write\",\"token.manage\",\"token.admin\"]",
|
||||
SecretHash = "PBKDF2-SHA256.100000.c3NwLWRlbW8td29ya2VyAA==.xQxe7BHCn9pdkqHozdyspEmKnz95uCUuxVvU2vgCEbo="
|
||||
});
|
||||
});
|
||||
|
||||
16
Program.cs
16
Program.cs
@@ -2,6 +2,7 @@
|
||||
using Microsoft.AspNetCore.Authentication.Negotiate;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.SelfService.Portal.Core.API.Authorization;
|
||||
using Microsoft.SelfService.Portal.Core.API.Context;
|
||||
using Microsoft.SelfService.Portal.Core.API.Interfaces;
|
||||
using Microsoft.SelfService.Portal.Core.API.Repository;
|
||||
@@ -109,20 +110,7 @@ builder.Services.AddAuthentication(options =>
|
||||
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
|
||||
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));
|
||||
});
|
||||
builder.Services.AddSelfServicePortalAuthorization();
|
||||
|
||||
var app = builder.Build();
|
||||
var frontendDistPath = Path.GetFullPath(Path.Combine(
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.SelfService.Portal.Core.API.Authorization;
|
||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Services
|
||||
@@ -138,13 +139,19 @@ namespace Microsoft.SelfService.Portal.Core.API.Services
|
||||
|
||||
return
|
||||
[
|
||||
"deployment.read",
|
||||
"deployment.write",
|
||||
"queue.process",
|
||||
"template.read",
|
||||
"credential.resolve",
|
||||
"token.manage",
|
||||
"token.admin"
|
||||
ApiScopes.ConfigurationRead,
|
||||
ApiScopes.ConfigurationWrite,
|
||||
ApiScopes.CredentialRead,
|
||||
ApiScopes.CredentialWrite,
|
||||
ApiScopes.CredentialResolve,
|
||||
ApiScopes.DeploymentRead,
|
||||
ApiScopes.DeploymentWrite,
|
||||
ApiScopes.QueueRead,
|
||||
ApiScopes.QueueProcess,
|
||||
ApiScopes.TemplateRead,
|
||||
ApiScopes.TemplateWrite,
|
||||
ApiScopes.TokenManage,
|
||||
ApiScopes.TokenAdmin
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,14 @@
|
||||
"AllowedTokenScopes": [
|
||||
"deployment.read",
|
||||
"deployment.write",
|
||||
"configuration.read",
|
||||
"configuration.write",
|
||||
"credential.read",
|
||||
"credential.write",
|
||||
"queue.process",
|
||||
"queue.read",
|
||||
"template.read",
|
||||
"template.write",
|
||||
"credential.resolve",
|
||||
"token.manage",
|
||||
"token.admin"
|
||||
|
||||
Reference in New Issue
Block a user