Details
-
Bug
-
Resolution: Fixed
-
Major
-
None
-
None
-
None
-
4
-
SDK16: Clmnr Proto & C++
Description
Motivation
When passing a custom X509CertificateFactory to the ClusterOptions, Queries stop working and fail with:
(Note: This seems to be affecting other HTTP services, not just Query. User management operations throw HTTP 401 - Unauthorized)
Unhandled exception. Couchbase.CouchbaseException: Error authorizing against cluster cause: Failure to authenticate user [2120] |
at Couchbase.Query.QueryResultExtensions.ThrowExceptionOnError[T](IQueryResult`1 result, QueryErrorContext context) |
at Couchbase.Query.QueryClient.ExecuteQuery[T](QueryOptions options, ITypeSerializer serializer, IRequestSpan span)
|
at Couchbase.Query.QueryClient.QueryAsync[T](String statement, QueryOptions options)
|
at Couchbase.Cluster.<>c__DisplayClass37_0`1.<<QueryAsync>g__Func|0>d.MoveNext() |
The specific line causing this issue is:
clusterOptions.X509CertificateFactory = CertificateFactory.FromCertificates(certificate);
|
Not adding a custom X509CertificateFactory, and instead only passing in custom CertificateCallbackValidation for both KV and Http services produces the correct and expected behaviour. (i.e. If the certificate is correct, operations succeed. If the certificate is incorrect, they don't.)
Code to replicate:
public class Program |
{
|
internal static readonly string WrongCert = |
@"-----BEGIN CERTIFICATE-----
|
MIIDDDCCAfSgAwIBAgIIF7nmQD3WCgQwDQYJKoZIhvcNAQELBQAwJDEiMCAGA1UE
|
AxMZQ291Y2hiYXNlIFNlcnZlciBjMzcxMTYzMzAeFw0xMzAxMDEwMDAwMDBaFw00
|
OTEyMzEyMzU5NTlaMCQxIjAgBgNVBAMTGUNvdWNoYmFzZSBTZXJ2ZXIgYzM3MTE2
|
MzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9UTImtOak5Co/r53s
|
GThiybcVCylrSGCwtqhYn26wzU7TslbxQizMEoMGF17EN5jh1XXFZPr0A9Ss7rcT
|
QWoRYf9JeiQm8c1CHRdrwo2d9ged/sg754uKNugpuSq9MlPcOCj6V/jtmWJvRNCa
|
jHEbg236SJac80lUw+0TvqvgZBlukqrUKiPf6omeHRDHIvaGik5Fad1P8MiQ4LdL
|
/N97MdyFoDZGjFhA/8JFOoSuEZGgw1bP+2ptiU6LEetfwXADokyWZIxG9cMj5lfr
|
/GuIBRM6B7o9Uf1KhttDfAprHp+sENSO3pFFpYI+s/nagyaqoBJjK2onub7z6XyR
|
wtutAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0G
|
A1UdDgQWBBSqOAxnXIOVlhM56XakY7YJicI3izANBgkqhkiG9w0BAQsFAAOCAQEA
|
ZrNj6SiXH+mgOiBbjBMSdLe3Wkc4LKaOHL9bOmz1CYktERV7iXqPTa1E2LzWpBBL
|
X68AhADDGOLmKhhcI/ka81E66bObKtf5pDQ58HeEv9XhQwkMBucAXTudNtK1PHB5
|
9+MJq/SMYIBswmFy1jVB34FpE3PYQ/hw81G5dtckan/tDhsP+Ur91zlvIWHZA1my |
ZvllpxZx6NG8sqdY64J7/KCYiTTSshtI6lpQNsYKn3qEEcNVU5tCiM8IUCwe+v7p
|
m5hAMgGnbsjWapDYPONrL1QAnpzAIuG8U4zEdKJy6AoQ7KrSbTckDyGxT06ZPcKq
|
KzsBw2nk6zu9eSH1vtjM7w==
|
-----END CERTIFICATE-----";
|
|
internal static readonly string CapellaCaCertPem = |
@"-----BEGIN CERTIFICATE-----
|
MIIDFTCCAf2gAwIBAgIRANLVkgOvtaXiQJi0V6qeNtswDQYJKoZIhvcNAQELBQAw
|
JDESMBAGA1UECgwJQ291Y2hiYXNlMQ4wDAYDVQQLDAVDbG91ZDAeFw0xOTEyMDYy
|
MjEyNTlaFw0yOTEyMDYyMzEyNTlaMCQxEjAQBgNVBAoMCUNvdWNoYmFzZTEOMAwG
|
A1UECwwFQ2xvdWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfvOIi
|
enG4Dp+hJu9asdxEMRmH70hDyMXv5ZjBhbo39a42QwR59y/rC/sahLLQuNwqif85
|
Fod1DkqgO6Ng3vecSAwyYVkj5NKdycQu5tzsZkghlpSDAyI0xlIPSQjoORA/pCOU
|
WOpymA9dOjC1bo6rDyw0yWP2nFAI/KA4Z806XeqLREuB7292UnSsgFs4/5lqeil6
|
rL3ooAw/i0uxr/TQSaxi1l8t4iMt4/gU+W52+8Yol0JbXBTFX6itg62ppb/Eugmn
|
mQRMgL67ccZs7cJ9/A0wlXencX2ohZQOR3mtknfol3FH4+glQFn27Q4xBCzVkY9j
|
KQ20T1LgmGSngBInAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
|
FJQOBPvrkU2In1Sjoxt97Xy8+cKNMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0B
|
AQsFAAOCAQEARgM6XwcXPLSpFdSf0w8PtpNGehmdWijPM3wHb7WZiS47iNen3oq8
|
m2mm6V3Z57wbboPpfI+VEzbhiDcFfVnK1CXMC0tkF3fnOG1BDDvwt4jU95vBiNjY
|
xdzlTP/Z+qr0cnVbGBSZ+fbXstSiRaaAVcqQyv3BRvBadKBkCyPwo+7svQnScQ5P
|
Js7HEHKVms5tZTgKIw1fbmgR2XHleah1AcANB+MAPBCcTgqurqr5G7W2aPSBLLGA
|
fRIiVzm7VFLc7kWbp7ENH39HVG6TZzKnfl9zJYeiklo5vQQhGSMhzBsO70z4RRzi
|
DPFAN/4qZAgD5q3AFNIq2WWADFQGSwVJhg==
|
-----END CERTIFICATE-----";
|
|
public static async Task Main(string[] args) |
{
|
var clusterOptions = new ClusterOptions |
{
|
ConnectionString = "couchbases://your-capella-hostname", |
UserName = "Administrator", |
Password = "Password123!" |
};
|
|
var certificate = new X509Certificate2( |
rawData: System.Text.Encoding.ASCII.GetBytes(CapellaCaCertPem),
|
password: (string)null!); |
clusterOptions.X509CertificateFactory = CertificateFactory.FromCertificates(certificate);
|
|
var x509CertCollection = new X509Certificate2Collection(certificate); |
|
RemoteCertificateValidationCallback certificateValidationCallback = GetValidatorWithPredefinedCertificates(x509CertCollection);
|
clusterOptions.KvCertificateCallbackValidation = certificateValidationCallback;
|
clusterOptions.HttpCertificateCallbackValidation = certificateValidationCallback;
|
|
|
//Query Test |
var cluster = await Cluster.ConnectAsync(clusterOptions).ConfigureAwait(false); |
var result = await cluster.QueryAsync<dynamic>("SELECT * from `default` limit 10;").ConfigureAwait(false); |
await foreach (var el in result.Rows)
|
{
|
Console.WriteLine(el.ToString());
|
}
|
|
//KV Test |
var bucket = await cluster.BucketAsync("default").ConfigureAwait(false); |
var scope = await bucket.DefaultScopeAsync().ConfigureAwait(false); |
var collection = await scope.CollectionAsync("_default").ConfigureAwait(false); |
|
await collection.UpsertAsync("myDoc", new {Content = "MyContent"}).ConfigureAwait(false); |
var myDoc = await collection.GetAsync("myDoc").ConfigureAwait(false); |
Console.WriteLine(myDoc.ContentAs<dynamic>());
|
|
}
|
|
private static RemoteCertificateValidationCallback GetValidatorWithPredefinedCertificates(X509Certificate2Collection certs) => |
(object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors) =>
|
{
|
if (sslPolicyErrors == SslPolicyErrors.None) |
{
|
return true; |
}
|
|
if (chain == null) |
{
|
return false; |
}
|
|
#if NET5_0_OR_GREATER |
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
|
foreach (var defaultCert in certs)
|
{
|
chain.ChainPolicy.CustomTrustStore.Add(defaultCert);
|
}
|
#endif
|
if (certificate is X509Certificate2 cert2) |
{
|
chain.Reset();
|
var built = chain.Build(cert2);
|
return built; |
}
|
return false; |
};
|
}
|
Attachments
Issue Links
For Gerrit Dashboard: NCBC-3760 | ||||||
---|---|---|---|---|---|---|
# | Subject | Branch | Project | Status | CR | V |
209101,2 | NCBC-3760: Passing an X509CertificateFactory breaks Http services (Auth failure) | master | couchbase-net-client | Status: MERGED | +2 | +1 |