diff --git a/CHANGELOG.md b/CHANGELOG.md index 187dc61d..2636f7cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +# Unreleased +- Fix a custom `nonce` and requested token `claims` being dropped when a sign-in is continued after a Device Policy app restart. + # 10.0.0 - **BREAKING**: Update to AppAuth 3.0.0 and GTMAppAuth 6.0.0, which raises the minimum deployment targets to iOS 15.0 and macOS 12.0, widens the `GTMSessionFetcher` dependency to allow 4.x and 5.x, and renames the version-specific Swift Package Manager manifest to `Package@swift-5.7.swift`. Projects that must keep supporting earlier OS versions should stay on GoogleSignIn 9.2.0. ([#628](https://github.com/google/GoogleSignIn-iOS/pull/628)) - Add `GIDSignIn.wrapperIdentifier` so SDKs that embed Google Sign-In can self-identify in Google's diagnostic logs via a new `gidwrapper` parameter. It is opt-in and pre-existing behavior is unchanged. ([#625](https://github.com/google/GoogleSignIn-iOS/pull/625)) diff --git a/GoogleSignIn/Sources/GIDSignInInternalOptions.m b/GoogleSignIn/Sources/GIDSignInInternalOptions.m index 4a87bddf..4ea6a0da 100644 --- a/GoogleSignIn/Sources/GIDSignInInternalOptions.m +++ b/GoogleSignIn/Sources/GIDSignInInternalOptions.m @@ -124,7 +124,9 @@ - (instancetype)optionsWithExtraParameters:(NSDictionary *)extraParams options->_loginHint = _loginHint; options->_completion = _completion; options->_scopes = _scopes; + options->_nonce = _nonce; options->_claims = _claims; + options->_claimsAsJSON = _claimsAsJSON; options->_extraParams = [extraParams copy]; } return options; diff --git a/GoogleSignIn/Tests/Unit/GIDSignInInternalOptionsTest.m b/GoogleSignIn/Tests/Unit/GIDSignInInternalOptionsTest.m index 13fcac4d..52c61010 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInInternalOptionsTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInInternalOptionsTest.m @@ -25,92 +25,139 @@ #import #endif -@interface GIDSignInInternalOptionsTest : XCTestCase -@end +static NSString *const kLoginHint = @"login_hint"; +static NSString *const kScope1 = @"scope1"; +static NSString *const kScope2 = @"scope2"; +static NSString *const kNonce = @"test_nonce"; +static NSString *const kClaimsAsJSON = @"{\"claim\":\"value\"}"; -@implementation GIDSignInInternalOptionsTest +@interface GIDSignInInternalOptionsTest : XCTestCase { + // Mock for the configuration passed to the option factories. + id _configuration; -- (void)testDefaultOptions { - id configuration = OCMStrictClassMock([GIDConfiguration class]); #if TARGET_OS_IOS || TARGET_OS_MACCATALYST - id presentingViewController = OCMStrictClassMock([UIViewController class]); + // Mock for the presenting view controller passed to the option factories. + id _presentingViewController; #elif TARGET_OS_OSX - id presentingWindow = OCMStrictClassMock([NSWindow class]); + // Mock for the presenting window passed to the option factories. + id _presentingWindow; #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST - NSString *loginHint = @"login_hint"; +} +@end - GIDSignInCompletion completion = ^(GIDSignInResult *_Nullable signInResult, - NSError * _Nullable error) {}; - GIDSignInInternalOptions *options = - [GIDSignInInternalOptions defaultOptionsWithConfiguration:configuration +@implementation GIDSignInInternalOptionsTest + +#pragma mark - Lifecycle + +- (void)setUp { + [super setUp]; + _configuration = OCMStrictClassMock([GIDConfiguration class]); #if TARGET_OS_IOS || TARGET_OS_MACCATALYST - presentingViewController:presentingViewController + _presentingViewController = OCMStrictClassMock([UIViewController class]); #elif TARGET_OS_OSX - presentingWindow:presentingWindow + _presentingWindow = OCMStrictClassMock([NSWindow class]); #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST - loginHint:loginHint - addScopesFlow:NO - completion:completion]; - XCTAssertTrue(options.interactive); - XCTAssertFalse(options.continuation); - XCTAssertFalse(options.addScopesFlow); - XCTAssertNil(options.extraParams); +} + +#pragma mark - Helpers + +// The claim set requested by `-optionsWithAllParameters`. `GIDClaim` implements +// `-isEqual:` by name and essentiality, so a freshly built set compares equal. +- (NSSet *)expectedClaims { + return [NSSet setWithObject:[GIDClaim authTimeClaim]]; +} - OCMVerifyAll(configuration); +- (GIDSignInInternalOptions *)optionsWithAllParameters { + GIDSignInCompletion completion = ^(GIDSignInResult *_Nullable signInResult, + NSError *_Nullable error) {}; + return [GIDSignInInternalOptions defaultOptionsWithConfiguration:_configuration #if TARGET_OS_IOS || TARGET_OS_MACCATALYST - OCMVerifyAll(presentingViewController); + presentingViewController:_presentingViewController #elif TARGET_OS_OSX - OCMVerifyAll(presentingWindow); + presentingWindow:_presentingWindow #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST + loginHint:kLoginHint + addScopesFlow:NO + scopes:@[kScope1, kScope2] + nonce:kNonce + claims:[self expectedClaims] + completion:completion]; } -- (void)testDefaultOptions_withAllParameters_initializesPropertiesCorrectly { - id configuration = OCMStrictClassMock([GIDConfiguration class]); +// Verifies the mocks created in `-setUp` have no unfulfilled expectations. +- (void)verifyConfigurationAndPresentationMocks { + OCMVerifyAll(_configuration); #if TARGET_OS_IOS || TARGET_OS_MACCATALYST - id presentingViewController = OCMStrictClassMock([UIViewController class]); + OCMVerifyAll(_presentingViewController); #elif TARGET_OS_OSX - id presentingWindow = OCMStrictClassMock([NSWindow class]); + OCMVerifyAll(_presentingWindow); #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST - NSString *loginHint = @"login_hint"; - NSArray *scopes = @[@"scope1", @"scope2"]; - NSString *nonce = @"test_nonce"; - NSSet *claims = [NSSet setWithObject:[GIDClaim authTimeClaim]]; - NSArray *expectedScopes = @[@"scope1", @"scope2", @"email", @"profile"]; +} +#pragma mark - Tests + +- (void)testDefaultOptions { GIDSignInCompletion completion = ^(GIDSignInResult *_Nullable signInResult, - NSError * _Nullable error) {}; + NSError *_Nullable error) {}; GIDSignInInternalOptions *options = - [GIDSignInInternalOptions defaultOptionsWithConfiguration:configuration + [GIDSignInInternalOptions defaultOptionsWithConfiguration:_configuration #if TARGET_OS_IOS || TARGET_OS_MACCATALYST - presentingViewController:presentingViewController + presentingViewController:_presentingViewController #elif TARGET_OS_OSX - presentingWindow:presentingWindow + presentingWindow:_presentingWindow #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST - loginHint:loginHint + loginHint:kLoginHint addScopesFlow:NO - scopes:scopes - nonce:nonce - claims:claims completion:completion]; XCTAssertTrue(options.interactive); XCTAssertFalse(options.continuation); XCTAssertFalse(options.addScopesFlow); XCTAssertNil(options.extraParams); + [self verifyConfigurationAndPresentationMocks]; +} + +- (void)testDefaultOptions_withAllParameters_initializesPropertiesCorrectly { + NSArray *expectedScopes = @[kScope1, kScope2, @"email", @"profile"]; + + GIDSignInInternalOptions *options = [self optionsWithAllParameters]; + + XCTAssertTrue(options.interactive); + XCTAssertFalse(options.continuation); + XCTAssertFalse(options.addScopesFlow); + XCTAssertNil(options.extraParams); + // Convert arrays to sets for comparison to make the test order-independent. - XCTAssertEqualObjects([NSSet setWithArray:options.scopes], [NSSet setWithArray:expectedScopes]); - XCTAssertEqualObjects(options.nonce, nonce); - XCTAssertEqualObjects(options.claims, claims); + XCTAssertEqualObjects([NSSet setWithArray:options.scopes], + [NSSet setWithArray:expectedScopes]); + XCTAssertEqualObjects(options.nonce, kNonce); + XCTAssertEqualObjects(options.claims, [self expectedClaims]); XCTAssertNil(options.claimsAsJSON); - OCMVerifyAll(configuration); -#if TARGET_OS_IOS || TARGET_OS_MACCATALYST - OCMVerifyAll(presentingViewController); -#elif TARGET_OS_OSX - OCMVerifyAll(presentingWindow); -#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST + [self verifyConfigurationAndPresentationMocks]; } +- (void)testOptionsWithExtraParameters_forContinuation_preservesAllPropertiesAndSetsContinuation { + GIDSignInInternalOptions *options = [self optionsWithAllParameters]; + options.claimsAsJSON = kClaimsAsJSON; + NSDictionary *extraParams = @{@"extra_key" : @"extra_value"}; + + GIDSignInInternalOptions *continuationOptions = + [options optionsWithExtraParameters:extraParams forContinuation:YES]; + + XCTAssertEqualObjects(continuationOptions.nonce, kNonce); + XCTAssertEqualObjects(continuationOptions.claims, [self expectedClaims]); + XCTAssertEqualObjects(continuationOptions.claimsAsJSON, kClaimsAsJSON); + XCTAssertTrue(continuationOptions.continuation); + XCTAssertEqualObjects(continuationOptions.extraParams, extraParams); + XCTAssertEqualObjects(continuationOptions.loginHint, kLoginHint); + XCTAssertEqualObjects([NSSet setWithArray:continuationOptions.scopes], + [NSSet setWithArray:options.scopes]); + XCTAssertFalse(continuationOptions.addScopesFlow); + XCTAssertTrue(continuationOptions.interactive); + + [self verifyConfigurationAndPresentationMocks]; +} - (void)testSilentOptions { GIDSignInCompletion completion = ^(GIDSignInResult *_Nullable signInResult,