Skip to content

Commit f33b2af

Browse files
sourabh1007kirankumarkolliealsur
authored
Emulator : Adds support for flag in connection string to ignore SSL check (#4251)
* first drfat * add test * add test * add documentation * builder changes * updating contract file * add tests * fix tests * remove builder method * updated contract * update gttpclient * cleanup * added validation nd doc * added validation * modified error message * Update Microsoft.Azure.Cosmos/src/CosmosClient.cs Co-authored-by: Kiran Kumar Kolli <[email protected]> * Update Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs Co-authored-by: Matias Quaranta <[email protected]> * remove validation * updated client options * remving test * rename flag to DisableServerCertificateValidation * updated docs * updated test * updated doc --------- Co-authored-by: Kiran Kumar Kolli <[email protected]> Co-authored-by: Matias Quaranta <[email protected]>
1 parent e11dc9b commit f33b2af

File tree

4 files changed

+107
-34
lines changed

4 files changed

+107
-34
lines changed

Microsoft.Azure.Cosmos/src/CosmosClient.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,9 @@ protected CosmosClient()
183183
/// </code>
184184
/// </example>
185185
/// <remarks>
186-
/// The returned reference doesn't guarantee credentials or connectivity validations because creation doesn't make any network calls.
186+
/// Emulator: To ignore SSL Certificate please suffix connectionstring with "DisableServerCertificateValidation=True;".
187+
/// When CosmosClientOptions.HttpClientFactory is used, SSL certificate needs to be handled appropriately.
188+
/// NOTE: DO NOT use this flag in production (only for emulator)
187189
/// </remarks>
188190
/// <seealso cref="CosmosClientOptions"/>
189191
/// <seealso cref="Fluent.CosmosClientBuilder"/>
@@ -195,7 +197,7 @@ public CosmosClient(
195197
: this(
196198
CosmosClientOptions.GetAccountEndpoint(connectionString),
197199
CosmosClientOptions.GetAccountKey(connectionString),
198-
clientOptions)
200+
CosmosClientOptions.GetCosmosClientOptionsWithCertificateFlag(connectionString, clientOptions))
199201
{
200202
}
201203

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

508516
CosmosClient cosmosClient = new CosmosClient(connectionString,
509517
cosmosClientOptions);

Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs

Lines changed: 60 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public class CosmosClientOptions
5151

5252
private const string ConnectionStringAccountEndpoint = "AccountEndpoint";
5353
private const string ConnectionStringAccountKey = "AccountKey";
54+
private const string ConnectionStringDisableServerCertificateValidation = "DisableServerCertificateValidation";
5455

5556
private const ApiType DefaultApiType = ApiType.None;
5657

@@ -651,7 +652,9 @@ internal Protocol ConnectionProtocol
651652
/// </summary>
652653
/// <remarks>
653654
/// <para>
654-
/// Customizing SSL verification is not recommended in production environments.
655+
/// Emulator: To ignore SSL Certificate please suffix connectionstring with "DisableServerCertificateValidation=True;".
656+
/// When CosmosClientOptions.HttpClientFactory is used, SSL certificate needs to be handled appropriately.
657+
/// NOTE: DO NOT use this flag in production (only for emulator)
655658
/// </para>
656659
/// </remarks>
657660
public Func<X509Certificate2, X509Chain, SslPolicyErrors, bool> ServerCertificateCustomValidationCallback { get; set; }
@@ -843,34 +846,62 @@ internal virtual ConnectionPolicy GetConnectionPolicy(int clientId)
843846
return (Documents.ConsistencyLevel)this.ConsistencyLevel.Value;
844847
}
845848

846-
internal static string GetAccountEndpoint(string connectionString)
847-
{
848-
return CosmosClientOptions.GetValueFromConnectionString(connectionString, CosmosClientOptions.ConnectionStringAccountEndpoint);
849-
}
850-
851-
internal static string GetAccountKey(string connectionString)
852-
{
853-
return CosmosClientOptions.GetValueFromConnectionString(connectionString, CosmosClientOptions.ConnectionStringAccountKey);
854-
}
855-
856-
private static string GetValueFromConnectionString(string connectionString, string keyName)
857-
{
858-
if (connectionString == null)
859-
{
860-
throw new ArgumentNullException(nameof(connectionString));
861-
}
862-
863-
DbConnectionStringBuilder builder = new DbConnectionStringBuilder { ConnectionString = connectionString };
864-
if (builder.TryGetValue(keyName, out object value))
865-
{
866-
string keyNameValue = value as string;
867-
if (!string.IsNullOrEmpty(keyNameValue))
868-
{
869-
return keyNameValue;
870-
}
871-
}
872-
873-
throw new ArgumentException("The connection string is missing a required property: " + keyName);
849+
internal static string GetAccountEndpoint(string connectionString)
850+
{
851+
return CosmosClientOptions.GetValueFromConnectionString<string>(connectionString, CosmosClientOptions.ConnectionStringAccountEndpoint, null);
852+
}
853+
854+
internal static string GetAccountKey(string connectionString)
855+
{
856+
return CosmosClientOptions.GetValueFromConnectionString<string>(connectionString, CosmosClientOptions.ConnectionStringAccountKey, null);
857+
}
858+
859+
internal static bool IsConnectionStringDisableServerCertificateValidationFlag(string connectionString)
860+
{
861+
return Convert.ToBoolean(CosmosClientOptions.GetValueFromConnectionString<bool>(connectionString, CosmosClientOptions.ConnectionStringDisableServerCertificateValidation, false));
862+
}
863+
864+
internal static CosmosClientOptions GetCosmosClientOptionsWithCertificateFlag(string connectionString, CosmosClientOptions clientOptions)
865+
{
866+
clientOptions ??= new CosmosClientOptions();
867+
if (CosmosClientOptions.IsConnectionStringDisableServerCertificateValidationFlag(connectionString))
868+
{
869+
clientOptions.ServerCertificateCustomValidationCallback = (_, _, _) => true;
870+
}
871+
872+
return clientOptions;
873+
}
874+
875+
private static T GetValueFromConnectionString<T>(string connectionString, string keyName, T defaultValue)
876+
{
877+
if (connectionString == null)
878+
{
879+
throw new ArgumentNullException(nameof(connectionString));
880+
}
881+
882+
DbConnectionStringBuilder builder = new DbConnectionStringBuilder { ConnectionString = connectionString };
883+
if (builder.TryGetValue(keyName, out object value))
884+
{
885+
string keyNameValue = value as string;
886+
if (!string.IsNullOrEmpty(keyNameValue))
887+
{
888+
try
889+
{
890+
return (T)Convert.ChangeType(value, typeof(T));
891+
}
892+
catch (InvalidCastException)
893+
{
894+
throw new ArgumentException("The connection string contains invalid property: " + keyName);
895+
}
896+
}
897+
}
898+
899+
if (defaultValue != null)
900+
{
901+
return defaultValue;
902+
}
903+
904+
throw new ArgumentException("The connection string is missing a required property: " + keyName);
874905
}
875906

876907
private void ValidateLimitToEndpointSettings()

Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,11 @@ public CosmosClientBuilder(
124124
/// </summary>
125125
/// <example>"AccountEndpoint=https://mytestcosmosaccount.documents.azure.com:443/;AccountKey={SecretAccountKey};"</example>
126126
/// <param name="connectionString">The connection string must contain AccountEndpoint and AccountKey or ResourceToken.</param>
127+
/// <remarks>
128+
/// Emulator: To ignore SSL Certificate please suffix connectionstring with "DisableServerCertificateValidation=True;".
129+
/// When CosmosClientOptions.HttpClientFactory is used, SSL certificate needs to be handled appropriately.
130+
/// NOTE: DO NOT use this flag in production (only for emulator)
131+
/// </remarks>
127132
public CosmosClientBuilder(string connectionString)
128133
{
129134
if (connectionString == null)
@@ -133,6 +138,8 @@ public CosmosClientBuilder(string connectionString)
133138

134139
this.accountEndpoint = CosmosClientOptions.GetAccountEndpoint(connectionString);
135140
this.accountKey = CosmosClientOptions.GetAccountKey(connectionString);
141+
142+
this.clientOptions = CosmosClientOptions.GetCosmosClientOptionsWithCertificateFlag(connectionString, this.clientOptions);
136143
}
137144

138145
/// <summary>

Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ namespace Microsoft.Azure.Cosmos.Tests
77
using System;
88
using System.Collections;
99
using System.Collections.Generic;
10-
using System.Collections.ObjectModel;
1110
using System.Linq;
1211
using System.Net;
13-
using System.Net.Http;
12+
using System.Net.Http;
13+
using System.Net.Security;
14+
using System.Security.Cryptography;
15+
using System.Security.Cryptography.X509Certificates;
1416
using global::Azure.Core;
1517
using Microsoft.Azure.Cosmos.Fluent;
1618
using Microsoft.Azure.Documents;
@@ -885,7 +887,32 @@ public void InvalidApplicationNameCatchTest()
885887
ApplicationName = illegal
886888
});
887889
}
888-
}
890+
}
891+
892+
[TestMethod]
893+
[DataRow(ConnectionString, false)]
894+
[DataRow(ConnectionString + "DisableServerCertificateValidation=true;", true)]
895+
public void TestServerCertificatesValidationCallback(string connStr, bool expectedIgnoreCertificateFlag)
896+
{
897+
//Arrange
898+
X509Certificate2 x509Certificate2 = new CertificateRequest("cn=www.test", ECDsa.Create(), HashAlgorithmName.SHA256).CreateSelfSigned(DateTime.Now, DateTime.Now.AddYears(1));
899+
X509Chain x509Chain = new X509Chain();
900+
SslPolicyErrors sslPolicyErrors = new SslPolicyErrors();
901+
902+
CosmosClient cosmosClient = new CosmosClient(connStr);
903+
904+
if (expectedIgnoreCertificateFlag)
905+
{
906+
Assert.IsNotNull(cosmosClient.ClientOptions.ServerCertificateCustomValidationCallback);
907+
Assert.IsTrue(cosmosClient
908+
.ClientOptions
909+
.ServerCertificateCustomValidationCallback(x509Certificate2, x509Chain, sslPolicyErrors));
910+
}
911+
else
912+
{
913+
Assert.IsNull(cosmosClient.ClientOptions.ServerCertificateCustomValidationCallback);
914+
}
915+
}
889916

890917
private class TestWebProxy : IWebProxy
891918
{

0 commit comments

Comments
 (0)