Skip to content

Commit 480178b

Browse files
[Auth] Fixed macOS extension keychain access by adding recommended kS… (#9102)
* [Auth] Fixed macOS extension keychain access by adding recommended kSecUseDataProtectionKeychain key * Refactored FIRAuthStoredUserManager to extract keychain query building to separated function.
1 parent 526f8ca commit 480178b

File tree

2 files changed

+34
-26
lines changed

2 files changed

+34
-26
lines changed

FirebaseAuth/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Unreleased
22
- [changed] Added a `X-Firebase-GMPID` header to network requests. (#9046)
33
- [fixed] Added multi-tenancy support to generic OAuth providers. (#7990)
4+
- [fixed] macOS Extension access to Shared Keychain by adding kSecUseDataProtectionKeychain recommended key (#6876)
45

56
# 8.9.0
67
- [changed] Improved error logging. (#8704)

FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.m

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,9 @@ - (FIRUser *)getStoredUserForAccessGroup:(NSString *)accessGroup
7575
shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices
7676
projectIdentifier:(NSString *)projectIdentifier
7777
error:(NSError *_Nullable *_Nullable)outError {
78-
NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
79-
query[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
80-
81-
query[(__bridge id)kSecAttrAccessGroup] = accessGroup;
82-
query[(__bridge id)kSecAttrService] = projectIdentifier;
83-
query[(__bridge id)kSecAttrAccount] = kSharedKeychainAccountValue;
84-
if (shareAuthStateAcrossDevices) {
85-
query[(__bridge id)kSecAttrSynchronizable] = (__bridge id)kCFBooleanTrue;
86-
}
87-
78+
NSMutableDictionary *query = [self keychainQueryForAccessGroup:accessGroup
79+
shareAuthStateAcrossDevices:shareAuthStateAcrossDevices
80+
projectIdentifier:projectIdentifier];
8881
NSData *data = [self.keychainServices getItemWithQuery:query error:outError];
8982
// If there's an outError parameter and it's populated, or there's no data, return.
9083
if ((outError && *outError) || !data) {
@@ -113,22 +106,15 @@ - (BOOL)setStoredUser:(FIRUser *)user
113106
shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices
114107
projectIdentifier:(NSString *)projectIdentifier
115108
error:(NSError *_Nullable *_Nullable)outError {
116-
NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
117-
query[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
109+
NSMutableDictionary *query = [self keychainQueryForAccessGroup:accessGroup
110+
shareAuthStateAcrossDevices:shareAuthStateAcrossDevices
111+
projectIdentifier:projectIdentifier];
118112
if (shareAuthStateAcrossDevices) {
119113
query[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlock;
120114
} else {
121115
query[(__bridge id)kSecAttrAccessible] =
122116
(__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
123117
}
124-
125-
query[(__bridge id)kSecAttrAccessGroup] = accessGroup;
126-
query[(__bridge id)kSecAttrService] = projectIdentifier;
127-
query[(__bridge id)kSecAttrAccount] = kSharedKeychainAccountValue;
128-
if (shareAuthStateAcrossDevices) {
129-
query[(__bridge id)kSecAttrSynchronizable] = (__bridge id)kCFBooleanTrue;
130-
}
131-
132118
#if TARGET_OS_WATCH
133119
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:false];
134120
#else
@@ -153,23 +139,44 @@ - (BOOL)removeStoredUserForAccessGroup:(NSString *)accessGroup
153139
shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices
154140
projectIdentifier:(NSString *)projectIdentifier
155141
error:(NSError *_Nullable *_Nullable)outError {
156-
NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
157-
query[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
142+
NSMutableDictionary *query = [self keychainQueryForAccessGroup:accessGroup
143+
shareAuthStateAcrossDevices:shareAuthStateAcrossDevices
144+
projectIdentifier:projectIdentifier];
158145
if (shareAuthStateAcrossDevices) {
159146
query[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlock;
160147
} else {
161148
query[(__bridge id)kSecAttrAccessible] =
162149
(__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
163150
}
164-
if (shareAuthStateAcrossDevices) {
165-
query[(__bridge id)kSecAttrSynchronizable] = (__bridge id)kCFBooleanTrue;
166-
}
151+
return [self.keychainServices removeItemWithQuery:query error:outError];
152+
}
153+
154+
#pragma mark - Internal Methods
167155

156+
- (NSMutableDictionary *)keychainQueryForAccessGroup:(NSString *)accessGroup
157+
shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices
158+
projectIdentifier:(NSString *)projectIdentifier {
159+
NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
160+
query[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
168161
query[(__bridge id)kSecAttrAccessGroup] = accessGroup;
169162
query[(__bridge id)kSecAttrService] = projectIdentifier;
170163
query[(__bridge id)kSecAttrAccount] = kSharedKeychainAccountValue;
171164

172-
return [self.keychainServices removeItemWithQuery:query error:outError];
165+
if (@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)) {
166+
/*
167+
"The data protection key affects operations only in macOS.
168+
Other platforms automatically behave as if the key is set to true,
169+
and ignore the key in the query dictionary. You can safely use the key on all platforms."
170+
[kSecUseDataProtectionKeychain](https://developer.apple.com/documentation/security/ksecusedataprotectionkeychain)
171+
*/
172+
query[(__bridge id)kSecUseDataProtectionKeychain] = (__bridge id)kCFBooleanTrue;
173+
}
174+
175+
if (shareAuthStateAcrossDevices) {
176+
query[(__bridge id)kSecAttrSynchronizable] = (__bridge id)kCFBooleanTrue;
177+
}
178+
179+
return query;
173180
}
174181

175182
@end

0 commit comments

Comments
 (0)