????
Current Path : C:/opt/pgsql/pgAdmin 4/python/Lib/site-packages/msal_extensions/ |
Current File : C:/opt/pgsql/pgAdmin 4/python/Lib/site-packages/msal_extensions/osx.py |
# pylint: disable=duplicate-code """Implements a macOS specific TokenCache, and provides auxiliary helper types.""" import os import ctypes as _ctypes OS_RESULT = _ctypes.c_int32 # pylint: disable=invalid-name class KeychainError(OSError): """The RuntimeError that will be run when a function interacting with Keychain fails.""" ACCESS_DENIED = -128 NO_SUCH_KEYCHAIN = -25294 NO_DEFAULT = -25307 ITEM_NOT_FOUND = -25300 def __init__(self, exit_status): super(KeychainError, self).__init__() 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' # pylint: disable=consider-using-f-string,line-too-long .format(self.exit_status)) def _get_native_location(name): # type: (str) -> str """ Fetches the location of a native MacOS library. :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) # pylint: disable=consider-using-f-string # Load native MacOS libraries _SECURITY = _ctypes.CDLL(_get_native_location('Security')) _CORE = _ctypes.CDLL(_get_native_location('CoreFoundation')) # Bind CFRelease from native MacOS libraries. _CORE_RELEASE = _CORE.CFRelease _CORE_RELEASE.argtypes = ( _ctypes.c_void_p, ) # Bind SecCopyErrorMessageString from native MacOS libraries. # https://developer.apple.com/documentation/security/1394686-seccopyerrormessagestring?language=objc _SECURITY_COPY_ERROR_MESSAGE_STRING = _SECURITY.SecCopyErrorMessageString _SECURITY_COPY_ERROR_MESSAGE_STRING.argtypes = ( OS_RESULT, _ctypes.c_void_p ) _SECURITY_COPY_ERROR_MESSAGE_STRING.restype = _ctypes.c_char_p # Bind SecKeychainOpen from native MacOS libraries. # https://developer.apple.com/documentation/security/1396431-seckeychainopen _SECURITY_KEYCHAIN_OPEN = _SECURITY.SecKeychainOpen _SECURITY_KEYCHAIN_OPEN.argtypes = ( _ctypes.c_char_p, _ctypes.POINTER(_ctypes.c_void_p) ) _SECURITY_KEYCHAIN_OPEN.restype = OS_RESULT # Bind SecKeychainCopyDefault from native MacOS libraries. # https://developer.apple.com/documentation/security/1400743-seckeychaincopydefault?language=objc _SECURITY_KEYCHAIN_COPY_DEFAULT = _SECURITY.SecKeychainCopyDefault _SECURITY_KEYCHAIN_COPY_DEFAULT.argtypes = ( _ctypes.POINTER(_ctypes.c_void_p), ) _SECURITY_KEYCHAIN_COPY_DEFAULT.restype = OS_RESULT # Bind SecKeychainItemFreeContent from native MacOS libraries. _SECURITY_KEYCHAIN_ITEM_FREE_CONTENT = _SECURITY.SecKeychainItemFreeContent _SECURITY_KEYCHAIN_ITEM_FREE_CONTENT.argtypes = ( _ctypes.c_void_p, _ctypes.c_void_p, ) _SECURITY_KEYCHAIN_ITEM_FREE_CONTENT.restype = OS_RESULT # Bind SecKeychainItemModifyAttributesAndData from native MacOS libraries. _SECURITY_KEYCHAIN_ITEM_MODIFY_ATTRIBUTES_AND_DATA = \ _SECURITY.SecKeychainItemModifyAttributesAndData _SECURITY_KEYCHAIN_ITEM_MODIFY_ATTRIBUTES_AND_DATA.argtypes = ( _ctypes.c_void_p, _ctypes.c_void_p, _ctypes.c_uint32, _ctypes.c_void_p, ) _SECURITY_KEYCHAIN_ITEM_MODIFY_ATTRIBUTES_AND_DATA.restype = OS_RESULT # Bind SecKeychainFindGenericPassword from native MacOS libraries. # https://developer.apple.com/documentation/security/1397301-seckeychainfindgenericpassword?language=objc _SECURITY_KEYCHAIN_FIND_GENERIC_PASSWORD = _SECURITY.SecKeychainFindGenericPassword _SECURITY_KEYCHAIN_FIND_GENERIC_PASSWORD.argtypes = ( _ctypes.c_void_p, _ctypes.c_uint32, _ctypes.c_char_p, _ctypes.c_uint32, _ctypes.c_char_p, _ctypes.POINTER(_ctypes.c_uint32), _ctypes.POINTER(_ctypes.c_void_p), _ctypes.POINTER(_ctypes.c_void_p), ) _SECURITY_KEYCHAIN_FIND_GENERIC_PASSWORD.restype = OS_RESULT # Bind SecKeychainAddGenericPassword from native MacOS # https://developer.apple.com/documentation/security/1398366-seckeychainaddgenericpassword?language=objc _SECURITY_KEYCHAIN_ADD_GENERIC_PASSWORD = _SECURITY.SecKeychainAddGenericPassword _SECURITY_KEYCHAIN_ADD_GENERIC_PASSWORD.argtypes = ( _ctypes.c_void_p, _ctypes.c_uint32, _ctypes.c_char_p, _ctypes.c_uint32, _ctypes.c_char_p, _ctypes.c_uint32, _ctypes.c_char_p, _ctypes.POINTER(_ctypes.c_void_p), ) _SECURITY_KEYCHAIN_ADD_GENERIC_PASSWORD.restype = OS_RESULT class Keychain(object): """Encapsulates the interactions with a particular MacOS Keychain.""" def __init__(self, filename=None): # type: (str) -> None self._ref = _ctypes.c_void_p() if filename: filename = os.path.expanduser(filename) self._filename = filename.encode('utf-8') else: self._filename = None def __enter__(self): if self._filename: status = _SECURITY_KEYCHAIN_OPEN(self._filename, self._ref) else: status = _SECURITY_KEYCHAIN_COPY_DEFAULT(self._ref) if status: raise OSError(status) return self def __exit__(self, *args): if self._ref: _CORE_RELEASE(self._ref) def get_generic_password(self, service, account_name): # type: (str, str) -> str """Fetch the password associated with a particular service and account. :param service: The service that this password is associated with. :param account_name: The account that this password is associated with. :return: The value of the password associated with the specified service and account. """ service = service.encode('utf-8') account_name = account_name.encode('utf-8') length = _ctypes.c_uint32() contents = _ctypes.c_void_p() exit_status = _SECURITY_KEYCHAIN_FIND_GENERIC_PASSWORD( self._ref, len(service), service, len(account_name), account_name, length, contents, None, ) if exit_status: raise KeychainError(exit_status=exit_status) value = _ctypes.create_string_buffer(length.value) _ctypes.memmove(value, contents.value, length.value) _SECURITY_KEYCHAIN_ITEM_FREE_CONTENT(None, contents) return value.raw.decode('utf-8') def set_generic_password(self, service, account_name, value): # type: (str, str, str) -> None """Associate a password with a given service and account. :param service: The service to associate this password with. :param account_name: The account to associate this password with. :param value: The string that should be used as the password. """ service = service.encode('utf-8') account_name = account_name.encode('utf-8') value = value.encode('utf-8') entry = _ctypes.c_void_p() find_exit_status = _SECURITY_KEYCHAIN_FIND_GENERIC_PASSWORD( self._ref, len(service), service, len(account_name), account_name, None, None, entry, ) if not find_exit_status: modify_exit_status = _SECURITY_KEYCHAIN_ITEM_MODIFY_ATTRIBUTES_AND_DATA( entry, None, len(value), value, ) if modify_exit_status: raise KeychainError(exit_status=modify_exit_status) elif find_exit_status == KeychainError.ITEM_NOT_FOUND: add_exit_status = _SECURITY_KEYCHAIN_ADD_GENERIC_PASSWORD( self._ref, len(service), service, len(account_name), account_name, len(value), value, None ) if add_exit_status: raise KeychainError(exit_status=add_exit_status) else: raise KeychainError(exit_status=find_exit_status) def get_internet_password(self, service, username): # type: (str, str) -> str """ Fetches a password associated with a domain and username. NOTE: THIS IS NOT YET IMPLEMENTED :param service: The website/service that this password is associated with. :param username: The account that this password is associated with. :return: The password that was associated with the given service and username. """ raise NotImplementedError() def set_internet_password(self, service, username, value): # type: (str, str, str) -> None """Sets a password associated with a domain and a username. NOTE: THIS IS NOT YET IMPLEMENTED :param service: The website/service that this password is associated with. :param username: The account that this password is associated with. :param value: The password that should be associated with the given service and username. """ raise NotImplementedError()