def _load_persistent_cache(allow_unencrypted, account_name, cache_name):
    # type: (Optional[bool], str, str) -> msal.TokenCache
    """Load the persistent cache using msal_extensions.

    On Windows the cache is a file protected by the Data Protection API. On Linux and macOS the cache is stored by
    libsecret and Keychain, respectively. On those platforms the cache uses the modified timestamp of a file on disk to
    decide whether to reload the cache.

    :param bool allow_unencrypted: when True, the cache will be kept in plaintext should encryption be impossible in the
        current environment
    """

    if sys.platform.startswith("win") and "LOCALAPPDATA" in os.environ:
        cache_location = os.path.join(os.environ["LOCALAPPDATA"],
                                      ".IdentityService", cache_name)
        persistence = msal_extensions.FilePersistenceWithDataProtection(
            cache_location)
    elif sys.platform.startswith("darwin"):
        # the cache uses this file's modified timestamp to decide whether to reload
        file_path = os.path.expanduser(
            os.path.join("~", ".IdentityService", cache_name))
        persistence = msal_extensions.KeychainPersistence(
            file_path, "Microsoft.Developer.IdentityService", account_name)
    elif sys.platform.startswith("linux"):
        # The cache uses this file's modified timestamp to decide whether to reload. Note this path is the same
        # as that of the plaintext fallback: a new encrypted cache will stomp an unencrypted cache.
        file_path = os.path.expanduser(
            os.path.join("~", ".IdentityService", cache_name))
        try:
            persistence = msal_extensions.LibsecretPersistence(
                file_path,
                cache_name,
                {"MsalClientID": "Microsoft.Developer.IdentityService"},
                label=account_name)
        except ImportError:
            if not allow_unencrypted:
                raise ValueError(
                    "PyGObject is required to encrypt the persistent cache. Please install that library or ",
                    "specify 'allow_unencrypted_cache=True' to store the cache without encryption.",
                )
            persistence = msal_extensions.FilePersistence(file_path)
    else:
        raise NotImplementedError(
            "A persistent cache is not available in this environment.")

    return msal_extensions.PersistedTokenCache(persistence)
Esempio n. 2
0
def _get_persistence(allow_unencrypted, account_name, cache_name):
    # type: (bool, str, str) -> msal_extensions.persistence.BasePersistence
    """Get an msal_extensions persistence instance for the current platform.

    On Windows the cache is a file protected by the Data Protection API. On Linux and macOS the cache is stored by
    libsecret and Keychain, respectively. On those platforms the cache uses the modified timestamp of a file on disk to
    decide whether to reload the cache.

    :param bool allow_unencrypted: when True, the cache will be kept in plaintext should encryption be impossible in the
        current environment
    """
    import msal_extensions

    if sys.platform.startswith("win") and "LOCALAPPDATA" in os.environ:
        cache_location = os.path.join(os.environ["LOCALAPPDATA"], ".IdentityService", cache_name)
        return msal_extensions.FilePersistenceWithDataProtection(cache_location)

    if sys.platform.startswith("darwin"):
        # the cache uses this file's modified timestamp to decide whether to reload
        file_path = os.path.expanduser(os.path.join("~", ".IdentityService", cache_name))
        return msal_extensions.KeychainPersistence(file_path, "Microsoft.Developer.IdentityService", account_name)

    if sys.platform.startswith("linux"):
        # The cache uses this file's modified timestamp to decide whether to reload. Note this path is the same
        # as that of the plaintext fallback: a new encrypted cache will stomp an unencrypted cache.
        file_path = os.path.expanduser(os.path.join("~", ".IdentityService", cache_name))
        try:
            return msal_extensions.LibsecretPersistence(
                file_path, cache_name, {"MsalClientID": "Microsoft.Developer.IdentityService"}, label=account_name
            )
        except Exception as ex:  # pylint:disable=broad-except
            _LOGGER.debug('msal-extensions is unable to encrypt a persistent cache: "%s"', ex, exc_info=True)
            if not allow_unencrypted:
                error = ValueError(
                    "Cache encryption is impossible because libsecret dependencies are not installed or are unusable,"
                    + " for example because no display is available (as in an SSH session). The chained exception has"
                    + ' more information. Specify "allow_unencrypted_storage=True" to store the cache unencrypted'
                    + " instead of raising this exception."
                )
                six.raise_from(error, ex)
        return msal_extensions.FilePersistence(file_path)

    raise NotImplementedError("A persistent cache is not available in this environment.")