Active IQ Unified Manager Discussions
Active IQ Unified Manager Discussions
Hi All,
I'm working with WFA and Powershell commands, and I have a simple question that nobody seems to be able to answer :
From a Powershell Console or Powershell ISE, how can I get credentials stored in WFA database?
I would like get credential objet or the password in clear text for debugging and developpement purpose, for directly working in Powershell ISE. The reason is there is no way to debug or develop Powershell in a simple and easy way in WFA.
Based on my research :
1. API documentation says clearly no password can be return, so it is not possible to get the password by calling rest/credentials API.
2. By importing WFA.dll in Powershell ISE, Get-WFACredentials cannot be used outside of WFA. This is apparently by design.
3. By editing the WFA.dll which contains Get-WFACredentials command, we can see the dll create a REST API request on localhost for retreiving the credentials with Basic Authentication using user/pwd "system123:system123". But impossible to reproduce the same API call with Powershell...
4. In WFA I found credentials are store in the table command_credential (containing columns user_name, password, ip, name,remote_system_type_id...). This table is only accessible with the root user of the database. Inside passwords look like to be stored with Base64 encoding, but it isn't. If password can be decrypted it would be possible to request by sql the field and get the password from here. Does someone know how to decrypt the password field in the database to cleartext password?
Thanks in advance!
JND.
This might help you out to troubleshoot the code on your own machine:
http://www.wfaguy.com/2017/08/debug-wfa-in-your-powershell-editor.html#more
I was even able to do that on a host that didn't have WFA installed at all. I just mapped a network drive (like W$) to my WFA dev system.
Hi,
It's not possible to enumerate WFA credentials externally to WFA (by design). What you can do though is create a WFA workflow that uses the WFA REST API to enumerate the details of each cached credential (EG name, IP Address) and then use the "Get-WFACredential" cmdlet to enumerate the credentials (username, password) as a credential object which can then either be exported\encrypted to the registry or use "Add-NcCredential" so that the credentials can be used by an external PowerShell process using Get-NcCredential. Hope that gives you some ideas?
/Matt
Hi,
Here is an example for development purposes in a non-production environment, the following code will export all WFA credentials of matchType "exact" to the local PowerShell Credential cache. If the credential is already added it will be removed and re-added (ensures that the credentials are updated in the powershell credential cache if you update them in WFA). Note that there is a pre-requisit to add administrative WFA credentials for the WFA server to ensure the REST API request for /rest/credentials is authenticated. You can then access the credentials in an external powershell session using the "Get-NcCredential" cmdlet. EG
Param( [Parameter(Mandatory=$True, HelpMessage="The WFA Server name or IP Address")] [String]$WFAServer, [Parameter(Mandatory=$True, HelpMessage="The WFA Server name or IP Address")] [ValidateSet("https","http")] [String]$Protocol="https" ) #'------------------------------------------------------------------------------ #'Enumerate the WFA Server credentials to authenticate the REST API request. #'------------------------------------------------------------------------------ $credentials = Get-WFACredentials $WFAServer #'------------------------------------------------------------------------------ [String]$uri = "$Protocol://$WFAServer/rest/credentials" Try{ [xml]$results = Invoke-RestMethod -Uri $uri -Method GET -ContentType "application/XML" -Credential $credentials -ErrorAction Stop }Catch{ Get-WFALogger -Error -Message $("Failed enumerating WFA Credential using URI ""$uri"". Error " + $_.Exception.Message) Throw "Failed enumerating WFA Credential using URI ""$uri""" } #'------------------------------------------------------------------------------ #'Add the WFA credentials to the PowerShell credential cache for external WFA use. #'------------------------------------------------------------------------------ [Int]$errorCount = 0 ForEach($result In $results.collection.credential){ Do{ #'------------------------------------------------------------------------ #'Ensure that only WFA credentials of the "exact" match type are exported. #'------------------------------------------------------------------------ If($result.matchType -ne "exact"){ Get-WFALogger -Info -Message $("The WFA credential """ + $result.name + """ is not an exact match. Exiting") Break; } #'------------------------------------------------------------------------ #'Enumerate the WFA credential #'------------------------------------------------------------------------ Try{ $c = Get-NcCredential -Name $result.name -ErrorAction Stop }Catch{ [Int]$errorCount++ Break; } #'------------------------------------------------------------------------ #'Remove the credential if it exists in the PowerShell credential cache. #'------------------------------------------------------------------------ [Bool]$IsRemoved = $True If($Null -ne $c){ Try{ Remove-NcCredential -Name $result.name -ErrorAction Stop Get-WFALogger -Info -Message $("Removed """ + $result.name + """ from the PowerShell credential cache") }Catch{ Get-WFALogger -Error -Message $("Failed Removing """ + $result.name + """ from the PowerShell credential cache") [Int]$errorCount++ [Bool]$IsRemoved = $False Break; } } #'------------------------------------------------------------------------ #'Add the credential to the PowerShell credential cache for external WFA use. #'------------------------------------------------------------------------ If($IsRemoved){ $wfaCredentials = Get-WFACredentials $result.ip Try{ Add-NcCredential -Name $result.name -SystemScope -Credential $wfaCredentials -ErrorAction Stop Get-WFALogger -Info -Message $("Added """ + $result.name + """ to the PowerShell credential cache") }Catch{ Get-WFALogger -Error -Message $("Failed Adding """ + $result.name + """ to the PowerShell credential cache. Error " + $_.Exception.Message) [Int]$errorCount++ Break; } } }Until($True) } #'------------------------------------------------------------------------------
Then on your WFA server you can run the "profile.ps1" to load the PSTK and retrive the credentials from the powershell cache. EG
PS C:\Program Files\NetApp\WFA\PoSH> .\profile.ps1 PS C:\Program Files\NetApp\WFA\PoSH> $credentials = Get-NcCredential -Name cluster1.testlab.local PS C:\Program Files\NetApp\WFA\PoSH> Connect-NcController -name cluster1.testlab.local -HTTPS -Credential $credentials.Credential
Also in your workflow you can use an MVEL function to enumerate the WFA servers FQDN rather than having to enter it. EG
def get_wfa_fqdn(hostname){ import java.net.InetAddress; InetAddress addr = java.net.InetAddress.getLocalHost().getCanonicalHostName(); return toLower(addr); }
On the input "WFAServer" use "get_wfa_fqdn('')"
Hope that gives you some ideas.
/Matt
P.S: Please Note the description for the "-Systemscope" parameter for the "Add-NcCredential" cmdlet ("This option should only be used on a system with limited user access").
-SystemScope Specify to save the credentials such that any process or user on the local system can access them. This option should only be used on a system with limited user access.
Hi,
Thanks all for your answers, I finally wrote this code that works find for me :
1. Create an admin user in WFA, in the exemple : psadm
2. Create the string value of the encrypted password with this code
$strPasswordClearText = "YourClearTextPassword" $strPasswordSecuredString = ConvertTo-SecureString $strPasswordClearText -AsPlainText -Force $passwordSecuredStringPlainText = $strPasswordSecuredString | ConvertFrom-SecureString $passwordSecuredStringPlainText
Here the Secured String password of $passwordSecuredStringPlainText is :
"01000000d08c9ddf0115d1118c7a00c04fc297eb01000000d9c3455651f52e4d87a365ab2c3e4d640000000002000000000003660000c00000001000000084a9b1e496323d9969ea83205bf9d6c40000000004800000a0000000100000002ad6b5b82a787143a4d42c4589caaf01300000000ae68a6eb6c2c0420b7b61ed87487560e3816613885df828f3d991a348b322ed96d3111370e8aeca6e0a9cdf44cefb2414000000e07c75358e13c145cc9605d05678fa8ea6ced35c"
This string has to be generated for each server.
3. The script (it will only work on localhost)
#Change with hostname or IP of credentials to request $Name = "Hostname or IP" #Change with your account name $strRestAPIUser = "psadm" #Change with your password string generated previously
#Used in order to avoid to store the clear text password in a script $strAdminPasswordEncrypted = "01000000d08c9ddf0115d1118c7a00c04fc297eb01000000d9c3455651f52e4d87a365ab2c3e4d640000000002000000000003660000c000000010000000701c3090622027d11999ac53e7e5f8650000000004800000a0000000100000005e3ae03ae1a30c76232fec3a46033fa220000000fe78980612d3f49f8860c66d3d6a9108769aa4660771a0dc529b925ecc884d83140000004a554b320d322b9c6ba2933c0ab4b7e465a53223" $strAdminPasswordSecureString = [System.Runtime.InteropServices.Marshal]::PtrToStringUni([System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode(($strAdminPasswordEncrypted | ConvertTo-SecureString))) | ConvertTo-SecureString -asPlainText -Force $strAdminPasswordClearText = [System.Runtime.InteropServices.Marshal]::PtrToStringUni([System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($strAdminPasswordSecureString)) #Get Session UUID $strRestAPIPassword = $strAdminPasswordClearText $strRestAPIToken = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("$($strRestAPIUser):$($strRestAPIPassword)")) $strURI_RequestUUID = "https://localhost/rest/execution/api/create" [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $objResponseUUID = Invoke-RestMethod -Uri $strURI_RequestUUID -Method POST -ContentType "application/xml" -Headers @{"Authorization"="Basic $($strRestAPIToken)";"Content-Length"="0"} -Body "" $strUUID = $objResponseUUID.genericSession.uuid #Get Credentials $strURI_RequestHost = "https://localhost/rest/execution/api/$($strUUID)/credentials?hostId=$($Name)" $objResponseHost = Invoke-RestMethod -Uri $strURI_RequestHost -Method Get -ContentType "application/xml" -Headers @{"Authorization"="Basic $($strRestAPIToken)"} #Returned credentials $objResponseHost.credential.name $objResponseHost.credential.userName $objResponseHost.credential.password
Hope it helps some of you!
JND