@@ -90,6 +90,14 @@ def _merge_claims_challenge_and_capabilities(capabilities, claims_challenge):
9090 return json .dumps (claims_dict )
9191
9292
93+ def _str2bytes (raw ):
94+ # A conversion based on duck-typing rather than six.text_type
95+ try :
96+ return raw .encode (encoding = "utf-8" )
97+ except :
98+ return raw
99+
100+
93101class ClientApplication (object ):
94102
95103 ACQUIRE_TOKEN_SILENT_ID = "84"
@@ -124,6 +132,7 @@ def __init__(
124132 "private_key": "...-----BEGIN PRIVATE KEY-----...",
125133 "thumbprint": "A1B2C3D4E5F6...",
126134 "public_certificate": "...-----BEGIN CERTIFICATE-----..." (Optional. See below.)
135+ "passphrase": "Passphrase if the private_key is encrypted (Optional)"
127136 }
128137
129138 *Added in version 0.5.0*:
@@ -252,8 +261,18 @@ def _build_client(self, client_credential, authority):
252261 headers = {}
253262 if 'public_certificate' in client_credential :
254263 headers ["x5c" ] = extract_certs (client_credential ['public_certificate' ])
264+ if not client_credential .get ("passphrase" ):
265+ unencrypted_private_key = client_credential ['private_key' ]
266+ else :
267+ from cryptography .hazmat .primitives import serialization
268+ from cryptography .hazmat .backends import default_backend
269+ unencrypted_private_key = serialization .load_pem_private_key (
270+ _str2bytes (client_credential ["private_key" ]),
271+ _str2bytes (client_credential ["passphrase" ]),
272+ backend = default_backend (), # It was a required param until 2020
273+ )
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 ,
0 commit comments