Skip to content

Commit 19e4b5d

Browse files
authored
merge release 2.1 to main (#14)
* fix JSON documentation for UO usage * safely access param dictionaries * fix manifest example for central provider Host param * add constructor parameter for loading SDK DLL; * add logging for SDK loading and invoking * add option to target NetFramework SDK for platform compatibility
1 parent 3d2686d commit 19e4b5d

File tree

10 files changed

+211
-34
lines changed

10 files changed

+211
-34
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
2.1.0
2+
- Added additional parameter option when using Unity Configuration to target the correct directory with the Net Password SDK DLL
3+
- Added additional parameter option when using Unity Configuration to specify if the Net Framework or Net Standard Password SDK should be used
4+
- Improve logging and error handling to report errors correctly
5+
16
2.0.1
27
- Bug fix for DLL compatibility issue preventing CyberArk from loading correctly on the Keyfactor Platform
38
- Include `manifest.json` and alternate `SDK-manifest.json` files and instructions on their use

README.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Keyfactor supports the retrieval of credentials from 3rd party Privileged Access
1212

1313
## Support for CyberArk PAM Provider
1414

15-
CyberArk PAM Provider is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket with your Keyfactor representative.
15+
CyberArk PAM Provider is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket via the Keyfactor Support Portal at https://support.keyfactor.com
1616

1717
###### To report a problem or suggest a new feature, use the **[Issues](../../issues)** tab. If you want to contribute actual bug fixes or proposed enhancements, use the **[Pull requests](../../pulls)** tab.
1818

@@ -79,6 +79,7 @@ Certificate Authentication cannot be required. This may necessitate creating a S
7979

8080
#### For SDK-based local Credential Provider
8181
To use a local Credential Provider instead, the Credential Provider will need to be installed on the machine that is using the PAM Provider. After installing the Credential Provider, copy the `NetStandardPasswordSDK.dll` assembly from the install location into the PAM Provider install location. This dll __needs__ to be adjacent to `cyberark-credentialprovider-pam.dll` to be properly loaded.
82+
__Important__: When running the SDK Credential Provider on Keyfactor Command, the `NetPasswordSDK.dll` needs to be copied instead of `NetStandardPasswordSDK.dll`. This library is compatible with .NET Framework which is necessary to work in Keyfactor Command.
8283

8384
After registering the Credential Provider during install, make sure the Provider for the machine has been granted permission to access the Safe, as well as the Application ID that will be used.
8485

@@ -92,7 +93,7 @@ A <code>manifest.json</code> file is included in the release. This file needs to
9293
~~~ json
9394
"Keyfactor:PAMProviders:CyberArk-CentralCredentialProvider:InitializationInfo": {
9495
"AppId": "myappid",
95-
"Host": "https://my.cyberark.instance:99999",
96+
"Host": "my.cyberark.instance:99999",
9697
"Site": "WithOutCert"
9798
}
9899
~~~
@@ -116,10 +117,10 @@ This file then needs to be edited to enter in the "initialization" parameters fo
116117

117118
#### Usage with the Keyfactor Universal Orchestrator
118119
To use the PAM Provider to resolve a field, for example a Server Password, instead of entering in the actual value for the Server Password, enter a `json` object with the parameters specifying the field.
119-
The parameters needed are the "instance" parameters above:
120+
The parameters needed are the "instance" parameters above (with appropriate characters escaped for correct JSON formatting):
120121

121122
~~~ json
122-
{"Safe":"MySafe","Folder":"Root\Secrets","Object":"MySecret"}
123+
{"Safe":"MySafe","Folder":"Root\\Secrets","Object":"MySecret"}
123124
~~~
124125

125126
If a field supports PAM but should not use PAM, simply enter in the actual value to be used instead of the `json` format object above.
@@ -148,9 +149,16 @@ The Keyfactor service and IIS Server should be restarted after making these chan
148149

149150

150151
For registering the CyberArk for use with the SDK-based Credential Provider, use the following `<register>` instead.
152+
Make sure to enter in the correct full path to the directory for `extensionPath` that has the SDK DLL for the PAM Provider.
151153

152154
```xml
153-
<register type="IPAMProvider" mapTo="Keyfactor.Extensions.Pam.CyberArk.SdkCredentialProviderPAM, cyberark-credentialprovider-pam" name="CyberArk-SdkCredentialProvider" />
155+
<register type="IPAMProvider" mapTo="Keyfactor.Extensions.Pam.CyberArk.SdkCredentialProviderPAM, cyberark-credentialprovider-pam" name="CyberArk-SdkCredentialProvider">
156+
<constructor>
157+
<param name="extensionPath">
158+
<value value="C:\Program Files\Keyfactor\Keyfactor Platform\WebAgentServices\bin"/>
159+
</param>
160+
</constructor>
161+
</register>
154162
```
155163

156164
##### Usage

cyberark-credentialprovider-pam/CentralCredentialProviderPAM.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,19 @@
2020

2121
namespace Keyfactor.Extensions.Pam.CyberArk
2222
{
23-
public class CentralCredentialProviderPAM : IPAMProvider
23+
public class CentralCredentialProviderPAM : CyberArkProvider, IPAMProvider
2424
{
2525
public string Name => "CyberArk-CentralCredentialProvider";
2626

2727
public string GetPassword(Dictionary<string, string> instanceParameters, Dictionary<string, string> initializationInfo)
2828
{
29-
string appId = initializationInfo["AppId"];
30-
string host = initializationInfo["Host"];
31-
string site = initializationInfo["Site"];
29+
string appId = GetRequiredValue(initializationInfo, "AppId");
30+
string host = GetRequiredValue(initializationInfo, "Host");
31+
string site = GetRequiredValue(initializationInfo, "Site");
3232

33-
string safe = instanceParameters["Safe"];
34-
string folder = instanceParameters["Folder"];
35-
string obj = instanceParameters["Object"];
33+
string safe = GetRequiredValue(instanceParameters, "Safe");
34+
string folder = GetRequiredValue(instanceParameters, "Folder");
35+
string obj = GetRequiredValue(instanceParameters, "Object");
3636

3737
var http = new HttpClient();
3838
http.BaseAddress = new Uri($"https://{host}/");
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2023 Keyfactor
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
namespace Keyfactor.Extensions.Pam.CyberArk
16+
{
17+
public static class Constants
18+
{
19+
public interface SDK
20+
{
21+
string DLL { get; }
22+
string PasswordSDKType { get; }
23+
string PasswordRequestType { get; }
24+
string PasswordSDKExceptionType { get; }
25+
string PasswordResponseType { get; }
26+
}
27+
28+
public class NetStandard : SDK
29+
{
30+
public string DLL => "NetStandardPasswordSDK.dll";
31+
public string PasswordSDKType => "CyberArk.AAM.NetStandardPasswordSDK.PasswordSDK";
32+
public string PasswordRequestType => "CyberArk.AAM.NetStandardPasswordSDK.PSDKPasswordRequest";
33+
public string PasswordSDKExceptionType => "CyberArk.AAM.NetStandardPasswordSDK.Exceptions.PSDKException";
34+
public string PasswordResponseType => "CyberArk.AAM.NetStandardPasswordSDK.PSDKPassword";
35+
}
36+
37+
public class NetFramework : SDK
38+
{
39+
public string DLL => "NetPasswordSDK.dll";
40+
public string PasswordSDKType => "CyberArk.AIM.NetPasswordSDK.PasswordSDK";
41+
public string PasswordRequestType => "CyberArk.AIM.NetPasswordSDK.PSDKPasswordRequest";
42+
public string PasswordSDKExceptionType => "CyberArk.AIM.NetPasswordSDK.Exceptions.PSDKException";
43+
public string PasswordResponseType => "CyberArk.AIM.NetPasswordSDK.PSDKPassword";
44+
}
45+
}
46+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2023 Keyfactor
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System;
16+
using System.Collections.Generic;
17+
18+
namespace Keyfactor.Extensions.Pam.CyberArk
19+
{
20+
public class CyberArkProvider
21+
{
22+
protected string GetRequiredValue(Dictionary<string, string> dict, string key)
23+
{
24+
if (!dict.ContainsKey(key)
25+
|| string.IsNullOrWhiteSpace(dict[key]))
26+
{
27+
string error = $"Required field {key} was missing a value or was not defined as expected in dictionary.";
28+
throw new ArgumentException(error);
29+
}
30+
return dict[key];
31+
}
32+
}
33+
}

cyberark-credentialprovider-pam/SdkCredentialProviderPAM.cs

Lines changed: 82 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,35 +12,77 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
using Keyfactor.Logging;
1516
using Keyfactor.Platform.Extensions;
17+
using Microsoft.Extensions.Logging;
1618
using System;
1719
using System.Collections.Generic;
1820
using System.IO;
1921
using System.Reflection;
2022

2123
namespace Keyfactor.Extensions.Pam.CyberArk
2224
{
23-
public class SdkCredentialProviderPAM : IPAMProvider
25+
public class SdkCredentialProviderPAM : CyberArkProvider, IPAMProvider
2426
{
2527
public string Name => "CyberArk-SdkCredentialProvider";
2628

29+
private readonly ILogger Logger;
30+
private readonly Constants.SDK SDKConstants;
31+
private readonly string ExtensionPath;
32+
private readonly bool UsingFrameworkLibrary = false;
33+
34+
public SdkCredentialProviderPAM()
35+
{
36+
Logger = LogHandler.GetClassLogger<SdkCredentialProviderPAM>();
37+
Logger.LogTrace($"Starting up {Name} with no constructor parameters.");
38+
SDKConstants = new Constants.NetStandard();
39+
Logger.LogTrace($"SDK to be targeted will be {SDKConstants.DLL}");
40+
41+
// when lookup path is not provided, use executing assembly location (running on UO)
42+
ExtensionPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
43+
Logger.LogInformation($"{Name} determined it will use the following directory to load the SDK: {ExtensionPath}");
44+
}
45+
46+
public SdkCredentialProviderPAM(string extensionPath, bool useFramework = true)
47+
{
48+
Logger = LogHandler.GetClassLogger<SdkCredentialProviderPAM>();
49+
Logger.LogTrace($"Starting up {Name} with constructor parameters provided.");
50+
UsingFrameworkLibrary = useFramework;
51+
if (UsingFrameworkLibrary)
52+
{
53+
SDKConstants = new Constants.NetFramework();
54+
}
55+
else
56+
{
57+
SDKConstants = new Constants.NetStandard();
58+
}
59+
Logger.LogTrace($"SDK to be targeted will be {SDKConstants.DLL}");
60+
61+
// Extension Path (for looking up DLL) can be passed in as a Unity Constructor parameter (running on Command)
62+
ExtensionPath = extensionPath;
63+
Logger.LogInformation($"{Name} determined it will use the following directory to load the SDK: {ExtensionPath}");
64+
}
65+
2766
public string GetPassword(Dictionary<string, string> instanceParameters, Dictionary<string, string> initializationInfo)
2867
{
29-
string appId = initializationInfo["AppId"];
68+
string appId = GetRequiredValue(initializationInfo, "AppId");
69+
Logger.LogInformation($"Configured with Initialization Parameters: AppId = {appId}");
3070

31-
string safe = instanceParameters["Safe"];
32-
string folder = instanceParameters["Folder"];
33-
string obj = instanceParameters["Object"];
71+
string safe = GetRequiredValue(instanceParameters, "Safe");
72+
string folder = GetRequiredValue(instanceParameters, "Folder");
73+
string obj = GetRequiredValue(instanceParameters, "Object");
74+
Logger.LogInformation($"Configured with Instance Parameters: Safe = {safe} ; Folder = {folder} ; Object = {obj}");
3475

35-
string executingDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
36-
string dll = Path.Combine(executingDir, "NetStandardPasswordSDK.dll");
76+
string dll = Path.Combine(ExtensionPath, SDKConstants.DLL);
77+
Logger.LogDebug($"Loading DLL: {dll}");
3778
var sdk = Assembly.LoadFrom(dll);
79+
Logger.LogTrace("Loaded SDK DLL.");
3880

3981
// get the types from the dll
40-
Type PasswordSDKType = sdk.GetType("CyberArk.AAM.NetStandardPasswordSDK.PasswordSDK");
41-
Type PasswordRequestType = sdk.GetType("CyberArk.AAM.NetStandardPasswordSDK.PSDKPasswordRequest");
42-
Type PasswordSDKExceptionType = sdk.GetType("CyberArk.AAM.NetStandardPasswordSDK.Exceptions.PSDKException");
43-
Type PasswordResponseType = sdk.GetType("CyberArk.AAM.NetStandardPasswordSDK.PSDKPassword");
82+
Type PasswordSDKType = sdk.GetType(SDKConstants.PasswordSDKType);
83+
Type PasswordRequestType = sdk.GetType(SDKConstants.PasswordRequestType);
84+
Type PasswordSDKExceptionType = sdk.GetType(SDKConstants.PasswordSDKExceptionType);
85+
Type PasswordResponseType = sdk.GetType(SDKConstants.PasswordResponseType);
4486

4587
// Create Password Request
4688
ConstructorInfo ctor = PasswordRequestType.GetConstructor(Type.EmptyTypes);
@@ -50,7 +92,9 @@ public string GetPassword(Dictionary<string, string> instanceParameters, Diction
5092
}
5193

5294
object passwordRequest;
95+
Logger.LogTrace("Attempting to invoke constructor of PSDKPasswordRequest type.");
5396
passwordRequest = ctor.Invoke(null);
97+
Logger.LogTrace($"Constructed PSDKPasswordRequest. {passwordRequest}");
5498

5599
PropertyInfo propertyInfo = PasswordRequestType.GetProperty("ConnectionTimeout");
56100
propertyInfo.SetValue(passwordRequest, 30);
@@ -73,14 +117,37 @@ public string GetPassword(Dictionary<string, string> instanceParameters, Diction
73117

74118

75119
// Sending the request to get the password
76-
object passwordResponse = PasswordSDKType.GetMethod("GetPassword").Invoke(null, new object[] { passwordRequest });
120+
Logger.LogTrace("Attempting to invoke GetPassword method of PasswordSDK type.");
121+
object passwordResponse;
122+
try
123+
{
124+
passwordResponse = PasswordSDKType.GetMethod("GetPassword").Invoke(null, new object[] { passwordRequest });
125+
}
126+
catch (TargetInvocationException ex)
127+
{
128+
Logger.LogError(ex.InnerException, "Error occurred when invoking GetPassword method.");
129+
Logger.LogError(ex.ToString());
130+
Logger.LogError(ex.InnerException.ToString());
131+
132+
throw ex.InnerException;
133+
}
134+
Logger.LogTrace("Invoked GetPassword method.");
77135

78136

79137
// Analyzing the response
80138
propertyInfo = PasswordResponseType.GetProperty("Content");
81-
var password = (char[])propertyInfo.GetValue(passwordResponse, null);
82-
83-
return new string(password);
139+
if (UsingFrameworkLibrary)
140+
{
141+
// for netframework
142+
var password = (string)propertyInfo.GetValue(passwordResponse, null);
143+
return password;
144+
}
145+
else
146+
{
147+
//for netstandard
148+
var password = (char[])propertyInfo.GetValue(passwordResponse, null);
149+
return new string(password);
150+
}
84151
}
85152
}
86153
}
Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFramework>netstandard2.0</TargetFramework>
55
<RootNamespace>Keyfactor.Extensions.Pam.CyberArk</RootNamespace>
66
</PropertyGroup>
77

88
<ItemGroup>
9+
<PackageReference Include="Keyfactor.Logging" Version="1.1.1" />
910
<PackageReference Include="Keyfactor.Platform.IPAMProvider" Version="1.0.0" />
10-
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
11+
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
12+
</ItemGroup>
13+
14+
<ItemGroup>
15+
<None Update="manifest.json">
16+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
17+
</None>
18+
<None Update="SDK-manifest.json">
19+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
20+
</None>
1121
</ItemGroup>
1222

1323
</Project>

cyberark-credentialprovider-pam/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
},
1010
"Keyfactor:PAMProviders:CyberArk-CentralCredentialProvider:InitializationInfo": {
1111
"AppId": "myappid",
12-
"Host": "https://my.cyberark.instance:99999",
12+
"Host": "my.cyberark.instance:99999",
1313
"Site": "WithOutCert"
1414
}
1515
}

readme-src/readme-config.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Certificate Authentication cannot be required. This may necessitate creating a S
66

77
#### For SDK-based local Credential Provider
88
To use a local Credential Provider instead, the Credential Provider will need to be installed on the machine that is using the PAM Provider. After installing the Credential Provider, copy the `NetStandardPasswordSDK.dll` assembly from the install location into the PAM Provider install location. This dll __needs__ to be adjacent to `cyberark-credentialprovider-pam.dll` to be properly loaded.
9+
__Important__: When running the SDK Credential Provider on Keyfactor Command, the `NetPasswordSDK.dll` needs to be copied instead of `NetStandardPasswordSDK.dll`. This library is compatible with .NET Framework which is necessary to work in Keyfactor Command.
910

1011
After registering the Credential Provider during install, make sure the Provider for the machine has been granted permission to access the Safe, as well as the Application ID that will be used.
1112

@@ -19,7 +20,7 @@ A <code>manifest.json</code> file is included in the release. This file needs to
1920
~~~ json
2021
"Keyfactor:PAMProviders:CyberArk-CentralCredentialProvider:InitializationInfo": {
2122
"AppId": "myappid",
22-
"Host": "https://my.cyberark.instance:99999",
23+
"Host": "my.cyberark.instance:99999",
2324
"Site": "WithOutCert"
2425
}
2526
~~~
@@ -43,10 +44,10 @@ This file then needs to be edited to enter in the "initialization" parameters fo
4344

4445
#### Usage with the Keyfactor Universal Orchestrator
4546
To use the PAM Provider to resolve a field, for example a Server Password, instead of entering in the actual value for the Server Password, enter a `json` object with the parameters specifying the field.
46-
The parameters needed are the "instance" parameters above:
47+
The parameters needed are the "instance" parameters above (with appropriate characters escaped for correct JSON formatting):
4748

4849
~~~ json
49-
{"Safe":"MySafe","Folder":"Root\Secrets","Object":"MySecret"}
50+
{"Safe":"MySafe","Folder":"Root\\Secrets","Object":"MySecret"}
5051
~~~
5152

5253
If a field supports PAM but should not use PAM, simply enter in the actual value to be used instead of the `json` format object above.

readme-src/readme-register.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11

22
For registering the CyberArk for use with the SDK-based Credential Provider, use the following `<register>` instead.
3+
Make sure to enter in the correct full path to the directory for `extensionPath` that has the SDK DLL for the PAM Provider.
34

45
```xml
5-
<register type="IPAMProvider" mapTo="Keyfactor.Extensions.Pam.CyberArk.SdkCredentialProviderPAM, cyberark-credentialprovider-pam" name="CyberArk-SdkCredentialProvider" />
6+
<register type="IPAMProvider" mapTo="Keyfactor.Extensions.Pam.CyberArk.SdkCredentialProviderPAM, cyberark-credentialprovider-pam" name="CyberArk-SdkCredentialProvider">
7+
<constructor>
8+
<param name="extensionPath">
9+
<value value="C:\Program Files\Keyfactor\Keyfactor Platform\WebAgentServices\bin"/>
10+
</param>
11+
</constructor>
12+
</register>
613
```

0 commit comments

Comments
 (0)