API Examples
Use KeePass with Pleasant Password Server
Below are examples of managing Passwords with Pleasant Password Server through a RESTful API. These have been accumulated over time in collaboration with our customers, and provided as a starting point.
The examples below have been updated to use RESTful API v6 (which added some endpoints and additional modifications). The examples were originally provided using RESTful API v4. RESTful API v5 also introduced improvements.
Notes:
- This section is still in progress and the examples are provided as-is. We are thankful to the members of the community who have contributed.
- If you do find a transcribing problem, error, or an improvement, please let us know so they can be updated.
Sections:
- Basic Endpoints
- Get Root Id
- Create Folder
- Update Folder
- Create Entry
- Update Entry
- curl
- Get Authentication Token
- Using the Authentication Token
- Find the Root Folder
- Create Entry
- Update Entry
- Update Password
- Search
- PowerShell
- PowerShell Environment Setup
- Handling Trust Warnings
- Output Password Info
- Create Entry
- Create Entry (alternate)
- Generate a Password
- Output a list of users
- Export to CSV file
- Onboarding Machines to Join a Domain
- Python
- Get an Entry Password
Basic Endpoints
Below are simply examples of the most common functions (endpoints), how they can be called through the HTTPS protocol, and what details they return.
Get Root Id
GET: https://server_name:port/api/v6/rest/credentialgroup/root
Returns: Id of Root Folder
Create Folder
POST: https://server_name:port/api/v6/rest/credentialgroup
Content:
{
Name: "API Folder",
ParentId: "<Parent Folder Id>",
}
Returns: Id of Created Folder
Update Folder
PUT: https://server_name:port/api/v6/rest/credentialgroup/Folder_Id
Content:
{
Id: "<Folder Id>",
Name: "New API Folder",
ParentId: "<Parent Folder Id>",
Notes: "It has notes now"
}
Returns: Nothing
Create Entry
POST: https://server_name:port/api/v6/rest/credential
Content:
{
Name: "API Credential",
GroupId: <Parent Folder Id>,
Username: "SteveCarlsberg",
Password: "12345"
}
Returns: Id of Created Entry
Update Entry
PUT: https://server_name:port/api/v6/rest/credential/Entry_Id
Content:
{
Id: "<Entry Id>",
Name: "API Credential Name Changed",
GroupId: "<Parent Folder ID>",
Username: "SteveCarlsberg",
Password: "678910"
}
curl Examples
Developers often use curl commands to test or execute commands against API URL's. Following are some brief setup, reference, and examples, which might help get you started.
- Windows Download: https://curl.haxx.se/download.html (use version posted by Viktor Szakáts)
- Reference Guide: Everything curl - PDF Guide (start at page 68)
Get Authentication Token
This provides an authentication, valid for a period of time, other
- Returns: a token string that can be used for other commands (until timeout is over: i.e. 3600 seconds)
- Parameters: also use the -k (or --insecure) option when testing without a valid certificate
curl --insecure -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=password&username=admin&password=admin" https://localhost:10001/oauth2/token
Using the Authentication Token
Once you aquire an access token, a header parameter "Authorization" must be set to the authorization token for all subsequent API calls. See:
- Examples: Get an Entry (curl), Create New Entry (powershell)
- Details: OAuth 2FA authentication
Find Root Folder GUID
https://localhost:10001/api/v6/rest/credentialgroup/root
Creating an Entry
(PowerShell)
$PasswordServerURL = "https://localhost:10001" $Cred = Get-Credential -Message "Enter your credentials to access Password Server"
$tokenParams = @{
grant_type='password';
username=$Cred.UserName;
password=$Cred.GetNetworkCredential().password;
} # Request a security token for the specified user that will be used to authenticate
# when requesting a password. $JSON = Invoke-WebRequest `
-Uri "$PasswordServerURL/OAuth2/Token" `
-Method POST `
-Body $tokenParams `
-ContentType "application/x-www-form-urlencoded" # The RESTful API returns a JSON object.
# Convert that to a PowerShell object and extract just the access_token. $Token = (ConvertFrom-Json $JSON.Content).access_token $headers = @{
"Accept" = "application/json"
"Authorization" = "$Token"
}
$Credential = @{
Id: "00000000-0000-0000-0000-000000000000",
Name: "<name>",
Username: "<username>",
Password: "<password>",
Url: "<url>",
Notes: "<notes>",
GroupId: "<Id of parent folder>",
Created: "<current date/time in this format: 2015-06-01T13:26:12.336084-06:00>",
Modified: "<current date/time in this format: 2015-06-01T13:26:12.336084-06:00>",
Expires: null,
UsageComment: null
}
[string]$NewId = Invoke-WebRequest `
-Uri "$PasswordServerURL/api/v6/rest/credential" `
-Headers $headers -Method Post `
-Body $Credential
Get an Entry
Get an Entry.
- Returns: an Entry object
curl --insecure -i -X GET -H "Authorization: Bearer sfpiaufohdfhefohfopaoeff03988fahf......asfsdfosyfopafshf" -H "Content-Type: application/json" -H "Cache-Control: no-cache" "https://localhost:10001/api/v6/rest/credential/0e35bab3-4ef8-4947-9d61-cf17e15da0c7"
Update Entry
Updating an Entry.
- Returns: an Entry object
curl --insecure -i -X PUT -H "Authorization: Bearer sfpiaufohdfhefohfopaoeff03988fahf......asfsdfosyfopafshf" -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d "{ \"Id\": \"0e35bab3-4ef8-4947-9d61-cf17e15da0c7\", \"Name\": \"Test\", \"Username\": \"Testuser\", \"Password\": \"abcd123\", \"GroupId\": \"g998r9b9-b2cf-4ac1-8a33-5f5e43cd3eb0\", \"Notes\": \"Test Note\"}" "https://localhost:10001/api/v6/rest/credential/0e35bab3-4ef8-4947-9d61-cf17e15da0c7"
Update Password field
API v5:
-
Instead use the Entry PATCH command in API v5, which allows update of a single field.
API v4:
- When updating the password with API v4 ALL fields of the credential must be submitted.
- 1. Start by getting the credential JSON from the API using the GET method, and store the object:
curl --insecure -i -X GET -H "Authorization: Bearer sfpiaufohdfhefohfopaoeff03988fahf......asfsdfosyfopafshf" -H "Content-Type: application/json" -H "Cache-Control: no-cache" "https://localhost:10001/api/v4/rest/credential/0e35bab3-4ef8-4947-9d61-cf17e15da0c7"
- 2. Then change the Password, and
- 3. PUT the whole object back to the server, to this URL:
https://localhost:10001/api/v4/rest/credential/EntryId
Search
curl --insecure -H "Content-Type: application/json" https://localhost:10001/api/v6/rest/search -d "{Search: \"Test\"}" -H "Authorization: Bearer sfpiaufohdfhefohfopaoeff03988fahf......asfsdfosyfopafshf"
PowerShell Examples
PowerShell Setup
Some of these scripts may require PowerShell version 5 or later.
Also note, that PowerShell version 6, provides additional features, and function parameters that you may find helpful in your development environment, for example, using the -SkipCertificateCheck parameter mentioned below.
See Handling Trust Warnings (below) for more information.
Handling Trust Warnings
You may receive a Certificate Trust error in your Development environment, due to only using the default placeholder Certificate. The FQDN will not match your server URL. So the recommendation for your Dev environment only, would be to either:
- Use PowerShell version 6: use the -SkipCertificateCheck parameter with Invoke-RestMethod, or
- Use a work-around method, for example, by running the following script (being sure to only include the appropriate encryption protocols):
add-type @" using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy { public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; } } "@
$AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12' [System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
Output Password Information
Provided by: Andy Viar, Mary Greeley Medical Center. Used with permission.
# URL of Pleasant Password Server $PasswordServerURL = "https://localhost:10001" # Prompt for a credential $Cred = Get-Credential -Message "Enter your credentials to access Password Server" -UserName MyUserName # Create OAuth2 token params $tokenParams = @{ grant_type='password'; username=$Cred.UserName; password=$Cred.GetNetworkCredential().password;} # Authenticate to Pleasant Password Server $JSON = Invoke-WebRequest -Uri "$PasswordServerURL/OAuth2/Token"-Method POST -Body $tokenParams -ContentType "application/x-www-form-urlencoded" # Generate JSON token $Token = (ConvertFrom-Json $JSON.Content).access_token # Prep JSON headers $headers = @{ "Accept" = "application/json" "Authorization" = "$Token" } # Define job to focus on user input box # Without this, the user must first manually click the input box $null = [Reflection.Assembly]::LoadWithPartialName("Microsoft.VisualBasic") $activateWindow = { $null = [Reflection.Assembly]::LoadWithPartialName("Microsoft.VisualBasic") $isWindowFound = $false while(-not $isWindowFound) { try { [Microsoft.VisualBasic.Interaction]::AppActivate($args[0]) $isWindowFound = $true } catch { sleep -Milliseconds 100 } } } # Start job to focus on user input box $job = Start-Job $activateWindow -ArgumentList "Output Password Info" # Prompt for search credential [void][Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') $title = 'Output Password Info' $msg = 'Find display information for which user:' $username = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title) # Remove job to focus on user input box Remove-Job $job -Force # Prep JSON body $body = @{ "search" = "$username" } # Execute command: search $Results = Invoke-RestMethod -method post -Uri "$PasswordServerURL/api/v6/rest/search" -body (ConvertTo-Json $body) -Headers $headers -ContentType 'application/json' # Loop through Entrie: Output results to the screen ForEach($Result in $Results.credentials) { $Result $CredentialID = $Result.id New-Object pscustomobject -Property @{'Name'=$Result.name;'Password' = (Invoke-WebRequest -Uri "$PasswordServerURL/api/v6/rest/credential/$CredentialID/password" -Headers $headers -Method Get)} }
Create New Entry
Provided by: Andy Viar, Mary Greeley Medical Center. Used with permission.
# URL of Pleasant Password Server $PasswordServerURL = "https://localhost:10001" # Prompt for a credential $Cred = Get-Credential -Message "Enter your credentials to access Pleasant Solutions Password Server" -UserName MyUserName # Create OAuth2 token params $tokenParams = @{ grant_type='password'; username=$Cred.UserName; password=$Cred.GetNetworkCredential().password;} # Authenticate to Pleasant Password Server $JSON = Invoke-WebRequest -Uri "$PasswordServerURL/OAuth2/Token" -Method POST -Body $tokenParams -ContentType "application/x-www-form-urlencoded" # Generate JSON token $Token = (ConvertFrom-Json $JSON.Content).access_token # Prep JSON headers $headers = @{ "Accept" = "application/json" "Authorization" = "$Token" } # Prep JSON body $body = @{ "Id" = "00000000-0000-0000-0000-000000000000" "Name" = "test-title" "Password" = "test-password" "Username" = "test-user" "Url" = "test-url" "Notes" = "test-notes" "GroupId" = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "Created" = "2018-01-22T12:00:00:00" "Modified" = "2018-01-22T12:00:00:00" } # GroupId = The GUID of the folder this Credential belongs to # Created = DateTimeOffset # Modified = DateTimeOffset # Execute command: Search $Results = Invoke-RestMethod -method post -Uri "$PasswordServerURL/api/v6/rest/credential" -body (ConvertTo-Json $body) -Headers $headers -ContentType 'application/json' # Loop through the entries: Output results to the screen ForEach($Result in $Results.credentials) { $Result }
Create New Entry - alternate version
Provided by: Charles Delroy, SmartOdds. Used with permission.
# Generates the token for adding it to the database, where $PasswordServerURL is the URL of the Pleasant Server. Function GenerateKeepassToken { [System.Reflection.Assembly]::LoadWithPartialName(‘Microsoft.VisualBasic’) | Out-Null $Cred = Get-Credential -UserName XXXXXXXXX -Message “Enter your Credentials to access Password Server” $tokenParams = @ { grant_type=’password’; username=$Cred.UserName; password=$Cred.GetNetworkCredential().password; } $JSON = Invoke-WebRequest -Uri “$PasswordServerURL/OAuth2/Token” -Method POST -Body $tokenParams -ContentType “application/x-www-form-urlencoded” -UseBasicParsing $Token = (ConvertFrom-Json $JSON.Content).access_token $Global:headers = @ { “Accept” = “application/json” “Authorization” = “$Token” } } # Inputs the created parameters (elsewhere in the script) and adds them into the database. Function AddToKeePass { $GroupID = $Global:GroupID $date = [System.DateTimeOffset]::Now $postParams = @{
Name=$Global:Description;
Username=$Global:FirstName;
Password=$Global:password;
GroupId=$GroupID;
Created="$Date";
Modified="$Date"
} $JsonPOST = ConvertTo-Json -InputObject $postParams $URI = " $PasswordServerURL/api/v6/rest/credential/" Invoke-RestMethod -ContentType application/json -Method POST -Headers $Global:Headers -Uri $URI -Body $JsonPOST }
Get Attachment
Provided by: An anonymous member of the community. Used with permission.
# Get & print the folder hierarchy Function Get-Hierarchy([PSCustomObject]$folder, [int]$depth) { $indent = " " * $depth * 2 # print the folder name "$($indent)FOLDER $($folder.id) $($folder.name)" # print the credentials in the folder ForEach($entry in $folder.Credentials) { # print the credential name "$($indent) ENTRY $($entry.id) $($entry.name)" # print the attachments of the credential ForEach($att in $entry.Attachments) { "$($indent) ATTACHMENT $($att.AttachmentId) $($att.FileName) ($($att.FileSize))" } } # recurse on the subfolders ForEach($subfolder in $folder.Children) { Get-Hierarchy($subfolder, $depth + 1) } } # URL of Pleasant Password Server $PasswordServerURL = "https://localhost:10001" # Prompt for a credential $Cred = Get-Credential -Message "Enter your credentials to access Password Server" -UserName MyUserName # Create OAuth2 token params $tokenParams = @{ grant_type='password'; username=$Cred.UserName; password=$Cred.GetNetworkCredential().password; } # Authenticate to Pleasant Password Server $JSON = Invoke-WebRequest -Uri "$PasswordServerURL/OAuth2/Token"-Method POST -Body $tokenParams -ContentType "application/x-www-form-urlencoded" # Generate JSON token $Token = (ConvertFrom-Json $JSON.Content).access_token # Prep JSON headers $headers = @{ "Authorization" = "Bearer $Token" } # Get and print the Folder hierarchy $root = Invoke-RestMethod -method get -Uri "$PasswordServerURL/api/v6/rest/folders" -Headers $headers -ContentType 'application/json' Get-Hierarchy($root, 0) # Prompt for attachments $entry_id = Read-Host - Prompt 'ID of CREDENTIAL that contains desired attachment' $att_id = Read-Host - Prompt 'ID of desired ATTACHMENT' # Retrieve attachment Invoke-RestMethod -method get -Uri "$PasswordServerURL/api/v6/rest/entries/$($entry_id)/attachments/$($att_id)" -Headers $headers -ContentType 'application/zip' -OutFile "temp.zip" Expand-Archive -Path "temp.zip" -DestinationPath "$PSScriptRoot/$att_id" Remove-Item "temp.zip"
Get One Time Password
# URL of Pleasant Password Server
$passwordserverurl = "https://localhost:10001"
# Prompt for a credential
$ppscred = Get-Credential -Message "Enter your credentials to access Password Server"
#Body for the search command via RESTfulAPI
$body = @{ "search" = "%" }
#Tokenparameter für OAuth2
$tokenparams = @{ grant_type = 'password'; username = $ppscred.GetNetworkCredential().UserName; password = $ppscred.GetNetworkCredential().Password; }
#Authentication against the PleasantPasswordServer
$json = Invoke-RestMethod `
-Uri "$passwordserverurl/OAuth2/Token" `
-Method POST `
-Body $tokenParams `
-ContentType "application/x-www-form-urlencoded"
#Reformat tokens in JSON
$token = $json.access_token
$token
#Create JSON header
$headers = @{ "Accept" = "application/json"; "Authorization" = "$token"; }
#Execution of the search command via RESTfulAPI
$allresults = Invoke-RestMethod `
-Method Post `
-Uri "$passwordserverurl/api/v6/rest/search" `
-Body (ConvertTo-Json $body) `
-Headers $headers `
-ContentType 'application/json'
$allresults
Generate a Password
Simple script for creating a new random string.
External Link:
Provided by: Florian Rossmark, Accriva Diagnostics. Linked with permission.
Output a List of Users
Description:
- The script will output a list of password server users
- The script provides the option to use Windows Credential Manager to store their username/password for the future, as this is more secure/convenient than providing these in plain text in a script.
- Installs/Imports CredentialManager module
- Prompts for username/password initially
- Subsequently stores this in the Windows Credential Manager LocalMachine (visible to administrators)
- This credential will be used in future iterations / other scripts.
Prerequisite:
- General Setting: Enable the setting "Allow User Access to be modified via API"
- Otherwise the script will fail silently
# Define the Pleasant Password Server URL endpoint $apiUrl = "https://myppass:10001/api/v5/rest/userinfo" # Define the OAuth2 token endpoint $tokenUrl = "https://myppass:10001/oauth2/token" # Install/Import the CredentialManager module if (Get-Module -ListAvailable -Name CredentialManager) { # Load the CredentialManager module Import-Module -Name CredentialManager } else { # Attempt to install the CredentialManager module try { Install-Module -Name CredentialManager -Force -Scope CurrentUser # Check if the CredentialManager module was installed successfully if (-not (Get-Module -ListAvailable -Name CredentialManager)) { Write-Host "The CredentialManager module is not installed. " Write-Host "Please install it manually." return } } catch { Write-Host "The CredentialManager module is not installed. " Write-Host "Please install it manually." return } } # Define the credential name $credName = "MyCred" # Check if the credential already exists if (Get-StoredCredential -Target $credName) { # Get the credential $Cred = Get-StoredCredential -Target $credName } else { # Prompt for a credential $Cred = Get-Credential -Message "Enter your credentials to access Pleasant Password Server" -UserName MyUserName # Inform the user about the storage of their credentials Write-Host "" Write-Host "If you wish to give permission, your username and password could be saved for future use." Write-Host "This would be:" Write-Host " - be stored in the Windows Credential Store." Write-Host " - available for future execution of this / other scripts." Write-Host " - accessible to users with administrative access." Write-Host " - available until manually removed, for example:" Write-Host " Remove-StoredCredential -Target "MyCred"" Write-Host "" # Ask the user for their permission to store their credentials $permission = Read-Host -Prompt "Do you give permission to store your username and password as MyCred? (y/n)" if ($permission -eq 'y') { # Store the credential New-StoredCredential -Target $credName -Username $Cred.UserName -Password $Cred.GetNetworkCredential().password -Persist LocalMachine Write-Host "" Write-Host "Your credentials have been stored." Write-Host "" } else { Write-Host "" Write-Host "Permission denied. Your credentials have not been stored." Write-Host "" } } # Create OAuth2 token params $tokenParams = @{ grant_type='password'; username=$Cred.UserName; password=$Cred.GetNetworkCredential().password; } # Get an OAuth2 token $tokenResponse = Invoke-RestMethod -Uri $tokenUrl -Method Post -Body $tokenParams -ContentType "application/x-www-form-urlencoded" # Extract the access token from the response $accessToken = $tokenResponse.access_token # Define the headers for the API request, including the access token $headers = @{ "Authorization" = "Bearer $accessToken" } # Call the API endpoint using Invoke-RestMethod $response = Invoke-RestMethod -Uri $apiUrl -Method Get -Headers $headers # Check if the response is empty if ($response -eq $null) { Write-Host "No response received from the API." } else { # Count the number of users $userCount = $response.Count Write-Host "Number of users: $userCount" # Output the user list $response # Convert the user list to CSV and output it $csv = $response | ConvertTo-Csv -NoTypeInformation $csv }
Export to CSV file
Provided by: Robert Vance, DMS iTech. Provided with permission.
Description:
One of the benefits of Password Server is the ability to control/manage your own data as you see fit.
You may wish to export all/various entries into a CSV file format for these purposes:
- For Disaster Recovery
- Understanding and organizing your data
- Reporting/Auditing purposes
Admins, Contact Us for this script for use in your environment.
Onboarding Machines to Join a Domain
Provided by: Florian Rossmark, Accriva Diagnostics. Linked with permission.
External Link:
Description:
One of the challenges in most daily IT operations is onboarding of workstations and servers (respective domain join). Over the years I came across and tried many ways to accomplish this. Today I wanted to share a script and solution others might find helpful, but first lets get down to some theory and background.
The Goals and Challenges:
- 1.) Simple domain join after a system was imaged
- 2.) Systems should have a local admin account ... with an individual password
- The PowerShell script below will do the following for you:
- 1.) Prompt for system name
- 2.) Prompt for Password Server credentials
- 3.) Prompt for credentials to join the system to the domain
- 4.) Create a local admin user account
- 5.) Generate a password
- 6.) Check for an existing Entry in Password Server
- 7.) Otherwise, create a new entry with:
- machine name, username, password, manufacturer, model, serial number / service tag,
- UEFI BIOS Windows license key, MAC addresses of all network cards Windows knows about
- 8.) Join the domain putting the system into the defined AD/LDAP OU
Python Examples
Get an Entry Password
Provided by: Justin Harris, Capture Technologie-PC911. Used with permission.
A simple class in Python to access the API with a method that gets an authorization token and another to get a password.
from urllib import request import json class PPS: def __init__(self, host='https://localhost:1001'): self.host = host self.token = None self.auth_header = None def get_token(self, user, passwd): url = f'{self.host}/oauth2/token' headers = {'Content-Type': 'application/x-www-form-urlencoded'} data = f'grant_type=password&username={user}&password={passwd}' req = request.Request(url, data.encode(), headers) res = request.urlopen(req) self.token = json.loads(res.readlines()[0].decode())['access_token'] self.auth_header = {'Authorization': f'Bearer {self.token}'} def get_credential(self, id): url = f'{self.host}/api/v6/rest/credential/{id}/password' headers = {**self.auth_header, 'Content-Type': 'application/json', 'Cache-Control': 'no-cache'} req = request.Request(url, None, headers) res = request.urlopen(req).readlines()[0].decode().strip('"') return res