Skip to content

Commit 88e9b22

Browse files
abhidnya13rayluo
authored andcommitted
Initial commit
Code refactoring Changing reference doc string Adding tests PR review 1 Adding dependencies and polishing code Python 2 compat
1 parent 1f56396 commit 88e9b22

File tree

3 files changed

+49
-1
lines changed

3 files changed

+49
-1
lines changed

msal/application.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import functools
22
import json
33
import time
4+
5+
import six
6+
from cryptography.hazmat.backends import default_backend
7+
from cryptography.hazmat.primitives import serialization
8+
49
try: # Python 2
510
from urlparse import urljoin
611
except: # Python 3
@@ -124,6 +129,7 @@ def __init__(
124129
"private_key": "...-----BEGIN PRIVATE KEY-----...",
125130
"thumbprint": "A1B2C3D4E5F6...",
126131
"public_certificate": "...-----BEGIN CERTIFICATE-----..." (Optional. See below.)
132+
"passphrase": "Passphrase if the private_key is encrypted (Optional)"
127133
}
128134
129135
*Added in version 0.5.0*:
@@ -252,8 +258,21 @@ def _build_client(self, client_credential, authority):
252258
headers = {}
253259
if 'public_certificate' in client_credential:
254260
headers["x5c"] = extract_certs(client_credential['public_certificate'])
261+
if not client_credential.get("passphrase"):
262+
unencrypted_private_key = client_credential['private_key']
263+
else:
264+
if isinstance(client_credential['private_key'], six.text_type):
265+
private_key = client_credential['private_key'].encode(encoding="utf-8")
266+
else:
267+
private_key = client_credential['private_key']
268+
if isinstance(client_credential['passphrase'], six.text_type):
269+
password = client_credential['passphrase'].encode(encoding="utf-8")
270+
else:
271+
password = client_credential['passphrase']
272+
unencrypted_private_key = serialization.load_pem_private_key(
273+
private_key, password=password, backend=default_backend())
255274
assertion = JwtAssertionCreator(
256-
client_credential["private_key"], algorithm="RS256",
275+
unencrypted_private_key, algorithm="RS256",
257276
sha1_thumbprint=client_credential.get("thumbprint"), headers=headers)
258277
client_assertion = assertion.create_regenerative_assertion(
259278
audience=authority.token_endpoint, issuer=self.client_id,

setup.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@
7474
install_requires=[
7575
'requests>=2.0.0,<3',
7676
'PyJWT[crypto]>=1.0.0,<2',
77+
'six>=1.6',
78+
'cryptography>=2.1.4'
7779
]
7880
)
7981

tests/test_application.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,33 @@ def test_extract_multiple_tag_enclosed_certs(self):
3939
self.assertEqual(["my_cert1", "my_cert2"], extract_certs(pem))
4040

4141

42+
class TestEncryptedKeyAsClientCredential(unittest.TestCase):
43+
# Internally, we use serialization.load_pem_private_key() to load an encrypted private key with a passphrase
44+
# This function takes in encrypted key in bytes and passphrase in bytes too
45+
# Our code handles such a conversion, adding test cases to verify such a conversion is needed
46+
47+
def test_encyrpted_key_in_bytes_and_string_password_should_error(self):
48+
private_key = b"""
49+
-----BEGIN ENCRYPTED PRIVATE KEY-----
50+
test_private_key
51+
-----END ENCRYPTED PRIVATE KEY-----
52+
"""
53+
with self.assertRaises(TypeError):
54+
# Using a unicode string for Python 2 to identify it as a string and not default to bytes
55+
serialization.load_pem_private_key(
56+
private_key, password=u"string_password", backend=default_backend())
57+
58+
def test_encyrpted_key_is_string_and_bytes_password_should_error(self):
59+
private_key = u"""
60+
-----BEGIN ENCRYPTED PRIVATE KEY-----
61+
test_private_key
62+
-----END ENCRYPTED PRIVATE KEY-----
63+
"""
64+
with self.assertRaises(TypeError):
65+
serialization.load_pem_private_key(
66+
private_key, password=b"byte_password", backend=default_backend())
67+
68+
4269
class TestClientApplicationAcquireTokenSilentErrorBehaviors(unittest.TestCase):
4370

4471
def setUp(self):

0 commit comments

Comments
 (0)