c74dd63281
- GET /api/docs serves a Swagger UI and GET /api/openapi.json serves an OpenAPI 3 spec built by walking the live chi router, so documented paths always match what the build serves. A small registry adds rich detail (request bodies, params, schemas) for the automation-critical operations (auth login, rule create/update/preview, connection introspection); RuleInput and friends are defined as reusable component schemas. - Add docs/examples/Create-OrchestrADRule.ps1: a no-alias PowerShell sample that builds headers/body as typed dictionaries, serializes with ConvertTo-Json, logs in, creates a SyncGroupMembership rule, and runs it. - README: new "API & Automation" section (Swagger + PowerShell), and a "Logging & Retention" section documenting log rotation and the new database maintenance/retention knobs. Tests cover spec generation from a router and registry well-formedness. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
111 lines
4.6 KiB
PowerShell
111 lines
4.6 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Creates an OrchestrAD dynamic-group rule through the REST API.
|
|
|
|
.DESCRIPTION
|
|
Demonstrates authenticating to OrchestrAD and creating a rule that syncs all
|
|
users whose department is "Sales" into a target group (creating the group if
|
|
missing, and keeping its membership exactly in step with the filter).
|
|
|
|
Style notes (as requested):
|
|
* Body and headers are built as strongly-typed dictionaries via
|
|
New-Object with the full type name.
|
|
* The body is converted to JSON with ConvertTo-Json.
|
|
* Full cmdlet names are used throughout — no aliases.
|
|
|
|
Requires PowerShell 7+ (uses -SkipCertificateCheck for the self-signed dev
|
|
certificate; drop that switch when a trusted certificate is in use).
|
|
|
|
.EXAMPLE
|
|
./Create-OrchestrADRule.ps1 -BaseUrl 'https://localhost:18090' -Username 'admin' -Password 'admin' -ConnectionId '57feb058-...' -TargetGroupDn 'CN=Sales,OU=Groups,DC=corp,DC=com'
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true)] [string] $BaseUrl,
|
|
[Parameter(Mandatory = $true)] [string] $Username,
|
|
[Parameter(Mandatory = $true)] [string] $Password,
|
|
[Parameter(Mandatory = $true)] [string] $ConnectionId,
|
|
[Parameter(Mandatory = $true)] [string] $TargetGroupDn,
|
|
[Parameter(Mandatory = $false)] [string] $Department = 'Sales'
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
# --- 1. Authenticate and obtain a bearer token ----------------------------------
|
|
|
|
$loginBody = New-Object 'System.Collections.Generic.Dictionary[String,Object]'
|
|
$loginBody.Add('username', $Username)
|
|
$loginBody.Add('password', $Password)
|
|
|
|
$loginResponse = Invoke-RestMethod -Method 'Post' -Uri "$BaseUrl/api/v1/auth/login" `
|
|
-ContentType 'application/json' -Body ($loginBody | ConvertTo-Json) -SkipCertificateCheck
|
|
|
|
$token = $loginResponse.data.token
|
|
Write-Output "Authenticated as '$Username'."
|
|
|
|
# --- 2. Build request headers as a dictionary -----------------------------------
|
|
|
|
$headers = New-Object 'System.Collections.Generic.Dictionary[String,String]'
|
|
$headers.Add('Authorization', "Bearer $token")
|
|
$headers.Add('Accept', 'application/json')
|
|
|
|
# --- 3. Build the rule body as nested dictionaries / lists ----------------------
|
|
|
|
# One condition: department equals $Department.
|
|
$condition = New-Object 'System.Collections.Generic.Dictionary[String,Object]'
|
|
$condition.Add('attributeName', 'department')
|
|
$condition.Add('operator', 'Equals')
|
|
$condition.Add('comparisonValue', $Department)
|
|
|
|
$conditions = New-Object 'System.Collections.Generic.List[Object]'
|
|
$conditions.Add($condition)
|
|
|
|
$group = New-Object 'System.Collections.Generic.Dictionary[String,Object]'
|
|
$group.Add('joinOperator', 'AND')
|
|
$group.Add('conditions', $conditions)
|
|
|
|
$conditionGroups = New-Object 'System.Collections.Generic.List[Object]'
|
|
$conditionGroups.Add($group)
|
|
|
|
# One action: sync membership to the target group (full add + remove).
|
|
$actionConfig = New-Object 'System.Collections.Generic.Dictionary[String,Object]'
|
|
$actionConfig.Add('targetGroupDn', $TargetGroupDn)
|
|
$actionConfig.Add('syncMode', 'FullSync')
|
|
$actionConfig.Add('createIfMissing', $true)
|
|
$actionConfig.Add('groupScope', 'Global')
|
|
$actionConfig.Add('groupType', 'Security')
|
|
|
|
$action = New-Object 'System.Collections.Generic.Dictionary[String,Object]'
|
|
$action.Add('actionType', 'SyncGroupMembership')
|
|
# configurationJson is a JSON *string*, so serialize the config dictionary.
|
|
$action.Add('configurationJson', ($actionConfig | ConvertTo-Json -Compress))
|
|
|
|
$actions = New-Object 'System.Collections.Generic.List[Object]'
|
|
$actions.Add($action)
|
|
|
|
$ruleBody = New-Object 'System.Collections.Generic.Dictionary[String,Object]'
|
|
$ruleBody.Add('name', "Sales - $Department")
|
|
$ruleBody.Add('description', 'Created via the OrchestrAD REST API')
|
|
$ruleBody.Add('adConnectionId', $ConnectionId)
|
|
$ruleBody.Add('objectType', 'User')
|
|
$ruleBody.Add('executionMode', 'Apply')
|
|
$ruleBody.Add('groupJoinOperator', 'AND')
|
|
$ruleBody.Add('conditionGroups', $conditionGroups)
|
|
$ruleBody.Add('actions', $actions)
|
|
|
|
# --- 4. Create the rule ---------------------------------------------------------
|
|
|
|
$json = $ruleBody | ConvertTo-Json -Depth 10
|
|
$rule = Invoke-RestMethod -Method 'Post' -Uri "$BaseUrl/api/v1/rules" `
|
|
-Headers $headers -ContentType 'application/json' -Body $json -SkipCertificateCheck
|
|
|
|
Write-Output ("Created rule '{0}' (id {1})." -f $rule.data.name, $rule.data.id)
|
|
|
|
# --- 5. (Optional) run it now ---------------------------------------------------
|
|
|
|
$run = Invoke-RestMethod -Method 'Post' -Uri "$BaseUrl/api/v1/rules/$($rule.data.id)/run" `
|
|
-Headers $headers -SkipCertificateCheck
|
|
Write-Output ("Run status: {0}" -f $run.data.status)
|