Uploaded image for project: 'Couchbase Java Client'
  1. Couchbase Java Client
  2. JCBC-2138

Setting a custom CertificateFactory causes user authentication issues for Query

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • Major
    • None
    • None
    • None
    • None
    • 0

    Description

      Motivation

      When passing a custom X509CertificateFactory to the ClusterOptions, Queries stop working and fail with:
      (Note: This might be affecting other HTTP services, not just Query)

      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.

      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>());
              
              // await Test(collection).ConfigureAwait(false);
       
          }
       
          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

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            emilien.bevierre Emilien Bevierre
            emilien.bevierre Emilien Bevierre
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews

                There are no open Gerrit changes

                PagerDuty