diff --git a/Microsoft.Azure.Cosmos/src/CosmosClient.cs b/Microsoft.Azure.Cosmos/src/CosmosClient.cs
index 7b143196fe..89c628635f 100644
--- a/Microsoft.Azure.Cosmos/src/CosmosClient.cs
+++ b/Microsoft.Azure.Cosmos/src/CosmosClient.cs
@@ -183,7 +183,9 @@ protected CosmosClient()
///
///
///
- /// 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)
///
///
///
@@ -195,7 +197,7 @@ public CosmosClient(
: this(
CosmosClientOptions.GetAccountEndpoint(connectionString),
CosmosClientOptions.GetAccountKey(connectionString),
- clientOptions)
+ CosmosClientOptions.GetCosmosClientOptionsWithCertificateFlag(connectionString, clientOptions))
{
}
@@ -495,6 +497,11 @@ public static async Task CreateAndInitializeAsync(string accountEn
/// ]]>
///
///
+ ///
+ /// 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)
+ ///
public static async Task CreateAndInitializeAsync(string connectionString,
IReadOnlyList<(string databaseId, string containerId)> containers,
CosmosClientOptions cosmosClientOptions = null,
@@ -504,6 +511,7 @@ public static async Task CreateAndInitializeAsync(string connectio
{
throw new ArgumentNullException(nameof(containers));
}
+ cosmosClientOptions = CosmosClientOptions.GetCosmosClientOptionsWithCertificateFlag(connectionString, cosmosClientOptions);
CosmosClient cosmosClient = new CosmosClient(connectionString,
cosmosClientOptions);
diff --git a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs
index c49183e435..1fd66c3169 100644
--- a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs
+++ b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs
@@ -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;
@@ -651,7 +652,9 @@ internal Protocol ConnectionProtocol
///
///
///
- /// 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.
+ /// NOTE: DO NOT use this flag in production (only for emulator)
///
///
public Func ServerCertificateCustomValidationCallback { get; set; }
@@ -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(connectionString, CosmosClientOptions.ConnectionStringAccountEndpoint, null);
+ }
+
+ internal static string GetAccountKey(string connectionString)
+ {
+ return CosmosClientOptions.GetValueFromConnectionString(connectionString, CosmosClientOptions.ConnectionStringAccountKey, null);
+ }
+
+ internal static bool IsConnectionStringDisableServerCertificateValidationFlag(string connectionString)
+ {
+ return Convert.ToBoolean(CosmosClientOptions.GetValueFromConnectionString(connectionString, CosmosClientOptions.ConnectionStringDisableServerCertificateValidation, false));
+ }
+
+ internal static CosmosClientOptions GetCosmosClientOptionsWithCertificateFlag(string connectionString, CosmosClientOptions clientOptions)
+ {
+ clientOptions ??= new CosmosClientOptions();
+ if (CosmosClientOptions.IsConnectionStringDisableServerCertificateValidationFlag(connectionString))
+ {
+ clientOptions.ServerCertificateCustomValidationCallback = (_, _, _) => true;
+ }
+
+ return clientOptions;
+ }
+
+ private static T GetValueFromConnectionString(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()
diff --git a/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs b/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs
index 5258987a35..e030411338 100644
--- a/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs
+++ b/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs
@@ -124,6 +124,11 @@ public CosmosClientBuilder(
///
/// "AccountEndpoint=https://mytestcosmosaccount.documents.azure.com:443/;AccountKey={SecretAccountKey};"
/// The connection string must contain AccountEndpoint and AccountKey or ResourceToken.
+ ///
+ /// 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)
+ ///
public CosmosClientBuilder(string connectionString)
{
if (connectionString == null)
@@ -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);
}
///
diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs
index b625858c09..51aee132ae 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs
@@ -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;
@@ -885,7 +887,32 @@ public void InvalidApplicationNameCatchTest()
ApplicationName = illegal
});
}
- }
+ }
+
+ [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);
+ Assert.IsTrue(cosmosClient
+ .ClientOptions
+ .ServerCertificateCustomValidationCallback(x509Certificate2, x509Chain, sslPolicyErrors));
+ }
+ else
+ {
+ Assert.IsNull(cosmosClient.ClientOptions.ServerCertificateCustomValidationCallback);
+ }
+ }
private class TestWebProxy : IWebProxy
{