diff --git a/README.md b/README.md index 048aaa3..ca22652 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # Microsoft Authentication Extensions for Python -The Microsoft Authentication Extensions for Python offers secure mechanisms for client applications to perform cross-platform token cache serialization and persistence. It gives additional support to the [Microsoft Authentication Library for Python (MSAL)](https://github.com/AzureAD/microsoft-authentication-library-for-python). +The Microsoft Authentication Extensions for Python offers secure mechanisms for client applications to perform cross-platform token cache serialization and persistence. It gives additional support to the [Microsoft Authentication Library for Python (MSAL)](https://github.com/AzureAD/microsoft-authentication-library-for-python). MSAL Python supports an in-memory cache by default and provides the [SerializableTokenCache](https://msal-python.readthedocs.io/en/latest/#msal.SerializableTokenCache) to perform cache serialization. You can read more about this in the MSAL Python [documentation](https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-python-token-cache-serialization). Developers are required to implement their own cache persistance across multiple platforms and Microsoft Authentication Extensions makes this simpler. -The supported platforms are Windows, Mac and Linux. +The supported platforms are Windows, Mac and Linux. - Windows - [DPAPI](https://docs.microsoft.com/en-us/dotnet/standard/security/how-to-use-data-protection) is used for encryption. - MAC - The MAC KeyChain is used. - Linux - [LibSecret](https://wiki.gnome.org/Projects/Libsecret) is used for encryption. @@ -28,7 +28,9 @@ You can find the changes for each version under ## Usage -The Microsoft Authentication Extensions library provides the `PersistedTokenCache` which accepts a platform-dependent persistence instance. This token cache can then be used to instantiate the `PublicClientApplication` in MSAL Python. +### Creating an encrypted token cache file to be used by MSAL + +The Microsoft Authentication Extensions library provides the `PersistedTokenCache` which accepts a platform-dependent persistence instance. This token cache can then be used to instantiate the `PublicClientApplication` in MSAL Python. The token cache includes a file lock, and auto-reload behavior under the hood. @@ -39,24 +41,16 @@ Here is an example of this pattern for multiple platforms (taken from the comple ```python def build_persistence(location, fallback_to_plaintext=False): """Build a suitable persistence instance based your current OS""" - if sys.platform.startswith('win'): - return FilePersistenceWithDataProtection(location) - if sys.platform.startswith('darwin'): - return KeychainPersistence(location, "my_service_name", "my_account_name") - if sys.platform.startswith('linux'): - try: - return LibsecretPersistence( - location, - schema_name="my_schema_name", - attributes={"my_attr1": "foo", "my_attr2": "bar"}, - ) - except: # pylint: disable=bare-except - if not fallback_to_plaintext: - raise - logging.exception("Encryption unavailable. Opting in to plain text.") - return FilePersistence(location) + try: + return build_encrypted_persistence(location) + except: + if not fallback_to_plaintext: + raise + logging.warning("Encryption unavailable. Opting in to plain text.") + return FilePersistence(location) persistence = build_persistence("token_cache.bin") +print("Type of persistence: {}".format(persistence.__class__.__name__)) print("Is this persistence encrypted?", persistence.is_encrypted) cache = PersistedTokenCache(persistence) @@ -66,6 +60,36 @@ Now you can use it in an MSAL application like this: app = msal.PublicClientApplication("my_client_id", token_cache=cache) ``` +### Creating an encrypted persistence file to store your own data + +Here is an example of this pattern for multiple platforms (taken from the complete [sample here](https://github.com/AzureAD/microsoft-authentication-extensions-for-python/blob/dev/sample/persistence_sample.py)): + +```python +def build_persistence(location, fallback_to_plaintext=False): + """Build a suitable persistence instance based your current OS""" + try: + return build_encrypted_persistence(location) + except: # pylint: disable=bare-except + if not fallback_to_plaintext: + raise + logging.warning("Encryption unavailable. Opting in to plain text.") + return FilePersistence(location) + +persistence = build_persistence("storage.bin", fallback_to_plaintext=False) +print("Type of persistence: {}".format(persistence.__class__.__name__)) +print("Is this persistence encrypted?", persistence.is_encrypted) + +data = { # It can be anything, here we demonstrate an arbitrary json object + "foo": "hello world", + "bar": "", + "service_principle_1": "blah blah...", + } + +persistence.save(json.dumps(data)) +assert json.loads(persistence.load()) == data +``` + + ## Community Help and Support We leverage Stack Overflow to work with the community on supporting Azure Active Directory and its SDKs, including this one! @@ -92,4 +116,4 @@ provided by the bot. You will only need to do this once across all repos using o ## We value and adhere to the Microsoft Open Source Code of Conduct -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. \ No newline at end of file +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/sample/persistence_sample.py b/sample/persistence_sample.py index de23e1c..0087bb5 100644 --- a/sample/persistence_sample.py +++ b/sample/persistence_sample.py @@ -11,7 +11,9 @@ def build_persistence(location, fallback_to_plaintext=False): try: return build_encrypted_persistence(location) except: # pylint: disable=bare-except - # Known issue: Currently, only Linux + # On Linux, encryption exception will be raised during initialization. + # On Windows and macOS, they won't be detected here, + # but will be raised during their load() or save(). if not fallback_to_plaintext: raise logging.warning("Encryption unavailable. Opting in to plain text.") diff --git a/sample/token_cache_sample.py b/sample/token_cache_sample.py index 6e241a8..c47c3a1 100644 --- a/sample/token_cache_sample.py +++ b/sample/token_cache_sample.py @@ -12,7 +12,9 @@ def build_persistence(location, fallback_to_plaintext=False): try: return build_encrypted_persistence(location) except: # pylint: disable=bare-except - # Known issue: Currently, only Linux + # On Linux, encryption exception will be raised during initialization. + # On Windows and macOS, they won't be detected here, + # but will be raised during their load() or save(). if not fallback_to_plaintext: raise logging.warning("Encryption unavailable. Opting in to plain text.")