Skip to content
This repository was archived by the owner on Jan 18, 2025. It is now read-only.

Commit 9dc6ba2

Browse files
committed
Deferring OpenSSL import until usage.
This is to speed up import times. In OpenSSL 0.14 the import takes 0.5 seconds due to cffi on-demand build of extensions in the cryptography library. For classes and functions which are conditionally defined based on the existence of OpenSSL.crypto, we check that the module exists (but don't import it) using imp.find_module.
1 parent 0a6241c commit 9dc6ba2

2 files changed

Lines changed: 17 additions & 5 deletions

File tree

oauth2client/crypt.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
"""Crypto-related routines for oauth2client."""
1717

1818
import base64
19+
import imp
1920
import json
2021
import logging
22+
import os
2123
import sys
2224
import time
2325

@@ -37,7 +39,10 @@ class AppIdentityError(Exception):
3739

3840

3941
try:
40-
from OpenSSL import crypto
42+
_, package_dir, _ = imp.find_module('OpenSSL')
43+
if not os.path.isfile(os.path.join(package_dir, 'crypto.py')):
44+
raise ImportError('No module named OpenSSL')
45+
del package_dir
4146

4247
class OpenSSLVerifier(object):
4348
"""Verifies the signature on a message."""
@@ -61,6 +66,7 @@ def verify(self, message, signature):
6166
True if message was signed by the private key associated with the public
6267
key that this object was constructed with.
6368
"""
69+
from OpenSSL import crypto
6470
try:
6571
if isinstance(message, six.text_type):
6672
message = message.encode('utf-8')
@@ -84,6 +90,7 @@ def from_string(key_pem, is_x509_cert):
8490
Raises:
8591
OpenSSL.crypto.Error if the key_pem can't be parsed.
8692
"""
93+
from OpenSSL import crypto
8794
if is_x509_cert:
8895
pubkey = crypto.load_certificate(crypto.FILETYPE_PEM, key_pem)
8996
else:
@@ -111,6 +118,7 @@ def sign(self, message):
111118
Returns:
112119
string, The signature of the message for the given key.
113120
"""
121+
from OpenSSL import crypto
114122
if isinstance(message, six.text_type):
115123
message = message.encode('utf-8')
116124
return crypto.sign(self._key, message, 'sha256')
@@ -129,6 +137,7 @@ def from_string(key, password=b'notasecret'):
129137
Raises:
130138
OpenSSL.crypto.Error if the key can't be parsed.
131139
"""
140+
from OpenSSL import crypto
132141
parsed_pem_key = _parse_pem_key(key)
133142
if parsed_pem_key:
134143
pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, parsed_pem_key)
@@ -149,6 +158,7 @@ def pkcs12_key_as_pem(private_key_text, private_key_password):
149158
Returns:
150159
String. PEM contents of ``private_key_text``.
151160
"""
161+
from OpenSSL import crypto
152162
decoded_body = base64.b64decode(private_key_text)
153163
if isinstance(private_key_password, six.string_types):
154164
private_key_password = private_key_password.encode('ascii')

tests/test_crypt.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,19 @@ def test_succeeds(self):
5858
self.assertTrue(pem_contents in [pkcs12_key_as_pem, alternate_pem])
5959

6060
def test_without_openssl(self):
61-
openssl_mod = sys.modules['OpenSSL']
61+
import os
62+
path_isfile = os.path.isfile
6263
try:
63-
sys.modules['OpenSSL'] = None
64+
os.path.isfile = lambda value: False
6465
reload(crypt)
6566
self.assertRaises(NotImplementedError, crypt.pkcs12_key_as_pem,
6667
'FOO', 'BAR')
6768
finally:
68-
sys.modules['OpenSSL'] = openssl_mod
69+
os.path.isfile = path_isfile
6970
reload(crypt)
7071

7172
def test_with_nonsense_key(self):
73+
from OpenSSL import crypto
7274
credentials = self._make_signed_jwt_creds(private_key=b'NOT_A_KEY')
73-
self.assertRaises(crypt.crypto.Error, crypt.pkcs12_key_as_pem,
75+
self.assertRaises(crypto.Error, crypt.pkcs12_key_as_pem,
7476
credentials.private_key, credentials.private_key_password)

0 commit comments

Comments
 (0)