keycloakRealmManager.ps1
class KeycloakRealmManagerVersion { [int]$Major = 1 [int]$Minor = 5 [int]$Build = 82 [int]$Revision = 790 [string]ToString() { return "keycloakRealmManager v$($this.Major).$($this.Minor).$($this.Build).$($this.Revision)" } } class KeycloakRealmManager { hidden [string]$realmClientName = "admin-cli" hidden [string]$realmClientSecret = [string]::Empty hidden [string]$userName = [string]::Empty hidden [string]$password = [string]::Empty hidden [array]$clients = @() hidden [array]$users = @() hidden [array]$groups = @() hidden [array]$roles = @() hidden [hashtable]$realms = @{} [string]$realmName [PSCustomObject]$realm = $null hidden [KeycloakTokenManager]$tokenManager hidden [KeycloakRealmManagerVersion]$version = [KeycloakRealmManagerVersion]::new() [string]getVersion() { return $this.version.ToString() } hidden [void]initializeMaster([uri]$realmUri) { [string]$local:keycloakBaseUrl = "$($realmUri.Scheme)://$($realmUri.Host)" $this.getRealmDetails([string]$keycloakBaseUrl, "master") } hidden [void]initializeRealm([uri]$realmUri, [bool]$create) { [string]$local:keycloakBaseUrl = "$($realmUri.Scheme)://$($realmUri.Host)" $local:segments = ($realmUri.Segments) [int]$local:realmsIndex = $local:segments.IndexOf("realms/") $this.realmName = $local:segments[$local:realmsIndex + 1].TrimEnd("/") if ($this.realmName -ne "master") { $local:realms = $this.getRealms($keycloakBaseUrl) if ($local:realms) { if ($local:realms.id.Contains($this.realmName)) { $this.getRealmDetails($local:keycloakBaseUrl, $this.realmName) } else { if ($create) { if ($this.createRealm($local:keycloakBaseUrl, $this.realmName)) { $this.initializeRealm($realmUri, $false) } else { throw @{ errorMessage = "Failed to create realm '$($this.realmName)'" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress } } else { throw @{ errorMessage = "Unknown realm '$($this.realmName)'" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress } } } else { throw @{ errorMessage = "Unable to get realms from keycloak" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress } } else { $this.realmName = "master" } } hidden [void]getRealmDetails([string]$keycloakBaseUrl, [string]$realmName) { $local:realmDetails = @{ public_key = $null realmUri = [uri]("$($keycloakBaseUrl)/realms/$($realmName)") realmAdminUri = [uri]("$($keycloakBaseUrl)/admin/realms/$($realmName)") realmTokenUri = $null } $local:result = Invoke-WebRequest -Method Get -Uri $local:realmDetails.realmUri -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::OK) { $local:content = ($local:result.Content | ConvertFrom-Json) $local:realmDetails.public_key = [string]$local:content.public_key $local:realmDetails.realmTokenUri = [uri]$local:content.'token-service' $this.realms[$realmName] = $local:realmDetails } } [uri]getRealmAdminUri() { return $this.realms[$this.realmName].realmAdminUri } [string]getRealmPublicKey() { return $this.realms[$this.realmName].public_key } [uri]getRealmUri() { return $this.realms[$this.realmName].realmUri } [uri]getRealmTokenUri() { return $this.realms[$this.realmName].realmTokenUri } hidden [bool]createRealm([string]$keycloakBaseUrl, [string]$realmName) { $local:realm = @{} $local:realm.Add("id", $realmName) $local:realm.Add("realm", $realmName) $local:realm.Add("enabled", $true) $local:body = ($local:realm | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress) [string]$local:url = "$keycloakBaseUrl/admin/realms" $local:result = Invoke-WebRequest -Method Post -Uri $local:url -Headers $this.tokenManager.getHeader() -Body $local:body -SkipHttpErrorCheck return ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::Created) } [bool]updateRealm() { $local:body = ($this.getRealm() | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress) [string]$local:url = "$($this.getRealmAdminUri())" $local:result = Invoke-WebRequest -Method Put -Uri $local:url -Headers $this.tokenManager.getHeader() -Body $local:body -SkipHttpErrorCheck return ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::NoContent) } [PSCustomObject]getRealm() { return $this.getRealm($false) } [PSCustomObject]getRealm([bool]$force) { if (($null -eq $this.realm) -or ($force -eq $true)) { [string]$local:url = "$($this.getRealmAdminUri())" $local:result = Invoke-WebRequest -Method Get -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::OK) { $this.realm = ($local:result.Content | ConvertFrom-Json -Depth 100) } } return $this.realm } hidden [array]getRealms([string]$keycloakBaseUrl) { [string]$local:url = "$keycloakBaseUrl/admin/realms?briefRepresentation=true" $local:result = Invoke-WebRequest -Method Get -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::OK) { return ($local:result.Content | ConvertFrom-Json) } return $null } [bool]deleteRealm() { [string]$local:url = "$($this.getRealmAdminUri())" $local:result = Invoke-WebRequest -Method Delete -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::NoContent) { $this.realms.Remove($this.realmName) $this.realmName = $null $this.clients = @() $this.users = @() $this.realm = $null } return ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::NoContent) } [array]getRealmComponents() { [string]$local:url = "$($this.getRealmAdminUri())/components" $local:result = Invoke-WebRequest -Method Get -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::OK) { return ($local:result.Content | ConvertFrom-Json) } return $null } [array]getRealmComponentKeysProviders() { $local:components = $this.getRealmComponents() if ($local:components) { return ($local:components | Where-Object { $_.providerType -eq "org.keycloak.keys.KeyProvider" }) } return $null } [bool]updateRealmComponentKeysProvider($keysProvider) { $local:body = ($keysProvider | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress) [string]$local:url = "$($this.getRealmAdminUri())/components/$($keysProvider.id)" $local:result = Invoke-WebRequest -Method Put -Uri $local:url -Body $local:body -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck return ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::NoContent) } [bool]createClient($clientName) { $local:client = $this.clients | Where-Object { $_.clientId -eq $clientName } if ($local:client) { throw @{ errorMessage = "Client with name '$($clientName)' already exists" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress } else { $local:client = @{} $local:client["clientId"] = $clientName $local:client["enabled"] = $true $local:body = ($local:client | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress) [string]$local:url = "$($this.getRealmAdminUri())/clients" $local:result = Invoke-WebRequest -Method Post -Uri $local:url -Body $local:body -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::Created) { $this.clients = $this.getClients($true) } return ($result.StatusCode -eq [System.Net.HttpStatusCode]::Created) } } [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')] [bool]createClientJWTCertificate([string]$clientName, [string]$keyPassword, [string]$storePassword) { $local:client = $this.getClient($clientName) if ($local:client) { [string]$local:url = "$($this.getRealmAdminUri())/clients/$($local:client.id)/certificates/jwt.credential/generate-and-download" $local:data = @{} $local:data["keyAlias"] = $clientName $local:data["realmAlias"] = $this.realmName $local:data["realmCertificate"] = $false $local:data["format"] = "JKS" $local:data["keyPassword"] = $keyPassword $local:data["storePassword"] = $storePassword $local:body = ($local:data | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress) $local:certificateName = "$clientName-JWT-$($this.realmName).jks" Remove-Item -Path $local:certificateName -Force -ErrorAction SilentlyContinue $local:result = Invoke-WebRequest -Method Post -Uri $local:url -Headers $this.tokenManager.getHeader() -Body $local:body -OutFile $local:certificateName -SkipHttpErrorCheck return ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::Created) } return $null } [bool]updateClient([PSCustomObject]$client) { $local:existingsClient = $this.getClients() | Where-Object { $_.id -eq $client.id } if ($local:existingsClient) { $local:body = ($client | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress) [string]$local:url = "$($this.getRealmAdminUri())/clients/$($client.id)" $local:result = Invoke-WebRequest -Method Put -Uri $local:url -Headers $this.tokenManager.getHeader() -Body $local:body -SkipHttpErrorCheck return ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::NoContent) } else { throw @{ errorMessage = "Client with name '$($client.clientId)' already exists" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress } } [bool]deleteClient([string]$clientName) { $local:client = $this.getClient($clientName) if ($local:client) { [string]$local:url = "$($this.getRealmAdminUri())/clients/$($local:client.id)" $local:result = Invoke-WebRequest -Method Delete -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck return ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::NoContent) } return $null } [array]getClients() { return $this.getClients($false) } [array]getClients([bool]$force) { if (($this.clients.Count -eq 0) -or ($force -eq $true)) { [string]$local:url = "$($this.getRealmAdminUri())/clients" $local:result = Invoke-WebRequest -Method Get -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::OK) { $this.clients = ($local:result.Content | ConvertFrom-Json -Depth 100) } else { throw throw @{ errorMessage = "Failed to get clients of realm '$($this.realmName)'" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress } } return $this.clients } [PSCustomObject]getClient([string]$clientName) { return $this.getClient($clientName, $false) } [PSCustomObject]getClient([string]$clientName, [bool]$force) { $local:clients = $this.getClients($force) if ($local:clients) { $local:client = $local:clients | Where-Object { $_.clientId -eq $clientName } if ($local:client) { return ($local:client | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii | ConvertFrom-Json -Depth 100) } # else { # throw @{ errorMessage = "Client with name '$($clientName)' not exists" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress # } } return $null } [string]getClientSecret($clientName) { $local:client = $this.getClient($clientName, $false) if ($local:client) { if ($null -ne $local:client.secret) { return ($local:client.secret) } # else { # throw @{ errorMessage = "Client '$($clientName)' has no client secret" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress # } } return $null } [string]getClientJWTCertificate($clientName) { $local:client = $this.getClient($clientName, $false) if ($local:client) { [string]$local:url = "$($this.getRealmAdminUri())/clients/$($local:client.id)/certificates/jwt.credential" $local:result = Invoke-WebRequest -Method Get -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq 200) { $local:content = ($local:result.Content | ConvertFrom-Json -Depth 100) $local:clientJWTCredential = $local:content.certificate if ($local:clientJWTCredential) { return $local:clientJWTCredential } } } return $null } [array]getClientProtocolMappers([string]$clientName) { $local:client = $this.getClient($clientName, $false) if ($local:client) { [string]$local:url = "$($this.getRealmAdminUri())/clients/$($local:client.id)/protocol-mappers/protocol/openid-connect" $local:result = Invoke-WebRequest -Method Get -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq 200) { $local:mappers = ($local:result.Content | ConvertFrom-Json -Depth 100) return $local:mappers } } return $null } [bool]addClientProtocolMapper([string]$clientName, [PSCustomObject]$clientMapper) { $local:client = $this.getClient($clientName, $false) if ($local:client) { [string]$local:url = "$($this.getRealmAdminUri())/clients/$($local:client.id)/protocol-mappers/models" $local:data = ($clientMapper | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii) $local:result = Invoke-WebRequest -Method Post -Uri $local:url -Headers $this.tokenManager.getHeader() -Body $local:data -SkipHttpErrorCheck return ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::Created) } return $false } [array]getRealmRoles() { return $this.getRealmRoles($false) } [array]getRealmRoles([bool]$force) { if (($this.roles.Count -eq 0) -or ($force -eq $true)) { [string]$local:url = "$($this.getRealmAdminUri())/roles" $local:result = Invoke-WebRequest -Method Get -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::OK) { $this.roles = ($local:result.Content | ConvertFrom-Json) } } return $this.roles } [PSCustomObject]getRealmRole([string]$roleName) { $local:roles = $this.getRealmRoles() if ($local:roles) { $local:role = $local:roles | Where-Object { $_.name -eq $roleName } if ($local:role) { return ($local:role | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii | ConvertFrom-Json -Depth 100) } } return $null } [bool]createRealmRole([string]$roleName) { return $this.createRealmRole($roleName, [string]::Empty) } [bool]createRealmRole([string]$roleName, $description) { $local:role = $this.getRealmRole($roleName) if ($local:role) { throw @{ errorMessage = "Realm role with name '$($roleName)' already exists" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress } else { [string]$local:url = "$($this.getRealmAdminUri())/roles" $local:data = @{} $local:data["name"] = $roleName if ([string]::IsNullOrEmpty($description) -eq $false) { $local:data["description"] = $description } $local:body = ($local:data | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress) $local:result = Invoke-WebRequest -Method Post -Uri $local:url -Body $local:body -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck return ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::Created) } } [bool]createGroup([string]$groupName) { $local:newGroup = [PSCustomObject]@{ name = $groupName } [string]$local:url = "$($this.getRealmAdminUri())/groups" $local:body = ($local:newGroup | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress) $local:result = Invoke-WebRequest -Method Post -Uri $local:url -Body $local:body -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::Created) { $this.groups = @() # clear cache } return ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::Created) } [array]getGroups() { return $this.getGroups($false) } [array]getGroups([bool]$force) { if (($this.groups.Count -eq 0) -or ($force -eq $true)) { $this.groups = @() [int32]$local:groupPageSize = 100 [Int32]$local:fetchedGroupsCount = 0 do { [string]$local:url = "$($this.getRealmAdminUri())/groups?first=$($this.groups.Count)&max=$($local:groupPageSize)" $local:result = Invoke-WebRequest -Method Get -Uri $url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::OK) { $local:fetchedGroups = ($local:result.Content | ConvertFrom-Json -Depth 100) $local:fetchedGroupsCount = $local:fetchedGroups.Count $this.groups += $local:fetchedGroups } # } until ($local:fetchedUsersCount -lt $local:userPageSize) } until ($local:fetchedGroupsCount -eq 0) } return $this.groups } [PSCustomObject]getGroupByName([string]$groupName) { return $this.getGroupByName($groupName, $false) } [PSCustomObject]getGroupByName([string]$groupName, [bool]$force) { $local:groups = $this.getGroups($force) if ($local:groups) { $local:group = $local:groups | Where-Object { $_.name -eq $groupName } if ($local:group) { return ($local:group | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii | ConvertFrom-Json -Depth 100) } } return $null } [bool]deleteGroup([PSCustomObject]$group) { [string]$local:url = "$($this.getRealmAdminUri())/groups/$($group.id)" $local:result = Invoke-WebRequest -Method Delete -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::NoContent) { $this.groups = @() # clear cache } return ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::NoContent) } [array]getGroupRoles([guid]$groupId) { $local:group = $this.getGroups() | Where-Object { $_.id -eq $groupId } if ($local:group) { [string]$local:url = "$($this.getRealmAdminUri())/groups/$($local:group.id)/role-mappings" $local:result = Invoke-WebRequest -Method Get -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::OK) { return [array]($local:result.Content | ConvertFrom-Json) } } return $null } [array]getAvailableRealmRolesForGroup([guid]$groupId) { $local:group = $this.getGroups() | Where-Object { $_.id -eq $groupId } if ($local:group) { [string]$local:url = "$($this.getRealmAdminUri())/groups/$($groupId)/role-mappings/realm/available" $local:result = Invoke-WebRequest -Method Get -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::OK) { return [array]($local:result.Content | ConvertFrom-Json) } } return $null } [bool]hasGroupRealmRole([guid]$groupId, [string]$roleName) { $local:group = $this.getGroups() | Where-Object { $_.id -eq $groupId } if ($local:group) { $local:groupRoles = $this.getGroupRoles($groupId) return ($null -ne ($local:groupRoles.realmMappings | Where-Object { $_.name -eq $roleName })) } return $null } [bool]addRealmRoleToGroup([guid]$groupId, [string]$roleName) { if ($this.hasGroupRealmRole($groupId, $roleName) -eq $false) { $local:realmRoles = $this.getAvailableRealmRolesForGroup($groupId) if ($local:realmRoles) { $local:realmRole = $local:realmRoles | Where-Object { $_.name -eq $roleName } if ($local:realmRole) { $local:body = "[$($local:realmRole | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress)]" [string]$local:url = "$($this.getRealmAdminUri())/groups/$($groupId)/role-mappings/realm" $local:result = Invoke-WebRequest -Method Post -Uri $local:url -Headers $script:realmManager.tokenManager.getHeader() -Body $local:body -SkipHttpErrorCheck return ($local:result.StatusCode -eq 204) } else { throw @{ errorMessage = "Realm role '$($roleName)' does not exist" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress } } else { throw @{ errorMessage = "No roles for group '$($groupId.TosTring())'" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress } } else { throw @{ errorMessage = "Group '$($groupId.TosTring())' already has realm role '$($roleName)'" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress } return $false } [bool]createUser([string]$userName) { $local:newUser = [PSCustomObject]@{ username = $userName enabled = $true credentials = @() } [string]$local:url = "$($this.getRealmAdminUri())/users" $local:body = ($local:newUser | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress) $local:result = Invoke-WebRequest -Method Post -Uri $local:url -Body $local:body -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::Created) { $this.users = @() # clear cache } return ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::Created) } [bool]createUser([PSCustomObject]$user) { [string]$local:url = "$($this.getRealmAdminUri())/users" $local:body = ($user | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress) $local:result = Invoke-WebRequest -Method Post -Uri $local:url -Body $local:body -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::Created) { $this.users = @() # clear cache } return ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::Created) } [bool]updateUser([PSCustomObject]$user) { if ($user) { [string]$local:url = "$($this.getRealmAdminUri())/users/$($user.id)" $local:body = ($user | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress) $local:result = Invoke-WebRequest -Method Put -Uri $local:url -Body $local:body -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::NoContent) { $this.users = @() # clear cache } return ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::NoContent) } return $false } [array]getUsers() { return $this.getUsers($false) } [array]getUsers([bool]$force) { if (($this.users.Count -eq 0) -or ($force -eq $true)) { $this.users = @() [int32]$local:userPageSize = 100 [Int32]$local:fetchedUsersCount = 0 do { [string]$local:url = "$($this.getRealmAdminUri())/users?first=$($this.users.Count)&max=$($local:userPageSize)" $local:result = Invoke-WebRequest -Method Get -Uri $url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::OK) { $local:fetchedUsers = ($local:result.Content | ConvertFrom-Json -Depth 100) $local:fetchedUsersCount = $local:fetchedUsers.Count $this.users += $local:fetchedUsers } # } until ($local:fetchedUsersCount -lt $local:userPageSize) } until ($local:fetchedUsersCount -eq 0) } return $this.users } [PSCustomObject]getUserById([guid]$userId) { return $this.getUserById($userId, $false) } [PSCustomObject]getUserById([guid]$userId, [bool]$force) { $local:users = $this.getUsers($force) if ($local:users) { $local:user = $local:users | Where-Object { $_.id -eq $userId.ToString() } if ($local:user) { return ($local:user | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii | ConvertFrom-Json -Depth 100) } } return $null } [PSCustomObject]getUserByUserName([string]$userName) { return $this.getUserByUserName($userName, $false) } [PSCustomObject]getUserByUserName([string]$userName, [bool]$force) { $local:users = $this.getUsers($force) if ($local:users) { $local:user = $local:users | Where-Object { $_.username -eq $userName } if ($local:user) { return ($local:user | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii | ConvertFrom-Json -Depth 100) } } return $null } [PSCustomObject]getUserByEMail([string]$email, [bool]$force) { $local:users = $this.getUsers($force) if ($local:users) { $local:user = $local:users | Where-Object { $_.email -eq $email } if ($local:user) { return ($local:user | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii | ConvertFrom-Json -Depth 100) } } return $null } [PSCustomObject]getUserFederatedIdentity([PSCustomObject]$user) { [string]$local:url = "$($this.getRealmAdminUri())/users/$($user.id)/federated-identity" $local:result = Invoke-WebRequest -Method Get -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::OK) { return [array]($local:result.Content | ConvertFrom-Json) } return $null } [PSCustomObject]getUserCredentials([PSCustomObject]$user) { [string]$local:url = "$($this.getRealmAdminUri())/users/$($user.id)/credentials" $local:result = Invoke-WebRequest -Method Get -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::OK) { return [array]($local:result.Content | ConvertFrom-Json) } return $null } [PSCustomObject]deleteUserCredentials([PSCustomObject]$user,[PSCustomObject]$credentials) { [string]$local:url = "$($this.getRealmAdminUri())/users/$($user.id)/credentials/$($credentials.id)" $local:result = Invoke-WebRequest -Method Delete -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck return ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::NoContent) } [bool]deleteUser([PSCustomObject]$user) { [string]$local:url = "$($this.getRealmAdminUri())/users/$($user.id)" $local:result = Invoke-WebRequest -Method Delete -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::NoContent) { $this.users = @() # clear cache } return ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::NoContent) } [array]getUserGroups([guid]$userId) { $local:user = $this.getUserById($userId) if ($local:user) { [string]$local:url = "$($this.getRealmAdminUri())/users/$($local:user.id)/groups" $local:result = Invoke-WebRequest -Method Get -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::OK) { return [array]($local:result.Content | ConvertFrom-Json) } } return $null } [bool]addUserToGroup([guid]$userId, [guid]$groupId) { [string]$local:url = "$($this.getRealmAdminUri())/users/$($userId)/groups/$($groupId)" $local:result = Invoke-WebRequest -Method Put -Uri $local:url -Headers $script:realmManager.tokenManager.getHeader() -SkipHttpErrorCheck return ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::NoContent) } [array]getUserRoles([guid]$userId) { $local:user = $this.getUserById($userId) if ($local:user) { [string]$local:url = "$($this.getRealmAdminUri())/users/$($local:user.id)/role-mappings" $local:result = Invoke-WebRequest -Method Get -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::OK) { return [array]($local:result.Content | ConvertFrom-Json) } } return $null } [array]getAvailableRealmRolesForUser([guid]$userId) { $local:user = $this.getUserById($userId) if ($local:user) { [string]$local:url = "$($this.getRealmAdminUri())/users/$($userId)/role-mappings/realm/available" $local:result = Invoke-WebRequest -Method Get -Uri $local:url -Headers $this.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::OK) { return [array]($local:result.Content | ConvertFrom-Json) } } return $null } [array]getUserClientRoleMappings([guid]$userId, [string]$clientName) { $local:user = $this.getUserById($userId) if ($local:user) { $local:client = $this.getClient($clientName) if ($local:client) { [string]$local:url = "$($this.getRealmAdminUri())/users/$($user.id)/role-mappings/clients/$($local:client.id)" $local:result = Invoke-WebRequest -Method Get -Uri $local:url -Headers $script:realmManager.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::OK) { return [array]($local:result.Content | ConvertFrom-Json) } } } return $null } [array]getAvailableUserClientRoleMappings([guid]$userId, [string]$clientName) { $local:user = $this.getUserById($userId) if ($local:user) { $local:client = $this.getClient($clientName) if ($local:client) { [string]$local:url = "$($this.getRealmAdminUri())/users/$($user.id)/role-mappings/clients/$($local:client.id)/available" $local:result = Invoke-WebRequest -Method Get -Uri $local:url -Headers $script:realmManager.tokenManager.getHeader() -SkipHttpErrorCheck if ($local:result.StatusCode -eq [System.Net.HttpStatusCode]::OK) { return [array]($local:result.Content | ConvertFrom-Json) } } } return $null } [bool]addUserClientRoleMapping([guid]$userId, [string]$clientName, [string]$roleName) { $local:client = $this.getClient($clientName) if ($local:client) { $local:availableClientRoles = $this.getAvailableUserClientRoleMappings($userId, $clientName) if ($local:availableClientRoles) { $local:availableClientRole = $local:availableClientRoles | Where-Object { $_.name -eq $roleName } if ($local:availableClientRole) { [string]$local:url = "$($this.getRealmAdminUri())/users/$($userId)/role-mappings/clients/$($local:client.id)" $local:role = [PSCustomObject]@{ description = $local:availableClientRole.description id = $local:availableClientRole.id name = $local:availableClientRole.name } $local:body = "[$($local:role | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress)]" $local:result = Invoke-WebRequest -Method Post -Uri $local:url -Headers $script:realmManager.tokenManager.getHeader() -Body $local:body -SkipHttpErrorCheck return ($local:result.StatusCode -eq 204) } } } return $false } [bool]hasUserClientRoleMapping([guid]$userId, [string]$clientName, [string]$roleName) { $local:user = $this.getUserById($userId) if ($local:user) { $local:userRoles = $this.getUserRoles($userId) return ($null -ne ($local:userRoles.clientMappings.$clientName.mappings | Where-Object { $_.name -eq $roleName })) } return $null } [bool]hasUserRealmRole([guid]$userId, [string]$roleName) { $local:user = $this.getUserById($userId) if ($local:user) { $local:userRoles = $this.getUserRoles($userId) return ($null -ne ($local:userRoles.realmMappings | Where-Object { $_.name -eq $roleName })) } return $null } [bool]addRealmRoleToUser([guid]$userId, [string]$roleName) { if ($this.hasUserRealmRole($userId, $roleName) -eq $false) { $local:realmRoles = $this.getAvailableRealmRolesForUser($userId) if ($local:realmRoles) { $local:realmRole = $local:realmRoles | Where-Object { $_.name -eq $roleName } if ($local:realmRole) { $local:body = "[$($local:realmRole | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress)]" [string]$local:url = "$($this.getRealmAdminUri())/users/$($userId)/role-mappings/realm" $local:result = Invoke-WebRequest -Method Post -Uri $local:url -Headers $script:realmManager.tokenManager.getHeader() -Body $local:body -SkipHttpErrorCheck return ($local:result.StatusCode -eq 204) } else { throw @{ errorMessage = "Realm role '$($roleName)' does not exist" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress } } else { throw @{ errorMessage = "No roles for user '$($userId.TosTring())'" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress } } else { throw @{ errorMessage = "User '$($userId.TosTring())' already has realm role '$($roleName)'" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress } return $false } [bool]isValid() { return (($null -ne $this.realms["master"]) -and ($null -ne $this.realms[$this.realmName])) } [void]dispose() { $this.tokenManager.dispose() $this.realmClientName = "admin-cli" $this.realmClientSecret = [string]::Empty $this.userName = [string]::Empty $this.password = [string]::Empty $this.clients = @() $this.users = @() $this.roles = @() $this.realms = @{} } KeycloakRealmManager([uri]$realmUri, [string]$clientName) { if ($null -eq $realmUri.Scheme) { throw @{ errorMessage = "Invalid realm uri" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress } $this.userName = [string]::Empty $this.password = [string]::Empty $this.realmClientName = $clientName $this.initializeMaster($realmUri) $this.tokenManager = [KeycloakTokenManager]::new($this.realms["master"].realmTokenUri, $this.realmClientName) $this.userName = $this.tokenManager.userName $this.initializeRealm($realmUri, $false) } [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')] KeycloakRealmManager([string]$userName, [string]$password, [uri]$realmUri) { if ($null -eq $realmUri.Scheme) { throw @{ errorMessage = "Invalid realm uri" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress } $this.userName = $userName $this.password = $password $this.initializeMaster($realmUri) $this.tokenManager = [KeycloakTokenManager]::new($userName, $password, $this.realms["master"].realmTokenUri, $this.realmClientName, [string]::Empty) $this.initializeRealm($realmUri, $false) } [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')] KeycloakRealmManager([string]$userName, [string]$password, [uri]$realmUri, [bool]$create) { if ($null -eq $realmUri.Scheme) { throw @{ errorMessage = "Invalid realm uri" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress } $this.userName = $userName $this.password = $password $this.initializeMaster($realmUri) $this.tokenManager = [KeycloakTokenManager]::new($userName, $password, $this.realms["master"].realmTokenUri, $this.realmClientName, [string]::Empty) $this.initializeRealm($realmUri, $create) } [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')] KeycloakRealmManager([string]$userName, [string]$password, [uri]$realmUri, [bool]$create, [string]$clientName, [string]$clientSecret) { if ($null -eq $realmUri.Scheme) { throw @{ errorMessage = "Invalid realm uri" } | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii -Compress } $this.realmClientName = $clientName $this.realmClientSecret = $clientSecret $this.userName = $userName $this.password = $password $this.initializeMaster($realmUri) $this.tokenManager = [KeycloakTokenManager]::new($userName, $password, $this.realms["master"].realmTokenUri, $this.realmClientName, $this.realmClientSecret) $this.initializeRealm($realmUri, $create) } } |