Skip to content

Commit 11cb684

Browse files
leefine02leefine02
authored andcommitted
1 parent cec1901 commit 11cb684

File tree

6 files changed

+212
-54
lines changed

6 files changed

+212
-54
lines changed

RemoteFile/RemoteCertificateStore.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@
2424
using Keyfactor.Logging;
2525
using System.Management.Automation;
2626
using System.Runtime.InteropServices;
27+
using Microsoft.CodeAnalysis.CSharp.Syntax;
2728

2829
namespace Keyfactor.Extensions.Orchestrator.RemoteFile
2930
{
3031
internal class RemoteCertificateStore
3132
{
3233
private const string NO_EXTENSION = "noext";
3334
private const string FULL_SCAN = "fullscan";
35+
private const string LOCAL_MACHINE_SUFFIX = "|localmachine";
3436

3537
internal enum ServerTypeEnum
3638
{
@@ -333,10 +335,12 @@ internal void Initialize()
333335
{
334336
logger.MethodEntry(LogLevel.Debug);
335337

338+
bool treatAsLocal = Server.ToLower().EndsWith(LOCAL_MACHINE_SUFFIX);
339+
336340
if (ServerType == ServerTypeEnum.Linux || RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
337-
RemoteHandler = new SSHHandler(Server, ServerId, ServerPassword, ServerType == ServerTypeEnum.Linux);
341+
RemoteHandler = treatAsLocal ? new LinuxLocalHandler() as IRemoteHandler : new SSHHandler(Server, ServerId, ServerPassword, ServerType == ServerTypeEnum.Linux) as IRemoteHandler;
338342
else
339-
RemoteHandler = new WinRMHandler(Server, ServerId, ServerPassword);
343+
RemoteHandler = new WinRMHandler(Server, ServerId, ServerPassword, treatAsLocal);
340344

341345
RemoteHandler.Initialize();
342346

RemoteFile/RemoteFile.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
<ItemGroup>
2323
<PackageReference Include="BouncyCastle.Cryptography" Version="2.3.0" />
24+
<PackageReference Include="CliWrap" Version="3.6.6" />
2425
<PackageReference Include="Keyfactor.Logging" Version="1.1.1" />
2526
<PackageReference Include="Keyfactor.Orchestrators.IOrchestratorJobExtensions" Version="0.7.0" />
2627
<PackageReference Include="Keyfactor.PKI" Version="5.0.0" />

RemoteFile/RemoteHandlers/BaseRemoteHandler.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Keyfactor.Logging;
99

1010
using Microsoft.Extensions.Logging;
11+
using System.Text.RegularExpressions;
1112

1213
namespace Keyfactor.Extensions.Orchestrator.RemoteFile.RemoteHandlers
1314
{
@@ -16,6 +17,7 @@ abstract class BaseRemoteHandler : IRemoteHandler
1617
internal ILogger _logger;
1718
internal const string PASSWORD_MASK_VALUE = "[PASSWORD]";
1819
internal const int PASSWORD_LENGTH_MAX = 100;
20+
internal const string LINUX_PERMISSION_REGEXP = "^[0-7]{3}$";
1921

2022
public string Server { get; set; }
2123

@@ -24,6 +26,13 @@ public BaseRemoteHandler()
2426
_logger = LogHandler.GetClassLogger(this.GetType());
2527
}
2628

29+
public static void AreLinuxPermissionsValid(string permissions)
30+
{
31+
Regex regex = new Regex(LINUX_PERMISSION_REGEXP);
32+
if (!regex.IsMatch(permissions))
33+
throw new RemoteFileException($"Invalid format for Linux file permissions. This value must be exactly 3 digits long with each digit between 0-7 but found {permissions} instead.");
34+
}
35+
2736
public abstract void Initialize();
2837

2938
public abstract void Terminate();
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// Copyright 2021 Keyfactor
2+
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
3+
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
4+
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
5+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
6+
// and limitations under the License.
7+
8+
using System;
9+
using System.IO;
10+
using System.Security.Cryptography;
11+
12+
using CliWrap;
13+
using CliWrap.Buffered;
14+
15+
using Renci.SshNet;
16+
17+
using Microsoft.Extensions.Logging;
18+
19+
using Keyfactor.Logging;
20+
using Keyfactor.PKI.PrivateKeys;
21+
using Keyfactor.PKI.PEM;
22+
23+
namespace Keyfactor.Extensions.Orchestrator.RemoteFile.RemoteHandlers
24+
{
25+
class LinuxLocalHandler : BaseRemoteHandler
26+
{
27+
private Command BaseCommand { get; set; }
28+
29+
internal LinuxLocalHandler()
30+
{
31+
_logger.MethodEntry(LogLevel.Debug);
32+
_logger.MethodExit(LogLevel.Debug);
33+
}
34+
35+
public override void Initialize()
36+
{
37+
_logger.MethodEntry(LogLevel.Debug);
38+
39+
BaseCommand = Cli.Wrap("/bin/bash");
40+
41+
_logger.MethodExit(LogLevel.Debug);
42+
}
43+
44+
public override void Terminate()
45+
{
46+
_logger.MethodEntry(LogLevel.Debug);
47+
_logger.MethodExit(LogLevel.Debug);
48+
}
49+
50+
public override string RunCommand(string commandText, object[] arguments, bool withSudo, string[] passwordsToMaskInLog)
51+
{
52+
_logger.MethodEntry(LogLevel.Debug);
53+
54+
string sudo = $"echo -e '\n' | sudo -i -S ";
55+
56+
try
57+
{
58+
if (withSudo)
59+
commandText = sudo + commandText;
60+
61+
string displayCommand = commandText;
62+
if (passwordsToMaskInLog != null)
63+
{
64+
foreach (string password in passwordsToMaskInLog)
65+
displayCommand = displayCommand.Replace(password, PASSWORD_MASK_VALUE);
66+
}
67+
68+
_logger.LogDebug($"RunCommand: {displayCommand}");
69+
70+
Command cmd = BaseCommand.WithArguments($@"-c ""{commandText}""");
71+
BufferedCommandResult result = cmd.ExecuteBufferedAsync().GetAwaiter().GetResult();
72+
73+
_logger.LogDebug($"Linux Local Results: {displayCommand}::: {result.StandardOutput}::: {result.StandardError}");
74+
75+
if (!String.IsNullOrEmpty(result.StandardError))
76+
throw new ApplicationException(result.StandardError);
77+
78+
_logger.MethodExit(LogLevel.Debug);
79+
80+
return result.StandardOutput;
81+
}
82+
catch (Exception ex)
83+
{
84+
_logger.LogError($"Exception during RunCommand...{RemoteFileException.FlattenExceptionMessages(ex, ex.Message)}");
85+
throw ex;
86+
}
87+
}
88+
89+
public override void UploadCertificateFile(string path, string fileName, byte[] certBytes)
90+
{
91+
_logger.MethodEntry(LogLevel.Debug);
92+
_logger.LogDebug($"UploadCertificateFile: {path}{fileName}");
93+
94+
string uploadPath = path+fileName;
95+
96+
try
97+
{
98+
File.WriteAllBytes(uploadPath, certBytes);
99+
}
100+
catch (Exception ex)
101+
{
102+
_logger.LogError($"Error attempting upload file to {uploadPath}...");
103+
_logger.LogError($"Upload Exception: {RemoteFileException.FlattenExceptionMessages(ex, ex.Message)}");
104+
throw new RemoteFileException($"Error attempting upload file to {uploadPath}.", ex);
105+
}
106+
107+
_logger.MethodExit(LogLevel.Debug);
108+
}
109+
110+
public override byte[] DownloadCertificateFile(string path)
111+
{
112+
_logger.MethodEntry(LogLevel.Debug);
113+
_logger.LogDebug($"DownloadCertificateFile: {path}");
114+
115+
byte[] rtnStore = new byte[] { };
116+
117+
try
118+
{
119+
rtnStore = File.ReadAllBytes(path);
120+
}
121+
catch (Exception ex)
122+
{
123+
_logger.LogError($"Error attempting download file {path}...");
124+
_logger.LogError($"Download Exception: {RemoteFileException.FlattenExceptionMessages(ex, ex.Message)}");
125+
throw new RemoteFileException($"Error attempting download file {path}.", ex);
126+
}
127+
128+
_logger.MethodExit(LogLevel.Debug);
129+
130+
return rtnStore;
131+
}
132+
133+
public override void CreateEmptyStoreFile(string path, string linuxFilePermissions, string linuxFileOwner)
134+
{
135+
_logger.MethodEntry(LogLevel.Debug);
136+
string[] linuxGroupOwner = linuxFileOwner.Split(":");
137+
string linuxFileGroup = linuxFileOwner;
138+
139+
if (linuxGroupOwner.Length == 2)
140+
{
141+
linuxFileOwner = linuxGroupOwner[0];
142+
linuxFileGroup = linuxGroupOwner[1];
143+
}
144+
145+
AreLinuxPermissionsValid(linuxFilePermissions);
146+
RunCommand($"install -m {linuxFilePermissions} -o {linuxFileOwner} -g {linuxFileGroup} /dev/null {path}", null, ApplicationSettings.UseSudo, null);
147+
148+
_logger.MethodExit(LogLevel.Debug);
149+
}
150+
151+
public override bool DoesFileExist(string path)
152+
{
153+
_logger.MethodEntry(LogLevel.Debug);
154+
_logger.LogDebug($"DoesFileExist: {path}");
155+
156+
return File.Exists(path);
157+
}
158+
159+
public override void RemoveCertificateFile(string path, string fileName)
160+
{
161+
_logger.LogDebug($"RemoveCertificateFile: {path} {fileName}");
162+
163+
RunCommand($"rm {path}{fileName}", null, ApplicationSettings.UseSudo, null);
164+
}
165+
}
166+
}

RemoteFile/RemoteHandlers/SSHHandler.cs

Lines changed: 28 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
using System.Collections.Generic;
1010
using System.IO;
1111
using System.Security.Cryptography;
12-
using System.Text.RegularExpressions;
1312
using System.Text;
1413

1514
using Renci.SshNet;
@@ -19,15 +18,12 @@
1918
using Keyfactor.Logging;
2019
using Keyfactor.PKI.PrivateKeys;
2120
using Keyfactor.PKI.PEM;
22-
using System.Runtime.InteropServices;
2321

2422
namespace Keyfactor.Extensions.Orchestrator.RemoteFile.RemoteHandlers
2523
{
2624
class SSHHandler : BaseRemoteHandler
2725
{
28-
private const string LINUX_PERMISSION_REGEXP = "^[0-7]{3}$";
2926
private ConnectionInfo Connection { get; set; }
30-
private bool RunLocal { get; set; }
3127
private bool IsStoreServerLinux { get; set; }
3228

3329
private SshClient sshClient;
@@ -37,59 +33,52 @@ internal SSHHandler(string server, string serverLogin, string serverPassword, bo
3733
_logger.MethodEntry(LogLevel.Debug);
3834

3935
Server = server;
40-
RunLocal = Server.ToLower() == "localhost" || Server.ToLower().EndsWith("|localmachine");
4136
IsStoreServerLinux = isStoreServerLinux;
4237

43-
if (!RunLocal)
38+
List<AuthenticationMethod> authenticationMethods = new List<AuthenticationMethod>();
39+
if (serverPassword.Length < PASSWORD_LENGTH_MAX)
4440
{
45-
List<AuthenticationMethod> authenticationMethods = new List<AuthenticationMethod>();
46-
if (serverPassword.Length < PASSWORD_LENGTH_MAX)
47-
{
48-
authenticationMethods.Add(new PasswordAuthenticationMethod(serverLogin, serverPassword));
49-
}
50-
else
51-
{
52-
PrivateKeyFile privateKeyFile;
41+
authenticationMethods.Add(new PasswordAuthenticationMethod(serverLogin, serverPassword));
42+
}
43+
else
44+
{
45+
PrivateKeyFile privateKeyFile;
5346

54-
try
47+
try
48+
{
49+
using (MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(FormatRSAPrivateKey(serverPassword))))
5550
{
56-
using (MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(FormatRSAPrivateKey(serverPassword))))
57-
{
58-
privateKeyFile = new PrivateKeyFile(ms);
59-
}
51+
privateKeyFile = new PrivateKeyFile(ms);
6052
}
61-
catch (Exception ex)
53+
}
54+
catch (Exception ex)
55+
{
56+
using (MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(ConvertToPKCS1(serverPassword))))
6257
{
63-
using (MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(ConvertToPKCS1(serverPassword))))
64-
{
65-
privateKeyFile = new PrivateKeyFile(ms);
66-
}
58+
privateKeyFile = new PrivateKeyFile(ms);
6759
}
68-
69-
authenticationMethods.Add(new PrivateKeyAuthenticationMethod(serverLogin, privateKeyFile));
7060
}
7161

72-
Connection = new ConnectionInfo(server, serverLogin, authenticationMethods.ToArray());
62+
authenticationMethods.Add(new PrivateKeyAuthenticationMethod(serverLogin, privateKeyFile));
7363
}
7464

65+
Connection = new ConnectionInfo(server, serverLogin, authenticationMethods.ToArray());
66+
7567
_logger.MethodExit(LogLevel.Debug);
7668
}
7769

7870
public override void Initialize()
7971
{
8072
_logger.MethodEntry(LogLevel.Debug);
8173

82-
if (!RunLocal)
74+
try
8375
{
84-
try
85-
{
86-
sshClient = new SshClient(Connection);
87-
sshClient.Connect();
88-
}
89-
catch (Exception ex)
90-
{
91-
throw new RemoteFileException($"Error making a SSH connection to remote server {Connection.Host}, for user {Connection.Username}. Please contact your company's system administrator to verify connection and permission settings.", ex);
92-
}
76+
sshClient = new SshClient(Connection);
77+
sshClient.Connect();
78+
}
79+
catch (Exception ex)
80+
{
81+
throw new RemoteFileException($"Error making a SSH connection to remote server {Connection.Host}, for user {Connection.Username}. Please contact your company's system administrator to verify connection and permission settings.", ex);
9382
}
9483

9584
_logger.MethodExit(LogLevel.Debug);
@@ -99,19 +88,15 @@ public override void Terminate()
9988
{
10089
_logger.MethodEntry(LogLevel.Debug);
10190

102-
if (!RunLocal)
103-
{
104-
sshClient.Disconnect();
105-
sshClient.Dispose();
106-
}
91+
sshClient.Disconnect();
92+
sshClient.Dispose();
10793

10894
_logger.MethodExit(LogLevel.Debug);
10995
}
11096

11197
public override string RunCommand(string commandText, object[] arguments, bool withSudo, string[] passwordsToMaskInLog)
11298
{
11399
_logger.MethodEntry(LogLevel.Debug);
114-
_logger.LogDebug($"RunCommand: {commandText}");
115100

116101
string sudo = $"sudo -i -S ";
117102
string echo = $"echo -e '\n' | ";
@@ -381,13 +366,6 @@ public override bool DoesFileExist(string path)
381366
}
382367
}
383368

384-
public static void AreLinuxPermissionsValid(string permissions)
385-
{
386-
Regex regex = new Regex(LINUX_PERMISSION_REGEXP);
387-
if (!regex.IsMatch(permissions))
388-
throw new RemoteFileException($"Invalid format for Linux file permissions. This value must be exactly 3 digits long with each digit between 0-7 but found {permissions} instead.");
389-
}
390-
391369
public override void RemoveCertificateFile(string path, string fileName)
392370
{
393371
_logger.LogDebug($"RemoveCertificateFile: {path} {fileName}");

RemoteFile/RemoteHandlers/WinRMHandler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ class WinRMHandler : BaseRemoteHandler
2828
private WSManConnectionInfo connectionInfo { get; set; }
2929
private bool RunLocal { get; set; }
3030

31-
internal WinRMHandler(string server, string serverLogin, string serverPassword)
31+
internal WinRMHandler(string server, string serverLogin, string serverPassword, bool treatAsLocal)
3232
{
3333
_logger.MethodEntry(LogLevel.Debug);
3434

3535
Server = server;
36-
RunLocal = Server.ToLower() == "localhost" || Server.ToLower().EndsWith("|localmachine");
36+
RunLocal = Server.ToLower() == "localhost" || treatAsLocal;
3737

3838
if (!RunLocal)
3939
{

0 commit comments

Comments
 (0)