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

Can't connect to Atlas - Error:No suitable servers found #313

Closed
Jeff-Lewis opened this issue Dec 16, 2016 · 15 comments
Closed

Can't connect to Atlas - Error:No suitable servers found #313

Jeff-Lewis opened this issue Dec 16, 2016 · 15 comments

Comments

@Jeff-Lewis
Copy link

I'm having trouble connecting to Atlas as well with PHP. Connect fine using other libs and MongoChef so whitelisting is not the issue.

  • Windows 10
  • PHP 5.6.29
  • mongodb.dll ext 1.2.2
  • "mongodb/mongodb": "^1.1.0" from composer
  • Atlas cluster running MongoDB 3.2
Error fetching Mongo. DB:myDB Coll:myCollection Error:No suitable servers found (`serverSelectionTryOnce` set): 
[TLS handshake failed: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed calling ismaster on 'myShard.mongodb.net:27017'] 
[TLS handshake failed: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed calling ismaster on 'myShard.mongodb.net:27017'] 
[TLS handshake failed: error:14090086:SSL routines:ssl3_get_serve query:{"theField":"theValue"} fields:{"projection":{"_id":1,"theField":1}}
exception 'MongoDB\Driver\Exception\ConnectionTimeoutException' with message 'No suitable servers found (`serverSelectionTryOnce` set): 
[TLS handshake failed: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed calling ismaster on 'myShard.mongodb.net:27017'] 
[TLS handshake failed: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed calling ismaster on 'myShard.mongodb.net:27017'] 
[TLS handshake failed: error:14090086:SSL routines:ssl3_get_serve' in C:\theapp\vendor\mongodb\mongodb\src\Collection.php:498
Stack trace:
#0 C:\theapp\vendor\mongodb\mongodb\src\Collection.php(498): MongoDB\Driver\Manager->selectServer(Object(MongoDB\Driver\ReadPreference))
#1 C:\theapp\MyMongoClass.php(143): MongoDB\Collection->find(Array, Array)

The sanitized url:

mongodb://theUser:[email protected]:27017,myShard.mongodb.net:27017,myShard.mongodb.net:27017/admin?ssl=true&replicaSet=myReplicaset&authSource=admin

Posted as suggested

@jmikola
Copy link
Member

jmikola commented Dec 16, 2016

@Jeff-Lewis: Can you substitute your cluster's hostname in the script below, run this through the same PHP environment, and share its output?

<?php

$uri = 'ssl://example-shard-00-00-00000.mongodb.net:27017';

$context = stream_context_create(['ssl' => ['capture_peer_cert' => true]]);
$client = stream_socket_client($uri, $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $context);
$response = stream_context_get_params($client);

$certificateProperties = openssl_x509_parse($response['options']['ssl']['peer_certificate']);
var_dump($certificateProperties);

@Jeff-Lewis
Copy link
Author

@jmikola thanks, here it is.

array (size=15)
  'name' => string '/C=US/ST=New York/L=New York/O=MongoDB, Inc./CN=*.mongodb.net' (length=61)
  'subject' => 
    array (size=5)
      'C' => string 'US' (length=2)
      'ST' => string 'New York' (length=8)
      'L' => string 'New York' (length=8)
      'O' => string 'MongoDB, Inc.' (length=13)
      'CN' => string '*.mongodb.net' (length=13)
  'hash' => string '1d8caf18' (length=8)
  'issuer' => 
    array (size=3)
      'C' => string 'US' (length=2)
      'O' => string 'DigiCert Inc' (length=12)
      'CN' => string 'DigiCert SHA2 Secure Server CA' (length=30)
  'version' => int 2
  'serialNumber' => string '5620855521718711109215588795519274262' (length=37)
  'validFrom' => string '160516000000Z' (length=13)
  'validTo' => string '180521120000Z' (length=13)
  'validFrom_time_t' => int 1463356800
  'validTo_time_t' => int 1526904000
  'signatureTypeSN' => string 'RSA-SHA256' (length=10)
  'signatureTypeLN' => string 'sha256WithRSAEncryption' (length=23)
  'signatureTypeNID' => int 668
  'purposes' => 
    array (size=9)
      1 => 
        array (size=3)
          0 => boolean true
          1 => boolean false
          2 => string 'sslclient' (length=9)
      2 => 
        array (size=3)
          0 => boolean true
          1 => boolean false
          2 => string 'sslserver' (length=9)
      3 => 
        array (size=3)
          0 => boolean true
          1 => boolean false
          2 => string 'nssslserver' (length=11)
      4 => 
        array (size=3)
          0 => boolean false
          1 => boolean false
          2 => string 'smimesign' (length=9)
      5 => 
        array (size=3)
          0 => boolean false
          1 => boolean false
          2 => string 'smimeencrypt' (length=12)
      6 => 
        array (size=3)
          0 => boolean false
          1 => boolean false
          2 => string 'crlsign' (length=7)
      7 => 
        array (size=3)
          0 => boolean true
          1 => boolean true
          2 => string 'any' (length=3)
      8 => 
        array (size=3)
          0 => boolean true
          1 => boolean false
          2 => string 'ocsphelper' (length=10)
      9 => 
        array (size=3)
          0 => boolean false
          1 => boolean false
          2 => string 'timestampsign' (length=13)
  'extensions' => 
    array (size=9)
      'authorityKeyIdentifier' => string 'keyid:0F:80:61:1C:82:31:61:D5:2F:28:E7:8D:46:38:B4:2C:E1:C6:D9:E2
' (length=66)
      'subjectKeyIdentifier' => string 'E1:AE:7D:1C:E9:D8:6E:15:B2:A3:A2:7D:65:53:DE:FF:A8:10:CD:98' (length=59)
      'subjectAltName' => string 'DNS:*.mongodb.net, DNS:mongodb.net' (length=34)
      'keyUsage' => string 'Digital Signature, Key Encipherment' (length=35)
      'extendedKeyUsage' => string 'TLS Web Server Authentication, TLS Web Client Authentication' (length=60)
      'crlDistributionPoints' => string '
Full Name:
  URI:http://crl3.digicert.com/ssca-sha2-g5.crl

Full Name:
  URI:http://crl4.digicert.com/ssca-sha2-g5.crl
' (length=120)
      'certificatePolicies' => string 'Policy: 2.16.840.1.114412.1.1
  CPS: https://www.digicert.com/CPS
Policy: 2.23.140.1.2.2
' (length=89)
      'authorityInfoAccess' => string 'OCSP - URI:http://ocsp.digicert.com
CA Issuers - URI:http://cacerts.digicert.com/DigiCertSHA2SecureServerCA.crt
' (length=112)
      'basicConstraints' => string 'CA:FALSE' (length=8)
Date	Subject

@jmikola
Copy link
Member

jmikola commented Dec 16, 2016

@Jeff-Lewis: Can you share phpinfo() output as well? Sorry for not asking for that earlier.

@jmikola
Copy link
Member

jmikola commented Dec 16, 2016

And a second test would be to attempt certification verification for another hostname with the same certificate authority as Atlas (e.g. MongoDB.com):

<?php

$uri = 'https://mongodb.com';

$context = stream_context_create([
    'ssl' => [
        'capture_peer_cert' => true,
        'verify_peer' => true,
        'verify_peer_name' => true,
        'allow_self_signed' => false,
    ],
]);
$contents = file_get_contents($uri, false, $context);
$response = stream_context_get_params($context);

$certificateProperties = openssl_x509_parse($response['options']['ssl']['peer_certificate']);
var_dump($certificateProperties);
var_dump(strlen($contents));

Additionally, if you substitute one of the Atlas hosts in the $uri above (using "https://" as the scheme but keeping the original host and port of 27017) and dump $contents in its entirety (instead of just its string length), you should get the following output:

"It looks like you are trying to access MongoDB over HTTP on the native driver port."

@Jeff-Lewis
Copy link
Author

Jeff-Lewis commented Dec 17, 2016

Here's mongodb.com

array (size=15)
  'name' => string '/C=US/ST=New York/L=New York/O=MongoDB, Inc./CN=*.mongodb.com' (length=61)
  'subject' => 
    array (size=5)
      'C' => string 'US' (length=2)
      'ST' => string 'New York' (length=8)
      'L' => string 'New York' (length=8)
      'O' => string 'MongoDB, Inc.' (length=13)
      'CN' => string '*.mongodb.com' (length=13)
  'hash' => string 'f2df7a34' (length=8)
  'issuer' => 
    array (size=3)
      'C' => string 'US' (length=2)
      'O' => string 'DigiCert Inc' (length=12)
      'CN' => string 'DigiCert SHA2 Secure Server CA' (length=30)
  'version' => int 2
  'serialNumber' => string '10981226426049099192253770553170957712' (length=38)
  'validFrom' => string '160805000000Z' (length=13)
  'validTo' => string '191103120000Z' (length=13)
  'validFrom_time_t' => int 1470355200
  'validTo_time_t' => int 1572778800
  'signatureTypeSN' => string 'RSA-SHA256' (length=10)
  'signatureTypeLN' => string 'sha256WithRSAEncryption' (length=23)
  'signatureTypeNID' => int 668
  'purposes' => 
    array (size=9)
      1 => 
        array (size=3)
          0 => boolean true
          1 => boolean false
          2 => string 'sslclient' (length=9)
      2 => 
        array (size=3)
          0 => boolean true
          1 => boolean false
          2 => string 'sslserver' (length=9)
      3 => 
        array (size=3)
          0 => boolean true
          1 => boolean false
          2 => string 'nssslserver' (length=11)
      4 => 
        array (size=3)
          0 => boolean false
          1 => boolean false
          2 => string 'smimesign' (length=9)
      5 => 
        array (size=3)
          0 => boolean false
          1 => boolean false
          2 => string 'smimeencrypt' (length=12)
      6 => 
        array (size=3)
          0 => boolean false
          1 => boolean false
          2 => string 'crlsign' (length=7)
      7 => 
        array (size=3)
          0 => boolean true
          1 => boolean true
          2 => string 'any' (length=3)
      8 => 
        array (size=3)
          0 => boolean true
          1 => boolean false
          2 => string 'ocsphelper' (length=10)
      9 => 
        array (size=3)
          0 => boolean false
          1 => boolean false
          2 => string 'timestampsign' (length=13)
  'extensions' => 
    array (size=9)
      'authorityKeyIdentifier' => string 'keyid:0F:80:61:1C:82:31:61:D5:2F:28:E7:8D:46:38:B4:2C:E1:C6:D9:E2
' (length=66)
      'subjectKeyIdentifier' => string '59:FB:5D:7E:18:38:B8:7E:7F:D0:FF:E8:9B:03:13:DF:62:83:E0:66' (length=59)
      'subjectAltName' => string 'DNS:*.mongodb.com, DNS:mongodb.com' (length=34)
      'keyUsage' => string 'Digital Signature, Key Encipherment' (length=35)
      'extendedKeyUsage' => string 'TLS Web Server Authentication, TLS Web Client Authentication' (length=60)
      'crlDistributionPoints' => string '
Full Name:
  URI:http://crl3.digicert.com/ssca-sha2-g5.crl

Full Name:
  URI:http://crl4.digicert.com/ssca-sha2-g5.crl
' (length=120)
      'certificatePolicies' => string 'Policy: 2.16.840.1.114412.1.1
  CPS: https://www.digicert.com/CPS
Policy: 2.23.140.1.2.2
' (length=89)
      'authorityInfoAccess' => string 'OCSP - URI:http://ocsp.digicert.com
CA Issuers - URI:http://cacerts.digicert.com/DigiCertSHA2SecureServerCA.crt
' (length=112)
      'basicConstraints' => string 'CA:FALSE' (length=8)

with strlen of 61522

Here's the php info

Also, I do get the "It looks like you are trying to access MongoDB over HTTP on the native driver port." message when using https scheme.

@jmikola
Copy link
Member

jmikola commented Dec 19, 2016

Based on your phpinfo() output, the OpenSSL extension has no special options defined. In the absence of cafile or capath options, OpenSSL in PHP 5.6.29 falls back to checking Windows' own certificate store. The MongoDB extension does not use PHP's OpenSSL extension, but libmongoc does use OpenSSL directly and should have equivalent logic here (CDRIVER-1182). Therefore, it's quite odd that you're able to verify the certificate via PHP streams but not libmongoc.

Could you attempt capturing some trace information via the mongodb.debug INI option? If you're running in a web server context, you can set this to a writable directory, which will cause the driver to dump one file per request. Alternatively, you can use "stderr" if running the script from a CLI context. These logs are quite verbose, so I would suggest either doing it only for a single request. You can enable the setting at runtime with ini_set() to avoid putting this in php.ini and having it apply globally.

@Jeff-Lewis
Copy link
Author

Here is the mongodb.debug output. I had to trim a little to remove connection info. If you need the complete frames, we'll have to go through Mongo support.
Thanks for your help!

@bjori
Copy link
Contributor

bjori commented Dec 20, 2016

[2016-12-20T08:25:09+00:00]     mongoc: WARNING > error opening system CA store
[2016-12-20T08:25:09+00:00]     mongoc: WARNING > error opening system CA store

the fallback on the system store failed some reason.

@jmikola
Copy link
Member

jmikola commented Dec 20, 2016

@Jeff-Lewis: As an temporary workaround, you may be able to get by with providing the path to a CA file explicitly via the ca_file option in $driverOptions, which is the third array parameter to the MongoDB\Client or MongoDB\Driver\Manager constructors.

With some help from http://stackoverflow.com/a/23554225/162228, it looks like the CA file for "DigiCert SHA2 Secure Server CA" is available on https://www.digicert.com/digicert-root-certificates.htm:

Issuer: DigiCert Global Root CA
Valid until: 08/Mar/2023
Serial #: 01:FD:A3:EB:6E:CA:75:C8:88:43:8B:72:4B:CF:BC:91
Thumbprint: 1FB86B1168EC743154062E8C9CC5B171A4B7CCB4
Download: https://www.digicert.com/CACerts/DigiCertSHA2SecureServerCA.crt

@jmikola
Copy link
Member

jmikola commented Dec 20, 2016

@bjori came up with a patch that opens the certificate store with a read-only flag (on the assumption that permissions were a factor here) and also adds more verbose error reporting in the event of a failure:

 src/mongoc/mongoc-openssl.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/src/mongoc/mongoc-openssl.c b/src/mongoc/mongoc-openssl.c
index 4b3a64f..96e119e 100644
--- a/src/mongoc/mongoc-openssl.c
+++ b/src/mongoc/mongoc-openssl.c
@@ -122,7 +122,20 @@ _mongoc_openssl_import_cert_store (LPWSTR store_name,
       store_name); /* system store name. "My" or "Root" */
 
    if (cert_store == NULL) {
-      MONGOC_WARNING ("error opening system CA store");
+      LPTSTR msg = NULL;
+      FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                        FORMAT_MESSAGE_FROM_SYSTEM |
+                        FORMAT_MESSAGE_ARGUMENT_ARRAY,
+                     NULL,
+                     GetLastError (),
+                     LANG_NEUTRAL,
+                     (LPTSTR) &msg,
+                     0,
+                     NULL);
+      MONGOC_ERROR ("Can't open CA store: 0x%.8X: '%s'",
+                    GetLastError (),
+                    msg);
+      LocalFree (msg);
       return false;
    }
 
@@ -158,12 +171,12 @@ _mongoc_openssl_import_cert_stores (SSL_CTX *context)
    }
 
    retval = _mongoc_openssl_import_cert_store (
-      L"root", CERT_SYSTEM_STORE_CURRENT_USER, store);
+      L"root", CERT_SYSTEM_STORE_CURRENT_USER|CERT_STORE_READONLY_FLAG, store);
    if (retval) {
       return retval;
    }
    return _mongoc_openssl_import_cert_store (
-      L"CA", CERT_SYSTEM_STORE_CURRENT_USER, store);
+      L"CA", CERT_SYSTEM_STORE_CURRENT_USER|CERT_STORE_READONLY_FLAG, store);
 }
 #endif

@Jeff-Lewis: I compiled this into a custom DLL based on your environment info from phpinfo(): php_mongodb-1.2.2-dev-5.6-nts-vc11-x86.zip. If possible, please test this out and let us know if it resolves the situation or produces an error. mongodb.debug tracing won't hurt, but MONGOC_ERROR() should trigger a PHP exception so full tracing shouldn't be necessary.

@Jeff-Lewis
Copy link
Author

Yes, your patch appears to work! Thank you @jmikola. Do you need the mongodb.debug or any other info?

@jmikola
Copy link
Member

jmikola commented Dec 21, 2016

@Jeff-Lewis: If you're didn't encounter an error/exception, there's no need for mongodb.debug logs. Glad to hear this is working for you.

I've opened CDRIVER-1964 upstream so that @bjori can incorporate his patch into libmongoc. I've also opened PHPC-881 as a local tracking ticket. Since our Windows builds always use bundled versions of libmongoc, this will be formally addressed when libmongoc releases a fix and we can bump our submodules. At that point, PHPC-881 will get a fix version for our subsequent release.

I'll close this, since there should be nothing further to address. Please watch the above JIRA tickets for updates.

@jmikola jmikola closed this as completed Dec 21, 2016
@jmikola
Copy link
Member

jmikola commented Jan 13, 2017

#313 bumps our libmongoc dependency, so we should have this fix released in 1.2.3 sometime next week.

@jmikola
Copy link
Member

jmikola commented Jan 18, 2017

@Jeff-Lewis: 1.2.3 was released yesterday with the fix. You'll find Windows DLLs here.

@Jeff-Lewis
Copy link
Author

@jmikola awesome, thank you! I'll give it a try shortly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants