Skip to content

Commit 7a7483c

Browse files
committed
use seperate migration keys
1 parent 0154b3b commit 7a7483c

2 files changed

Lines changed: 139 additions & 56 deletions

File tree

GoogleSignIn/Sources/GIDAuthStateMigration.m

Lines changed: 77 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,13 @@
2626

2727
NS_ASSUME_NONNULL_BEGIN
2828

29-
// User preference key to detect whether or not the migration check has been performed.
30-
static NSString *const kMigrationCheckPerformedKey = @"GID_MigrationCheckPerformed";
29+
// User preference key to detect whether or not the migration to GTMAppAuth has been performed.
30+
static NSString *const kGTMAppAuthMigrationCheckPerformedKey = @"GID_MigrationCheckPerformed";
31+
32+
// User preference key to detect whether or not the data protected migration has been performed.
33+
static NSString *const kDataProtectedMigrationCheckPerformedKey =
34+
@"GID_DataProtectedMigrationCheckPerformed";
35+
3136

3237
// Keychain account used to store additional state in SDKs previous to v5, including GPPSignIn.
3338
static NSString *const kOldKeychainAccount = @"GooglePlus";
@@ -63,45 +68,85 @@ - (void)migrateIfNeededWithTokenURL:(NSURL *)tokenURL
6368
callbackPath:(NSString *)callbackPath
6469
keychainName:(NSString *)keychainName
6570
isFreshInstall:(BOOL)isFreshInstall {
66-
// See if we've performed the migration check previously.
67-
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
68-
if ([defaults boolForKey:kMigrationCheckPerformedKey]) {
71+
// If this is a fresh install, take no action and mark the migration checks as having been
72+
// performed.
73+
if (isFreshInstall) {
74+
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
75+
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
76+
[defaults setBool:YES forKey:kDataProtectedMigrationCheckPerformedKey];
77+
#elif TARGET_OS_IOS
78+
[defaults setBool:YES forKey:kGTMAppAuthMigrationCheckPerformedKey];
79+
#endif
6980
return;
7081
}
7182

72-
// If this is not a fresh install, attempt to migrate state. If this is a fresh install, take no
73-
// action and go on to mark the migration check as having been performed.
74-
if (!isFreshInstall) {
75-
GTMAuthSession *authSession = nil;
7683
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
77-
// Migrate from the fileBasedKeychain to dataProtectedKeychain with GTMAppAuth 5.0.
78-
GTMKeychainAttribute *fileBasedKeychain = [GTMKeychainAttribute useFileBasedKeychain];
79-
NSSet *attributes = [NSSet setWithArray:@[fileBasedKeychain]];
80-
GTMKeychainStore *keychainStoreLegacy =
81-
[[GTMKeychainStore alloc] initWithItemName:self.keychainStore.itemName
82-
keychainAttributes:attributes];
83-
authSession = [keychainStoreLegacy retrieveAuthSessionWithError:nil];
84+
[self performDataProtectedMigrationIfNeeded];
8485
#elif TARGET_OS_IOS
85-
// Migrate from GPPSignIn 1.x or GIDSignIn 1.0 - 4.x to the GTMAppAuth storage introduced in
86-
// GIDSignIn 5.0.
87-
authSession = [self extractAuthSessionWithTokenURL:tokenURL callbackPath:callbackPath];
86+
[self performGIDMigrationIfNeededWithTokenURL:tokenURL
87+
callbackPath:callbackPath
88+
keychainName:keychainName]
8889
#endif
89-
// If migration was successful, save our migrated state to the keychain.
90-
if (authSession) {
91-
NSError *err;
92-
[self.keychainStore saveAuthSession:authSession error:&err];
93-
// If we're unable to save to the keychain, return without marking migration performed.
94-
if (err) {
95-
return;
96-
};
90+
}
91+
9792
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
98-
[keychainStoreLegacy removeAuthSessionWithError:nil];
99-
#endif
100-
}
93+
// Migrate from the fileBasedKeychain to dataProtectedKeychain with GTMAppAuth 5.0.
94+
- (void)performDataProtectedMigrationIfNeeded {
95+
// See if we've performed the migration check previously.
96+
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
97+
if ([defaults boolForKey:kDataProtectedMigrationCheckPerformedKey]) {
98+
return;
99+
}
100+
// Migrate from the fileBasedKeychain to dataProtectedKeychain with GTMAppAuth 5.0.
101+
GTMKeychainAttribute *fileBasedKeychain = [GTMKeychainAttribute useFileBasedKeychain];
102+
NSSet *attributes = [NSSet setWithArray:@[fileBasedKeychain]];
103+
GTMKeychainStore *keychainStoreLegacy =
104+
[[GTMKeychainStore alloc] initWithItemName:self.keychainStore.itemName
105+
keychainAttributes:attributes];
106+
GTMAuthSession *authSession = [keychainStoreLegacy retrieveAuthSessionWithError:nil];
107+
// If migration was successful, save our migrated state to the keychain.
108+
if (authSession) {
109+
NSError *err;
110+
[self.keychainStore saveAuthSession:authSession error:&err];
111+
// If we're unable to save to the keychain, return without marking migration performed.
112+
if (err) {
113+
return;
114+
};
115+
[keychainStoreLegacy removeAuthSessionWithError:nil];
101116
}
102117

103118
// Mark the migration check as having been performed.
104-
[defaults setBool:YES forKey:kMigrationCheckPerformedKey];
119+
[defaults setBool:YES forKey:kDataProtectgedMigrationCheckPerformedKey];
120+
}
121+
122+
#elif TARGET_OS_IOS
123+
// Migrate from GPPSignIn 1.x or GIDSignIn 1.0 - 4.x to the GTMAppAuth storage introduced in
124+
// GIDSignIn 5.0.
125+
- (void)performGIDMigrationIfNeededWithTokenURL:(NSURL *)tokenURL
126+
callbackPath:(NSString *)callbackPath
127+
keychainName:(NSString *)keychainName {
128+
// See if we've performed the migration check previously.
129+
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
130+
if ([defaults boolForKey:kGTMAppAuthMigrationCheckPerformedKey]) {
131+
return;
132+
}
133+
134+
// Attempt migration
135+
GTMAuthSession *authSession =
136+
[self extractAuthSessionWithTokenURL:tokenURL callbackPath:callbackPath];
137+
138+
// If migration was successful, save our migrated state to the keychain.
139+
if (authSession) {
140+
NSError *err;
141+
[self.keychainStore saveAuthSession:authSession error:&err];
142+
// If we're unable to save to the keychain, return without marking migration performed.
143+
if (err) {
144+
return;
145+
};
146+
}
147+
148+
// Mark the migration check as having been performed.
149+
[defaults setBool:YES forKey:kGTMAppAuthMigrationCheckPerformedKey];
105150
}
106151

107152
// Returns a |GTMAuthSession| object containing any old auth state or |nil| if none
@@ -202,6 +247,7 @@ + (nullable NSString *)passwordForService:(NSString *)service {
202247
NSString *password = [[NSString alloc] initWithData:passwordData encoding:NSUTF8StringEncoding];
203248
return password;
204249
}
250+
#endif
205251

206252
@end
207253

GoogleSignIn/Tests/Unit/GIDAuthStateMigrationTest.m

Lines changed: 62 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@
5252
static NSString *const kRedirectURI =
5353
@"com.googleusercontent.apps.223520599684-kg64hfn0h950oureqacja2fltg00msv3:/callback/path";
5454

55-
static NSString *const kMigrationCheckPerformedKey = @"GID_MigrationCheckPerformed";
55+
static NSString *const kGTMAppAuthMigrationCheckPerformedKey = @"GID_MigrationCheckPerformed";
56+
static NSString *const kDataProtectedMigrationCheckPerformedKey =
57+
@"GID_DataProtectedMigrationCheckPerformed";
5658
static NSString *const kFingerprintService = @"fingerprint";
5759

5860
NS_ASSUME_NONNULL_BEGIN
@@ -132,39 +134,64 @@ - (void)tearDown {
132134

133135
#pragma mark - Tests
134136

135-
- (void)testMigrateIfNeeded_NoPreviousMigration {
137+
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
138+
- (void)testMigrateIfNeeded_NoPreviousMigration_DataProtectedMigration {
136139
[[[_mockUserDefaults stub] andReturn:_mockUserDefaults] standardUserDefaults];
137-
[[[_mockUserDefaults expect] andReturnValue:@NO] boolForKey:kMigrationCheckPerformedKey];
138-
[[_mockUserDefaults expect] setBool:YES forKey:kMigrationCheckPerformedKey];
140+
[[[_mockUserDefaults expect] andReturnValue:@NO] boolForKey:kDataProtectedMigrationCheckPerformedKey];
141+
[[_mockUserDefaults expect] setBool:YES forKey:kDataProtectedMigrationCheckPerformedKey];
139142

140143
[[_mockGTMKeychainStore expect] saveAuthSession:OCMOCK_ANY error:OCMArg.anyObjectRef];
141-
142-
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
143144
[[[_mockGTMKeychainStore expect] andReturn:kKeychainName] itemName];
145+
146+
// set the auth session that will be migrated
144147
OIDAuthState *authState = [OIDAuthState testInstance];
145148
GTMAuthSession *authSession = [[GTMAuthSession alloc] initWithAuthState:authState];
146149
NSError *err;
147150
[_realLegacyGTMKeychainStore saveAuthSession:authSession error:&err];
148151
XCTAssertNil(err);
149-
#else
150-
[self setUpCommonExtractAuthorizationMocksWithFingerPrint:kSavedFingerprint];
151-
#endif
152152

153153
GIDAuthStateMigration *migration =
154154
[[GIDAuthStateMigration alloc] initWithKeychainStore:_mockGTMKeychainStore];
155155
[migration migrateIfNeededWithTokenURL:[NSURL URLWithString:kTokenURL]
156156
callbackPath:kCallbackPath
157157
keychainName:kKeychainName
158158
isFreshInstall:NO];
159-
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
159+
160+
// verify that the auth session was removed during migration
160161
XCTAssertNil([_realLegacyGTMKeychainStore retrieveAuthSessionWithError:nil]);
161-
#endif
162162
}
163163

164-
- (void)testMigrateIfNeeded_HasPreviousMigration {
164+
- (void)testMigrateIfNeeded_KeychainFailure_DataProtectedMigration {
165+
[[[_mockUserDefaults stub] andReturn:_mockUserDefaults] standardUserDefaults];
166+
[[[_mockUserDefaults expect] andReturnValue:@NO] boolForKey:kDataProtectedMigrationCheckPerformedKey];
167+
168+
NSError *keychainSaveError = [NSError new];
169+
OCMStub([_mockGTMKeychainStore saveAuthSession:OCMOCK_ANY error:[OCMArg setTo:keychainSaveError]]);
170+
171+
[[[_mockGTMKeychainStore expect] andReturn:kKeychainName] itemName];
172+
OIDAuthState *authState = [OIDAuthState testInstance];
173+
GTMAuthSession *authSession = [[GTMAuthSession alloc] initWithAuthState:authState];
174+
NSError *err;
175+
[_realLegacyGTMKeychainStore saveAuthSession:authSession error:&err];
176+
XCTAssertNil(err);
177+
178+
GIDAuthStateMigration *migration =
179+
[[GIDAuthStateMigration alloc] initWithKeychainStore:_mockGTMKeychainStore];
180+
[migration migrateIfNeededWithTokenURL:[NSURL URLWithString:kTokenURL]
181+
callbackPath:kCallbackPath
182+
keychainName:kKeychainName
183+
isFreshInstall:NO];
184+
XCTAssertNotNil([_realLegacyGTMKeychainStore retrieveAuthSessionWithError:nil]);
185+
}
186+
187+
#else
188+
189+
- (void)testMigrateIfNeeded_NoPreviousMigration_GTMAppAuthMigration {
165190
[[[_mockUserDefaults stub] andReturn:_mockUserDefaults] standardUserDefaults];
166-
[[[_mockUserDefaults expect] andReturnValue:@YES] boolForKey:kMigrationCheckPerformedKey];
167-
[[_mockUserDefaults reject] setBool:YES forKey:kMigrationCheckPerformedKey];
191+
[[[_mockUserDefaults expect] andReturnValue:@NO] boolForKey:kMigrationCheckPerformedKey];
192+
[[_mockUserDefaults expect] setBool:YES forKey:kMigrationCheckPerformedKey];
193+
194+
[[_mockGTMKeychainStore expect] saveAuthSession:OCMOCK_ANY error:OCMArg.anyObjectRef];
168195

169196
GIDAuthStateMigration *migration =
170197
[[GIDAuthStateMigration alloc] initWithKeychainStore:_mockGTMKeychainStore];
@@ -174,33 +201,43 @@ - (void)testMigrateIfNeeded_HasPreviousMigration {
174201
isFreshInstall:NO];
175202
}
176203

177-
- (void)testMigrateIfNeeded_KeychainFailure {
204+
- (void)testMigrateIfNeeded_KeychainFailure_GTMAppAuthMigration {
178205
[[[_mockUserDefaults stub] andReturn:_mockUserDefaults] standardUserDefaults];
179206
[[[_mockUserDefaults expect] andReturnValue:@NO] boolForKey:kMigrationCheckPerformedKey];
180207

181208
NSError *keychainSaveError = [NSError new];
182209
OCMStub([_mockGTMKeychainStore saveAuthSession:OCMOCK_ANY error:[OCMArg setTo:keychainSaveError]]);
183210

184-
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
185-
[[[_mockGTMKeychainStore expect] andReturn:kKeychainName] itemName];
186-
OIDAuthState *authState = [OIDAuthState testInstance];
187-
GTMAuthSession *authSession = [[GTMAuthSession alloc] initWithAuthState:authState];
188-
NSError *err;
189-
[_realLegacyGTMKeychainStore saveAuthSession:authSession error:&err];
190-
XCTAssertNil(err);
191-
#else
192211
[self setUpCommonExtractAuthorizationMocksWithFingerPrint:kSavedFingerprint];
193-
#endif
194212

195213
GIDAuthStateMigration *migration =
196214
[[GIDAuthStateMigration alloc] initWithKeychainStore:_mockGTMKeychainStore];
197215
[migration migrateIfNeededWithTokenURL:[NSURL URLWithString:kTokenURL]
198216
callbackPath:kCallbackPath
199217
keychainName:kKeychainName
200218
isFreshInstall:NO];
219+
}
220+
221+
#endif
222+
223+
224+
225+
- (void)testMigrateIfNeeded_HasPreviousMigration {
226+
[[[_mockUserDefaults stub] andReturn:_mockUserDefaults] standardUserDefaults];
201227
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
202-
XCTAssertNotNil([_realLegacyGTMKeychainStore retrieveAuthSessionWithError:nil]);
228+
[[[_mockUserDefaults expect] andReturnValue:@YES] boolForKey:kDataProtectedMigrationCheckPerformedKey];
229+
[[_mockUserDefaults reject] setBool:YES forKey:kDataProtectedMigrationCheckPerformedKey];
230+
#else
231+
[[[_mockUserDefaults expect] andReturnValue:@YES] boolForKey:kGTMAppAuthMigrationCheckPerformedKey];
232+
[[_mockUserDefaults reject] setBool:YES forKey:kGTMAppAuthMigrationCheckPerformedKey];
203233
#endif
234+
235+
GIDAuthStateMigration *migration =
236+
[[GIDAuthStateMigration alloc] initWithKeychainStore:_mockGTMKeychainStore];
237+
[migration migrateIfNeededWithTokenURL:[NSURL URLWithString:kTokenURL]
238+
callbackPath:kCallbackPath
239+
keychainName:kKeychainName
240+
isFreshInstall:NO];
204241
}
205242

206243
- (void)testMigrateIfNeeded_isFreshInstall {

0 commit comments

Comments
 (0)