Closed az-oolloow closed 2 years ago
I tried working around this by changing init()
like so:
FileProtectionHelper.shared.defaultMode = FileProtectionType.completeUntilFirstUserAuthentication.rawValue
KeychainHelper.setAccessibleAttribute(.afterFirstUnlock)
SFKeychainItemWrapper.setAccessibleAttribute(kSecAttrAccessibleAfterFirstUnlock)
MobileSyncSDKManager.initializeSDK()
(just changing FileProtectionHelper.shared.defaultMode
is not enough because then SmartStore
can't access keychain to get decryption key and it promptly deletes the sqlite file 🤦♂️)
However, this causes the following log when app is launched in the background:
2391 error 17:14:23.220890+1100 logoutRepro CLASS: SFGeneratedKeyStore Error saving key com.salesforce.keystore.generatedKeystoreKeychainId_store to the keychain.
115 default 17:14:23.221796+1100 securityd insert failed for item <genp,acct=3MVG9G9pzCUSkzZsYYhywRx6_tAGvwMYaCWnrEbAtcEhExreYyj7nOrfHua1fw9Bs9AN8zJxbOxmsQ4_l4Il6-203134478,svce=com.salesforce.oauth.access,agrp=8498Z5DRCR.com.myteamid.testme.logoutRepro,sync=0,musr=, |otherAttr,tomb=0,cdat=2021-10-20 06:14:23 +0000,mdat=2021-10-20 06:14:23 +0000,crtr=com.salesforce.mobilesdk,pdmn=aku,sha1=C8228E03E0ABF46AD1AFC8DE5163C9CBFA079EF6,UUID=64965DEB-6B05-475A-B001-40137364CFB3,persistref=7AB2C6315E7E490197B7132D6ED8AE0C,clip=0> with Error Domain=NSOSStatusErrorDomain Code=-25308 "ks_crypt: e00002e2 failed to 'od' item (class 9, bag: 0) Access to item attempted while keychain is locked." UserInfo={numberOfErrorsDeep=0, NSDescription=ks_crypt: e00002e2 failed to 'od' item (class 9, bag: 0) Access to item attempted while keychain is locked.}
115 default 17:14:23.221848+1100 securityd logoutRepro[2391]/1#4 LF=0 add Error Domain=NSOSStatusErrorDomain Code=-25308 "ks_crypt: e00002e2 failed to 'od' item (class 9, bag: 0) Access to item attempted while keychain is locked." UserInfo={numberOfErrorsDeep=0, NSDescription=ks_crypt: e00002e2 failed to 'od' item (class 9, bag: 0) Access to item attempted while keychain is locked.}
2391 error 17:14:23.222042+1100 logoutRepro CLASS: SFOAuthKeychainCredentials Could not read com.salesforce.oauth.access from keychain, Error Domain=com.salesforce.security.keychainException Code=-25308 "User interaction is not allowed." UserInfo={NSLocalizedDescription=User interaction is not allowed., com.salesforce.security.keychainException.errorCode=-25308}
115 default 17:14:23.224015+1100 securityd logoutRepro[2391]/1#4 LF=0 update Error Domain=NSOSStatusErrorDomain Code=-25308 "ks_crypt: e00002e2 failed to 'od' item (class 9, bag: 0) Access to item attempted while keychain is locked." UserInfo={numberOfErrorsDeep=0, NSDescription=ks_crypt: e00002e2 failed to 'od' item (class 9, bag: 0) Access to item attempted while keychain is locked.}
2391 error 17:14:23.224128+1100 logoutRepro CLASS: SFGeneratedKeyStore Error saving key com.salesforce.keystore.generatedKeystoreKeychainId_store to the keychain.
115 default 17:14:23.225025+1100 securityd insert failed for item <genp,acct=3MVG9G9pzCUSkzZsYYhywRx6_tAGvwMYaCWnrEbAtcEhExreYyj7nOrfHua1fw9Bs9AN8zJxbOxmsQ4_l4Il6-203134478,svce=com.salesforce.oauth.refresh,agrp=8498Z5DRCR.com.myteamid.testme.logoutRepro,sync=0,musr=, |otherAttr,tomb=0,cdat=2021-10-20 06:14:23 +0000,mdat=2021-10-20 06:14:23 +0000,crtr=com.salesforce.mobilesdk,pdmn=aku,sha1=54EB5DAD11FFBA978517ED6DEA2F846F21DEA55E,UUID=D15EC88E-F349-4ECB-BA58-8C438F34A78C,persistref=9FF4E3D021E94BFB93C2ECB3379D23A6,clip=0> with Error Domain=NSOSStatusErrorDomain Code=-25308 "ks_crypt: e00002e2 failed to 'od' item (class 9, bag: 0) Access to item attempted while keychain is locked." UserInfo={numberOfErrorsDeep=0, NSDescription=ks_crypt: e00002e2 failed to 'od' item (class 9, bag: 0) Access to item attempted while keychain is locked.}
115 default 17:14:23.225267+1100 securityd logoutRepro[2391]/1#4 LF=0 add Error Domain=NSOSStatusErrorDomain Code=-25308 "ks_crypt: e00002e2 failed to 'od' item (class 9, bag: 0) Access to item attempted while keychain is locked." UserInfo={numberOfErrorsDeep=0, NSDescription=ks_crypt: e00002e2 failed to 'od' item (class 9, bag: 0) Access to item attempted while keychain is locked.}
2391 error 17:14:23.225399+1100 logoutRepro CLASS: SFOAuthKeychainCredentials Could not read com.salesforce.oauth.refresh from keychain, Error Domain=com.salesforce.security.keychainException Code=-25308 "User interaction is not allowed." UserInfo={NSLocalizedDescription=User interaction is not allowed., com.salesforce.security.keychainException.errorCode=-25308}
115 default 17:14:23.255494+1100 securityd logoutRepro[2391]/1#4 LF=0 update Error Domain=NSOSStatusErrorDomain Code=-25308 "ks_crypt: e00002e2 failed to 'od' item (class 9, bag: 0) Access to item attempted while keychain is locked." UserInfo={numberOfErrorsDeep=0, NSDescription=ks_crypt: e00002e2 failed to 'od' item (class 9, bag: 0) Access to item attempted while keychain is locked.}
2391 error 17:14:23.255548+1100 logoutRepro CLASS: SFGeneratedKeyStore Error saving key com.salesforce.keystore.generatedKeystoreKeychainId_store to the keychain.
This is using the same default forceios
app with 9.2.0 SDK.
Interestingly pdmn=aku
in the log suggests that even despite my changes, somewhere
in the SDK the default access level is used (kSecAttrAccessibleAfterFirstUnlock
would be ck
)
Having the same error. Any updates?
@dLiubchenko we're working on this now and will post when we have more info
@bbirman, thank you for answer! BTW, we are facing with this problem on Hybrid application too
FWIW until we hear back from @bbirman or the team we are staying on our fork of 8.3 SDK where the new keychain class doesn't exist so this can be worked around via:
Upgrade flag to reset the file protection to e.g. completeUntilFirstUserAuthentication
like so:
if let r = SFDirectoryManager.shared().directory(forUser: nil, type: .libraryDirectory, components: nil) {
SFPathUtil.secureFile(atPath: r, recursive: true, fileProtection: FileProtectionType.completeUntilFirstUserAuthentication.rawValue)
}
FileProtectionHelper
default mode to match BEFORE you init the SDK
FileProtectionHelper.shared.defaultMode = FileProtectionType.completeUntilFirstUserAuthentication.rawValue
SFKeychainItemWrapper
accessible attribute like so
SFKeychainItemWrapper.setAccessibleAttribute(kSecAttrAccessibleAfterFirstUnlock)
After this we have no issues with the app launching in the background.
@bbirman @az-oolloow any ETA for this issue to be fixed?
@az-oolloow Could you please provide more detail about in which files you made these changes? We are using 9.1 and so I don't know if that makes a difference.
@pushp1010 I do not work for Salesforce, so can only suggest workarounds like I did for the above, and as mentioned I could not get it to work with 9.2.0.
@MattSynaptic I am on 8.3 so I don't know whether my fix will work for you. It did not solve the issue fully in 9.2 as the new Keychain access class written in Swift by the SDK team just doesn't behave.
Basically, somewhere in your app you would have MobileSyncSDKManager.initializeSDK()
or equivalent (e.g. in AppDelegate
)
You would add the code I specified before you init the SDK.
If you already have users in the field it is prudent to do the steps 1 (where we call secureFile
) and 3 (where we call setAccessibleAttribute
) when UIApplication.shared.isProtectedDataAvailable
The best way to migrate (for OUR app, not sure it this applies to yours)
UIApplication.shared.isProtectedDataAvailable
. If not, exit the app delegate init.
If isProtectedDataAvailable is true, migrate file and keychain permissions, set flag in userdefaults, init sdk, set the variable to true.application: didFinishLaunchingWithOptions
check if the variable is set. If yes, do nothing other than whatever your app normally does.
If sdk has not been inited, check if UIApplication.shared.isProtectedDataAvailable
. If not, throw a hissy fit. (this is a dead end, but I never had anyone hit it. I just display an empty VC here).
If isProtectedDataAvailable is true, migrate file and keychain permissions, set flag in userdefaults, init sdk, set the variable to true. (this is same as what you'd do in AppDelegate init).This logic handles cases where you have new installs as well as people upgrading to new version of your app and makes sure all the things are accessible correctly.
FYI @bbirman has merged a PR fix and I have made a clarifying comment there: https://github.com/forcedotcom/SalesforceMobileSDK-iOS/pull/3447#issuecomment-982654888
Please fill out the following details:
forceios
npm package method, 8.3.0 with legacy migration removed (also confirmed the code is the same in latestdev
branch)Connect the device to the mac Open Console In the console, filter by
Any
AppName
Build an app using SF SDK Login Make sure device has passcode/faceid/touch id Kill the app Lock the screen Wait until iOS wakes up your app in the background (typically under 30 minutes, I found no way to speed this up, sometimes launching and killing the app rapidly a few times causes iOS to decide to re-launch it just 1 minute after you killed it and sometimes it does take over 30 minutes). The symbol of this is the following log:(you can see full log below, basically there will be a lot of messages, > 20 with the specified filter settings) Open the app again
Actual behavior: User is logged out and is presented with a 'please log in'
Expected Behavior: User is not logged out
Analysis:
This issue stems from the fact that
SFDefaultUserAccountPersister
savesUserAccount.plist
usingNSFileProtectionType.NSFileProtectionComplete
(which is really weird because on top of OS encryption SDK already uses it's own AES encryption so this like...extra protection
?)It seems that Apple made some changes in iOS 15 that cause the app to be launched more frequently in the background (?) and this happens.
You can see it clearly in the log here:
2247 default 14:14:22.961899+1100 logoutRepro CLASS: SFDefaultUserAccountPersister User account data could not be decrypted. Can't load account.
Here's where the
protection
is specified for the file: https://github.com/forcedotcom/SalesforceMobileSDK-iOS/blob/dev/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFDefaultUserAccountPersister.m#L219Here's where the encrypted file is actually nil when you do
MobileSyncSDKManager.initializeSDK()
in the background: https://github.com/forcedotcom/SalesforceMobileSDK-iOS/blob/dev/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFDefaultUserAccountPersister.m#L233When this happens,
SFDefaultUserAccountPersister
simply deletesUserAccount.plist
file, which is then not found on next app launch, and so user is prompted to log in again.Note: we didn't even need to specify any background modes for this to happen