OLD | NEW |
(Empty) | |
| 1 # Copyright 2011 Google Inc. |
| 2 # |
| 3 # Permission is hereby granted, free of charge, to any person obtaining a |
| 4 # copy of this software and associated documentation files (the |
| 5 # "Software"), to deal in the Software without restriction, including |
| 6 # without limitation the rights to use, copy, modify, merge, publish, dis- |
| 7 # tribute, sublicense, and/or sell copies of the Software, and to permit |
| 8 # persons to whom the Software is furnished to do so, subject to the fol- |
| 9 # lowing conditions: |
| 10 # |
| 11 # The above copyright notice and this permission notice shall be included |
| 12 # in all copies or substantial portions of the Software. |
| 13 # |
| 14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| 15 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- |
| 16 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT |
| 17 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| 18 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| 20 # IN THE SOFTWARE. |
| 21 |
| 22 """ |
| 23 Tests to validate correct validation of SSL server certificates. |
| 24 |
| 25 Note that this test assumes two external dependencies are available: |
| 26 - A http proxy, which by default is assumed to be at host 'cache' and port |
| 27 3128. This can be overridden with environment variables PROXY_HOST and |
| 28 PROXY_PORT, respectively. |
| 29 - An ssl-enabled web server that will return a valid certificate signed by one |
| 30 of the bundled CAs, and which can be reached by an alternate hostname that |
| 31 does not match the CN in that certificate. By default, this test uses host |
| 32 'www' (without fully qualified domain). This can be overridden with |
| 33 environment variable INVALID_HOSTNAME_HOST. If no suitable host is already |
| 34 available, such a mapping can be established by temporarily adding an IP |
| 35 address for, say, www.google.com or www.amazon.com to /etc/hosts. |
| 36 """ |
| 37 |
| 38 import os |
| 39 import ssl |
| 40 import unittest |
| 41 |
| 42 import boto |
| 43 from boto import exception, https_connection |
| 44 from boto.gs.connection import GSConnection |
| 45 from boto.s3.connection import S3Connection |
| 46 |
| 47 # File 'other_cacerts.txt' contains a valid CA certificate of a CA that is used |
| 48 # by neither S3 nor Google Cloud Storage. Validation against this CA cert should |
| 49 # result in a certificate error. |
| 50 DEFAULT_CA_CERTS_FILE = os.path.join( |
| 51 os.path.dirname(os.path.abspath(__file__ )), 'other_cacerts.txt') |
| 52 |
| 53 |
| 54 PROXY_HOST = os.environ.get('PROXY_HOST', 'cache') |
| 55 PROXY_PORT = os.environ.get('PROXY_PORT', '3128') |
| 56 |
| 57 # This test assumes that this host returns a certificate signed by one of the |
| 58 # trusted CAs, but with a Common Name that won't match host name 'www' (i.e., |
| 59 # the server should return a certificate with CN 'www.<somedomain>.com'). |
| 60 INVALID_HOSTNAME_HOST = os.environ.get('INVALID_HOSTNAME_HOST', 'www') |
| 61 |
| 62 class CertValidationTest (unittest.TestCase): |
| 63 |
| 64 def setUp(self): |
| 65 # Clear config |
| 66 for section in boto.config.sections(): |
| 67 boto.config.remove_section(section) |
| 68 |
| 69 # Enable https_validate_certificates. |
| 70 boto.config.add_section('Boto') |
| 71 boto.config.setbool('Boto', 'https_validate_certificates', True) |
| 72 |
| 73 # Set up bogus credentials so that the auth module is willing to go |
| 74 # ahead and make a request; the request should fail with a service-level |
| 75 # error if it does get to the service (S3 or GS). |
| 76 boto.config.add_section('Credentials') |
| 77 boto.config.set('Credentials', 'gs_access_key_id', 'xyz') |
| 78 boto.config.set('Credentials', 'gs_secret_access_key', 'xyz') |
| 79 boto.config.set('Credentials', 'aws_access_key_id', 'xyz') |
| 80 boto.config.set('Credentials', 'aws_secret_access_key', 'xyz') |
| 81 |
| 82 def enableProxy(self): |
| 83 boto.config.set('Boto', 'proxy', PROXY_HOST) |
| 84 boto.config.set('Boto', 'proxy_port', PROXY_PORT) |
| 85 |
| 86 def assertConnectionThrows(self, connection_class, error): |
| 87 conn = connection_class() |
| 88 self.assertRaises(error, conn.get_all_buckets) |
| 89 |
| 90 def do_test_valid_cert(self): |
| 91 # When connecting to actual servers with bundled root certificates, no |
| 92 # cert errors should be thrown; instead we will get "invalid |
| 93 # credentials" errors since the config used does not contain any |
| 94 # credentials. |
| 95 self.assertConnectionThrows(S3Connection, exception.S3ResponseError) |
| 96 self.assertConnectionThrows(GSConnection, exception.GSResponseError) |
| 97 |
| 98 def test_valid_cert(self): |
| 99 self.do_test_valid_cert() |
| 100 |
| 101 def test_valid_cert_with_proxy(self): |
| 102 self.enableProxy() |
| 103 self.do_test_valid_cert() |
| 104 |
| 105 def do_test_invalid_signature(self): |
| 106 boto.config.set('Boto', 'ca_certificates_file', DEFAULT_CA_CERTS_FILE) |
| 107 self.assertConnectionThrows(S3Connection, ssl.SSLError) |
| 108 self.assertConnectionThrows(GSConnection, ssl.SSLError) |
| 109 |
| 110 def test_invalid_signature(self): |
| 111 self.do_test_invalid_signature() |
| 112 |
| 113 def test_invalid_signature_with_proxy(self): |
| 114 self.enableProxy() |
| 115 self.do_test_invalid_signature() |
| 116 |
| 117 def do_test_invalid_host(self): |
| 118 boto.config.set('Credentials', 'gs_host', INVALID_HOSTNAME_HOST) |
| 119 boto.config.set('Credentials', 's3_host', INVALID_HOSTNAME_HOST) |
| 120 self.assertConnectionThrows(S3Connection, ssl.SSLError) |
| 121 self.assertConnectionThrows(GSConnection, ssl.SSLError) |
| 122 |
| 123 def do_test_invalid_host(self): |
| 124 boto.config.set('Credentials', 'gs_host', INVALID_HOSTNAME_HOST) |
| 125 boto.config.set('Credentials', 's3_host', INVALID_HOSTNAME_HOST) |
| 126 self.assertConnectionThrows( |
| 127 S3Connection, https_connection.InvalidCertificateException) |
| 128 self.assertConnectionThrows( |
| 129 GSConnection, https_connection.InvalidCertificateException) |
| 130 |
| 131 def test_invalid_host(self): |
| 132 self.do_test_invalid_host() |
| 133 |
| 134 def test_invalid_host_with_proxy(self): |
| 135 self.enableProxy() |
| 136 self.do_test_invalid_host() |
| 137 |
OLD | NEW |