Skip to content
This repository was archived by the owner on Jun 1, 2024. It is now read-only.

Add Sink configure option to effectively disable SSL Certificate Verification #562

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,8 @@ In your `appsettings.json` file, under the `Serilog` node, :
"connectionPool": "My.Namespace.MyConnectionPool, My.Assembly.Name",
"customFormatter": "My.Namespace.MyCustomFormatter, My.Assembly.Name",
"customDurableFormatter": "My.Namespace.MyCustomDurableFormatter, My.Assembly.Name",
"failureSink": "My.Namespace.MyFailureSink, My.Assembly.Name"
"failureSink": "My.Namespace.MyFailureSink, My.Assembly.Name",
"ignoreServerCertificateValidation": "false"
}
}]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@
using Serilog.Sinks.Elasticsearch;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using Elasticsearch.Net;
using Serilog.Formatting;
using Serilog.Sinks.Elasticsearch.Durable;
using Serilog.Sinks.Elasticsearch.Sinks.ElasticSearch;

namespace Serilog
{
Expand Down Expand Up @@ -100,9 +103,14 @@ public static LoggerConfiguration Elasticsearch(
string connectionGlobalHeaders,
LoggingLevelSwitch levelSwitch)
{
var modifyConnectionSettingsOptions = new ModifyConnectionSettingsOptions
{
ConnectionGlobalHeaders = connectionGlobalHeaders
};

return Elasticsearch(loggerSinkConfiguration, nodeUris, indexFormat, templateName, typeName, batchPostingLimit, period, inlineFields, restrictedToMinimumLevel, bufferBaseFilename,
bufferFileSizeLimitBytes, bufferLogShippingInterval, connectionGlobalHeaders, levelSwitch, 5, EmitEventFailureHandling.WriteToSelfLog, 100000, null, false,
AutoRegisterTemplateVersion.ESv7, false, RegisterTemplateRecovery.IndexAnyway, null, null, null);
bufferFileSizeLimitBytes, bufferLogShippingInterval, levelSwitch, 5, EmitEventFailureHandling.WriteToSelfLog, 100000, null, false,
AutoRegisterTemplateVersion.ESv7, false, RegisterTemplateRecovery.IndexAnyway, null, null, null, modifyConnectionSettingsOptions: modifyConnectionSettingsOptions);
}

/// <summary>
Expand All @@ -122,7 +130,6 @@ public static LoggerConfiguration Elasticsearch(
/// <param name="bufferFileSizeLimitBytes"><see cref="ElasticsearchSinkOptions.BufferFileSizeLimitBytes"/></param>
/// <param name="bufferFileCountLimit"><see cref="ElasticsearchSinkOptions.BufferFileCountLimit"/></param>
/// <param name="bufferLogShippingInterval"><see cref="ElasticsearchSinkOptions.BufferLogShippingInterval"/></param>
/// <param name="connectionGlobalHeaders">A comma or semi-colon separated list of key value pairs of headers to be added to each elastic http request</param>
/// <param name="connectionTimeout"><see cref="ElasticsearchSinkOptions.ConnectionTimeout"/>The connection timeout (in seconds) when sending bulk operations to elasticsearch (defaults to 5).</param>
/// <param name="emitEventFailure"><see cref="ElasticsearchSinkOptions.EmitEventFailure"/>Specifies how failing emits should be handled.</param>
/// <param name="queueSizeLimit"><see cref="ElasticsearchSinkOptions.QueueSizeLimit"/>The maximum number of events that will be held in-memory while waiting to ship them to Elasticsearch. Beyond this limit, events will be dropped. The default is 100,000. Has no effect on durable log shipping.</param>
Expand All @@ -145,6 +152,7 @@ public static LoggerConfiguration Elasticsearch(
/// <param name="templateCustomSettings">Add custom elasticsearch settings to the template</param>
/// <param name="detectElasticsearchVersion">Turns on detection of elasticsearch version via background HTTP call. This will also set `TypeName` automatically, according to the version of Elasticsearch.</param>
/// <param name="batchAction">Configures the OpType being used when inserting document in batch. Must be set to create for data streams.</param>
/// <param name="modifyConnectionSettingsOptions">Provides options for modifying the Elasticsearch connection.</param>
/// <returns>LoggerConfiguration object</returns>
/// <exception cref="ArgumentNullException"><paramref name="nodeUris"/> is <see langword="null" />.</exception>
public static LoggerConfiguration Elasticsearch(
Expand All @@ -160,7 +168,6 @@ public static LoggerConfiguration Elasticsearch(
string bufferBaseFilename = null,
long? bufferFileSizeLimitBytes = null,
long bufferLogShippingInterval = 5000,
string connectionGlobalHeaders = null,
LoggingLevelSwitch levelSwitch = null,
int connectionTimeout = 5,
EmitEventFailureHandling emitEventFailure = EmitEventFailureHandling.WriteToSelfLog,
Expand All @@ -184,7 +191,8 @@ public static LoggerConfiguration Elasticsearch(
int? bufferFileCountLimit = null,
Dictionary<string,string> templateCustomSettings = null,
ElasticOpType batchAction = ElasticOpType.Index,
bool detectElasticsearchVersion = true)
bool detectElasticsearchVersion = true,
ModifyConnectionSettingsOptions modifyConnectionSettingsOptions = null)
{
if (string.IsNullOrEmpty(nodeUris))
throw new ArgumentNullException(nameof(nodeUris), "No Elasticsearch node(s) specified.");
Expand Down Expand Up @@ -231,20 +239,7 @@ public static LoggerConfiguration Elasticsearch(
}
options.BufferLogShippingInterval = TimeSpan.FromMilliseconds(bufferLogShippingInterval);

if (!string.IsNullOrWhiteSpace(connectionGlobalHeaders))
{
NameValueCollection headers = new NameValueCollection();
connectionGlobalHeaders
.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)
.ToList()
.ForEach(headerValueStr =>
{
var headerValue = headerValueStr.Split(new[] { '=' }, 2, StringSplitOptions.RemoveEmptyEntries);
headers.Add(headerValue[0], headerValue[1]);
});

options.ModifyConnectionSettings = (c) => c.GlobalHeaders(headers);
}
SetSinkOptionsModifyConnectionSettings(options, modifyConnectionSettingsOptions);

options.ConnectionTimeout = TimeSpan.FromSeconds(connectionTimeout);
options.EmitEventFailure = emitEventFailure;
Expand Down Expand Up @@ -276,5 +271,52 @@ public static LoggerConfiguration Elasticsearch(

return Elasticsearch(loggerSinkConfiguration, options);
}

private static void SetSinkOptionsModifyConnectionSettings(ElasticsearchSinkOptions options,
ModifyConnectionSettingsOptions settingsOptions)
{
var headers = new NameValueCollection();

if (!string.IsNullOrWhiteSpace(settingsOptions.ConnectionGlobalHeaders))
{
settingsOptions.ConnectionGlobalHeaders
.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)
.ToList()
.ForEach(headerValueStr =>
{
var headerValue = headerValueStr.Split(new[] { '=' }, 2, StringSplitOptions.RemoveEmptyEntries);
headers.Add(headerValue[0], headerValue[1]);
});
}

options.ModifyConnectionSettings = (c) =>
{
if (headers.Count > 0)
c.GlobalHeaders(headers);

c.ServerCertificateValidationCallback((obj, certificate, chain, errors) =>
ServerCertificateValidation(obj, certificate, chain, errors, settingsOptions));

return c;
};
}

private static bool ServerCertificateValidation(object obj, X509Certificate certificate, X509Chain chain,
SslPolicyErrors errors, ModifyConnectionSettingsOptions options)
{
if (errors.HasFlag(SslPolicyErrors.RemoteCertificateChainErrors) &&
options.IgnoreSslRemoteCertificateChainErrors)
return true;

if (errors.HasFlag(SslPolicyErrors.RemoteCertificateNameMismatch) &&
options.IgnoreSslRemoteCertificateNameMismatchErrors)
return true;

if (errors.HasFlag(SslPolicyErrors.RemoteCertificateNotAvailable) &&
options.IgnoreSslRemoteCertificateNotAvailableErrors)
return true;

return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Serilog.Sinks.Elasticsearch.Sinks.ElasticSearch;

public class ModifyConnectionSettingsOptions
{
public string ConnectionGlobalHeaders { get; set; }

public bool IgnoreSslRemoteCertificateChainErrors { get; set; }

public bool IgnoreSslRemoteCertificateNameMismatchErrors { get; set; }

public bool IgnoreSslRemoteCertificateNotAvailableErrors { get; set; }
}