Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating Keychain Item with type 'Web Form Password' on Mac OS X

I'm working on an application where when a user selects a menu item they are brought to a webpage. The webpage requires authentication, and to make things simpler for the user I would like to pass along their authentication information to Safari/Firefox/Chrome that is stored in my application.

I've tried creating generic and internet keychain items, which show up beautifully in Keychain Access, but no web browsers pick up on them.

I've noticed that the keychain items being stored for the browsers have the type "Web Form Password".

When I try to create a keychain item with the type 'kSecAuthenticationTypeHTMLForm' it shows in Keychain Access as 'internet password'. I've modified some code from the EMKeychain class:

+ (EMInternetKeychainItem *)addInternetKeychainItemForServer:(NSString *)server
                                            withUsername:(NSString *)username
                                                password:(NSString *)password
                                                    path:(NSString *)path
                                                    port:(NSInteger)port
                                                protocol:(SecProtocolType)protocol
{
if (!username || !server || !password)
    return nil;

const char *serverCString = [server UTF8String];
const char *usernameCString = [username UTF8String];
const char *passwordCString = [password UTF8String];
const char *pathCString = [path UTF8String];

if (!path || [path length] == 0)
    pathCString = "";

SecKeychainItemRef item = nil;
OSStatus returnStatus = SecKeychainAddInternetPassword(NULL, strlen(serverCString), serverCString, 0, NULL, strlen(usernameCString), usernameCString, strlen(pathCString), pathCString, port, protocol, kSecAuthenticationTypeHTMLForm, strlen(passwordCString), (void *)passwordCString, &item);

if (returnStatus != noErr || !item)
{
    if (_logsErrors)
        NSLog(@"Error (%@) - %s", NSStringFromSelector(_cmd), GetMacOSStatusErrorString(returnStatus));
    return nil;
}
return [EMInternetKeychainItem _internetKeychainItemWithCoreKeychainItem:item forServer:server username:username password:password path:path port:port protocol:protocol];
}
like image 799
joshbillions Avatar asked Dec 17 '22 08:12

joshbillions


1 Answers

The most likely problem is that the keychain entry is created with an ACL that does not give access to its contents to Safari. (I think Chrome and Firefox use their own proprietary password databases instead of the keychain, so modifying the keychain won't affect those browsers.)

Try using SecKeychainItemSetAccess to permit access to all applications. I use the following code to create such a permissive SecAccess object:

// Create an access object.
SecAccessRef access;
status = SecAccessCreate(CFSTR("item description"), 
                         NULL, // Only this app has access (this'll get changed in a moment)
                         &access);
if (status) { ... }

// Override access control to provide full access to all applications.
NSArray *aclList = nil;
status = SecAccessCopyACLList(access, (CFArrayRef *)&aclList);
if (status) { ... }
for (id object in aclList) { // will do just one iteration
    SecACLRef acl = (SecACLRef)object;

    CFArrayRef applist = NULL;
    CFStringRef desc = NULL;
    CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR cakps;

    status = SecACLCopySimpleContents(acl, &applist, &desc, &cakps);
    if (status)  { ... }

    status = SecACLSetSimpleContents(acl, 
                                     NULL, // All applications.
                                     desc,
                                     &cakps);
    if (status) { ... }

    if (applist != NULL)
        CFRelease(applist);
    if (desc != NULL)
        CFRelease(desc);
}
like image 106
Karoy Lorentey Avatar answered Jan 19 '23 01:01

Karoy Lorentey