Skip to content

Commit dc45185

Browse files
authored
Fix keychain access issues caused by prewarming (#9622)
* Try listening to `UIApplicationProtectedDataDidBecomeAvailable`. * Handle platform availability. * More platform availability handling. * Fix static analysis issue. * Update changelog.
1 parent a2b3758 commit dc45185

File tree

2 files changed

+97
-49
lines changed

2 files changed

+97
-49
lines changed

FirebaseAuth/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# v9.0.0
22
- [fixed] **Breaking change:** Fixed an ObjC-to-Swift API conversion error where `getStoredUser(forAccessGroup:)` returned a non-optional type. This change is breaking for Swift users only (#8599).
3+
- [fixed] Fixed an iOS 15 keychain access issue related to prewarming. (#8695)
34

45
# v8.14.0
56
- [added] Started to collect the Firebase user agent for Firebase Auth. (#9066)

FirebaseAuth/Sources/Auth/FIRAuth.m

Lines changed: 96 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,12 @@ @implementation FIRAuth {
420420
UIApplicationDidEnterBackgroundNotification.
421421
*/
422422
id<NSObject> _applicationDidEnterBackgroundObserver;
423+
424+
/** @var _protectedDataDidBecomeAvailableObserver
425+
@brief An opaque object to act as the observer for
426+
UIApplicationProtectedDataDidBecomeAvailable.
427+
*/
428+
id<NSObject> _protectedDataDidBecomeAvailableObserver;
423429
}
424430

425431
+ (void)load {
@@ -485,65 +491,107 @@ - (nullable instancetype)initWithAPIKey:(NSString *)APIKey
485491
_firebaseAppName = [appName copy];
486492
#if TARGET_OS_IOS
487493
_settings = [[FIRAuthSettings alloc] init];
494+
495+
[GULAppDelegateSwizzler proxyOriginalDelegateIncludingAPNSMethods];
496+
[GULSceneDelegateSwizzler proxyOriginalSceneDelegate];
497+
#endif // TARGET_OS_IOS
498+
499+
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST
488500
static Class applicationClass = nil;
489501
// iOS App extensions should not call [UIApplication sharedApplication], even if UIApplication
490502
// responds to it.
491503
if (![GULAppEnvironmentUtil isAppExtension]) {
492504
Class cls = NSClassFromString(@"UIApplication");
493-
if (cls && [cls respondsToSelector:NSSelectorFromString(@"sharedApplication")]) {
505+
if (cls && [cls respondsToSelector:@selector(sharedApplication)]) {
494506
applicationClass = cls;
495507
}
496508
}
497509
UIApplication *application = [applicationClass sharedApplication];
498-
499-
[GULAppDelegateSwizzler proxyOriginalDelegateIncludingAPNSMethods];
500-
[GULSceneDelegateSwizzler proxyOriginalSceneDelegate];
501-
#endif // TARGET_OS_IOS
502-
503-
// Continue with the rest of initialization in the work thread.
504-
__weak FIRAuth *weakSelf = self;
505-
dispatch_async(FIRAuthGlobalWorkQueue(), ^{
506-
// Load current user from Keychain.
507-
FIRAuth *strongSelf = weakSelf;
508-
if (!strongSelf) {
509-
return;
510-
}
511-
NSString *keychainServiceName =
512-
[FIRAuth keychainServiceNameForAppName:strongSelf->_firebaseAppName];
513-
if (keychainServiceName) {
514-
strongSelf->_keychainServices =
515-
[[FIRAuthKeychainServices alloc] initWithService:keychainServiceName];
516-
strongSelf.storedUserManager =
517-
[[FIRAuthStoredUserManager alloc] initWithServiceName:keychainServiceName];
510+
if ([application respondsToSelector:@selector(isProtectedDataAvailable)]) {
511+
if ([application isProtectedDataAvailable]) {
512+
[self protectedDataInitialization];
513+
} else {
514+
// Add listener for UIApplicationProtectedDataDidBecomeAvailable.
515+
self->_protectedDataDidBecomeAvailableObserver = [[NSNotificationCenter defaultCenter]
516+
addObserverForName:UIApplicationProtectedDataDidBecomeAvailable
517+
object:nil
518+
queue:nil
519+
usingBlock:^(NSNotification *notification) {
520+
[self protectedDataInitialization];
521+
}];
518522
}
523+
} else {
524+
[self protectedDataInitialization];
525+
}
526+
#else
527+
[self protectedDataInitialization];
528+
#endif // TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST
529+
}
530+
return self;
531+
}
519532

520-
NSError *error;
521-
NSString *storedUserAccessGroup =
522-
[strongSelf.storedUserManager getStoredUserAccessGroupWithError:&error];
523-
if (!error) {
524-
if (!storedUserAccessGroup) {
525-
FIRUser *user;
526-
if ([strongSelf getUser:&user error:&error]) {
527-
strongSelf.tenantID = user.tenantID;
528-
[strongSelf updateCurrentUser:user byForce:NO savingToDisk:NO error:&error];
529-
self->_lastNotifiedUserToken = user.rawAccessToken;
530-
} else {
531-
FIRLogError(kFIRLoggerAuth, @"I-AUT000001",
532-
@"Error loading saved user when starting up: %@", error);
533-
}
533+
- (void)protectedDataInitialization {
534+
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST
535+
[[NSNotificationCenter defaultCenter] removeObserver:_protectedDataDidBecomeAvailableObserver
536+
name:UIApplicationProtectedDataDidBecomeAvailable
537+
object:nil];
538+
#endif // TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST
539+
// Continue with the rest of initialization in the work thread.
540+
__weak FIRAuth *weakSelf = self;
541+
dispatch_async(FIRAuthGlobalWorkQueue(), ^{
542+
// Load current user from Keychain.
543+
FIRAuth *strongSelf = weakSelf;
544+
if (!strongSelf) {
545+
return;
546+
}
547+
NSString *keychainServiceName =
548+
[FIRAuth keychainServiceNameForAppName:strongSelf->_firebaseAppName];
549+
if (keychainServiceName) {
550+
strongSelf->_keychainServices =
551+
[[FIRAuthKeychainServices alloc] initWithService:keychainServiceName];
552+
strongSelf.storedUserManager =
553+
[[FIRAuthStoredUserManager alloc] initWithServiceName:keychainServiceName];
554+
}
555+
556+
NSError *error;
557+
NSString *storedUserAccessGroup =
558+
[strongSelf.storedUserManager getStoredUserAccessGroupWithError:&error];
559+
if (!error) {
560+
if (!storedUserAccessGroup) {
561+
FIRUser *user;
562+
if ([strongSelf getUser:&user error:&error]) {
563+
strongSelf.tenantID = user.tenantID;
564+
[strongSelf updateCurrentUser:user byForce:NO savingToDisk:NO error:&error];
565+
self->_lastNotifiedUserToken = user.rawAccessToken;
534566
} else {
535-
[strongSelf internalUseUserAccessGroup:storedUserAccessGroup error:&error];
536-
if (error) {
537-
FIRLogError(kFIRLoggerAuth, @"I-AUT000001",
538-
@"Error loading saved user when starting up: %@", error);
539-
}
567+
FIRLogError(kFIRLoggerAuth, @"I-AUT000001",
568+
@"Error loading saved user when starting up: %@", error);
540569
}
541570
} else {
542-
FIRLogError(kFIRLoggerAuth, @"I-AUT000001",
543-
@"Error loading saved user when starting up: %@", error);
571+
[strongSelf internalUseUserAccessGroup:storedUserAccessGroup error:&error];
572+
if (error) {
573+
FIRLogError(kFIRLoggerAuth, @"I-AUT000001",
574+
@"Error loading saved user when starting up: %@", error);
575+
}
544576
}
577+
} else {
578+
FIRLogError(kFIRLoggerAuth, @"I-AUT000001", @"Error loading saved user when starting up: %@",
579+
error);
580+
}
545581

546582
#if TARGET_OS_IOS
583+
static Class applicationClass = nil;
584+
// iOS App extensions should not call [UIApplication sharedApplication], even if UIApplication
585+
// responds to it.
586+
if (![GULAppEnvironmentUtil isAppExtension]) {
587+
Class cls = NSClassFromString(@"UIApplication");
588+
if (cls && [cls respondsToSelector:@selector(sharedApplication)]) {
589+
applicationClass = cls;
590+
}
591+
}
592+
UIApplication *application = [applicationClass sharedApplication];
593+
594+
if (application) {
547595
// Initialize for phone number auth.
548596
strongSelf->_tokenManager = [[FIRAuthAPNSTokenManager alloc] initWithApplication:application];
549597

@@ -553,17 +601,16 @@ - (nullable instancetype)initWithAPIKey:(NSString *)APIKey
553601
strongSelf->_notificationManager = [[FIRAuthNotificationManager alloc]
554602
initWithApplication:application
555603
appCredentialManager:strongSelf->_appCredentialManager];
604+
}
556605

557-
[GULAppDelegateSwizzler registerAppDelegateInterceptor:strongSelf];
606+
[GULAppDelegateSwizzler registerAppDelegateInterceptor:strongSelf];
558607
#if ((TARGET_OS_IOS || TARGET_OS_TV) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 130000))
559-
if (@available(iOS 13, tvos 13, *)) {
560-
[GULSceneDelegateSwizzler registerSceneDelegateInterceptor:strongSelf];
561-
}
608+
if (@available(iOS 13, tvos 13, *)) {
609+
[GULSceneDelegateSwizzler registerSceneDelegateInterceptor:strongSelf];
610+
}
562611
#endif // ((TARGET_OS_IOS || TARGET_OS_TV) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 130000))
563612
#endif // TARGET_OS_IOS
564-
});
565-
}
566-
return self;
613+
});
567614
}
568615

569616
- (void)dealloc {

0 commit comments

Comments
 (0)