Open jeff-h opened 6 years ago
@jeff-h Command line toon doesn't have a bundle. You cannot embed dynamic framework as well as general applications. The simple way to solve it is that you link statically with your app. Just drag and drop KeychainAccess.swift to your project.
Thanks! That's actually exactly what I did in order to get KeychainAccess into my command line tool. It works well.
The issue I'm describing above is different though; both the main app and the command line tool do have access to the keychain thanks to KeychainAccess, but my issue is with getting them to share the same keychain items, without requiring the user to enter their keychain password to unlock the keychain item.
For example, the main app will ask the user for a password to access a remote server. For unrelated reasons, I need my command line tool to have access to that exact same password. I can get the command line tool to access it, but when I do, it pops up the auth dialog as pictured above.
Did you ever get this working? I've got the same dilemma.
Unfortunately not. I've wondered if it's because I don't have a paid Apple developer account — kind of hoping that when I get one this problem might go away. Is this possibly the cause in your case?
Oh, well... I do have a paid account. It doesn't seem to make a difference. Thanks!
Rats, so much for that theory then. Please let me know if you find anything else related to this issue!
How did this go? Having the same issue. However I suspect it’s hard to do. The main purpose of keychain is to protect passwords from apps stealing passwords.
Still no solution here.
Static linking is one of the solutions. Use Swift Package Manager.
@kishikawakatsumi just to clarify, this issue is not about how to include KeychainAccess in a command line tool. I've statically linked the Keychain.swift
into my command line code from the start and it works fine, with one major exception:
The command line tool, despite being embedded into the primary app (and 'Keychain Sharing" configured) does not give seamless access to the keychain items created by the app. When the command line tool requests an item that the main app created, it pops up the auth dialog.
I'll see if I can put together a tiny demo app to illustrate the issue.
OK, I have finally put together a demo of the problem: https://github.com/jeff-h/sharedKeychainAccessDemo
There are three components:
KeychainOne: this app saves two entries into the Keychain and marks them as synchronizable(true)
*
KeychainTwo: this app retrieves the two entries from the Keychain (that were added by KeychainOne). This works perfectly.
KeychainTwo also embeds a Command Line Tool (see below) which it runs, and prints the output.
CommandLineTool: this attempts to retrieves the same two entries from the Keychain. However, this never succeeds.
I'm hoping you might have a chance to compile the sample apps, and see if you can see what I am missing.
^ this was key to getting access groups to work between two apps on macOS; I finally discovered the following in these Apple Docs: "kSecAttrAccessGroup (iOS; also macOS if kSecAttrSynchronizable specified)"
@jeff-h This reply is probably too late, but I did some digging with the goal to get a better understanding on how the keychain works.
I have come to the conclusion that what you want is not possible.
Let me take you through my observations:
In KeychainOne you write the keychain items with synchronizable
set to true
This makes that the items are written to the keychain iCloud
The items are written with an accessGroup
In order to read from the iCloud the keychain-acccess-group
must be set. This is a property that is inserted into your application using codesign
. You can actually view those properties using codesign:
codesign -d --entitlements :- ~/Library/Developer/Xcode/DerivedData/KeychainOne-afabdbcccjdiuvcbtmjqjhxeqchu/Build/Products/Debug/KeychainOne.app
which then produces the following output:
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.application-identifier</key>
<string>2XJSMU4L5Z.com.marmaladesoul.KeychainOne</string>
<key>com.apple.developer.team-identifier</key>
<string>2XJSMU4L5Z</string>
<key>com.apple.security.application-groups</key>
<string>2XJSMU4L5Z.com.marmaladesoul.appgroup</string>
<key>com.apple.security.get-task-allow</key>
<true/>
<key>keychain-access-groups</key>
<array>
<string>2XJSMU4L5Z.com.marmaladesoul.shared</string>
</array>
</dict>
</plist>
Note the keychain-access-groups
. It lists the groups that this application has access to. (I changed the name of the access group because of experiments but that can be ignored)
If you check the output from KeychainTwo.app
you will see a similar result. Just a different com.apple.application-identifier
value.
Then check the output from the CommandLineTool
:
codesign -d --entitlements :- ~/Library/Developer/Xcode/DerivedData/KeychainOne-afabdbcccjdiuvcbtmjqjhxeqchu/Build/Products/Debug/CommandLineTool
which then produces the following output:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.get-task-allow</key>
<true/>
</dict>
</plist>
As you can see it lacks the keychain-access-groups
.
As a result it will never be able to read the value of the password. In fact this link seems to suggest that accessing the iCloud keychain from the command line will never work.
So if you want to share the passwords between the 3 applications your only option is to set the synchronizable
value to false
in KeychainOne.app
. If you do this you will see that your command line tool will print the passwords.
Thanks for your research! It's never too late, but unfortunately I've forgotten the details about all this. When I circle back to it in future I will definitely trace through your comment and hopefully make sense of things.
My macOS app stores server credentials in the keychain using KeychainAccess, and this works perfectly.
I also have written a command line tool, which is embedded into the app's bundle. I'd like this tool to also have access to the passwords stored in the Keychain by the main app.
HOWEVER, for the life of me I cannot get the two to share access to the same keychain items. The command-line tool always pops up the "auth dialog":
I suspect my code is correct. In both the main app and the tool, the following does give me access to the password data from the keychain:
I am guessing my problem is in the configuration of the two projects in Xcode. For the macOS app, I have "app target > Capabilities > Keychain Sharing" turned on, and the keychain group it generated there is what's used in the code above (
24F6D23HXS.com.obfuscated.app-name
). Turning this on also caused a provisioning profile to be generated, which seems fine.However, the target settings for the command line tool has no Capabilities section, so I can't turn on "Keychain Sharing". Also there's no apparent way to select the provisioning profile the macOS app is using (not sure if I need to do this or not).
Can anyone give me any pointers on how to get this working?