-
-
Notifications
You must be signed in to change notification settings - Fork 160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MacOS "Internet password" keychain items #624
Comments
Actually, I see the problem - cfstr_to_str is actually dealing with converting the CFData that is represented by "kSecValueData", not CFstring, and the name mislead me. I found some ancient but still useful stuff at https://github.com/mountainstorm/MobileDevice/blob/41645fd0e7e3e674f0e963daaa374e3f44f18d67/CoreFoundation.py and have something that can get the attributes of a "kSecClassInternetPassword". I might try and clean it up and submit something as a suggestion if I ever get a chance. |
Here is a working stand-alone version of the above code: from keyring.backends.macOS import api
CFTypeRef = api.c_void_p
CFDictionaryRef = api.c_void_p
CFDictionaryGetValue = api._found.CFDictionaryGetValue
CFDictionaryGetValue.restype = CFTypeRef
CFDictionaryGetValue.argtypes = [CFDictionaryRef, CFTypeRef]
def find_internet_password(server, protocol, username, not_found_ok=False):
# https://developer.apple.com/documentation/security/keychain_services/keychain_items/searching_for_keychain_items?language=objc
q = api.create_query(
kSecClass=api.k_('kSecClassInternetPassword'),
kSecMatchLimit=api.k_('kSecMatchLimitOne'),
kSecAttrServer=server,
kSecAttrProtocol=protocol,
kSecAttrAccount=username,
kSecReturnAttributes=api.create_cfbool(True),
kSecReturnData=api.create_cfbool(True),
)
data = api.c_void_p()
status = api.SecItemCopyMatching(q, api.byref(data))
if status == api.error.item_not_found and not_found_ok:
return
api.Error.raise_for_status(status)
password = CFDictionaryGetValue(data, api.k_('kSecValueData'))
password = api.cfstr_to_str(password)
return password
password = find_internet_password('http://proxy.com', 'htpx', 'username')
print(password) |
This is very useful in automatically getting proxy credentials from the machine. As a workaround, one can simply call: |
Nice work. I'm very interested in providing a more complete interface. I'd very much like to build up the API module and possibly expose some of that through the Keyring (there's a mechanism by which environment variables can set properties on a keyring and thus affect behavior, so e.g. something like I recommend to start with expanding the APIs to support the functionality as best as possible and second to capture what are the use-cases that we're trying to support (do we want this to work with the CLI ( |
For anyone who ends up here on a similar search: just a big heads-up that the underlying macOS CLI tool, The implementation above does provide value as it finds internet passwords from the login keychain (or any other local keychain), but if we were ever to support iCloud Keychain as well, it sounds like it would have to involve some GUI-based flow. |
I was hoping to use keyring to retrieve existing internet passwords on the MacOS keychain for things like ssh server passwords, etc. It looks like keyring deals with "application password" items ("kSecClassGenericPassword"), and can't retrieve "Internet password" items ("kSecClassInternetPassword"). I came up with a variation on your routine, and while I was at it, thought I'd try and retrieve the attributes on the item as well, by setting "kSecReturnAttributes" in the query as well.
It seemed to work - I apparently get the promised CFDictionary back, and I cobbled together a CFDictionaryGetValue() routine from other sources. I can get the item data value (the password) from the dictionary entry "kSecValueData", and convert it as you do with cfstr_to_str(). But while I can successfully retrieve other keys like "kSecAttrServer", which should be the name of the server and also a CFString, cfstr_to_str() crashes with "[__NSCFString bytes]: unrecognized selector sent to instance", so it doesn't seem to be a CFString as expected, or something?
I don't really know the MacOS APIs (at least since MacOS 9 or so), and I may be missing something obvious between that and the whole coercing into Python, so I thought I'd check if anyone here might have an idea.
Also, while the keyring API doesn't seem to be set up to handle multiple flavours of passwords like this, would there be any interest in having the macOS.api have superset functions that can handle some of the other types as a convenience for MacOS folks?
The text was updated successfully, but these errors were encountered: