Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emulator : Adds support for flag in connection string to ignore SSL check #4251

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
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
12 changes: 10 additions & 2 deletions Microsoft.Azure.Cosmos/src/CosmosClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,9 @@ protected CosmosClient()
/// </code>
/// </example>
/// <remarks>
/// The returned reference doesn't guarantee credentials or connectivity validations because creation doesn't make any network calls.
/// Emulator: To ignore SSL Certificate please suffix connectionstring with "DisableServerCertificateValidation=True;".
/// When CosmosClientOptions.HttpClientFactory is used, SSL certificate needs to be handled appropriately.
/// NOTE: DO NOT use this flag in production (only for emulator)
/// </remarks>
/// <seealso cref="CosmosClientOptions"/>
/// <seealso cref="Fluent.CosmosClientBuilder"/>
Expand All @@ -195,7 +197,7 @@ public CosmosClient(
: this(
CosmosClientOptions.GetAccountEndpoint(connectionString),
CosmosClientOptions.GetAccountKey(connectionString),
clientOptions)
CosmosClientOptions.GetCosmosClientOptionsWithCertificateFlag(connectionString, clientOptions))
{
}

Expand Down Expand Up @@ -495,6 +497,11 @@ public static async Task<CosmosClient> CreateAndInitializeAsync(string accountEn
/// ]]>
/// </code>
/// </example>
/// <remarks>
/// Emulator: To ignore SSL Certificate please suffix connectionstring with "DisableServerCertificateValidation=True;".
/// When CosmosClientOptions.HttpClientFactory is used, SSL certificate needs to be handled appropriately.
/// NOTE: DO NOT use this flag in production (only for emulator)
/// </remarks>
public static async Task<CosmosClient> CreateAndInitializeAsync(string connectionString,
IReadOnlyList<(string databaseId, string containerId)> containers,
CosmosClientOptions cosmosClientOptions = null,
Expand All @@ -504,6 +511,7 @@ public static async Task<CosmosClient> CreateAndInitializeAsync(string connectio
{
throw new ArgumentNullException(nameof(containers));
}
cosmosClientOptions = CosmosClientOptions.GetCosmosClientOptionsWithCertificateFlag(connectionString, cosmosClientOptions);

CosmosClient cosmosClient = new CosmosClient(connectionString,
cosmosClientOptions);
Expand Down
89 changes: 60 additions & 29 deletions Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public class CosmosClientOptions

private const string ConnectionStringAccountEndpoint = "AccountEndpoint";
private const string ConnectionStringAccountKey = "AccountKey";
private const string ConnectionStringDisableServerCertificateValidation = "DisableServerCertificateValidation";

private const ApiType DefaultApiType = ApiType.None;

Expand Down Expand Up @@ -651,7 +652,9 @@ internal Protocol ConnectionProtocol
/// </summary>
/// <remarks>
/// <para>
/// Customizing SSL verification is not recommended in production environments.
/// Emulator: To ignore SSL Certificate please suffix connectionstring with "DisableServerCertificateValidation=True;".
/// When CosmosClientOptions.HttpClientFactory is used, SSL certificate needs to be handled appropriately.
sourabh1007 marked this conversation as resolved.
Show resolved Hide resolved
/// NOTE: DO NOT use this flag in production (only for emulator)
/// </para>
/// </remarks>
public Func<X509Certificate2, X509Chain, SslPolicyErrors, bool> ServerCertificateCustomValidationCallback { get; set; }
Expand Down Expand Up @@ -843,34 +846,62 @@ internal virtual ConnectionPolicy GetConnectionPolicy(int clientId)
return (Documents.ConsistencyLevel)this.ConsistencyLevel.Value;
}

internal static string GetAccountEndpoint(string connectionString)
{
return CosmosClientOptions.GetValueFromConnectionString(connectionString, CosmosClientOptions.ConnectionStringAccountEndpoint);
}

internal static string GetAccountKey(string connectionString)
{
return CosmosClientOptions.GetValueFromConnectionString(connectionString, CosmosClientOptions.ConnectionStringAccountKey);
}

private static string GetValueFromConnectionString(string connectionString, string keyName)
{
if (connectionString == null)
{
throw new ArgumentNullException(nameof(connectionString));
}

DbConnectionStringBuilder builder = new DbConnectionStringBuilder { ConnectionString = connectionString };
if (builder.TryGetValue(keyName, out object value))
{
string keyNameValue = value as string;
if (!string.IsNullOrEmpty(keyNameValue))
{
return keyNameValue;
}
}

throw new ArgumentException("The connection string is missing a required property: " + keyName);
internal static string GetAccountEndpoint(string connectionString)
{
return CosmosClientOptions.GetValueFromConnectionString<string>(connectionString, CosmosClientOptions.ConnectionStringAccountEndpoint, null);
}

internal static string GetAccountKey(string connectionString)
{
return CosmosClientOptions.GetValueFromConnectionString<string>(connectionString, CosmosClientOptions.ConnectionStringAccountKey, null);
}

internal static bool IsConnectionStringDisableServerCertificateValidationFlag(string connectionString)
{
return Convert.ToBoolean(CosmosClientOptions.GetValueFromConnectionString<bool>(connectionString, CosmosClientOptions.ConnectionStringDisableServerCertificateValidation, false));
}

internal static CosmosClientOptions GetCosmosClientOptionsWithCertificateFlag(string connectionString, CosmosClientOptions clientOptions)
{
clientOptions ??= new CosmosClientOptions();
if (CosmosClientOptions.IsConnectionStringDisableServerCertificateValidationFlag(connectionString))
{
clientOptions.ServerCertificateCustomValidationCallback = (_, _, _) => true;
sourabh1007 marked this conversation as resolved.
Show resolved Hide resolved
sourabh1007 marked this conversation as resolved.
Show resolved Hide resolved
}

return clientOptions;
}

private static T GetValueFromConnectionString<T>(string connectionString, string keyName, T defaultValue)
{
if (connectionString == null)
{
throw new ArgumentNullException(nameof(connectionString));
}

DbConnectionStringBuilder builder = new DbConnectionStringBuilder { ConnectionString = connectionString };
if (builder.TryGetValue(keyName, out object value))
{
string keyNameValue = value as string;
if (!string.IsNullOrEmpty(keyNameValue))
{
try
{
return (T)Convert.ChangeType(value, typeof(T));
}
catch (InvalidCastException)
{
throw new ArgumentException("The connection string contains invalid property: " + keyName);
}
}
}

if (defaultValue != null)
{
return defaultValue;
}

throw new ArgumentException("The connection string is missing a required property: " + keyName);
}

private void ValidateLimitToEndpointSettings()
Expand Down
7 changes: 7 additions & 0 deletions Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ public CosmosClientBuilder(
/// </summary>
/// <example>"AccountEndpoint=https://mytestcosmosaccount.documents.azure.com:443/;AccountKey={SecretAccountKey};"</example>
/// <param name="connectionString">The connection string must contain AccountEndpoint and AccountKey or ResourceToken.</param>
/// <remarks>
/// Emulator: To ignore SSL Certificate please suffix connectionstring with "DisableServerCertificateValidation=True;".
/// When CosmosClientOptions.HttpClientFactory is used, SSL certificate needs to be handled appropriately.
/// NOTE: DO NOT use this flag in production (only for emulator)
/// </remarks>
public CosmosClientBuilder(string connectionString)
{
if (connectionString == null)
Expand All @@ -133,6 +138,8 @@ public CosmosClientBuilder(string connectionString)

this.accountEndpoint = CosmosClientOptions.GetAccountEndpoint(connectionString);
this.accountKey = CosmosClientOptions.GetAccountKey(connectionString);

this.clientOptions = CosmosClientOptions.GetCosmosClientOptionsWithCertificateFlag(connectionString, this.clientOptions);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ namespace Microsoft.Azure.Cosmos.Tests
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http;
using System.Net.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using global::Azure.Core;
using Microsoft.Azure.Cosmos.Fluent;
using Microsoft.Azure.Documents;
Expand Down Expand Up @@ -885,7 +887,32 @@ public void InvalidApplicationNameCatchTest()
ApplicationName = illegal
});
}
}
}
sourabh1007 marked this conversation as resolved.
Show resolved Hide resolved

[TestMethod]
[DataRow(ConnectionString, false)]
[DataRow(ConnectionString + "DisableServerCertificateValidation=true;", true)]
public void TestServerCertificatesValidationCallback(string connStr, bool expectedIgnoreCertificateFlag)
{
//Arrange
X509Certificate2 x509Certificate2 = new CertificateRequest("cn=www.test", ECDsa.Create(), HashAlgorithmName.SHA256).CreateSelfSigned(DateTime.Now, DateTime.Now.AddYears(1));
X509Chain x509Chain = new X509Chain();
SslPolicyErrors sslPolicyErrors = new SslPolicyErrors();

CosmosClient cosmosClient = new CosmosClient(connStr);

if (expectedIgnoreCertificateFlag)
{
Assert.IsNotNull(cosmosClient.ClientOptions.ServerCertificateCustomValidationCallback);
sourabh1007 marked this conversation as resolved.
Show resolved Hide resolved
Assert.IsTrue(cosmosClient
.ClientOptions
.ServerCertificateCustomValidationCallback(x509Certificate2, x509Chain, sslPolicyErrors));
}
else
{
Assert.IsNull(cosmosClient.ClientOptions.ServerCertificateCustomValidationCallback);
}
}

private class TestWebProxy : IWebProxy
{
Expand Down
Loading