Posts

Post not yet marked as solved
1 Replies
285 Views
I am integrating Apple's iOS implementation of WebAuthN using the ASAuthorization APIS provided by Apple. I am integrating with the Django py_webauthn host backend. I have the entire registration & account creations process working. And I almost have the account authentication process working. But there seems to be an issue between the version of authenticationData generated by iOS subsequent to the client (iPhone) authentication process and what py_webauthn is expecting. It results in a consistent "Leftover bytes detected while parsing authentication data" error on the host. According to the documentation, this error is generated when all the authenticatorData has been parsed but there are leftover bytes in the data. I believe if I get past this issue everything will be working. I could use some help here and provide code/logs below. But in the hopes that someone from the Authentication development team at Apple is watching for these posts, I have a related question. Can we assume that the generated private key AND sign_count data is shared across an iOS user's devices through KeyChain cloud? Do we have to advise our users that they should enable this?? Here is code (OBJ C) and logs, in the hopes that someone can advise... and hoping that the code can help others trying to implement this capability. Thanks..... iPhone Client - (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization //Check to make sure that we are authenticating user after receiving authorization challenge from host NSLog(@"%s retrieve public/private key",__FUNCTION__); NSDictionary *pubKeyDict = [NSDictionary dictionary]; ASAuthorizationPlatformPublicKeyCredentialAssertion *appleCred = (ASAuthorizationPlatformPublicKeyCredentialAssertion *)authorization.credential; NSDictionary *clientJSON = [NSJSONSerialization JSONObjectWithData:appleCred.rawClientDataJSON options:NSJSONReadingMutableContainers error:nil]; NSLog(@"%s clientJSON = %@",__FUNCTION__,clientJSON); NSString *clientJSONString = [ServerUtilities encodeBase64URLData:appleCred.rawClientDataJSON]; NSString *authenticatorString = [ServerUtilities encodeBase64URLData:appleCred.rawAuthenticatorData]; NSString *signatureString = [ServerUtilities encodeBase64URLData:appleCred.signature]; NSDictionary *respDict = [NSDictionary dictionaryWithObjectsAndKeys clientJSONString, @"clientDataJSON", authenticatorString, @"signature", signatureString, @"authenticatorData", nil]; NSLog(@"%s respDict - %@",__FUNCTION__,respDict); NSString *credIDString = [ServerUtilities encodeBase64URLData:appleCred.credentialID]; NSDictionary *regDict = [NSDictionary dictionaryWithObjectsAndKeys: credIDString, @"id", respDict, @"response", @"public-key",@"type", nil]; pubKeyDict = [NSDictionary dictionaryWithObjectsAndKeys: credentialEmail, kEMAIL, regDict, @"auth_cred", nil]; NSLog(@"%s pubKeyDict - %@",__FUNCTION__,pubKeyDict); //Post JSON serialized version of pubKeyDict to host Xcode log pubKeyDict - { "auth_cred" = { id = "JNMBbZF_PQM7O64RY_MXQqhAyKk"; response = { authenticatorData = "MEYCIQDgVFINihy9nPuuRrZWkLPahEfLy3huCV9_seOuM5gSlgIhAP_99EVQjXhyJy37ccRxQenSxt7oPNrQ4VjVDSW5Ej8l"; clientDataJSON = eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoidkhYcTdKTG05Z2dNU1BienNpZThFWUJsVW16V2N3WXlvOFBnT0FKMlR1b0VBbGVBbkQ0NGFNVDg3RG93YnZaZUNxLWxTdC1uNTFkUWJpVzgxNVhZRlEiLCJvcmlnaW4iOiJodHRwczovL2FuY2hvci1hd2F5LmNvbSJ9; signature = "WJ3tJNMYfNST99x-EAdNDrnsUOCxqFzvDgXCyTcTg6sdAAAAAA"; }; type = "public-key"; }; email = "my@email.com"; } Django Python Host auth_cred_json - {'id': 'JNMBbZF_PQM7O64RY_MXQqhAyKk', 'response': {'clientDataJSON': 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoidkhYcTdKTG05Z2dNU1BienNpZThFWUJsVW16V2N3WXlvOFBnT0FKMlR1b0VBbGVBbkQ0NGFNVDg3RG93YnZaZUNxLWxTdC1uNTFkUWJpVzgxNVhZRlEiLCJvcmlnaW4iOiJodHRwczovL2FuY2hvci1hd2F5LmNvbSJ9', 'signature': 'WJ3tJNMYfNST99x-EAdNDrnsUOCxqFzvDgXCyTcTg6sdAAAAAA', 'authenticatorData': 'MEYCIQDgVFINihy9nPuuRrZWkLPahEfLy3huCV9_seOuM5gSlgIhAP_99EVQjXhyJy37ccRxQenSxt7oPNrQ4VjVDSW5Ej8l'}, 'type': 'public-key', 'rawId': 'JNMBbZF_PQM7O64RY_MXQqhAyKk'} AuthorizationCredential generated by 'parse_authentication_credential_json' id='JNMBbZF_PQM7O64RY_MXQqhAyKk' raw_id=b'$\\xd3\\x01m\\x91\\x7f=\\x03;;\\xae\\x11c\\xf3\\x17B\\xa8@\\xc8\\xa9' response=AuthenticatorAssertionResponse( client_data_json=b'{ "type":"webauthn.get", "challenge":"vHXq7JLm9ggMSPbzsie8EYBlUmzWcwYyo8PgOAJ2TuoEAleAnD44aMT87DowbvZeCq-lSt-n51dQbiW815XYFQ", "origin":"https://anchor-away.com" }', authenticator_data=b"0F\\x02!\\x00\\xe0TR\\r\\x8a\\x1c\\xbd\\x9c\\xfb\\xaeF\\xb6V\\x90\\xb3\\xda\\x84G\\xcb\\xcbxn\\t_\\x7f\\xb1\\xe3\\xae3\\x98\\x12\\x96\\x02!\\x00\\xff\\xfd\\xf4EP\\x8dxr'-\\xfbq\\xc4qA\\xe9\\xd2\\xc6\\xde\\xe8<\\xda\\xd0\\xe1X\\xd5\\r%\\xb9\\x12?%", signature=b'X\\x9d\\xed$\\xd3\\x18|\\xd4\\x93\\xf7\\xdc~\\x10\\x07M\\x0e\\xb9\\xecP\\xe0\\xb1\\xa8\\\\\\xef\\x0e\\x05\\xc2\\xc97\\x13\\x83\\xab\\x1d\\x00\\x00\\x00\\x00', user_handle=None )
Posted
by eric_s.
Last updated
.
Post not yet marked as solved
1 Replies
426 Views
From a strategy perspective I use BGAppRefreshTask and BGProcessingTasks, successfully implementing them for events triggered within the client application. But there are certain events that are best triggered from the host, such as when we deploy a new set of vendor or price lists. We are trying to implement this background process using Push Notifications. We have successfully implemented sending APNS notifications from the host and receive this .json message in. application: didReceiveRemoteNotification: fetchCompletionHandler: using this code: - (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler { NSLog(@"userInfo - %@", userInfo); switch (application.applicationState) { case UIApplicationStateBackground: { //Check to see if this is a configs file update background notification NSArray *dictKeys = [userInfo allKeys]; BOOL foundConfigs = NO; for (NSString *dk in dictKeys) if ([dk isEqualToString:kCONFIGSVERSION]) foundConfigs = YES; if (foundConfigs) { id configVersion = [userInfo objectForKey:kCONFIGSVERSION]; NSLog(@"AAAppDelegate configVersion - %@", configVersion); if ([ServerUtilities deviceAssociatedWithAccount]) [self.bkSessionManager retrieveAndInstallUpdatedConfigFilesWithVersion:[configVersion integerValue]]; } NSLog(@"AAAppDelegate remote notification handler"); completionHandler(UIBackgroundFetchResultNewData); } break; case UIApplicationStateActive: NSLog(@"AAAppDelegate application is active"); completionHandler(UIBackgroundFetchResultNoData); break; case UIApplicationStateInactive: NSLog(@"AAAppDelegate application is inactive"); completionHandler(UIBackgroundFetchResultNoData); break; default: break; } In the Xcode simulator running on an iPhone XS, we place the application in background and then send the APNS message from the host, receiving this .json message in the userInfo dictionary: userInfo - { "app_version" = "0.1"; aps = { "content-available" = 1; }; "configs_version" = 1; "dev_os" = 13; "os_type" = ios; } Receipt of this notification then triggers the client to initiate URLSession and retrieve the appropriate files from the host in order to update values on the client. As we are seeing inconsistent behavior we suspect that we are not implementing the URLSession properly. When setting up the URLSession should it be configured using: NSURLSessionConfiguration defaultSessionConfiguration or NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier: ? This is important to know since using backgroundSession requires us to set up the sessions as download tasks and the defaultSession as data tasks. I have tried various combinations so far without success. Any leads here will help...
Posted
by eric_s.
Last updated
.