Skip to content

Commit e7ffad0

Browse files
authored
Merge branch 'main' into patch-1
2 parents 4e672e1 + 4a17a8d commit e7ffad0

File tree

13 files changed

+160
-25
lines changed

13 files changed

+160
-25
lines changed

GoogleSignIn/Sources/GIDSignIn.m

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -272,12 +272,25 @@ - (void)signInWithPresentingViewController:(UIViewController *)presentingViewCon
272272
hint:(nullable NSString *)hint
273273
additionalScopes:(nullable NSArray<NSString *> *)additionalScopes
274274
completion:(nullable GIDSignInCompletion)completion {
275+
[self signInWithPresentingViewController:presentingViewController
276+
hint:hint
277+
additionalScopes:additionalScopes
278+
nonce:nil
279+
completion:completion];
280+
}
281+
282+
- (void)signInWithPresentingViewController:(UIViewController *)presentingViewController
283+
hint:(nullable NSString *)hint
284+
additionalScopes:(nullable NSArray<NSString *> *)additionalScopes
285+
nonce:(nullable NSString *)nonce
286+
completion:(nullable GIDSignInCompletion)completion {
275287
GIDSignInInternalOptions *options =
276288
[GIDSignInInternalOptions defaultOptionsWithConfiguration:_configuration
277289
presentingViewController:presentingViewController
278290
loginHint:hint
279291
addScopesFlow:NO
280292
scopes:additionalScopes
293+
nonce:nonce
281294
completion:completion];
282295
[self signInWithOptions:options];
283296
}
@@ -350,12 +363,25 @@ - (void)signInWithPresentingWindow:(NSWindow *)presentingWindow
350363
hint:(nullable NSString *)hint
351364
additionalScopes:(nullable NSArray<NSString *> *)additionalScopes
352365
completion:(nullable GIDSignInCompletion)completion {
366+
[self signInWithPresentingWindow:presentingWindow
367+
hint:hint
368+
additionalScopes:additionalScopes
369+
nonce:nil
370+
completion:completion];
371+
}
372+
373+
- (void)signInWithPresentingWindow:(NSWindow *)presentingWindow
374+
hint:(nullable NSString *)hint
375+
additionalScopes:(nullable NSArray<NSString *> *)additionalScopes
376+
nonce:(nullable NSString *)nonce
377+
completion:(nullable GIDSignInCompletion)completion {
353378
GIDSignInInternalOptions *options =
354379
[GIDSignInInternalOptions defaultOptionsWithConfiguration:_configuration
355380
presentingWindow:presentingWindow
356381
loginHint:hint
357382
addScopesFlow:NO
358383
scopes:additionalScopes
384+
nonce:nonce
359385
completion:completion];
360386
[self signInWithOptions:options];
361387
}
@@ -573,7 +599,7 @@ - (void)signInWithOptions:(GIDSignInInternalOptions *)options {
573599
if (!_configuration) {
574600
// NOLINTNEXTLINE(google-objc-avoid-throwing-exception)
575601
[NSException raise:NSInvalidArgumentException
576-
format:@"No active configuration. Make sure GIDClientID is set in Info.plist."];
602+
format:@"No active configuration. Make sure GIDClientID is set in Info.plist."];
577603
return;
578604
}
579605

@@ -667,7 +693,6 @@ - (void)authorizationRequestWithOptions:(GIDSignInInternalOptions *)options comp
667693
[_timedLoader startTiming];
668694
[self->_appCheck getLimitedUseTokenWithCompletion:^(GACAppCheckToken * _Nullable token,
669695
NSError * _Nullable error) {
670-
OIDAuthorizationRequest *request = nil;
671696
if (token) {
672697
additionalParameters[kClientAssertionTypeParameter] = kClientAssertionTypeParameterValue;
673698
additionalParameters[kClientAssertionParameter] = token.token;
@@ -677,7 +702,7 @@ - (void)authorizationRequestWithOptions:(GIDSignInInternalOptions *)options comp
677702
NSLog(@"[Google Sign-In iOS]: Error retrieving App Check limited use token: %@", error);
678703
}
679704
#endif
680-
request = [self authorizationRequestWithOptions:options
705+
OIDAuthorizationRequest *request = [self authorizationRequestWithOptions:options
681706
additionalParameters:additionalParameters];
682707
if (self->_timedLoader.animationStatus == GIDTimedLoaderAnimationStatusAnimating) {
683708
[self->_timedLoader stopTimingWithCompletion:^{
@@ -707,6 +732,7 @@ - (void)authorizationRequestWithOptions:(GIDSignInInternalOptions *)options comp
707732
scopes:options.scopes
708733
redirectURL:[self redirectURLWithOptions:options]
709734
responseType:OIDResponseTypeCode
735+
nonce:options.nonce
710736
additionalParameters:additionalParameters];
711737
return request;
712738
}
@@ -758,7 +784,7 @@ - (NSURL *)redirectURLWithOptions:(GIDSignInInternalOptions *)options {
758784

759785
- (void)processAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse
760786
error:(NSError *)error
761-
emmSupport:(NSString *)emmSupport{
787+
emmSupport:(NSString *)emmSupport {
762788
if (_restarting) {
763789
// The auth flow is restarting, so the work here would be performed in the next round.
764790
_restarting = NO;
@@ -803,7 +829,8 @@ - (void)processAuthorizationResponse:(OIDAuthorizationResponse *)authorizationRe
803829
} else {
804830
NSString *errorString = [error localizedDescription];
805831
GIDSignInErrorCode errorCode = kGIDSignInErrorCodeUnknown;
806-
if (error.code == OIDErrorCodeUserCanceledAuthorizationFlow) {
832+
if (error.code == OIDErrorCodeUserCanceledAuthorizationFlow ||
833+
error.code == OIDErrorCodeProgramCanceledAuthorizationFlow) {
807834
// The user has canceled the flow at the iOS modal dialog.
808835
errorString = kUserCanceledError;
809836
errorCode = kGIDSignInErrorCodeCanceled;

GoogleSignIn/Sources/GIDSignInInternalOptions.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ NS_ASSUME_NONNULL_BEGIN
6464
/// The login hint to be used during the flow.
6565
@property(nonatomic, copy, nullable) NSString *loginHint;
6666

67+
/// A cryptographically random value used to associate a Client session with an ID Token,
68+
/// and to mitigate replay attacks.
69+
@property(nonatomic, readonly, copy, nullable) NSString *nonce;
70+
6771
/// Creates the default options.
6872
#if TARGET_OS_IOS || TARGET_OS_MACCATALYST
6973
+ (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)configuration
@@ -77,6 +81,7 @@ NS_ASSUME_NONNULL_BEGIN
7781
loginHint:(nullable NSString *)loginHint
7882
addScopesFlow:(BOOL)addScopesFlow
7983
scopes:(nullable NSArray *)scopes
84+
nonce:(nullable NSString *)nonce
8085
completion:(nullable GIDSignInCompletion)completion;
8186

8287
#elif TARGET_OS_OSX
@@ -91,6 +96,7 @@ NS_ASSUME_NONNULL_BEGIN
9196
loginHint:(nullable NSString *)loginHint
9297
addScopesFlow:(BOOL)addScopesFlow
9398
scopes:(nullable NSArray *)scopes
99+
nonce:(nullable NSString *)nonce
94100
completion:(nullable GIDSignInCompletion)completion;
95101
#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
96102

GoogleSignIn/Sources/GIDSignInInternalOptions.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@ + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)con
3131
loginHint:(nullable NSString *)loginHint
3232
addScopesFlow:(BOOL)addScopesFlow
3333
scopes:(nullable NSArray *)scopes
34+
nonce:(nullable NSString *)nonce
3435
completion:(nullable GIDSignInCompletion)completion {
3536
#elif TARGET_OS_OSX
3637
+ (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)configuration
3738
presentingWindow:(nullable NSWindow *)presentingWindow
3839
loginHint:(nullable NSString *)loginHint
3940
addScopesFlow:(BOOL)addScopesFlow
4041
scopes:(nullable NSArray *)scopes
42+
nonce:(nullable NSString *)nonce
4143
completion:(nullable GIDSignInCompletion)completion {
4244
#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
4345
GIDSignInInternalOptions *options = [[GIDSignInInternalOptions alloc] init];
@@ -54,6 +56,7 @@ + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)con
5456
options->_loginHint = loginHint;
5557
options->_completion = completion;
5658
options->_scopes = [GIDScopes scopesWithBasicProfile:scopes];
59+
options->_nonce = nonce;
5760
}
5861
return options;
5962
}
@@ -80,6 +83,7 @@ + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)con
8083
loginHint:loginHint
8184
addScopesFlow:addScopesFlow
8285
scopes:@[]
86+
nonce:nil
8387
completion:completion];
8488
return options;
8589
}

GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,31 @@ NS_EXTENSION_UNAVAILABLE("The sign-in flow is not supported in App Extensions.")
196196
NSError *_Nullable error))completion
197197
NS_EXTENSION_UNAVAILABLE("The sign-in flow is not supported in App Extensions.");
198198

199+
200+
/// Starts an interactive sign-in flow on iOS using the provided hint, additional scopes, and nonce.
201+
///
202+
/// The completion will be called at the end of this process. Any saved sign-in state will be
203+
/// replaced by the result of this flow. Note that this method should not be called when the app is
204+
/// starting up, (e.g in `application:didFinishLaunchingWithOptions:`); instead use the
205+
/// `restorePreviousSignInWithCompletion:` method to restore a previous sign-in.
206+
///
207+
/// @param presentingViewController The view controller used to present `SFSafariViewController` on
208+
/// iOS 9 and 10.
209+
/// @param hint An optional hint for the authorization server, for example the user's ID or email
210+
/// address, to be prefilled if possible.
211+
/// @param additionalScopes An optional array of scopes to request in addition to the basic profile scopes.
212+
/// @param nonce A custom nonce.
213+
/// @param completion The optional block that is called on completion. This block will
214+
/// be called asynchronously on the main queue.
215+
- (void)signInWithPresentingViewController:(UIViewController *)presentingViewController
216+
hint:(nullable NSString *)hint
217+
additionalScopes:(nullable NSArray<NSString *> *)additionalScopes
218+
nonce:(nullable NSString *)nonce
219+
completion:
220+
(nullable void (^)(GIDSignInResult *_Nullable signInResult,
221+
NSError *_Nullable error))completion
222+
NS_EXTENSION_UNAVAILABLE("The sign-in flow is not supported in App Extensions.");
223+
199224
#elif TARGET_OS_OSX
200225

201226
/// Starts an interactive sign-in flow on macOS.
@@ -229,7 +254,7 @@ NS_EXTENSION_UNAVAILABLE("The sign-in flow is not supported in App Extensions.")
229254
completion:(nullable void (^)(GIDSignInResult *_Nullable signInResult,
230255
NSError *_Nullable error))completion;
231256

232-
/// Starts an interactive sign-in flow on macOS using the provided hint.
257+
/// Starts an interactive sign-in flow on macOS using the provided hint and additional scopes.
233258
///
234259
/// The completion will be called at the end of this process. Any saved sign-in state will be
235260
/// replaced by the result of this flow. Note that this method should not be called when the app is
@@ -248,6 +273,28 @@ NS_EXTENSION_UNAVAILABLE("The sign-in flow is not supported in App Extensions.")
248273
completion:(nullable void (^)(GIDSignInResult *_Nullable signInResult,
249274
NSError *_Nullable error))completion;
250275

276+
/// Starts an interactive sign-in flow on macOS using the provided hint, additional scopes, and nonce.
277+
///
278+
/// The completion will be called at the end of this process. Any saved sign-in state will be
279+
/// replaced by the result of this flow. Note that this method should not be called when the app is
280+
/// starting up, (e.g in `application:didFinishLaunchingWithOptions:`); instead use the
281+
/// `restorePreviousSignInWithCompletion:` method to restore a previous sign-in.
282+
///
283+
/// @param presentingWindow The window used to supply `presentationContextProvider` for `ASWebAuthenticationSession`.
284+
/// @param hint An optional hint for the authorization server, for example the user's ID or email
285+
/// address, to be prefilled if possible.
286+
/// @param additionalScopes An optional array of scopes to request in addition to the basic profile scopes.
287+
/// @param nonce A custom nonce.
288+
/// @param completion The optional block that is called on completion. This block will
289+
/// be called asynchronously on the main queue.
290+
- (void)signInWithPresentingWindow:(NSWindow *)presentingWindow
291+
hint:(nullable NSString *)hint
292+
additionalScopes:(nullable NSArray<NSString *> *)additionalScopes
293+
nonce:(nullable NSString *)nonce
294+
completion:(nullable void (^)(GIDSignInResult *_Nullable signInResult,
295+
NSError *_Nullable error))completion;
296+
297+
251298
#endif
252299

253300
@end

GoogleSignIn/Tests/Unit/GIDSignInTest.m

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -500,8 +500,7 @@ - (void)testRestorePreviousSignInNoRefresh_hasPreviousUser {
500500

501501
// Mock generating a GIDConfiguration when initializing GIDGoogleUser.
502502
OIDAuthorizationResponse *authResponse =
503-
[OIDAuthorizationResponse testInstanceWithAdditionalParameters:nil
504-
errorString:nil];
503+
[OIDAuthorizationResponse testInstance];
505504

506505
OCMStub([_authState lastAuthorizationResponse]).andReturn(authResponse);
507506
OCMStub([_tokenResponse idToken]).andReturn(kFakeIDToken);
@@ -676,7 +675,8 @@ - (void)testOAuthLogin_AdditionalScopes {
676675
oldAccessToken:NO
677676
modalCancel:NO
678677
useAdditionalScopes:YES
679-
additionalScopes:nil];
678+
additionalScopes:nil
679+
manualNonce:nil];
680680

681681
expectedScopeString = [@[ @"email", @"profile" ] componentsJoinedByString:@" "];
682682
XCTAssertEqualObjects(_savedAuthorizationRequest.scope, expectedScopeString);
@@ -690,7 +690,8 @@ - (void)testOAuthLogin_AdditionalScopes {
690690
oldAccessToken:NO
691691
modalCancel:NO
692692
useAdditionalScopes:YES
693-
additionalScopes:@[ kScope ]];
693+
additionalScopes:@[ kScope ]
694+
manualNonce:nil];
694695

695696
expectedScopeString = [@[ kScope, @"email", @"profile" ] componentsJoinedByString:@" "];
696697
XCTAssertEqualObjects(_savedAuthorizationRequest.scope, expectedScopeString);
@@ -704,7 +705,8 @@ - (void)testOAuthLogin_AdditionalScopes {
704705
oldAccessToken:NO
705706
modalCancel:NO
706707
useAdditionalScopes:YES
707-
additionalScopes:@[ kScope, kScope2 ]];
708+
additionalScopes:@[ kScope, kScope2 ]
709+
manualNonce:nil];
708710

709711
expectedScopeString = [@[ kScope, kScope2, @"email", @"profile" ] componentsJoinedByString:@" "];
710712
XCTAssertEqualObjects(_savedAuthorizationRequest.scope, expectedScopeString);
@@ -796,6 +798,37 @@ - (void)testOpenIDRealm {
796798
XCTAssertEqual(params[kOpenIDRealmKey], kOpenIDRealm, @"OpenID Realm should match.");
797799
}
798800

801+
- (void)testManualNonce {
802+
_signIn.configuration = [[GIDConfiguration alloc] initWithClientID:kClientId
803+
serverClientID:nil
804+
hostedDomain:nil
805+
openIDRealm:kOpenIDRealm];
806+
807+
OCMStub(
808+
[_keychainStore saveAuthSession:OCMOCK_ANY error:OCMArg.anyObjectRef]
809+
).andDo(^(NSInvocation *invocation) {
810+
self->_keychainSaved = self->_saveAuthorizationReturnValue;
811+
});
812+
813+
NSString* manualNonce = @"manual_nonce";
814+
815+
[self OAuthLoginWithAddScopesFlow:NO
816+
authError:nil
817+
tokenError:nil
818+
emmPasscodeInfoRequired:NO
819+
keychainError:NO
820+
restoredSignIn:NO
821+
oldAccessToken:NO
822+
modalCancel:NO
823+
useAdditionalScopes:NO
824+
additionalScopes:@[]
825+
manualNonce:manualNonce];
826+
827+
XCTAssertEqualObjects(_savedAuthorizationRequest.nonce,
828+
manualNonce,
829+
@"Provided nonce should match nonce in authorization request.");
830+
}
831+
799832
- (void)testOAuthLogin_LoginHint {
800833
_hint = kUserEmail;
801834

@@ -1375,7 +1408,8 @@ - (void)OAuthLoginWithAddScopesFlow:(BOOL)addScopesFlow
13751408
oldAccessToken:oldAccessToken
13761409
modalCancel:modalCancel
13771410
useAdditionalScopes:NO
1378-
additionalScopes:nil];
1411+
additionalScopes:nil
1412+
manualNonce:nil];
13791413
}
13801414

13811415
// The authorization flow with parameters to control which branches to take.
@@ -1388,18 +1422,20 @@ - (void)OAuthLoginWithAddScopesFlow:(BOOL)addScopesFlow
13881422
oldAccessToken:(BOOL)oldAccessToken
13891423
modalCancel:(BOOL)modalCancel
13901424
useAdditionalScopes:(BOOL)useAdditionalScopes
1391-
additionalScopes:(NSArray *)additionalScopes {
1425+
additionalScopes:(NSArray *)additionalScopes
1426+
manualNonce:(NSString *)nonce {
13921427
if (restoredSignIn) {
13931428
// clearAndAuthenticateWithOptions
13941429
[[[_authorization expect] andReturn:_authState] authState];
1395-
BOOL isAuthorized = restoredSignIn ? YES : NO;
1430+
BOOL isAuthorized = restoredSignIn;
13961431
[[[_authState expect] andReturnValue:[NSNumber numberWithBool:isAuthorized]] isAuthorized];
13971432
}
13981433

13991434
NSDictionary<NSString *, NSString *> *additionalParameters = emmPasscodeInfoRequired ?
14001435
@{ @"emm_passcode_info_required" : @"1" } : nil;
14011436
OIDAuthorizationResponse *authResponse =
14021437
[OIDAuthorizationResponse testInstanceWithAdditionalParameters:additionalParameters
1438+
nonce:nonce
14031439
errorString:authError];
14041440

14051441
OIDTokenResponse *tokenResponse =
@@ -1475,6 +1511,8 @@ - (void)OAuthLoginWithAddScopesFlow:(BOOL)addScopesFlow
14751511
[_signIn signInWithPresentingWindow:_presentingWindow
14761512
#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
14771513
hint:_hint
1514+
additionalScopes:nil
1515+
nonce:nonce
14781516
completion:completion];
14791517
}
14801518
}

0 commit comments

Comments
 (0)