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.
194 lines
6.3 KiB
PowerShell
194 lines
6.3 KiB
PowerShell
param(
|
|
[string]$ApiBaseUrl = 'http://localhost:5286/api',
|
|
|
|
[string]$ClientId = 'ssp-demo-worker',
|
|
|
|
[string]$ClientSecret = 'DemoOnly-DoNotUseInProduction!',
|
|
|
|
[int]$ApiTimeoutSec = 30
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
function Invoke-TestApi {
|
|
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
|
|
}
|
|
catch {
|
|
$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 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 = 'configuration.read'
|
|
}
|
|
|
|
$token.accessToken | Should Not BeNullOrEmpty
|
|
$token.tokenType | Should Be 'Bearer'
|
|
$token.expiresIn | Should BeGreaterThan 0
|
|
$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 = 'configuration.read'
|
|
}
|
|
|
|
$definitions = @(Invoke-TestApi -Method GET -Path 'configuration-definitions?kind=Parameter' -BearerToken $token.accessToken)
|
|
|
|
@($definitions).Count | Should BeGreaterThan 0
|
|
@($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
|
|
clientSecret = $ClientSecret
|
|
scope = 'token.manage token.admin deployment.read'
|
|
}
|
|
|
|
$managedToken = Invoke-TestApi -Method POST -Path 'tokens/my' -BearerToken $adminToken.accessToken -Body @{
|
|
name = 'Pester managed token'
|
|
scope = 'deployment.read'
|
|
}
|
|
|
|
$managedToken.id | Should Not BeNullOrEmpty
|
|
$managedToken.accessToken | Should Not BeNullOrEmpty
|
|
$managedToken.scope | Should Be 'deployment.read'
|
|
|
|
$myTokens = @(Invoke-TestApi -Method GET -Path 'tokens/my' -BearerToken $adminToken.accessToken)
|
|
@($myTokens | Where-Object { $_.id -eq $managedToken.id }).Count | Should Be 1
|
|
|
|
$allTokens = @(Invoke-TestApi -Method GET -Path 'tokens/admin' -BearerToken $adminToken.accessToken)
|
|
@($allTokens | Where-Object { $_.id -eq $managedToken.id }).Count | Should Be 1
|
|
|
|
$deletedToken = Invoke-TestApi -Method DELETE -Path ('tokens/my/{0}' -f $managedToken.id) -BearerToken $adminToken.accessToken
|
|
|
|
$deletedToken.id | Should Be $managedToken.id
|
|
$deletedToken.revokedAt | Should Not BeNullOrEmpty
|
|
$deletedToken.isActive | Should Be $false
|
|
|
|
$myTokensAfterDelete = @(Invoke-TestApi -Method GET -Path 'tokens/my' -BearerToken $adminToken.accessToken)
|
|
$myTokenAfterDelete = $myTokensAfterDelete | Where-Object { [string]$_.id -eq [string]$managedToken.id } | Select-Object -First 1
|
|
if ($myTokenAfterDelete) {
|
|
$myTokenAfterDelete.isActive | Should Be $false
|
|
}
|
|
|
|
$adminTokensAfterDelete = @(Invoke-TestApi -Method GET -Path 'tokens/admin' -BearerToken $adminToken.accessToken)
|
|
$revokedToken = $adminTokensAfterDelete | Where-Object { [string]$_.id -eq [string]$managedToken.id } | Select-Object -First 1
|
|
if ($revokedToken) {
|
|
$revokedToken.revokedAt | Should Not BeNullOrEmpty
|
|
$revokedToken.isActive | Should Be $false
|
|
}
|
|
}
|
|
}
|