blueprint 2-way-ssl
Implemented bp/2-way-ssl using eventlet-based SSL. Change-Id: I5aeb622aded13b406e01c78a2d8c245543306180
This commit is contained in:
parent
33d107aa1d
commit
f537a8259b
@ -15,5 +15,6 @@ graft bin
|
|||||||
graft doc
|
graft doc
|
||||||
graft tests
|
graft tests
|
||||||
graft tools
|
graft tools
|
||||||
recursive-include keystone *.json *.xml *.cfg README
|
graft examples
|
||||||
|
recursive-include keystone *.json *.xml *.cfg *.pem README
|
||||||
global-exclude *.pyc *.sdx *.log *.db *.swp
|
global-exclude *.pyc *.sdx *.log *.db *.swp
|
||||||
|
@ -28,7 +28,11 @@ CONF = config.CONF
|
|||||||
|
|
||||||
def create_server(conf, name, host, port):
|
def create_server(conf, name, host, port):
|
||||||
app = deploy.loadapp('config:%s' % conf, name=name)
|
app = deploy.loadapp('config:%s' % conf, name=name)
|
||||||
return wsgi.Server(app, host=host, port=port)
|
server = wsgi.Server(app, host=host, port=port)
|
||||||
|
if CONF.ssl.enable:
|
||||||
|
server.set_ssl(CONF.ssl.certfile, CONF.ssl.keyfile,
|
||||||
|
CONF.ssl.ca_certs, CONF.ssl.cert_required)
|
||||||
|
return server
|
||||||
|
|
||||||
|
|
||||||
def serve(*servers):
|
def serve(*servers):
|
||||||
|
@ -60,6 +60,7 @@ values are organized into the following sections:
|
|||||||
* ``[catalog]`` - service catalog driver configuration
|
* ``[catalog]`` - service catalog driver configuration
|
||||||
* ``[token]`` - token driver configuration
|
* ``[token]`` - token driver configuration
|
||||||
* ``[policy]`` - policy system driver configuration for RBAC
|
* ``[policy]`` - policy system driver configuration for RBAC
|
||||||
|
* ``[ssl]`` - SSL configuration
|
||||||
|
|
||||||
The Keystone configuration file is expected to be named ``keystone.conf``.
|
The Keystone configuration file is expected to be named ``keystone.conf``.
|
||||||
When starting keystone, you can specify a different configuration file to
|
When starting keystone, you can specify a different configuration file to
|
||||||
@ -149,6 +150,58 @@ choosing the output levels and formats.
|
|||||||
.. _Paste: http://pythonpaste.org/
|
.. _Paste: http://pythonpaste.org/
|
||||||
.. _`python logging module`: http://docs.python.org/library/logging.html
|
.. _`python logging module`: http://docs.python.org/library/logging.html
|
||||||
|
|
||||||
|
SSL
|
||||||
|
---
|
||||||
|
|
||||||
|
Keystone may be configured to support 2-way SSL out-of-the-box. The x509
|
||||||
|
certificates used by Keystone must be obtained externally and configured for use
|
||||||
|
with Keystone as described in this section. However, a set of sample certficates
|
||||||
|
is provided in the examples/ssl directory with the Keystone distribution for testing.
|
||||||
|
Here is the description of each of them and their purpose:
|
||||||
|
|
||||||
|
Types of certificates
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
ca.pem
|
||||||
|
Certificate Authority chain to validate against.
|
||||||
|
|
||||||
|
keystone.pem
|
||||||
|
Public certificate for Keystone server.
|
||||||
|
|
||||||
|
middleware.pem
|
||||||
|
Public and private certificate for Keystone middleware/client.
|
||||||
|
|
||||||
|
cakey.pem
|
||||||
|
Private key for the CA.
|
||||||
|
|
||||||
|
keystonekey.pem
|
||||||
|
Private key for the Keystone server.
|
||||||
|
|
||||||
|
Note that you may choose whatever names you want for these certificates, or combine
|
||||||
|
the public/private keys in the same file if you wish. These certificates are just
|
||||||
|
provided as an example.
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
To enable SSL with client authentication, modify the etc/keystone.conf file accordingly
|
||||||
|
under the [ssl] section. SSL configuration example using the included sample
|
||||||
|
certificates::
|
||||||
|
|
||||||
|
[ssl]
|
||||||
|
enable = True
|
||||||
|
certfile = <path to keystone.pem>
|
||||||
|
keyfile = <path to keystonekey.pem>
|
||||||
|
ca_certs = <path to ca.pem>
|
||||||
|
cert_required = True
|
||||||
|
|
||||||
|
* ``enable``: True enables SSL. Defaults to False.
|
||||||
|
* ``certfile``: Path to Keystone public certificate file.
|
||||||
|
* ``keyfile``: Path to Keystone private certificate file. If the private key is included in the certfile, the keyfile maybe omitted.
|
||||||
|
* ``ca_certs``: Path to CA trust chain.
|
||||||
|
* ``cert_required``: Requires client certificate. Defaults to False.
|
||||||
|
|
||||||
|
|
||||||
Sample Configuration Files
|
Sample Configuration Files
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
@ -133,6 +133,9 @@ a WSGI component. Example for the auth_token middleware::
|
|||||||
admin_tenant_name = service
|
admin_tenant_name = service
|
||||||
;Uncomment next line and check ip:port to use memcached to cache tokens
|
;Uncomment next line and check ip:port to use memcached to cache tokens
|
||||||
;memcache_servers = 127.0.0.1:11211
|
;memcache_servers = 127.0.0.1:11211
|
||||||
|
;Uncomment next 2 lines if Keystone server is validating client cert
|
||||||
|
certfile = <path to middleware public cert>
|
||||||
|
keyfile = <path to middleware private cert>
|
||||||
|
|
||||||
Configuration Options
|
Configuration Options
|
||||||
---------------------
|
---------------------
|
||||||
@ -153,6 +156,9 @@ Configuration Options
|
|||||||
* ``auth_port``: (optional, default `35357`) the port used to validate tokens
|
* ``auth_port``: (optional, default `35357`) the port used to validate tokens
|
||||||
* ``auth_protocol``: (optional, default `https`)
|
* ``auth_protocol``: (optional, default `https`)
|
||||||
* ``auth_uri``: (optional, defaults to `auth_protocol`://`auth_host`:`auth_port`)
|
* ``auth_uri``: (optional, defaults to `auth_protocol`://`auth_host`:`auth_port`)
|
||||||
|
* ``certfile``: (required, if Keystone server requires client cert)
|
||||||
|
* ``keyfile``: (required, if Keystone server requires client cert) This can be
|
||||||
|
the same as the certfile if the certfile includes the private key.
|
||||||
|
|
||||||
Caching for improved response
|
Caching for improved response
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
@ -81,6 +81,14 @@
|
|||||||
[ec2]
|
[ec2]
|
||||||
# driver = keystone.contrib.ec2.backends.kvs.Ec2
|
# driver = keystone.contrib.ec2.backends.kvs.Ec2
|
||||||
|
|
||||||
|
[ssl]
|
||||||
|
#enable = True
|
||||||
|
#certfile = /etc/keystone/ssl/certs/keystone.pem
|
||||||
|
#keyfile = /etc/keystone/ssl/private/keystonekey.pem
|
||||||
|
#ca_certs = /etc/keystone/ssl/certs/ca.pem
|
||||||
|
#cert_required = True
|
||||||
|
|
||||||
|
|
||||||
[ldap]
|
[ldap]
|
||||||
# url = ldap://localhost
|
# url = ldap://localhost
|
||||||
# user = dc=Manager,dc=example,dc=com
|
# user = dc=Manager,dc=example,dc=com
|
||||||
|
22
examples/ssl/certs/ca.pem
Normal file
22
examples/ssl/certs/ca.pem
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDmTCCAwKgAwIBAgIJALMGu1g0q5GjMA0GCSqGSIb3DQEBBQUAMIGQMQswCQYD
|
||||||
|
VQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVJvc2V2aWxsZTESMBAGA1UE
|
||||||
|
ChMJT3BlbnN0YWNrMREwDwYDVQQLEwhLZXlzdG9uZTESMBAGA1UEAxMJbG9jYWxo
|
||||||
|
b3N0MSUwIwYJKoZIhvcNAQkBFhZrZXlzdG9uZUBvcGVuc3RhY2sub3JnMB4XDTEx
|
||||||
|
MTAyMDE2MDQ0MloXDTIxMTAxNzE2MDQ0MlowgZAxCzAJBgNVBAYTAlVTMQswCQYD
|
||||||
|
VQQIEwJDQTESMBAGA1UEBxMJUm9zZXZpbGxlMRIwEAYDVQQKEwlPcGVuc3RhY2sx
|
||||||
|
ETAPBgNVBAsTCEtleXN0b25lMRIwEAYDVQQDEwlsb2NhbGhvc3QxJTAjBgkqhkiG
|
||||||
|
9w0BCQEWFmtleXN0b25lQG9wZW5zdGFjay5vcmcwgZ8wDQYJKoZIhvcNAQEBBQAD
|
||||||
|
gY0AMIGJAoGBAMfYcS0Fs7DRqdGSMVyrLk91vdzs+K6a6NOgppxhETqrOMAjW5yL
|
||||||
|
ajE2Ly48qfO/BRZR0kgTGSpnv7oiFzWLCvPf63nUnCalkE+uBpksY7BpphnTCJ8F
|
||||||
|
IsZ6aggAGKto9mmADpiKxt1uSQ6DDpPm8quXbMdSZTFOOVQNPYhwPMYvAgMBAAGj
|
||||||
|
gfgwgfUwHQYDVR0OBBYEFGA/MhYYUnjIdH9FWFVVo/YODkZBMIHFBgNVHSMEgb0w
|
||||||
|
gbqAFGA/MhYYUnjIdH9FWFVVo/YODkZBoYGWpIGTMIGQMQswCQYDVQQGEwJVUzEL
|
||||||
|
MAkGA1UECBMCQ0ExEjAQBgNVBAcTCVJvc2V2aWxsZTESMBAGA1UEChMJT3BlbnN0
|
||||||
|
YWNrMREwDwYDVQQLEwhLZXlzdG9uZTESMBAGA1UEAxMJbG9jYWxob3N0MSUwIwYJ
|
||||||
|
KoZIhvcNAQkBFhZrZXlzdG9uZUBvcGVuc3RhY2sub3JnggkAswa7WDSrkaMwDAYD
|
||||||
|
VR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBoeuR/pRznAtStj4Axe8Xq1ivL
|
||||||
|
jXFt2G9Pj+MwLs2wokcUBYz6/rJdSTjW21s4/FQCHiw9K7HA63c4mbjkRRgtJlXo
|
||||||
|
F5PiQqv4F1KqZmWeIDGxOGStQbgc77unsYYXILI27pSqQLKc9xlli77LekY+BzTK
|
||||||
|
tr5JYtKMaby4lJTg3A==
|
||||||
|
-----END CERTIFICATE-----
|
62
examples/ssl/certs/keystone.pem
Normal file
62
examples/ssl/certs/keystone.pem
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
Certificate:
|
||||||
|
Data:
|
||||||
|
Version: 3 (0x2)
|
||||||
|
Serial Number: 1 (0x1)
|
||||||
|
Signature Algorithm: sha1WithRSAEncryption
|
||||||
|
Issuer: C=US, ST=CA, L=Roseville, O=Openstack, OU=Keystone, CN=localhost/emailAddress=keystone@openstack.org
|
||||||
|
Validity
|
||||||
|
Not Before: Oct 20 16:34:17 2011 GMT
|
||||||
|
Not After : Oct 19 16:34:17 2012 GMT
|
||||||
|
Subject: C=US, ST=CA, L=Roseville, O=Openstack, OU=Keystone, CN=localhost/emailAddress=keystone@openstack.org
|
||||||
|
Subject Public Key Info:
|
||||||
|
Public Key Algorithm: rsaEncryption
|
||||||
|
RSA Public Key: (1024 bit)
|
||||||
|
Modulus (1024 bit):
|
||||||
|
00:9e:5a:5c:be:dc:20:d4:af:36:5c:33:6d:72:44:
|
||||||
|
94:59:c6:a9:24:ed:fa:8b:2c:53:ab:24:7d:79:46:
|
||||||
|
cc:a6:45:05:b0:57:b4:0d:d6:8f:f4:d9:a5:11:64:
|
||||||
|
e4:78:b1:26:30:de:fb:4a:72:c8:97:e7:31:4f:55:
|
||||||
|
bb:5b:16:d7:22:1b:13:ca:fc:6b:04:bd:15:9c:09:
|
||||||
|
51:d6:f9:14:51:67:a3:42:4a:81:ce:98:0f:6e:5c:
|
||||||
|
ac:7f:36:be:0f:79:ad:07:81:75:a2:21:a8:5f:e5:
|
||||||
|
9c:22:71:4c:db:63:b6:44:29:65:22:76:6e:07:98:
|
||||||
|
de:be:58:3f:b2:fe:cd:27:f7
|
||||||
|
Exponent: 65537 (0x10001)
|
||||||
|
X509v3 extensions:
|
||||||
|
X509v3 Basic Constraints:
|
||||||
|
CA:FALSE
|
||||||
|
Netscape Comment:
|
||||||
|
OpenSSL Generated Certificate
|
||||||
|
X509v3 Subject Key Identifier:
|
||||||
|
C1:E3:A1:36:45:3F:B5:3B:11:A1:23:A4:7E:3A:A0:F9:BC:F6:93:A3
|
||||||
|
X509v3 Authority Key Identifier:
|
||||||
|
keyid:60:3F:32:16:18:52:78:C8:74:7F:45:58:55:55:A3:F6:0E:0E:46:41
|
||||||
|
|
||||||
|
Signature Algorithm: sha1WithRSAEncryption
|
||||||
|
06:86:d7:5d:93:11:94:ce:23:ae:74:b2:16:09:99:32:63:3d:
|
||||||
|
d9:be:8f:99:87:43:7c:0d:27:25:5c:08:c2:d6:18:37:3c:4e:
|
||||||
|
b9:06:51:53:a9:d7:93:da:14:a1:25:96:2b:eb:8d:81:9d:68:
|
||||||
|
8d:ec:b8:1f:9e:09:80:25:fb:be:f8:20:5b:fc:ca:6c:3d:38:
|
||||||
|
c7:09:36:aa:dd:f8:0c:01:35:3e:c5:c5:3b:60:24:8c:5f:c5:
|
||||||
|
44:e7:7f:9b:ce:b6:d5:85:b7:93:e4:8a:a5:a9:90:ff:2d:09:
|
||||||
|
56:8c:e6:17:1f:07:33:0a:46:73:b1:65:13:d8:6f:39:76:3a:
|
||||||
|
93:87
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQUFADCBkDELMAkGA1UEBhMCVVMx
|
||||||
|
CzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlSb3NldmlsbGUxEjAQBgNVBAoTCU9wZW5z
|
||||||
|
dGFjazERMA8GA1UECxMIS2V5c3RvbmUxEjAQBgNVBAMTCWxvY2FsaG9zdDElMCMG
|
||||||
|
CSqGSIb3DQEJARYWa2V5c3RvbmVAb3BlbnN0YWNrLm9yZzAeFw0xMTEwMjAxNjM0
|
||||||
|
MTdaFw0xMjEwMTkxNjM0MTdaMIGQMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex
|
||||||
|
EjAQBgNVBAcTCVJvc2V2aWxsZTESMBAGA1UEChMJT3BlbnN0YWNrMREwDwYDVQQL
|
||||||
|
EwhLZXlzdG9uZTESMBAGA1UEAxMJbG9jYWxob3N0MSUwIwYJKoZIhvcNAQkBFhZr
|
||||||
|
ZXlzdG9uZUBvcGVuc3RhY2sub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
|
||||||
|
gQCeWly+3CDUrzZcM21yRJRZxqkk7fqLLFOrJH15RsymRQWwV7QN1o/02aURZOR4
|
||||||
|
sSYw3vtKcsiX5zFPVbtbFtciGxPK/GsEvRWcCVHW+RRRZ6NCSoHOmA9uXKx/Nr4P
|
||||||
|
ea0HgXWiIahf5ZwicUzbY7ZEKWUidm4HmN6+WD+y/s0n9wIDAQABo3sweTAJBgNV
|
||||||
|
HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZp
|
||||||
|
Y2F0ZTAdBgNVHQ4EFgQUweOhNkU/tTsRoSOkfjqg+bz2k6MwHwYDVR0jBBgwFoAU
|
||||||
|
YD8yFhhSeMh0f0VYVVWj9g4ORkEwDQYJKoZIhvcNAQEFBQADgYEABobXXZMRlM4j
|
||||||
|
rnSyFgmZMmM92b6PmYdDfA0nJVwIwtYYNzxOuQZRU6nXk9oUoSWWK+uNgZ1ojey4
|
||||||
|
H54JgCX7vvggW/zKbD04xwk2qt34DAE1PsXFO2AkjF/FROd/m8621YW3k+SKpamQ
|
||||||
|
/y0JVozmFx8HMwpGc7FlE9hvOXY6k4c=
|
||||||
|
-----END CERTIFICATE-----
|
77
examples/ssl/certs/middleware.pem
Normal file
77
examples/ssl/certs/middleware.pem
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
Certificate:
|
||||||
|
Data:
|
||||||
|
Version: 3 (0x2)
|
||||||
|
Serial Number: 1 (0x1)
|
||||||
|
Signature Algorithm: sha1WithRSAEncryption
|
||||||
|
Issuer: C=US, ST=CA, L=Roseville, O=Openstack, OU=Keystone, CN=localhost/emailAddress=keystone@openstack.org
|
||||||
|
Validity
|
||||||
|
Not Before: Oct 20 17:22:02 2011 GMT
|
||||||
|
Not After : Oct 19 17:22:02 2012 GMT
|
||||||
|
Subject: C=US, ST=CA, O=Openstack, OU=Middleware, CN=localhost/emailAddress=middleware@openstack.org
|
||||||
|
Subject Public Key Info:
|
||||||
|
Public Key Algorithm: rsaEncryption
|
||||||
|
RSA Public Key: (1024 bit)
|
||||||
|
Modulus (1024 bit):
|
||||||
|
00:cb:8d:ff:0a:f8:1f:da:0b:65:d9:15:86:e7:4a:
|
||||||
|
89:07:81:26:7a:2e:ef:67:30:bb:5b:88:3e:73:31:
|
||||||
|
0e:c9:d9:eb:84:55:7c:57:1b:07:8a:29:7f:41:ed:
|
||||||
|
1a:47:b2:c4:74:3c:dc:52:81:81:ba:6c:43:b8:44:
|
||||||
|
bd:83:20:28:4a:82:03:34:f2:1e:88:89:1c:f3:d6:
|
||||||
|
ef:02:27:9f:7b:4b:dc:ed:50:91:7a:13:a0:8f:5f:
|
||||||
|
44:10:a6:17:01:6f:7d:7a:3a:a2:1a:28:4e:6e:c5:
|
||||||
|
b6:06:0b:ba:5c:c9:e9:15:39:95:54:63:bb:40:90:
|
||||||
|
5d:5d:76:f6:ae:ed:ee:ed:85
|
||||||
|
Exponent: 65537 (0x10001)
|
||||||
|
X509v3 extensions:
|
||||||
|
X509v3 Basic Constraints:
|
||||||
|
CA:FALSE
|
||||||
|
Netscape Comment:
|
||||||
|
OpenSSL Generated Certificate
|
||||||
|
X509v3 Subject Key Identifier:
|
||||||
|
5A:34:DE:19:11:FF:77:19:2E:E5:6C:36:FA:42:17:6B:46:AF:6A:61
|
||||||
|
X509v3 Authority Key Identifier:
|
||||||
|
keyid:60:3F:32:16:18:52:78:C8:74:7F:45:58:55:55:A3:F6:0E:0E:46:41
|
||||||
|
|
||||||
|
Signature Algorithm: sha1WithRSAEncryption
|
||||||
|
a2:1b:e0:d3:e5:c5:35:ad:18:cb:79:a4:fc:f3:d6:7b:53:1e:
|
||||||
|
dd:28:95:e0:6c:b0:db:fe:aa:30:04:19:c8:99:7a:eb:cb:ed:
|
||||||
|
dd:74:29:ad:f8:89:6a:ed:d0:10:35:b3:62:36:a2:b0:cc:9f:
|
||||||
|
86:e8:96:fd:d7:1b:5e:2c:64:b5:5d:f3:bf:1a:1a:07:8b:01:
|
||||||
|
1f:5f:09:c3:e1:62:cd:30:35:1a:08:e1:cd:71:be:8c:87:de:
|
||||||
|
f6:7d:40:1b:c6:5f:f0:80:a0:68:55:01:00:74:86:08:52:7e:
|
||||||
|
c7:fd:62:f9:e3:d0:f8:0b:b0:64:d9:20:70:80:ec:95:11:74:
|
||||||
|
fb:0b
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDAzCCAmygAwIBAgIBATANBgkqhkiG9w0BAQUFADCBkDELMAkGA1UEBhMCVVMx
|
||||||
|
CzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlSb3NldmlsbGUxEjAQBgNVBAoTCU9wZW5z
|
||||||
|
dGFjazERMA8GA1UECxMIS2V5c3RvbmUxEjAQBgNVBAMTCWxvY2FsaG9zdDElMCMG
|
||||||
|
CSqGSIb3DQEJARYWa2V5c3RvbmVAb3BlbnN0YWNrLm9yZzAeFw0xMTEwMjAxNzIy
|
||||||
|
MDJaFw0xMjEwMTkxNzIyMDJaMIGAMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex
|
||||||
|
EjAQBgNVBAoTCU9wZW5zdGFjazETMBEGA1UECxMKTWlkZGxld2FyZTESMBAGA1UE
|
||||||
|
AxMJbG9jYWxob3N0MScwJQYJKoZIhvcNAQkBFhhtaWRkbGV3YXJlQG9wZW5zdGFj
|
||||||
|
ay5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMuN/wr4H9oLZdkVhudK
|
||||||
|
iQeBJnou72cwu1uIPnMxDsnZ64RVfFcbB4opf0HtGkeyxHQ83FKBgbpsQ7hEvYMg
|
||||||
|
KEqCAzTyHoiJHPPW7wInn3tL3O1QkXoToI9fRBCmFwFvfXo6ohooTm7FtgYLulzJ
|
||||||
|
6RU5lVRju0CQXV129q7t7u2FAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4
|
||||||
|
QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBRa
|
||||||
|
NN4ZEf93GS7lbDb6QhdrRq9qYTAfBgNVHSMEGDAWgBRgPzIWGFJ4yHR/RVhVVaP2
|
||||||
|
Dg5GQTANBgkqhkiG9w0BAQUFAAOBgQCiG+DT5cU1rRjLeaT889Z7Ux7dKJXgbLDb
|
||||||
|
/qowBBnImXrry+3ddCmt+Ilq7dAQNbNiNqKwzJ+G6Jb91xteLGS1XfO/GhoHiwEf
|
||||||
|
XwnD4WLNMDUaCOHNcb6Mh972fUAbxl/wgKBoVQEAdIYIUn7H/WL549D4C7Bk2SBw
|
||||||
|
gOyVEXT7Cw==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIICXAIBAAKBgQDLjf8K+B/aC2XZFYbnSokHgSZ6Lu9nMLtbiD5zMQ7J2euEVXxX
|
||||||
|
GweKKX9B7RpHssR0PNxSgYG6bEO4RL2DIChKggM08h6IiRzz1u8CJ597S9ztUJF6
|
||||||
|
E6CPX0QQphcBb316OqIaKE5uxbYGC7pcyekVOZVUY7tAkF1ddvau7e7thQIDAQAB
|
||||||
|
AoGAITSpzV1KvOQtGiuz1RlIn0vHPhlX/opplfX00g/HrM/65pyXaxJCuZwpYVTP
|
||||||
|
e7DC8X9YJbFwuzucFHxKOhDN4YbnW145bgfHbI9KLXtZiDvXvHg2MGKjpL/S3Lp3
|
||||||
|
zzWBo8gknmFGLK41WbYCCWKcvikEb3/KowcooznY5X5BjWECQQD6NC9Bi2EUUyPR
|
||||||
|
B2ZT3C3h2Hj53yqLkJzP0PaxTC+j7rsycy5r7UiOK8+8aC1T9EsaJrmEKlYBmlbd
|
||||||
|
lVdhohpNAkEA0EUphaVGURlNmXZgYdSZ1rrpJTvKbFtXmUCowi7Ml2h/oTuHDFHf
|
||||||
|
i4P8//79YB1uJ4Ll9edjJsZqtAErUTnMGQJBAJcKp7hutqU5Z3bJe8mGMqCTOLzH
|
||||||
|
LvzfyPpfkH0Jm/zfolxbUhvPO6yv4BFB5pM295uK4xVZJWCEVoofnIeQ/0UCQHuK
|
||||||
|
ex3esv5KTyCX+oYtkW+xgbjnZaSu7iBnHXPKROwPPZ4LbIlfS4Y7rejAfdX0vzHK
|
||||||
|
0NP0BHmsuwC5rNNKwIkCQBZqTnLVcisz1FRM2g/OKfWMx+lhVf5fIng+jUEJCdNE
|
||||||
|
fGjCUu4BRs+nXq6EzoijLvtrmRmFL7VYAKdabSVeLRc=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
18
examples/ssl/private/cakey.pem
Normal file
18
examples/ssl/private/cakey.pem
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
Proc-Type: 4,ENCRYPTED
|
||||||
|
DEK-Info: DES-EDE3-CBC,116D8984CC1AC50A
|
||||||
|
|
||||||
|
PnDGqu3+5ITsGtOwCucdQBs7UmPpJKk3x+UuBdpJuygMEgGM70P+eN+RLTH/vaAl
|
||||||
|
GFWV9wvlL7j+azrEYlbiKhHn4+6SmDSWjjSVM5wGclzH/UYhyhVe/GZsJ8axW278
|
||||||
|
6EdwzmrbvIjuPTN/dJjyXdeOlFFpoCST8TI03+qYo9T0L86560Y3SjTr/hHhlVyL
|
||||||
|
PgwfcN3wdarhPloJvFoV10kNH3MBpgGeclNQcNVRH7+Z2DwzHgV3bW28w1h4dOI7
|
||||||
|
RrPpa1YaAi0lTltuiZYLUtTBI/+xEDf3kFkeSNSdl3sLp9faHUoosVObdFfLCmV1
|
||||||
|
+66MdqgesPFipkfGPlTGuUX9CmYMooCn+hs7+tVZUqCl/fcErFWeW8iS5+nrat7f
|
||||||
|
HBiAsOTZ96AEvy/FksYPymrdaK085aODgPqSfR2pvMuF66iKS1xRZiTpMnDApTVN
|
||||||
|
A6BOZdJgTqGX4yny7ORxQ90xkv39oZYS9cc10Hqec1DG1LWy9dfvavEPk7/GejiT
|
||||||
|
Z5SMbIHHiNe5tNTomGqtgLIhjfoRXH14zbPGbJ5bI0REJ+sdUM3ItH75tTHYQUIb
|
||||||
|
S8UQBkHzU+ExK4q5E3BvKR7UH0KD5z6B6QhAyCB6mQp+63nsIP5cImXuAY9u0s1a
|
||||||
|
3tOmvUpXWDpqJLeAShb3DAPz5+FMx4mbT5oZq1Y8q5RDqMSSrB7XilAroCqasUIb
|
||||||
|
LoLNMri7WKcrCT1dKjN4y17ucwU8wLPo7Lpo+x5/XWqQA5qSB83YG9nh6nuzYNyo
|
||||||
|
aUsLH4cfAj3vCPU+KQux5jJfpcma9fyxVfCfa55dmakmGM8ww6ZXXQ==
|
||||||
|
-----END RSA PRIVATE KEY-----
|
15
examples/ssl/private/keystonekey.pem
Normal file
15
examples/ssl/private/keystonekey.pem
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIICXAIBAAKBgQCeWly+3CDUrzZcM21yRJRZxqkk7fqLLFOrJH15RsymRQWwV7QN
|
||||||
|
1o/02aURZOR4sSYw3vtKcsiX5zFPVbtbFtciGxPK/GsEvRWcCVHW+RRRZ6NCSoHO
|
||||||
|
mA9uXKx/Nr4Pea0HgXWiIahf5ZwicUzbY7ZEKWUidm4HmN6+WD+y/s0n9wIDAQAB
|
||||||
|
AoGAf6eY3MPYM5yL1ggfUt62OSlNcdfnAgrZ6D2iaQIKOH+r9ly9aepuYpSR3VPY
|
||||||
|
WvN0NjGLopil3M8jkTEruGLRSgin8+v+qlcRFsoXamegc3NV4XtxJhSmSIocKIIK
|
||||||
|
14w5YxcDz1QGqoati4LxQ1D6V5eNhiO65YhdcUDarGnlcAECQQDK4vcBGLY7H91f
|
||||||
|
lGT/oFJ0crqF4V+bLxMO28NhtS0G+GoM0MKrPfIu+nZDlKQzzHUlEZMNXSLz1T+T
|
||||||
|
po92UVe3AkEAx87ZKDK4xZZRNz0dAe29a3gQ6PmVkav1+NIxr0MP7Ff4tH6K/uoz
|
||||||
|
96OZpZg+TxdaoxSeNltuUelt3/xPs9AxwQJBAI01t1FuD7fLD9ssf7djsMAX8jao
|
||||||
|
jFCITS10S+K/pR1K3RUaX8OsE9oavSGAXWEoFwi72KvefStU6zErJoLlTrUCQCG5
|
||||||
|
wmHMne+L/c1rHVhT/qMDMyd/6UUbV3tWT1ib4zYraylcKq34bikgjjCrT+kdsgjQ
|
||||||
|
1BustyRQWGF0PyfEvoECQGhVOY2byAOEau+GeTC0c3LIDoErx6WaW3d9ty3Tmx3G
|
||||||
|
Y81XHlbO4Lw2q8fWZ8Ah2ptjv2IpKj0GAGRiJ5NnPTM=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
@ -107,7 +107,8 @@ class BufferedHTTPConnection(HTTPConnection):
|
|||||||
|
|
||||||
|
|
||||||
def http_connect(ipaddr, port, device, partition, method, path,
|
def http_connect(ipaddr, port, device, partition, method, path,
|
||||||
headers=None, query_string=None, ssl=False):
|
headers=None, query_string=None, ssl=False, key_file=None,
|
||||||
|
cert_file=None):
|
||||||
"""
|
"""
|
||||||
Helper function to create an HTTPConnection object. If ssl is set True,
|
Helper function to create an HTTPConnection object. If ssl is set True,
|
||||||
HTTPSConnection will be used. However, if ssl=False, BufferedHTTPConnection
|
HTTPSConnection will be used. However, if ssl=False, BufferedHTTPConnection
|
||||||
@ -122,26 +123,18 @@ def http_connect(ipaddr, port, device, partition, method, path,
|
|||||||
:param headers: dictionary of headers
|
:param headers: dictionary of headers
|
||||||
:param query_string: request query string
|
:param query_string: request query string
|
||||||
:param ssl: set True if SSL should be used (default: False)
|
:param ssl: set True if SSL should be used (default: False)
|
||||||
|
:param key_file Private key file (not needed if cert_file has private key)
|
||||||
|
:param cert_file Certificate file (Keystore)
|
||||||
:returns: HTTPConnection object
|
:returns: HTTPConnection object
|
||||||
"""
|
"""
|
||||||
if ssl:
|
|
||||||
conn = HTTPSConnection('%s:%s' % (ipaddr, port))
|
|
||||||
else:
|
|
||||||
conn = BufferedHTTPConnection('%s:%s' % (ipaddr, port))
|
|
||||||
path = quote('/' + device + '/' + str(partition) + path)
|
path = quote('/' + device + '/' + str(partition) + path)
|
||||||
if query_string:
|
return http_connect_raw(ipaddr, port, device, partition, method, path,
|
||||||
path += '?' + query_string
|
headers, query_string, ssl, key_file, cert_file)
|
||||||
conn.path = path
|
|
||||||
conn.putrequest(method, path)
|
|
||||||
if headers:
|
|
||||||
for header, value in headers.iteritems():
|
|
||||||
conn.putheader(header, value)
|
|
||||||
conn.endheaders()
|
|
||||||
return conn
|
|
||||||
|
|
||||||
|
|
||||||
def http_connect_raw(ipaddr, port, method, path, headers=None,
|
def http_connect_raw(ipaddr, port, method, path, headers=None,
|
||||||
query_string=None, ssl=False):
|
query_string=None, ssl=False, key_file=None,
|
||||||
|
cert_file=None):
|
||||||
"""
|
"""
|
||||||
Helper function to create an HTTPConnection object. If ssl is set True,
|
Helper function to create an HTTPConnection object. If ssl is set True,
|
||||||
HTTPSConnection will be used. However, if ssl=False, BufferedHTTPConnection
|
HTTPSConnection will be used. However, if ssl=False, BufferedHTTPConnection
|
||||||
@ -154,10 +147,13 @@ def http_connect_raw(ipaddr, port, method, path, headers=None,
|
|||||||
:param headers: dictionary of headers
|
:param headers: dictionary of headers
|
||||||
:param query_string: request query string
|
:param query_string: request query string
|
||||||
:param ssl: set True if SSL should be used (default: False)
|
:param ssl: set True if SSL should be used (default: False)
|
||||||
|
:param key_file Private key file (not needed if cert_file has private key)
|
||||||
|
:param cert_file Certificate file (Keystore)
|
||||||
:returns: HTTPConnection object
|
:returns: HTTPConnection object
|
||||||
"""
|
"""
|
||||||
if ssl:
|
if ssl:
|
||||||
conn = HTTPSConnection('%s:%s' % (ipaddr, port))
|
conn = HTTPSConnection('%s:%s' % (ipaddr, port), key_file=key_file,
|
||||||
|
cert_file=cert_file)
|
||||||
else:
|
else:
|
||||||
conn = BufferedHTTPConnection('%s:%s' % (ipaddr, port))
|
conn = BufferedHTTPConnection('%s:%s' % (ipaddr, port))
|
||||||
if query_string:
|
if query_string:
|
||||||
|
@ -23,12 +23,10 @@
|
|||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import eventlet
|
|
||||||
import eventlet.wsgi
|
import eventlet.wsgi
|
||||||
eventlet.patcher.monkey_patch(all=False, socket=True, time=True)
|
eventlet.patcher.monkey_patch(all=False, socket=True, time=True)
|
||||||
import routes
|
|
||||||
import routes.middleware
|
import routes.middleware
|
||||||
import webob
|
import ssl
|
||||||
import webob.dec
|
import webob.dec
|
||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
@ -61,6 +59,8 @@ class Server(object):
|
|||||||
self.pool = eventlet.GreenPool(threads)
|
self.pool = eventlet.GreenPool(threads)
|
||||||
self.socket_info = {}
|
self.socket_info = {}
|
||||||
self.greenthread = None
|
self.greenthread = None
|
||||||
|
self.do_ssl = False
|
||||||
|
self.cert_required = False
|
||||||
|
|
||||||
def start(self, key=None, backlog=128):
|
def start(self, key=None, backlog=128):
|
||||||
"""Run a WSGI server with the given application."""
|
"""Run a WSGI server with the given application."""
|
||||||
@ -69,9 +69,30 @@ class Server(object):
|
|||||||
'host': self.host,
|
'host': self.host,
|
||||||
'port': self.port})
|
'port': self.port})
|
||||||
socket = eventlet.listen((self.host, self.port), backlog=backlog)
|
socket = eventlet.listen((self.host, self.port), backlog=backlog)
|
||||||
self.greenthread = self.pool.spawn(self._run, self.application, socket)
|
|
||||||
if key:
|
if key:
|
||||||
self.socket_info[key] = socket.getsockname()
|
self.socket_info[key] = socket.getsockname()
|
||||||
|
# SSL is enabled
|
||||||
|
if self.do_ssl:
|
||||||
|
if self.cert_required:
|
||||||
|
cert_reqs = ssl.CERT_REQUIRED
|
||||||
|
else:
|
||||||
|
cert_reqs = ssl.CERT_NONE
|
||||||
|
sslsocket = eventlet.wrap_ssl(socket, certfile=self.certfile,
|
||||||
|
keyfile=self.keyfile,
|
||||||
|
server_side=True,
|
||||||
|
cert_reqs=cert_reqs,
|
||||||
|
ca_certs=self.ca_certs)
|
||||||
|
socket = sslsocket
|
||||||
|
|
||||||
|
self.greenthread = self.pool.spawn(self._run, self.application, socket)
|
||||||
|
|
||||||
|
def set_ssl(self, certfile, keyfile=None, ca_certs=None,
|
||||||
|
cert_required=True):
|
||||||
|
self.certfile = certfile
|
||||||
|
self.keyfile = keyfile
|
||||||
|
self.ca_certs = ca_certs
|
||||||
|
self.cert_required = cert_required
|
||||||
|
self.do_ssl = True
|
||||||
|
|
||||||
def kill(self):
|
def kill(self):
|
||||||
if self.greenthread:
|
if self.greenthread:
|
||||||
|
@ -145,6 +145,12 @@ register_str('admin_port', default=35357)
|
|||||||
register_str('public_port', default=5000)
|
register_str('public_port', default=5000)
|
||||||
register_str('onready')
|
register_str('onready')
|
||||||
|
|
||||||
|
#ssl options
|
||||||
|
register_bool('enable', group='ssl', default=False)
|
||||||
|
register_str('certfile', group='ssl', default=None)
|
||||||
|
register_str('keyfile', group='ssl', default=None)
|
||||||
|
register_str('ca_certs', group='ssl', default=None)
|
||||||
|
register_bool('cert_required', group='ssl', default=False)
|
||||||
|
|
||||||
# sql options
|
# sql options
|
||||||
register_str('connection', group='sql', default='sqlite:///keystone.db')
|
register_str('connection', group='sql', default='sqlite:///keystone.db')
|
||||||
|
@ -125,17 +125,21 @@ class AuthProtocol(object):
|
|||||||
# where to find the auth service (we use this to validate tokens)
|
# where to find the auth service (we use this to validate tokens)
|
||||||
self.auth_host = conf.get('auth_host')
|
self.auth_host = conf.get('auth_host')
|
||||||
self.auth_port = int(conf.get('auth_port', 35357))
|
self.auth_port = int(conf.get('auth_port', 35357))
|
||||||
auth_protocol = conf.get('auth_protocol', 'https')
|
self.auth_protocol = conf.get('auth_protocol', 'https')
|
||||||
if auth_protocol == 'http':
|
if self.auth_protocol == 'http':
|
||||||
self.http_client_class = httplib.HTTPConnection
|
self.http_client_class = httplib.HTTPConnection
|
||||||
else:
|
else:
|
||||||
self.http_client_class = httplib.HTTPSConnection
|
self.http_client_class = httplib.HTTPSConnection
|
||||||
|
|
||||||
default_auth_uri = '%s://%s:%s' % (auth_protocol,
|
default_auth_uri = '%s://%s:%s' % (self.auth_protocol,
|
||||||
self.auth_host,
|
self.auth_host,
|
||||||
self.auth_port)
|
self.auth_port)
|
||||||
self.auth_uri = conf.get('auth_uri', default_auth_uri)
|
self.auth_uri = conf.get('auth_uri', default_auth_uri)
|
||||||
|
|
||||||
|
# SSL
|
||||||
|
self.cert_file = conf.get('certfile')
|
||||||
|
self.key_file = conf.get('keyfile')
|
||||||
|
|
||||||
# Credentials used to verify this component with the Auth service since
|
# Credentials used to verify this component with the Auth service since
|
||||||
# validating tokens is a privileged call
|
# validating tokens is a privileged call
|
||||||
self.admin_token = conf.get('admin_token')
|
self.admin_token = conf.get('admin_token')
|
||||||
@ -252,7 +256,11 @@ class AuthProtocol(object):
|
|||||||
return self.admin_token
|
return self.admin_token
|
||||||
|
|
||||||
def _get_http_connection(self):
|
def _get_http_connection(self):
|
||||||
return self.http_client_class(self.auth_host, self.auth_port)
|
if self.auth_protocol == 'http':
|
||||||
|
return self.http_client_class(self.auth_host, self.auth_port)
|
||||||
|
else:
|
||||||
|
return self.http_client_class(self.auth_host, self.auth_port,
|
||||||
|
self.key_file, self.cert_file)
|
||||||
|
|
||||||
def _json_request(self, method, path, body=None, additional_headers=None):
|
def _json_request(self, method, path, body=None, additional_headers=None):
|
||||||
"""HTTP request helper used to make json requests.
|
"""HTTP request helper used to make json requests.
|
||||||
|
@ -60,11 +60,14 @@ class S3Token(object):
|
|||||||
# where to find the auth service (we use this to validate tokens)
|
# where to find the auth service (we use this to validate tokens)
|
||||||
self.auth_host = conf.get('auth_host')
|
self.auth_host = conf.get('auth_host')
|
||||||
self.auth_port = int(conf.get('auth_port', 35357))
|
self.auth_port = int(conf.get('auth_port', 35357))
|
||||||
auth_protocol = conf.get('auth_protocol', 'https')
|
self.auth_protocol = conf.get('auth_protocol', 'https')
|
||||||
if auth_protocol == 'http':
|
if self.auth_protocol == 'http':
|
||||||
self.http_client_class = httplib.HTTPConnection
|
self.http_client_class = httplib.HTTPConnection
|
||||||
else:
|
else:
|
||||||
self.http_client_class = httplib.HTTPSConnection
|
self.http_client_class = httplib.HTTPSConnection
|
||||||
|
# SSL
|
||||||
|
self.cert_file = conf.get('certfile')
|
||||||
|
self.key_file = conf.get('keyfile')
|
||||||
|
|
||||||
def deny_request(self, code):
|
def deny_request(self, code):
|
||||||
error_table = {
|
error_table = {
|
||||||
@ -86,7 +89,11 @@ class S3Token(object):
|
|||||||
headers = {'Content-Type': 'application/json'}
|
headers = {'Content-Type': 'application/json'}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conn = self.http_client_class(self.auth_host, self.auth_port)
|
if self.auth_protocol == 'http':
|
||||||
|
conn = self.http_client_class(self.auth_host, self.auth_port)
|
||||||
|
else:
|
||||||
|
conn = self.http_client_class(self.auth_host, self.auth_port,
|
||||||
|
self.key_file, self.cert_file)
|
||||||
conn.request('POST', '/v2.0/s3tokens',
|
conn.request('POST', '/v2.0/s3tokens',
|
||||||
body=creds_json,
|
body=creds_json,
|
||||||
headers=headers)
|
headers=headers)
|
||||||
|
@ -32,7 +32,7 @@ from keystone.common import wsgi
|
|||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
ROOTDIR = os.path.dirname(os.path.dirname(__file__))
|
ROOTDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
VENDOR = os.path.join(ROOTDIR, 'vendor')
|
VENDOR = os.path.join(ROOTDIR, 'vendor')
|
||||||
TESTSDIR = os.path.join(ROOTDIR, 'tests')
|
TESTSDIR = os.path.join(ROOTDIR, 'tests')
|
||||||
ETCDIR = os.path.join(ROOTDIR, 'etc')
|
ETCDIR = os.path.join(ROOTDIR, 'etc')
|
||||||
@ -236,9 +236,13 @@ class TestCase(unittest.TestCase):
|
|||||||
def appconfig(self, config):
|
def appconfig(self, config):
|
||||||
return deploy.appconfig(self._paste_config(config))
|
return deploy.appconfig(self._paste_config(config))
|
||||||
|
|
||||||
def serveapp(self, config, name=None):
|
def serveapp(self, config, name=None, cert=None, key=None, ca=None,
|
||||||
|
cert_required=None):
|
||||||
app = self.loadapp(config, name=name)
|
app = self.loadapp(config, name=name)
|
||||||
server = wsgi.Server(app, host="127.0.0.1", port=0)
|
server = wsgi.Server(app, host="127.0.0.1", port=0)
|
||||||
|
if cert is not None and ca is not None and key is not None:
|
||||||
|
server.set_ssl(certfile=cert, keyfile=key, ca_certs=ca,
|
||||||
|
cert_required=cert_required)
|
||||||
server.start(key='socket')
|
server.start(key='socket')
|
||||||
|
|
||||||
# Service catalog tests need to know the port we ran on.
|
# Service catalog tests need to know the port we ran on.
|
||||||
|
103
tests/test_ssl.py
Normal file
103
tests/test_ssl.py
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2012 OpenStack LLC
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
# implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import httplib
|
||||||
|
import ssl
|
||||||
|
|
||||||
|
from keystone import test
|
||||||
|
from keystone import config
|
||||||
|
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
|
||||||
|
CERTDIR = test.rootdir("examples/ssl/certs")
|
||||||
|
KEYDIR = test.rootdir("examples/ssl/private")
|
||||||
|
CERT = os.path.join(CERTDIR, 'keystone.pem')
|
||||||
|
KEY = os.path.join(KEYDIR, 'keystonekey.pem')
|
||||||
|
CA = os.path.join(CERTDIR, 'ca.pem')
|
||||||
|
CLIENT = os.path.join(CERTDIR, 'middleware.pem')
|
||||||
|
|
||||||
|
|
||||||
|
class SSLTestCase(test.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(SSLTestCase, self).setUp()
|
||||||
|
self.load_backends()
|
||||||
|
|
||||||
|
def test_1way_ssl_ok(self):
|
||||||
|
"""
|
||||||
|
Make sure both public and admin API work with 1-way SSL.
|
||||||
|
"""
|
||||||
|
self.public_server = self.serveapp('keystone', name='main',
|
||||||
|
cert=CERT, key=KEY, ca=CA)
|
||||||
|
self.admin_server = self.serveapp('keystone', name='admin',
|
||||||
|
cert=CERT, key=KEY, ca=CA)
|
||||||
|
# Verify Admin
|
||||||
|
conn = httplib.HTTPSConnection('127.0.0.1', CONF.admin_port)
|
||||||
|
conn.request('GET', '/')
|
||||||
|
resp = conn.getresponse()
|
||||||
|
self.assertEqual(resp.status, 300)
|
||||||
|
# Verify Public
|
||||||
|
conn = httplib.HTTPSConnection('127.0.0.1', CONF.public_port)
|
||||||
|
conn.request('GET', '/')
|
||||||
|
resp = conn.getresponse()
|
||||||
|
self.assertEqual(resp.status, 300)
|
||||||
|
|
||||||
|
def test_2way_ssl_ok(self):
|
||||||
|
"""
|
||||||
|
Make sure both public and admin API work with 2-way SSL. Requires
|
||||||
|
client certificate.
|
||||||
|
"""
|
||||||
|
self.public_server = self.serveapp('keystone', name='main',
|
||||||
|
cert=CERT, key=KEY, ca=CA, cert_required=True)
|
||||||
|
self.admin_server = self.serveapp('keystone', name='admin',
|
||||||
|
cert=CERT, key=KEY, ca=CA, cert_required=True)
|
||||||
|
# Verify Admin
|
||||||
|
conn = httplib.HTTPSConnection(
|
||||||
|
'127.0.0.1', CONF.admin_port, CLIENT, CLIENT)
|
||||||
|
conn.request('GET', '/')
|
||||||
|
resp = conn.getresponse()
|
||||||
|
self.assertEqual(resp.status, 300)
|
||||||
|
# Verify Public
|
||||||
|
conn = httplib.HTTPSConnection(
|
||||||
|
'127.0.0.1', CONF.public_port, CLIENT, CLIENT)
|
||||||
|
conn.request('GET', '/')
|
||||||
|
resp = conn.getresponse()
|
||||||
|
self.assertEqual(resp.status, 300)
|
||||||
|
|
||||||
|
def test_2way_ssl_fail(self):
|
||||||
|
"""
|
||||||
|
Expect to fail when client does not present proper certificate.
|
||||||
|
"""
|
||||||
|
self.public_server = self.serveapp('keystone', name='main',
|
||||||
|
cert=CERT, key=KEY, ca=CA, cert_required=True)
|
||||||
|
self.admin_server = self.serveapp('keystone', name='admin',
|
||||||
|
cert=CERT, key=KEY, ca=CA, cert_required=True)
|
||||||
|
# Verify Admin
|
||||||
|
conn = httplib.HTTPSConnection('127.0.0.1', CONF.admin_port)
|
||||||
|
try:
|
||||||
|
conn.request('GET', '/')
|
||||||
|
self.fail('Admin API shoulda failed with SSL handshake!')
|
||||||
|
except ssl.SSLError:
|
||||||
|
pass
|
||||||
|
# Verify Public
|
||||||
|
conn = httplib.HTTPSConnection('127.0.0.1', CONF.public_port)
|
||||||
|
try:
|
||||||
|
conn.request('GET', '/')
|
||||||
|
self.fail('Public API shoulda failed with SSL handshake!')
|
||||||
|
except ssl.SSLError:
|
||||||
|
pass
|
Loading…
Reference in New Issue
Block a user