I’ve been attempting to implement Keychain services for iOS because there has been some interest in it, and I see it as something I will probably need in the future, however I have reached an impasse because I cannot determine what value to use for the constant kCFBooleanTrue, which represents the true value for a CFBoolean. Using the Swift playground, and code:
import CoreFoundation
var tmp = kCFBooleanTrue
print(tmp)
I get an output of “1” indicating that kCFBooleanTrue should have a value of 1, however using a value of 1, an error is logged in the console:
Jan 5 19:22:17 s-kingj.local securityd[8344]: securityd_xpc_dictionary_handler My iOS App.debug[62140] copy_matching The operation couldnt be completed. (OSStatus error -50 - add_return: value 1 is not CFBoolean)
Determining the value of kCFBooleanTrue is the last step in my Keychain services implementation, but also the most important since it is required to retrieve a password stored on the keychain. Any help with this would be appreciated.
Looks to me like it’s actually a pointer to a structure.
I think you might have to implement a function that returns the boolean value you want.
Check out CFNumber.h and follow the rabbit hole from there. Good luck. My head started hurting when I realized I need to look in multiple header files to figure this out. Maybe something is already implemented for NSBoolean in MacOS lib you could pull from. I didn’t check.
declare sub setObjectForKey lib FoundationLib selector "setObject:forKey:" (obj_id as ptr, obj as ptr, key as CFStringRef)
declare function NSClassFromString lib FoundationLib (clsName as CFStringRef) as ptr
Declare Function numberWithBool lib "Cocoa" selector "numberWithBool:" (class_ref as ptr,value as Boolean) as ptr
dim kcfbooleantrue as ptr=numberWithBool(NSClassFromString("NSNumber"),true)
setObjectForKey(dictRef, kcfbooleantrue, kSecReturnData)
It works exactly the same as the desktop keychain, except that I called the class JK_KeychainItem and the module KeychainServices incase Xojo adds keychain support so that there is no duplicate naming.
To save a password you create a new item and set the account name, label, or any other properties you want to, then call KeychainServices.AddPassword:
dim item as new KeychainServices.JK_KeychainItem
item.AccountName = "Foo"
KeychainServices.AddPassword(item,"Bar")
To retrieve a password, you create a new item, set the same properties you used to save the password, then retrieve the password with KeychainServices.FindPassword:
dim item2 as new KeychainServices.JK_KeychainItem
item2.AccountName = "Foo"
dim pswd as Text = KeychainServices.FindPassword(item2) //pswd is set to "Bar"
[quote=157409:@Jason King]It works exactly the same as the desktop keychain, except that I called the class JK_KeychainItem and the module KeychainServices incase Xojo adds keychain support so that there is no duplicate naming.
To save a password you create a new item and set the account name, label, or any other properties you want to, then call KeychainServices.AddPassword:
dim item as new KeychainServices.JK_KeychainItem
item.AccountName = "Foo"
KeychainServices.AddPassword(item,"Bar")
To retrieve a password, you create a new item, set the same properties you used to save the password, then retrieve the password with KeychainServices.FindPassword:
dim item2 as new KeychainServices.JK_KeychainItem
item2.AccountName = "Foo"
dim pswd as Text = KeychainServices.FindPassword(item2) //pswd is set to "Bar"[/quote]
I’m having a bit of trouble with this though I’m probably using it the wrong way.
I want to store my user’s username (accountname) and password in the keychain if they choose to have the app remember their login details. According to the docs it looks as though I should be able to do this but I only seem to be able to retrieve the password, not the accountname property.
When the user chooses “remember me” on my Login View, I save their username and password:
dim kc as new KeychainServices.JK_KeychainItem
kc.ServiceName = "myAppName"
kc.AccountName = User.Username
KeychainServices.AddPassword(kc, User.Password)
When my app next starts, I call FindPassword to find the keychain item and then access the AccountName property to retrieve the username:
dim kc as new KeychainServices.JK_KeychainItem
kc.ServiceName = "myAppName"
User.Password = KeychainServices.FindPassword(kc)
User.Username = kc.AccountName
However the AccountName property is always blank. The AddPassword method only seems to save the password and not the other properties, including AccountName.
Hi Jason, I made the project so it mimicked the Keychainitem we are used to for desktop. Unfortunately that means that the username cannot be saved as well as it is implemented. (I’m actually not sure if it’s possible to save the username anyway.) Maybe you could save the username and password as two separate items on the keychain?
Thanks and yes it “mimics” the desktop KeyChainItem partially, except that the desktop KeyChainItem allows saving of the additional KeyChainItem properties, such as the AccountName.
So if you add this code to a desktop app, both the AccountName and Password will be saved to the KeyChain:
[quote]'Save username and password
dim kc as new KeychainItem
kc.ServiceName = “myAppName”
kc.AccountName = “AppUser”
System.KeyChain.AddPassword(kc, “AppPassword”)
[/quote]
And then if you add this code to a desktop app, both the AccountName and Password will be returned from the KeyChain:
[quote]'Retrieve username and password
dim kc as new KeychainItem
kc.ServiceName = “myAppName”
dim passWord as string = System.Keychain.FindPassword(kc)
dim userName as string = kc.AccountName[/quote]
So while your implementation is able to save a password to the KeyChain, it seems to ignore the other properties of the KeyChainItem. These other properties make the KeyChainItem particularly useful as they allow you to save and retrieve all of a user’s login credentials if they choose to have these remembered by the app.
I updated the project so that it has the exact same functionality as the Desktop KeychainItem and will fill the properties of a passed KeychainItem when performing a lookup with KeychainServices.FindPassword(). Please redownload the project from the link below because there were substantial changes to the code. Enjoy!
Jason, I downloaded the file at the link above and the code doesn’t compile. It was no biggie to fix. Maybe you were testing something? I just wanted to put this here in case anyone else has the problem.
Putting this on View1 Open will work:
[code] using KeychainServices
dim item1 as new JK_KeychainItem
item1.ServiceName = “awesomeApp”
item1.AccountName = “username”
item1.Comment = “This is a comment”
item1.Description = “Username and password”
item1.Label = “Unlabeled”
KeychainServices.AddPassword item1, “password”
dim item2 as new JK_KeychainItem
item2.ServiceName = “awesomeApp”
dim thePassword as Text = KeychainServices.FindPassword(item2)
dim theAccountName as Text = Item2.AccountName
dim theComment as Text = Item2.Comment
dim theDescription as Text = Item2.Description
dim theLabel as Text = Item2.Label
dim theServiceName as Text = Item2.ServiceName