Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-msal-extensions for openSUSE:Factory checked in at 2022-01-04 19:37:43 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-msal-extensions (Old) and /work/SRC/openSUSE:Factory/.python-msal-extensions.new.1896 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-msal-extensions" Tue Jan 4 19:37:43 2022 rev:4 rq:943621 version:0.3.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-msal-extensions/python-msal-extensions.changes 2020-12-09 22:21:26.487676601 +0100 +++ /work/SRC/openSUSE:Factory/.python-msal-extensions.new.1896/python-msal-extensions.changes 2022-01-04 19:37:55.977964862 +0100 @@ -1,0 +2,13 @@ +Mon Jan 3 15:05:19 UTC 2022 - John Paul Adrian Glaubitz <adrian.glaub...@suse.com> + +- Update to version 0.3.1 + + Enhancement: Better concurrency (#61, #63, #100) + + Bugfix: Now supports user home dir in drive root on Windows (#83, #84) + + Enhancement: This package can now be run inside container + + Enhancement: Improvement compatibility with PyInstaller 3.5 on Python 2.7 (#85, #91) + + Enhancement: Catchable exception when persistence is unavailable (#92, #93) + + Enhancement: Support dependency portalocker 2.0+ (#94, #97) + + Enhancement: Improve documentation (#77, #102) + + Including license in release package (#76) + +------------------------------------------------------------------- Old: ---- msal-extensions-0.3.0.tar.gz New: ---- msal-extensions-0.3.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-msal-extensions.spec ++++++ --- /var/tmp/diff_new_pack.ULuwOM/_old 2022-01-04 19:37:56.457965490 +0100 +++ /var/tmp/diff_new_pack.ULuwOM/_new 2022-01-04 19:37:56.465965501 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-msal-extensions # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -21,7 +21,7 @@ %define skip_python2 1 %endif Name: python-msal-extensions -Version: 0.3.0 +Version: 0.3.1 Release: 0 Summary: Microsoft Authentication Library (MSAL) for Python Extensions License: MIT ++++++ msal-extensions-0.3.0.tar.gz -> msal-extensions-0.3.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-extensions-0.3.0/LICENSE new/msal-extensions-0.3.1/LICENSE --- old/msal-extensions-0.3.0/LICENSE 1970-01-01 01:00:00.000000000 +0100 +++ new/msal-extensions-0.3.1/LICENSE 2021-12-13 05:46:45.000000000 +0100 @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-extensions-0.3.0/PKG-INFO new/msal-extensions-0.3.1/PKG-INFO --- old/msal-extensions-0.3.0/PKG-INFO 2020-09-01 22:43:13.000000000 +0200 +++ new/msal-extensions-0.3.1/PKG-INFO 2021-12-13 05:46:55.792970000 +0100 @@ -1,104 +1,109 @@ Metadata-Version: 2.1 Name: msal-extensions -Version: 0.3.0 +Version: 0.3.1 Summary: UNKNOWN Home-page: UNKNOWN -License: UNKNOWN -Description: - # 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). - - 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. - - 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. - - > Note: It is recommended to use this library for cache persistance support for Public client applications such as Desktop apps only. In web applications, this may lead to scale and performance issues. Web applications are recommended to persist the cache in session. Take a look at this [webapp sample](https://github.com/Azure-Samples/ms-identity-python-webapp). - - ## Installation - - You can find Microsoft Authentication Extensions for Python on [Pypi](https://pypi.org/project/msal-extensions/). - 1. If you haven't already, [install and/or upgrade the pip](https://pip.pypa.io/en/stable/installing/) - of your Python environment to a recent version. We tested with pip 18.1. - 2. Run `pip install msal-extensions`. - - ## Versions - - This library follows [Semantic Versioning](http://semver.org/). - - You can find the changes for each version under - [Releases](https://github.com/AzureAD/microsoft-authentication-extensions-for-python/releases). - - ## 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. - - The token cache includes a file lock, and auto-reload behavior under the hood. - - - - 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/token_cache_sample.py)): - - ```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) - - persistence = build_persistence("token_cache.bin") - print("Is this persistence encrypted?", persistence.is_encrypted) - - cache = PersistedTokenCache(persistence) - ``` - Now you can use it in an MSAL application like this: - ```python - app = msal.PublicClientApplication("my_client_id", token_cache=cache) - ``` - - ## Community Help and Support - - We leverage Stack Overflow to work with the community on supporting Azure Active Directory and its SDKs, including this one! - We highly recommend you ask your questions on Stack Overflow (we're all on there!). - Also browse existing issues to see if someone has had your question before. - - We recommend you use the "msal" tag so we can see it! - Here is the latest Q&A on Stack Overflow for MSAL: - [http://stackoverflow.com/questions/tagged/msal](http://stackoverflow.com/questions/tagged/msal) - - - ## Contributing - - All code is licensed under the MIT license and we triage actively on GitHub. - - This project welcomes contributions and suggestions. Most contributions require you to agree to a - Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us - the rights to use your contribution. For details, visit https://cla.microsoft.com. - - When you submit a pull request, a CLA-bot will automatically determine whether you need to provide - a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions - provided by the bot. You will only need to do this once across all repos using our CLA. - - - ## 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 [openc...@microsoft.com](mailto:openc...@microsoft.com) with any additional questions or comments. +License: MIT +Project-URL: Changelog, https://github.com/AzureAD/microsoft-authentication-extensions-for-python/releases Platform: UNKNOWN -Classifier: Development Status :: 2 - Pre-Alpha +Classifier: License :: OSI Approved :: MIT License +Classifier: Development Status :: 4 - Beta Description-Content-Type: text/markdown +License-File: LICENSE + + +# 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). + +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. +- 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. + +> Note: It is recommended to use this library for cache persistance support for Public client applications such as Desktop apps only. In web applications, this may lead to scale and performance issues. Web applications are recommended to persist the cache in session. Take a look at this [webapp sample](https://github.com/Azure-Samples/ms-identity-python-webapp). + +## Installation + +You can find Microsoft Authentication Extensions for Python on [Pypi](https://pypi.org/project/msal-extensions/). +1. If you haven't already, [install and/or upgrade the pip](https://pip.pypa.io/en/stable/installing/) + of your Python environment to a recent version. We tested with pip 18.1. +2. Run `pip install msal-extensions`. + +## Versions + +This library follows [Semantic Versioning](http://semver.org/). + +You can find the changes for each version under +[Releases](https://github.com/AzureAD/microsoft-authentication-extensions-for-python/releases). + +## 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. + +The token cache includes a file lock, and auto-reload behavior under the hood. + + + +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/token_cache_sample.py)): + +```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) + +persistence = build_persistence("token_cache.bin") +print("Is this persistence encrypted?", persistence.is_encrypted) + +cache = PersistedTokenCache(persistence) +``` +Now you can use it in an MSAL application like this: +```python +app = msal.PublicClientApplication("my_client_id", token_cache=cache) +``` + +## Community Help and Support + +We leverage Stack Overflow to work with the community on supporting Azure Active Directory and its SDKs, including this one! +We highly recommend you ask your questions on Stack Overflow (we're all on there!). +Also browse existing issues to see if someone has had your question before. + +We recommend you use the "msal" tag so we can see it! +Here is the latest Q&A on Stack Overflow for MSAL: +[http://stackoverflow.com/questions/tagged/msal](http://stackoverflow.com/questions/tagged/msal) + + +## Contributing + +All code is licensed under the MIT license and we triage actively on GitHub. + +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit https://cla.microsoft.com. + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + + +## 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 [openc...@microsoft.com](mailto:openc...@microsoft.com) with any additional questions or comments. + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-extensions-0.3.0/msal_extensions/__init__.py new/msal-extensions-0.3.1/msal_extensions/__init__.py --- old/msal-extensions-0.3.0/msal_extensions/__init__.py 2020-09-01 22:42:14.000000000 +0200 +++ new/msal-extensions-0.3.1/msal_extensions/__init__.py 2021-12-13 05:46:45.000000000 +0100 @@ -1,5 +1,5 @@ """Provides auxiliary functionality to the `msal` package.""" -__version__ = "0.3.0" +__version__ = "0.3.1" import sys diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-extensions-0.3.0/msal_extensions/cache_lock.py new/msal-extensions-0.3.1/msal_extensions/cache_lock.py --- old/msal-extensions-0.3.0/msal_extensions/cache_lock.py 2020-09-01 22:42:14.000000000 +0200 +++ new/msal-extensions-0.3.1/msal_extensions/cache_lock.py 2021-12-13 05:46:45.000000000 +0100 @@ -2,9 +2,15 @@ import os import sys import errno -import portalocker +import time +import logging from distutils.version import LooseVersion +import portalocker + + +logger = logging.getLogger(__name__) + class CrossPlatLock(object): """Offers a mechanism for waiting until another process is finished interacting with a shared @@ -14,7 +20,8 @@ def __init__(self, lockfile_path): self._lockpath = lockfile_path # Support for passing through arguments to the open syscall was added in v1.4.0 - open_kwargs = {'buffering': 0} if LooseVersion(portalocker.__version__) >= LooseVersion("1.4.0") else {} + open_kwargs = ({'buffering': 0} + if LooseVersion(portalocker.__version__) >= LooseVersion("1.4.0") else {}) self._lock = portalocker.Lock( lockfile_path, mode='wb+', @@ -25,9 +32,32 @@ flags=portalocker.LOCK_EX | portalocker.LOCK_NB, **open_kwargs) + def _try_to_create_lock_file(self): + timeout = 5 + check_interval = 0.25 + current_time = getattr(time, "monotonic", time.time) + timeout_end = current_time() + timeout + pid = os.getpid() + while timeout_end > current_time(): + try: + with open(self._lockpath, 'x'): # pylint: disable=unspecified-encoding + return True + except ValueError: # This needs to be the first clause, for Python 2 to hit it + logger.warning("Python 2 does not support atomic creation of file") + return False + except FileExistsError: # Only Python 3 will reach this clause + logger.debug( + "Process %d found existing lock file, will retry after %f second", + pid, check_interval) + time.sleep(check_interval) + return False + def __enter__(self): + pid = os.getpid() + if not self._try_to_create_lock_file(): + logger.warning("Process %d failed to create lock file", pid) file_handle = self._lock.__enter__() - file_handle.write('{} {}'.format(os.getpid(), sys.argv[0]).encode('utf-8')) + file_handle.write('{} {}'.format(pid, sys.argv[0]).encode('utf-8')) # pylint: disable=consider-using-f-string return file_handle def __exit__(self, *args): @@ -38,5 +68,5 @@ # file for itself. os.remove(self._lockpath) except OSError as ex: # pylint: disable=invalid-name - if ex.errno != errno.ENOENT and ex.errno != errno.EACCES: + if ex.errno not in (errno.ENOENT, errno.EACCES): raise diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-extensions-0.3.0/msal_extensions/libsecret.py new/msal-extensions-0.3.1/msal_extensions/libsecret.py --- old/msal-extensions-0.3.0/msal_extensions/libsecret.py 2020-09-01 22:42:14.000000000 +0200 +++ new/msal-extensions-0.3.1/msal_extensions/libsecret.py 2021-12-13 05:46:45.000000000 +0100 @@ -13,33 +13,29 @@ pip install wheel PYGOBJECT_WITHOUT_PYCAIRO=1 pip install --no-build-isolation pygobject """ -import logging - -logger = logging.getLogger(__name__) try: - import gi # https://github.com/AzureAD/microsoft-authentication-extensions-for-python/wiki/Encryption-on-Linux + import gi # https://github.com/AzureAD/microsoft-authentication-extensions-for-python/wiki/Encryption-on-Linux # pylint: disable=line-too-long except ImportError: - logger.exception( - """Runtime dependency of PyGObject is missing. + raise ImportError("""Unable to import module 'gi' +Runtime dependency of PyGObject is missing. Depends on your Linux distro, you could install it system-wide by something like: sudo apt install python3-gi python3-gi-cairo gir1.2-secret-1 If necessary, please refer to PyGObject's doc: https://pygobject.readthedocs.io/en/latest/getting_started.html -""") - raise +""") # Message via exception rather than log try: # pylint: disable=no-name-in-module gi.require_version("Secret", "1") # Would require a package gir1.2-secret-1 # pylint: disable=wrong-import-position from gi.repository import Secret # Would require a package gir1.2-secret-1 -except (ValueError, ImportError): - logger.exception( +except (ValueError, ImportError) as ex: + raise type(ex)( """Require a package "gir1.2-secret-1" which could be installed by: sudo apt install gir1.2-secret-1 - """) - raise + """) # Message via exception rather than log + class LibSecretAgent(object): """A loader/saver built on top of low-level libsecret""" @@ -51,7 +47,7 @@ label="", # Helpful when visualizing secrets by other viewers attribute_types=None, # {name: SchemaAttributeType, ...} collection=None, # None means default collection - ): # pylint: disable=bad-continuation + ): """This agent is built on top of lower level libsecret API. Content stored via libsecret is associated with a bunch of attributes. @@ -126,14 +122,13 @@ agent.save(payload) # It would fail when running inside an SSH session assert agent.load() == payload # This line is probably not reachable agent.clear() - except (gi.repository.GLib.Error, AssertionError): + except (gi.repository.GLib.Error, AssertionError): # pylint: disable=no-member + # https://pygobject.readthedocs.io/en/latest/guide/api/error_handling.html#examples message = """libsecret did not perform properly. * If you encountered error "Remote error from secret service: org.freedesktop.DBus.Error.ServiceUnknown", you may need to install gnome-keyring package. * Headless mode (such as in an ssh session) is not supported. """ - logger.exception(message) # This log contains trace stack for debugging - logger.warning(message) # This is visible by default - raise + raise RuntimeError(message) # Message via exception rather than log diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-extensions-0.3.0/msal_extensions/osx.py new/msal-extensions-0.3.1/msal_extensions/osx.py --- old/msal-extensions-0.3.0/msal_extensions/osx.py 2020-09-01 22:42:14.000000000 +0200 +++ new/msal-extensions-0.3.1/msal_extensions/osx.py 2021-12-13 05:46:45.000000000 +0100 @@ -5,7 +5,7 @@ import os import ctypes as _ctypes -OS_RESULT = _ctypes.c_int32 +OS_RESULT = _ctypes.c_int32 # pylint: disable=invalid-name class KeychainError(OSError): @@ -21,10 +21,9 @@ self.exit_status = exit_status # TODO: pylint: disable=fixme # use SecCopyErrorMessageString to fetch the appropriate message here. - self.message = \ - '{} ' \ - 'see https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/MacErrors.h'\ - .format(self.exit_status) + self.message = ( + '{} see https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/MacErrors.h' # pylint: disable=consider-using-f-string,line-too-long + .format(self.exit_status)) def _get_native_location(name): # type: (str) -> str @@ -33,7 +32,7 @@ :param name: The name of the library to be loaded. :return: The location of the library on a MacOS filesystem. """ - return '/System/Library/Frameworks/{0}.framework/{0}'.format(name) + return '/System/Library/Frameworks/{0}.framework/{0}'.format(name) # pylint: disable=consider-using-f-string # Load native MacOS libraries diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-extensions-0.3.0/msal_extensions/persistence.py new/msal-extensions-0.3.1/msal_extensions/persistence.py --- old/msal-extensions-0.3.0/msal_extensions/persistence.py 2020-09-01 22:42:14.000000000 +0200 +++ new/msal-extensions-0.3.1/msal_extensions/persistence.py 2021-12-13 05:46:45.000000000 +0100 @@ -10,9 +10,10 @@ import os import errno import logging +import sys try: from pathlib import Path # Built-in in Python 3 -except: +except ImportError: from pathlib2 import Path # An extra lib for Python 2 @@ -28,14 +29,19 @@ def _mkdir_p(path): """Creates a directory, and any necessary parents. - This implementation based on a Stack Overflow question that can be found here: - https://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python - If the path provided is an existing file, this function raises an exception. :param path: The directory name that should be created. """ if not path: return # NO-OP + + if sys.version_info >= (3, 2): + os.makedirs(path, exist_ok=True) + return + + # This fallback implementation is based on a Stack Overflow question: + # https://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python + # Known issue: it won't work when the path is a root folder like "C:\\" try: os.makedirs(path) except OSError as exp: @@ -53,10 +59,12 @@ # https://github.com/AzureAD/microsoft-authentication-extensions-for-python/blob/0.2.2/msal_extensions/token_cache.py#L38 # Now we want to maintain backward compatibility even when using Python 2.x # It makes no difference in Python 3.3+ where IOError is an alias of OSError. - def __init__( - self, - err_no=errno.ENOENT, message="Persistence not found", location=None): - super(PersistenceNotFound, self).__init__(err_no, message, location) + """This happens when attempting BasePersistence.load() on a non-existent persistence instance""" + def __init__(self, err_no=None, message=None, location=None): + super(PersistenceNotFound, self).__init__( + err_no or errno.ENOENT, + message or "Persistence not found", + location) class BasePersistence(ABC): @@ -105,14 +113,14 @@ def save(self, content): # type: (str) -> None """Save the content into this persistence""" - with open(self._location, 'w+') as handle: + with open(self._location, 'w+') as handle: # pylint: disable=unspecified-encoding handle.write(content) def load(self): # type: () -> str """Load content from this persistence""" try: - with open(self._location, 'r') as handle: + with open(self._location, 'r') as handle: # pylint: disable=unspecified-encoding return handle.read() except EnvironmentError as exp: # EnvironmentError in Py 2.7 works across platform if exp.errno == errno.ENOENT: @@ -214,12 +222,12 @@ try: return locker.get_generic_password( self._service_name, self._account_name) - except self._KeychainError as ex: + except self._KeychainError as ex: # pylint: disable=invalid-name if ex.exit_status == self._KeychainError.ITEM_NOT_FOUND: # This happens when a load() is called before a save(). # We map it into cross-platform error for unified catching. raise PersistenceNotFound( - location="Service:{} Account:{}".format( + location="Service:{} Account:{}".format( # pylint: disable=consider-using-f-string self._service_name, self._account_name), message=( "Keychain persistence not initialized. " diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-extensions-0.3.0/msal_extensions/token_cache.py new/msal-extensions-0.3.1/msal_extensions/token_cache.py --- old/msal-extensions-0.3.0/msal_extensions/token_cache.py 2020-09-01 22:42:14.000000000 +0200 +++ new/msal-extensions-0.3.1/msal_extensions/token_cache.py 2021-12-13 05:46:45.000000000 +0100 @@ -15,7 +15,30 @@ logger = logging.getLogger(__name__) class PersistedTokenCache(msal.SerializableTokenCache): - """A token cache using given persistence layer, coordinated by a file lock.""" + """A token cache backed by a persistence layer, coordinated by a file lock, + to sustain a certain level of multi-process concurrency for a desktop app. + + The scenario is that multiple instances of same desktop app + (or even multiple different apps) + create their own ``PersistedTokenCache`` instances, + which are all backed by the same token cache file on disk + (known as a persistence). The goal is to have Single Sign On (SSO). + + Each instance of ``PersistedTokenCache`` holds a snapshot of the token cache + in memory. + Each :func:`~find` call will + automatically reload token cache from the persistence when necessary, + so that it will have fresh data. + Each :func:`~modify` call will + automatically reload token cache from the persistence when necessary, + so that new writes will be appended on top of latest token cache data, + and then the new data will be immediately flushed back to the persistence. + + Note: :func:`~deserialize` and :func:`~serialize` remain the same + as their counterparts in the parent class ``msal.SerializableTokenCache``. + In other words, they do not have the "reload from persistence if necessary" + nor the "flush back to persistence" behavior. + """ def __init__(self, persistence, lock_location=None): super(PersistedTokenCache, self).__init__() @@ -50,9 +73,21 @@ self._last_sync = time.time() def find(self, credential_type, **kwargs): # pylint: disable=arguments-differ - with CrossPlatLock(self._lock_location): - self._reload_if_necessary() - return super(PersistedTokenCache, self).find(credential_type, **kwargs) + # Use optimistic locking rather than CrossPlatLock(self._lock_location) + retry = 3 + for attempt in range(1, retry + 1): + try: + self._reload_if_necessary() + except Exception: # pylint: disable=broad-except + # Presumably other processes are writing the file, causing dirty read + if attempt < retry: + logger.debug("Unable to load token cache file in No. %d attempt", attempt) + time.sleep(0.5) + else: + raise # End of retry. Re-raise the exception as-is. + else: # If reload encountered no error, the data is considered intact + return super(PersistedTokenCache, self).find(credential_type, **kwargs) + return [] # Not really reachable here. Just to keep pylint happy. class FileTokenCache(PersistedTokenCache): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-extensions-0.3.0/msal_extensions/windows.py new/msal-extensions-0.3.1/msal_extensions/windows.py --- old/msal-extensions-0.3.0/msal_extensions/windows.py 2020-09-01 22:42:14.000000000 +0200 +++ new/msal-extensions-0.3.1/msal_extensions/windows.py 2021-12-13 05:46:45.000000000 +0100 @@ -5,6 +5,9 @@ _LOCAL_FREE = ctypes.windll.kernel32.LocalFree _GET_LAST_ERROR = ctypes.windll.kernel32.GetLastError _MEMCPY = ctypes.cdll.msvcrt.memcpy +_MEMCPY.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t] # Note: + # Suggested by https://github.com/AzureAD/microsoft-authentication-extensions-for-python/issues/85 # pylint: disable=line-too-long + # Matching https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/memcpy-wmemcpy?view=msvc-160 # pylint: disable=line-too-long _CRYPT_PROTECT_DATA = ctypes.windll.crypt32.CryptProtectData _CRYPT_UNPROTECT_DATA = ctypes.windll.crypt32.CryptUnprotectData _CRYPTPROTECT_UI_FORBIDDEN = 0x01 @@ -67,7 +70,7 @@ if _CRYPT_PROTECT_DATA( ctypes.byref(message_blob), - u"python_data", + u"python_data", # pylint: disable=redundant-u-string-prefix entropy, None, None, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-extensions-0.3.0/msal_extensions.egg-info/PKG-INFO new/msal-extensions-0.3.1/msal_extensions.egg-info/PKG-INFO --- old/msal-extensions-0.3.0/msal_extensions.egg-info/PKG-INFO 2020-09-01 22:43:13.000000000 +0200 +++ new/msal-extensions-0.3.1/msal_extensions.egg-info/PKG-INFO 2021-12-13 05:46:55.000000000 +0100 @@ -1,104 +1,109 @@ Metadata-Version: 2.1 Name: msal-extensions -Version: 0.3.0 +Version: 0.3.1 Summary: UNKNOWN Home-page: UNKNOWN -License: UNKNOWN -Description: - # 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). - - 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. - - 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. - - > Note: It is recommended to use this library for cache persistance support for Public client applications such as Desktop apps only. In web applications, this may lead to scale and performance issues. Web applications are recommended to persist the cache in session. Take a look at this [webapp sample](https://github.com/Azure-Samples/ms-identity-python-webapp). - - ## Installation - - You can find Microsoft Authentication Extensions for Python on [Pypi](https://pypi.org/project/msal-extensions/). - 1. If you haven't already, [install and/or upgrade the pip](https://pip.pypa.io/en/stable/installing/) - of your Python environment to a recent version. We tested with pip 18.1. - 2. Run `pip install msal-extensions`. - - ## Versions - - This library follows [Semantic Versioning](http://semver.org/). - - You can find the changes for each version under - [Releases](https://github.com/AzureAD/microsoft-authentication-extensions-for-python/releases). - - ## 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. - - The token cache includes a file lock, and auto-reload behavior under the hood. - - - - 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/token_cache_sample.py)): - - ```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) - - persistence = build_persistence("token_cache.bin") - print("Is this persistence encrypted?", persistence.is_encrypted) - - cache = PersistedTokenCache(persistence) - ``` - Now you can use it in an MSAL application like this: - ```python - app = msal.PublicClientApplication("my_client_id", token_cache=cache) - ``` - - ## Community Help and Support - - We leverage Stack Overflow to work with the community on supporting Azure Active Directory and its SDKs, including this one! - We highly recommend you ask your questions on Stack Overflow (we're all on there!). - Also browse existing issues to see if someone has had your question before. - - We recommend you use the "msal" tag so we can see it! - Here is the latest Q&A on Stack Overflow for MSAL: - [http://stackoverflow.com/questions/tagged/msal](http://stackoverflow.com/questions/tagged/msal) - - - ## Contributing - - All code is licensed under the MIT license and we triage actively on GitHub. - - This project welcomes contributions and suggestions. Most contributions require you to agree to a - Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us - the rights to use your contribution. For details, visit https://cla.microsoft.com. - - When you submit a pull request, a CLA-bot will automatically determine whether you need to provide - a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions - provided by the bot. You will only need to do this once across all repos using our CLA. - - - ## 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 [openc...@microsoft.com](mailto:openc...@microsoft.com) with any additional questions or comments. +License: MIT +Project-URL: Changelog, https://github.com/AzureAD/microsoft-authentication-extensions-for-python/releases Platform: UNKNOWN -Classifier: Development Status :: 2 - Pre-Alpha +Classifier: License :: OSI Approved :: MIT License +Classifier: Development Status :: 4 - Beta Description-Content-Type: text/markdown +License-File: LICENSE + + +# 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). + +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. +- 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. + +> Note: It is recommended to use this library for cache persistance support for Public client applications such as Desktop apps only. In web applications, this may lead to scale and performance issues. Web applications are recommended to persist the cache in session. Take a look at this [webapp sample](https://github.com/Azure-Samples/ms-identity-python-webapp). + +## Installation + +You can find Microsoft Authentication Extensions for Python on [Pypi](https://pypi.org/project/msal-extensions/). +1. If you haven't already, [install and/or upgrade the pip](https://pip.pypa.io/en/stable/installing/) + of your Python environment to a recent version. We tested with pip 18.1. +2. Run `pip install msal-extensions`. + +## Versions + +This library follows [Semantic Versioning](http://semver.org/). + +You can find the changes for each version under +[Releases](https://github.com/AzureAD/microsoft-authentication-extensions-for-python/releases). + +## 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. + +The token cache includes a file lock, and auto-reload behavior under the hood. + + + +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/token_cache_sample.py)): + +```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) + +persistence = build_persistence("token_cache.bin") +print("Is this persistence encrypted?", persistence.is_encrypted) + +cache = PersistedTokenCache(persistence) +``` +Now you can use it in an MSAL application like this: +```python +app = msal.PublicClientApplication("my_client_id", token_cache=cache) +``` + +## Community Help and Support + +We leverage Stack Overflow to work with the community on supporting Azure Active Directory and its SDKs, including this one! +We highly recommend you ask your questions on Stack Overflow (we're all on there!). +Also browse existing issues to see if someone has had your question before. + +We recommend you use the "msal" tag so we can see it! +Here is the latest Q&A on Stack Overflow for MSAL: +[http://stackoverflow.com/questions/tagged/msal](http://stackoverflow.com/questions/tagged/msal) + + +## Contributing + +All code is licensed under the MIT license and we triage actively on GitHub. + +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit https://cla.microsoft.com. + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + + +## 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 [openc...@microsoft.com](mailto:openc...@microsoft.com) with any additional questions or comments. + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-extensions-0.3.0/msal_extensions.egg-info/SOURCES.txt new/msal-extensions-0.3.1/msal_extensions.egg-info/SOURCES.txt --- old/msal-extensions-0.3.0/msal_extensions.egg-info/SOURCES.txt 2020-09-01 22:43:13.000000000 +0200 +++ new/msal-extensions-0.3.1/msal_extensions.egg-info/SOURCES.txt 2021-12-13 05:46:55.000000000 +0100 @@ -1,3 +1,4 @@ +LICENSE README.md setup.cfg setup.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-extensions-0.3.0/msal_extensions.egg-info/requires.txt new/msal-extensions-0.3.1/msal_extensions.egg-info/requires.txt --- old/msal-extensions-0.3.0/msal_extensions.egg-info/requires.txt 2020-09-01 22:43:13.000000000 +0200 +++ new/msal-extensions-0.3.1/msal_extensions.egg-info/requires.txt 2021-12-13 05:46:55.000000000 +0100 @@ -1,10 +1,16 @@ msal<2.0.0,>=0.4.1 -[:platform_system != "Windows"] -portalocker~=1.0 - -[:platform_system == "Windows"] -portalocker~=1.6 - [:python_version < "3.0"] pathlib2 + +[:python_version == "2.7" and platform_system != "Windows"] +portalocker<2,>=1.0 + +[:python_version == "2.7" and platform_system == "Windows"] +portalocker<2,>=1.6 + +[:python_version >= "3.5" and platform_system != "Windows"] +portalocker<3,>=1.0 + +[:python_version >= "3.5" and platform_system == "Windows"] +portalocker<3,>=1.6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-extensions-0.3.0/setup.cfg new/msal-extensions-0.3.1/setup.cfg --- old/msal-extensions-0.3.0/setup.cfg 2020-09-01 22:43:13.000000000 +0200 +++ new/msal-extensions-0.3.1/setup.cfg 2021-12-13 05:46:55.792970000 +0100 @@ -1,6 +1,13 @@ [bdist_wheel] universal = 1 +[metadata] +license = MIT +project_urls = Changelog = https://github.com/AzureAD/microsoft-authentication-extensions-for-python/releases +classifiers = + License :: OSI Approved :: MIT License + Development Status :: 4 - Beta + [egg_info] tag_build = tag_date = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msal-extensions-0.3.0/setup.py new/msal-extensions-0.3.1/setup.py --- old/msal-extensions-0.3.0/setup.py 2020-09-01 22:42:14.000000000 +0200 +++ new/msal-extensions-0.3.1/setup.py 2021-12-13 05:46:45.000000000 +0100 @@ -19,14 +19,20 @@ packages=find_packages(), long_description=long_description, long_description_content_type="text/markdown", - classifiers=[ - 'Development Status :: 2 - Pre-Alpha', - ], package_data={'': ['LICENSE']}, install_requires=[ 'msal>=0.4.1,<2.0.0', - "portalocker~=1.6;platform_system=='Windows'", - "portalocker~=1.0;platform_system!='Windows'", + + # In order to implement these requirements: + # Lowerbound = (1.6 if playform_system == 'Windows' else 1.0) + # Upperbound < (3 if python_version >= '3.5' else 2) + # The following 4 lines use the `and` syntax defined here: + # https://www.python.org/dev/peps/pep-0508/#grammar + "portalocker<3,>=1.0;python_version>='3.5' and platform_system!='Windows'", + "portalocker<2,>=1.0;python_version=='2.7' and platform_system!='Windows'", + "portalocker<3,>=1.6;python_version>='3.5' and platform_system=='Windows'", + "portalocker<2,>=1.6;python_version=='2.7' and platform_system=='Windows'", + "pathlib2;python_version<'3.0'", ## We choose to NOT define a hard dependency on this. # "pygobject>=3,<4;platform_system=='Linux'",