Skip to content

Commit 60c2a74

Browse files
authored
Merge pull request #103 from AzureAD/unified-persistence-api
Making all platform-dependent parameters optional
2 parents 9ffc5b7 + 42d482d commit 60c2a74

File tree

4 files changed

+17
-20
lines changed

4 files changed

+17
-20
lines changed

msal_extensions/persistence.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import abc
1010
import os
1111
import errno
12+
import hashlib
1213
import logging
1314
import sys
1415
try:
@@ -50,6 +51,9 @@ def _mkdir_p(path):
5051
else:
5152
raise
5253

54+
def _auto_hash(input_string):
55+
return hashlib.sha256(input_string.encode('utf-8')).hexdigest()
56+
5357

5458
# We do not aim to wrap every os-specific exception.
5559
# Here we define only the most common one,
@@ -197,19 +201,18 @@ class KeychainPersistence(BasePersistence):
197201
and protected by native Keychain libraries on OSX"""
198202
is_encrypted = True
199203

200-
def __init__(self, signal_location, service_name, account_name):
204+
def __init__(self, signal_location, service_name=None, account_name=None):
201205
"""Initialization could fail due to unsatisfied dependency.
202206
203207
:param signal_location: See :func:`persistence.LibsecretPersistence.__init__`
204208
"""
205-
if not (service_name and account_name): # It would hang on OSX
206-
raise ValueError("service_name and account_name are required")
207209
from .osx import Keychain, KeychainError # pylint: disable=import-outside-toplevel
208210
self._file_persistence = FilePersistence(signal_location) # Favor composition
209211
self._Keychain = Keychain # pylint: disable=invalid-name
210212
self._KeychainError = KeychainError # pylint: disable=invalid-name
211-
self._service_name = service_name
212-
self._account_name = account_name
213+
default_service_name = "msal-extensions" # This is also our package name
214+
self._service_name = service_name or default_service_name
215+
self._account_name = account_name or _auto_hash(signal_location)
213216

214217
def save(self, content):
215218
with self._Keychain() as locker:
@@ -247,7 +250,7 @@ class LibsecretPersistence(BasePersistence):
247250
and protected by native libsecret libraries on Linux"""
248251
is_encrypted = True
249252

250-
def __init__(self, signal_location, schema_name, attributes, **kwargs):
253+
def __init__(self, signal_location, schema_name=None, attributes=None, **kwargs):
251254
"""Initialization could fail due to unsatisfied dependency.
252255
253256
:param string signal_location:
@@ -262,7 +265,8 @@ def __init__(self, signal_location, schema_name, attributes, **kwargs):
262265
from .libsecret import ( # This uncertain import is deferred till runtime
263266
LibSecretAgent, trial_run)
264267
trial_run()
265-
self._agent = LibSecretAgent(schema_name, attributes, **kwargs)
268+
self._agent = LibSecretAgent(
269+
schema_name or _auto_hash(signal_location), attributes or {}, **kwargs)
266270
self._file_persistence = FilePersistence(signal_location) # Favor composition
267271

268272
def save(self, content):

sample/persistence_sample.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ def build_persistence(location, fallback_to_plaintext=False):
1010
if sys.platform.startswith('win'):
1111
return FilePersistenceWithDataProtection(location)
1212
if sys.platform.startswith('darwin'):
13-
return KeychainPersistence(location, "my_service_name", "my_account_name")
13+
return KeychainPersistence(location)
1414
if sys.platform.startswith('linux'):
1515
try:
1616
return LibsecretPersistence(
@@ -21,8 +21,6 @@ def build_persistence(location, fallback_to_plaintext=False):
2121
# unless there would frequently be a desktop session and
2222
# a remote ssh session being active simultaneously.
2323
location,
24-
schema_name="my_schema_name",
25-
attributes={"my_attr1": "foo", "my_attr2": "bar"},
2624
)
2725
except: # pylint: disable=bare-except
2826
if not fallback_to_plaintext:
@@ -31,6 +29,7 @@ def build_persistence(location, fallback_to_plaintext=False):
3129
return FilePersistence(location)
3230

3331
persistence = build_persistence("storage.bin", fallback_to_plaintext=False)
32+
print("Type of persistence: {}".format(persistence.__class__.__name__))
3433
print("Is this persistence encrypted?", persistence.is_encrypted)
3534

3635
data = { # It can be anything, here we demonstrate an arbitrary json object

sample/token_cache_sample.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ def build_persistence(location, fallback_to_plaintext=False):
1010
if sys.platform.startswith('win'):
1111
return FilePersistenceWithDataProtection(location)
1212
if sys.platform.startswith('darwin'):
13-
return KeychainPersistence(location, "my_service_name", "my_account_name")
13+
return KeychainPersistence(location)
1414
if sys.platform.startswith('linux'):
1515
try:
1616
return LibsecretPersistence(
@@ -21,8 +21,6 @@ def build_persistence(location, fallback_to_plaintext=False):
2121
# unless there would frequently be a desktop session and
2222
# a remote ssh session being active simultaneously.
2323
location,
24-
schema_name="my_schema_name",
25-
attributes={"my_attr1": "foo", "my_attr2": "bar"},
2624
)
2725
except: # pylint: disable=bare-except
2826
if not fallback_to_plaintext:
@@ -31,6 +29,7 @@ def build_persistence(location, fallback_to_plaintext=False):
3129
return FilePersistence(location)
3230

3331
persistence = build_persistence("token_cache.bin")
32+
print("Type of persistence: {}".format(persistence.__class__.__name__))
3433
print("Is this persistence encrypted?", persistence.is_encrypted)
3534

3635
cache = PersistedTokenCache(persistence)

tests/test_persistence.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,7 @@ def test_nonexistent_file_persistence_with_data_protection(temp_location):
5454
not sys.platform.startswith('darwin'),
5555
reason="Requires OSX. Whether running on TRAVIS CI does not seem to matter.")
5656
def test_keychain_persistence(temp_location):
57-
_test_persistence_roundtrip(KeychainPersistence(
58-
temp_location, "my_service_name", "my_account_name"))
57+
_test_persistence_roundtrip(KeychainPersistence(temp_location))
5958

6059
@pytest.mark.skipif(
6160
not sys.platform.startswith('darwin'),
@@ -69,11 +68,7 @@ def test_nonexistent_keychain_persistence(temp_location):
6968
is_running_on_travis_ci or not sys.platform.startswith('linux'),
7069
reason="Requires Linux Desktop. Headless or SSH session won't work.")
7170
def test_libsecret_persistence(temp_location):
72-
_test_persistence_roundtrip(LibsecretPersistence(
73-
temp_location,
74-
"my_schema_name",
75-
{"my_attr_1": "foo", "my_attr_2": "bar"},
76-
))
71+
_test_persistence_roundtrip(LibsecretPersistence(temp_location))
7772

7873
@pytest.mark.skipif(
7974
is_running_on_travis_ci or not sys.platform.startswith('linux'),

0 commit comments

Comments
 (0)