GIDAuthStateMigrationTest.m 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // Copyright 2021 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #import <XCTest/XCTest.h>
  15. #import "GoogleSignIn/Sources/GIDAuthStateMigration.h"
  16. #import "GoogleSignIn/Sources/GIDSignInCallbackSchemes.h"
  17. @import GTMAppAuth;
  18. #ifdef SWIFT_PACKAGE
  19. @import AppAuth;
  20. @import OCMock;
  21. #else
  22. #import <AppAuth/AppAuth.h>
  23. #import <OCMock/OCMock.h>
  24. #endif
  25. static NSString *const kTokenURL = @"https://host.com/example/token/url";
  26. static NSString *const kCallbackPath = @"/callback/path";
  27. static NSString *const kKeychainName = @"keychain_name";
  28. static NSString *const kBundleID = @"com.google.GoogleSignInInternalSample.dev";
  29. static NSString *const kClientID =
  30. @"223520599684-kg64hfn0h950oureqacja2fltg00msv3.apps.googleusercontent.com";
  31. static NSString *const kDotReversedClientID =
  32. @"com.googleusercontent.apps.223520599684-kg64hfn0h950oureqacja2fltg00msv3";
  33. static NSString *const kSavedFingerprint = @"com.google.GoogleSignInInternalSample.dev-"
  34. "223520599684-kg64hfn0h950oureqacja2fltg00msv3.apps.googleusercontent.com-email profile";
  35. static NSString *const kSavedFingerprint_HostedDomain =
  36. @"com.google.GoogleSignInInternalSample.dev-"
  37. "223520599684-kg64hfn0h950oureqacja2fltg00msv3.apps.googleusercontent.com-email profile-"
  38. "hd=test.com";
  39. static NSString *const kGTMOAuth2PersistenceString = @"param1=value1&param2=value2";
  40. static NSString *const kAdditionalTokenRequestParametersPostfix = @"~~atrp";
  41. static NSString *const kAdditionalTokenRequestParameters = @"param3=value3&param4=value4";
  42. static NSString *const kFinalPersistenceString =
  43. @"param1=value1&param2=value2&param3=value3&param4=value4";
  44. static NSString *const kRedirectURI =
  45. @"com.googleusercontent.apps.223520599684-kg64hfn0h950oureqacja2fltg00msv3:/callback/path";
  46. static NSString *const kMigrationCheckPerformedKey = @"GID_MigrationCheckPerformed";
  47. static NSString *const kFingerprintService = @"fingerprint";
  48. NS_ASSUME_NONNULL_BEGIN
  49. @interface GIDAuthStateMigration ()
  50. + (nullable NSString *)passwordForService:(NSString *)service;
  51. /// Returns a `GTMAuthSession` given the provided token URL.
  52. ///
  53. /// This method enables using an instance of `GIDAuthStateMigration` that is created with a fake
  54. /// `GTMKeychainStore` and thereby minimizes mocking.
  55. - (nullable GTMAuthSession *)
  56. extractAuthSessionWithTokenURL:(NSURL *)tokenURL callbackPath:(NSString *)callbackPath;
  57. @end
  58. @interface GIDAuthStateMigrationTest : XCTestCase
  59. @end
  60. @implementation GIDAuthStateMigrationTest {
  61. id _mockUserDefaults;
  62. id _mockGTMAppAuthFetcherAuthorization;
  63. id _mockGIDAuthStateMigration;
  64. id _mockGTMKeychainStore;
  65. id _mockKeychainHelper;
  66. id _mockNSBundle;
  67. id _mockGIDSignInCallbackSchemes;
  68. id _mockGTMOAuth2Compatibility;
  69. }
  70. - (void)setUp {
  71. [super setUp];
  72. _mockUserDefaults = OCMClassMock([NSUserDefaults class]);
  73. _mockGTMAppAuthFetcherAuthorization = OCMStrictClassMock([GTMAuthSession class]);
  74. _mockGIDAuthStateMigration = OCMStrictClassMock([GIDAuthStateMigration class]);
  75. _mockGTMKeychainStore = OCMStrictClassMock([GTMKeychainStore class]);
  76. _mockKeychainHelper = OCMProtocolMock(@protocol(GTMKeychainHelper));
  77. _mockNSBundle = OCMStrictClassMock([NSBundle class]);
  78. _mockGIDSignInCallbackSchemes = OCMStrictClassMock([GIDSignInCallbackSchemes class]);
  79. _mockGTMOAuth2Compatibility = OCMStrictClassMock([GTMOAuth2Compatibility class]);
  80. }
  81. - (void)tearDown {
  82. [_mockUserDefaults verify];
  83. [_mockUserDefaults stopMocking];
  84. [_mockGTMAppAuthFetcherAuthorization verify];
  85. [_mockGTMAppAuthFetcherAuthorization stopMocking];
  86. [_mockGIDAuthStateMigration verify];
  87. [_mockGIDAuthStateMigration stopMocking];
  88. [_mockGTMKeychainStore verify];
  89. [_mockGTMKeychainStore stopMocking];
  90. [_mockKeychainHelper verify];
  91. [_mockKeychainHelper stopMocking];
  92. [_mockNSBundle verify];
  93. [_mockNSBundle stopMocking];
  94. [_mockGIDSignInCallbackSchemes verify];
  95. [_mockGIDSignInCallbackSchemes stopMocking];
  96. [_mockGTMOAuth2Compatibility verify];
  97. [_mockGTMOAuth2Compatibility stopMocking];
  98. [super tearDown];
  99. }
  100. #pragma mark - Tests
  101. - (void)testMigrateIfNeeded_NoPreviousMigration {
  102. [[[_mockUserDefaults stub] andReturn:_mockUserDefaults] standardUserDefaults];
  103. [[[_mockUserDefaults expect] andReturnValue:@NO] boolForKey:kMigrationCheckPerformedKey];
  104. [[_mockUserDefaults expect] setBool:YES forKey:kMigrationCheckPerformedKey];
  105. [[_mockGTMKeychainStore expect] saveAuthSession:OCMOCK_ANY error:OCMArg.anyObjectRef];
  106. [self setUpCommonExtractAuthorizationMocksWithFingerPrint:kSavedFingerprint];
  107. GIDAuthStateMigration *migration =
  108. [[GIDAuthStateMigration alloc] initWithKeychainStore:_mockGTMKeychainStore];
  109. [migration migrateIfNeededWithTokenURL:[NSURL URLWithString:kTokenURL]
  110. callbackPath:kCallbackPath
  111. keychainName:kKeychainName
  112. isFreshInstall:NO];
  113. }
  114. - (void)testMigrateIfNeeded_HasPreviousMigration {
  115. [[[_mockUserDefaults stub] andReturn:_mockUserDefaults] standardUserDefaults];
  116. [[[_mockUserDefaults expect] andReturnValue:@YES] boolForKey:kMigrationCheckPerformedKey];
  117. [[_mockUserDefaults reject] setBool:YES forKey:kMigrationCheckPerformedKey];
  118. GIDAuthStateMigration *migration =
  119. [[GIDAuthStateMigration alloc] initWithKeychainStore:_mockGTMKeychainStore];
  120. [migration migrateIfNeededWithTokenURL:[NSURL URLWithString:kTokenURL]
  121. callbackPath:kCallbackPath
  122. keychainName:kKeychainName
  123. isFreshInstall:NO];
  124. }
  125. - (void)testMigrateIfNeeded_KeychainFailure {
  126. [[[_mockUserDefaults stub] andReturn:_mockUserDefaults] standardUserDefaults];
  127. [[[_mockUserDefaults expect] andReturnValue:@NO] boolForKey:kMigrationCheckPerformedKey];
  128. NSError *keychainSaveError = [NSError new];
  129. OCMStub([_mockGTMKeychainStore saveAuthSession:OCMOCK_ANY error:[OCMArg setTo:keychainSaveError]]);
  130. [self setUpCommonExtractAuthorizationMocksWithFingerPrint:kSavedFingerprint];
  131. GIDAuthStateMigration *migration =
  132. [[GIDAuthStateMigration alloc] initWithKeychainStore:_mockGTMKeychainStore];
  133. [migration migrateIfNeededWithTokenURL:[NSURL URLWithString:kTokenURL]
  134. callbackPath:kCallbackPath
  135. keychainName:kKeychainName
  136. isFreshInstall:NO];
  137. }
  138. - (void)testMigrateIfNeeded_isFreshInstall {
  139. [[[_mockUserDefaults stub] andReturn:_mockUserDefaults] standardUserDefaults];
  140. [[[_mockUserDefaults expect] andReturnValue:@NO]
  141. boolForKey:kMigrationCheckPerformedKey];
  142. [[_mockUserDefaults expect] setBool:YES forKey:kMigrationCheckPerformedKey];
  143. GIDAuthStateMigration *migration =
  144. [[GIDAuthStateMigration alloc] initWithKeychainStore:_mockGTMKeychainStore];
  145. [migration migrateIfNeededWithTokenURL:[NSURL URLWithString:kTokenURL]
  146. callbackPath:kCallbackPath
  147. keychainName:kKeychainName
  148. isFreshInstall:YES];
  149. }
  150. - (void)testExtractAuthorization {
  151. [self setUpCommonExtractAuthorizationMocksWithFingerPrint:kSavedFingerprint];
  152. GIDAuthStateMigration *migration =
  153. [[GIDAuthStateMigration alloc] initWithKeychainStore:_mockGTMKeychainStore];
  154. GTMAuthSession *authorization =
  155. [migration extractAuthSessionWithTokenURL:[NSURL URLWithString:kTokenURL]
  156. callbackPath:kCallbackPath];
  157. XCTAssertNotNil(authorization);
  158. }
  159. - (void)testExtractAuthorization_HostedDomain {
  160. [self setUpCommonExtractAuthorizationMocksWithFingerPrint:kSavedFingerprint_HostedDomain];
  161. GIDAuthStateMigration *migration =
  162. [[GIDAuthStateMigration alloc] initWithKeychainStore:_mockGTMKeychainStore];
  163. GTMAuthSession *authorization =
  164. [migration extractAuthSessionWithTokenURL:[NSURL URLWithString:kTokenURL]
  165. callbackPath:kCallbackPath];
  166. XCTAssertNotNil(authorization);
  167. }
  168. #pragma mark - Helpers
  169. // Generate the service name for the stored additional token request parameters string.
  170. - (NSString *)additionalTokenRequestParametersKeyFromFingerprint:(NSString *)fingerprint {
  171. return [NSString stringWithFormat:@"%@%@", fingerprint, kAdditionalTokenRequestParametersPostfix];
  172. }
  173. - (void)setUpCommonExtractAuthorizationMocksWithFingerPrint:(NSString *)fingerprint {
  174. [[[_mockGIDAuthStateMigration expect] andReturn:fingerprint]
  175. passwordForService:kFingerprintService];
  176. (void)[[[_mockKeychainHelper expect] andReturn:kGTMOAuth2PersistenceString]
  177. passwordForService:fingerprint error:OCMArg.anyObjectRef];
  178. [[[_mockGTMKeychainStore expect] andReturn:_mockKeychainHelper] keychainHelper];
  179. [[[_mockNSBundle expect] andReturn:_mockNSBundle] mainBundle];
  180. [[[_mockNSBundle expect] andReturn:kBundleID] bundleIdentifier];
  181. [[[_mockGIDSignInCallbackSchemes expect] andReturn:_mockGIDSignInCallbackSchemes] alloc];
  182. (void)[[[_mockGIDSignInCallbackSchemes expect] andReturn:_mockGIDSignInCallbackSchemes]
  183. initWithClientIdentifier:kClientID];
  184. [[[_mockGIDSignInCallbackSchemes expect] andReturn:kDotReversedClientID] clientIdentifierScheme];
  185. [[[_mockGIDAuthStateMigration expect] andReturn:kAdditionalTokenRequestParameters]
  186. passwordForService:[self additionalTokenRequestParametersKeyFromFingerprint:fingerprint]];
  187. }
  188. @end
  189. NS_ASSUME_NONNULL_END