feat(connect): add -SkipCertificateCheck and -AllowInsecureTransport switches #11
@@ -84,5 +84,38 @@ namespace PSInfisicalAPI.Tests
|
|||||||
Assert.Equal("explicit-org", cmdlet.CallResolveOrganizationId(ConnectionWithDefaults(), "explicit-org"));
|
Assert.Equal("explicit-org", cmdlet.CallResolveOrganizationId(ConnectionWithDefaults(), "explicit-org"));
|
||||||
Assert.Empty(logger.VerboseEntries);
|
Assert.Empty(logger.VerboseEntries);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InfisicalConnection_Defaults_TransportFlags_To_False()
|
||||||
|
{
|
||||||
|
InfisicalConnection connection = new InfisicalConnection();
|
||||||
|
Assert.False(connection.SkipCertificateCheck);
|
||||||
|
Assert.False(connection.AllowInsecureTransport);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ShouldSkipCertificateCheck_Reads_From_Current_Session()
|
||||||
|
{
|
||||||
|
InfisicalConnection previous = InfisicalSessionManager.Current;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TestCmdlet cmdlet = CreateCmdletWith(new RecordingLogger());
|
||||||
|
MethodInfo virt = typeof(InfisicalCmdletBase).GetMethod("ShouldSkipCertificateCheck", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
InfisicalSessionManager.SetCurrent(null);
|
||||||
|
Assert.False((bool)virt.Invoke(cmdlet, null));
|
||||||
|
|
||||||
|
InfisicalConnection session = ConnectionWithDefaults();
|
||||||
|
session.IsConnected = true;
|
||||||
|
session.SkipCertificateCheck = true;
|
||||||
|
InfisicalSessionManager.SetCurrent(session);
|
||||||
|
|
||||||
|
Assert.True((bool)virt.Invoke(cmdlet, null));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
InfisicalSessionManager.SetCurrent(previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,12 +62,24 @@ namespace PSInfisicalAPI.Cmdlets
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public SwitchParameter PassThru { get; set; }
|
public SwitchParameter PassThru { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public SwitchParameter SkipCertificateCheck { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public SwitchParameter AllowInsecureTransport { get; set; }
|
||||||
|
|
||||||
|
protected override bool ShouldSkipCertificateCheck()
|
||||||
|
{
|
||||||
|
return SkipCertificateCheck.IsPresent;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void ProcessRecord()
|
protected override void ProcessRecord()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ResolveMissingParametersFromEnvironment();
|
ResolveMissingParametersFromEnvironment();
|
||||||
ValidateRequiredParameters();
|
ValidateRequiredParameters();
|
||||||
|
ValidateTransportSafety();
|
||||||
|
|
||||||
IInfisicalAuthProvider provider;
|
IInfisicalAuthProvider provider;
|
||||||
InfisicalAuthenticationRequest request;
|
InfisicalAuthenticationRequest request;
|
||||||
@@ -179,7 +191,9 @@ namespace PSInfisicalAPI.Cmdlets
|
|||||||
ConnectedAtUtc = DateTimeOffset.UtcNow,
|
ConnectedAtUtc = DateTimeOffset.UtcNow,
|
||||||
ExpiresAtUtc = authResult.ExpiresAtUtc,
|
ExpiresAtUtc = authResult.ExpiresAtUtc,
|
||||||
IsConnected = true,
|
IsConnected = true,
|
||||||
AccessToken = authResult.AccessToken
|
AccessToken = authResult.AccessToken,
|
||||||
|
SkipCertificateCheck = SkipCertificateCheck.IsPresent,
|
||||||
|
AllowInsecureTransport = AllowInsecureTransport.IsPresent
|
||||||
};
|
};
|
||||||
|
|
||||||
InfisicalSessionManager.SetCurrent(connection);
|
InfisicalSessionManager.SetCurrent(connection);
|
||||||
@@ -195,6 +209,26 @@ namespace PSInfisicalAPI.Cmdlets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ValidateTransportSafety()
|
||||||
|
{
|
||||||
|
bool isHttp = BaseUri != null && string.Equals(BaseUri.Scheme, "http", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
if (isHttp && !AllowInsecureTransport.IsPresent)
|
||||||
|
{
|
||||||
|
throw new InfisicalConfigurationException("BaseUri '" + BaseUri + "' is not HTTPS. Re-run Connect-Infisical with -AllowInsecureTransport to permit plaintext.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SkipCertificateCheck.IsPresent)
|
||||||
|
{
|
||||||
|
Logger.Warning(Component, "SkipCertificateCheck is enabled. TLS certificate validation is disabled for this session. Do not use in production.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AllowInsecureTransport.IsPresent && isHttp)
|
||||||
|
{
|
||||||
|
Logger.Warning(Component, "AllowInsecureTransport is enabled and BaseUri uses HTTP. Credentials and secrets will traverse the network unencrypted. Do not use in production.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ResolveMissingParametersFromEnvironment()
|
private void ResolveMissingParametersFromEnvironment()
|
||||||
{
|
{
|
||||||
bool tokenSet = string.Equals(ParameterSetName, ParameterSetToken, StringComparison.Ordinal);
|
bool tokenSet = string.Equals(ParameterSetName, ParameterSetToken, StringComparison.Ordinal);
|
||||||
|
|||||||
@@ -31,13 +31,19 @@ namespace PSInfisicalAPI.Cmdlets
|
|||||||
{
|
{
|
||||||
if (_httpClient == null)
|
if (_httpClient == null)
|
||||||
{
|
{
|
||||||
_httpClient = new InfisicalHttpClient(Logger);
|
_httpClient = new InfisicalHttpClient(Logger, 100, ShouldSkipCertificateCheck());
|
||||||
}
|
}
|
||||||
|
|
||||||
return _httpClient;
|
return _httpClient;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual bool ShouldSkipCertificateCheck()
|
||||||
|
{
|
||||||
|
InfisicalConnection current = InfisicalSessionManager.Current;
|
||||||
|
return current != null && current.SkipCertificateCheck;
|
||||||
|
}
|
||||||
|
|
||||||
protected void ThrowTerminatingForException(string component, string operation, Exception exception)
|
protected void ThrowTerminatingForException(string component, string operation, Exception exception)
|
||||||
{
|
{
|
||||||
InfisicalErrorDetails details = InfisicalErrorHandler.BuildDetails(component, operation, exception);
|
InfisicalErrorDetails details = InfisicalErrorHandler.BuildDetails(component, operation, exception);
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ namespace PSInfisicalAPI.Connections
|
|||||||
public DateTimeOffset ConnectedAtUtc { get; set; }
|
public DateTimeOffset ConnectedAtUtc { get; set; }
|
||||||
public DateTimeOffset? ExpiresAtUtc { get; set; }
|
public DateTimeOffset? ExpiresAtUtc { get; set; }
|
||||||
public bool IsConnected { get; set; }
|
public bool IsConnected { get; set; }
|
||||||
|
public bool SkipCertificateCheck { get; set; }
|
||||||
|
public bool AllowInsecureTransport { get; set; }
|
||||||
|
|
||||||
public Dictionary<string, string> ResolvedEndpointVersions { get; } = new Dictionary<string, string>(StringComparer.Ordinal);
|
public Dictionary<string, string> ResolvedEndpointVersions { get; } = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Net.Security;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using PSInfisicalAPI.Errors;
|
using PSInfisicalAPI.Errors;
|
||||||
using PSInfisicalAPI.Logging;
|
using PSInfisicalAPI.Logging;
|
||||||
@@ -11,13 +13,18 @@ namespace PSInfisicalAPI.Http
|
|||||||
public sealed class InfisicalHttpClient : IInfisicalHttpClient
|
public sealed class InfisicalHttpClient : IInfisicalHttpClient
|
||||||
{
|
{
|
||||||
private const string Component = "HttpClient";
|
private const string Component = "HttpClient";
|
||||||
|
private static readonly PropertyInfo PerRequestCertCallbackProperty =
|
||||||
|
typeof(HttpWebRequest).GetProperty("ServerCertificateValidationCallback");
|
||||||
|
|
||||||
private readonly IInfisicalLogger _logger;
|
private readonly IInfisicalLogger _logger;
|
||||||
private readonly int _timeoutSeconds;
|
private readonly int _timeoutSeconds;
|
||||||
|
private readonly bool _skipCertificateCheck;
|
||||||
|
|
||||||
public InfisicalHttpClient(IInfisicalLogger logger, int timeoutSeconds = 100)
|
public InfisicalHttpClient(IInfisicalLogger logger, int timeoutSeconds = 100, bool skipCertificateCheck = false)
|
||||||
{
|
{
|
||||||
_logger = logger ?? NullInfisicalLogger.Instance;
|
_logger = logger ?? NullInfisicalLogger.Instance;
|
||||||
_timeoutSeconds = timeoutSeconds;
|
_timeoutSeconds = timeoutSeconds;
|
||||||
|
_skipCertificateCheck = skipCertificateCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InfisicalHttpResponse Send(InfisicalHttpRequest request)
|
public InfisicalHttpResponse Send(InfisicalHttpRequest request)
|
||||||
@@ -44,6 +51,11 @@ namespace PSInfisicalAPI.Http
|
|||||||
webRequest.ReadWriteTimeout = _timeoutSeconds * 1000;
|
webRequest.ReadWriteTimeout = _timeoutSeconds * 1000;
|
||||||
webRequest.UseDefaultCredentials = true;
|
webRequest.UseDefaultCredentials = true;
|
||||||
|
|
||||||
|
if (_skipCertificateCheck)
|
||||||
|
{
|
||||||
|
ApplyInsecureCertificateBypass(webRequest);
|
||||||
|
}
|
||||||
|
|
||||||
IWebProxy systemProxy = WebRequest.GetSystemWebProxy();
|
IWebProxy systemProxy = WebRequest.GetSystemWebProxy();
|
||||||
if (systemProxy != null)
|
if (systemProxy != null)
|
||||||
{
|
{
|
||||||
@@ -95,6 +107,20 @@ namespace PSInfisicalAPI.Http
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ApplyInsecureCertificateBypass(HttpWebRequest webRequest)
|
||||||
|
{
|
||||||
|
RemoteCertificateValidationCallback callback = (sender, certificate, chain, errors) => true;
|
||||||
|
|
||||||
|
if (PerRequestCertCallbackProperty != null && PerRequestCertCallbackProperty.CanWrite)
|
||||||
|
{
|
||||||
|
PerRequestCertCallbackProperty.SetValue(webRequest, callback, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Warning(Component, "Per-request ServerCertificateValidationCallback unavailable on this runtime; falling back to global ServicePointManager override for this process.");
|
||||||
|
ServicePointManager.ServerCertificateValidationCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
private static void ApplyHeaders(HttpWebRequest webRequest, IDictionary<string, string> headers)
|
private static void ApplyHeaders(HttpWebRequest webRequest, IDictionary<string, string> headers)
|
||||||
{
|
{
|
||||||
if (headers == null)
|
if (headers == null)
|
||||||
|
|||||||
Reference in New Issue
Block a user