From 549213eb78b78da809235450449c1a6fddf6f0be Mon Sep 17 00:00:00 2001 From: pinlu Date: Thu, 30 Jun 2022 14:06:13 -0700 Subject: [PATCH 01/17] Create branch GIDGoogleUser-restructure to track PRs relating to GIDGoogleUser --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 36e6965f..7ec2546e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,6 +7,7 @@ on: pull_request: branches: - main + - GIDGoogleUser-restructure workflow_dispatch: jobs: From 85206374775457f86ab6874457215790f59ffcd1 Mon Sep 17 00:00:00 2001 From: pinlu Date: Sat, 9 Jul 2022 18:01:05 -0700 Subject: [PATCH 02/17] Create class GIDUserAuth (#177) * Create class GIDUserAuth Add class GIDUserAuth to represent the outcome of a successful signIn or addScopes flow. --- GoogleSignIn/Sources/GIDUserAuth.m | 35 ++++++++++++++++ GoogleSignIn/Sources/GIDUserAuth_Private.h | 33 +++++++++++++++ .../Sources/Public/GoogleSignIn/GIDUserAuth.h | 40 +++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 GoogleSignIn/Sources/GIDUserAuth.m create mode 100644 GoogleSignIn/Sources/GIDUserAuth_Private.h create mode 100644 GoogleSignIn/Sources/Public/GoogleSignIn/GIDUserAuth.h diff --git a/GoogleSignIn/Sources/GIDUserAuth.m b/GoogleSignIn/Sources/GIDUserAuth.m new file mode 100644 index 00000000..90dfa289 --- /dev/null +++ b/GoogleSignIn/Sources/GIDUserAuth.m @@ -0,0 +1,35 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDUserAuth.h" + +#import "GoogleSignIn/Sources/GIDUserAuth_Private.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h" + +@implementation GIDUserAuth + +- (instancetype)initWithGoogleUser:(GIDGoogleUser *)user + serverAuthCode:(nullable NSString *)serverAuthCode { + self = [super init]; + if (self) { + _user = user; + _serverAuthCode = serverAuthCode; + } + + return self; +} + +@end diff --git a/GoogleSignIn/Sources/GIDUserAuth_Private.h b/GoogleSignIn/Sources/GIDUserAuth_Private.h new file mode 100644 index 00000000..2f80b9ee --- /dev/null +++ b/GoogleSignIn/Sources/GIDUserAuth_Private.h @@ -0,0 +1,33 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDUserAuth.h" + +NS_ASSUME_NONNULL_BEGIN + +// Private |GIDUserAuth| methods that are used in this SDK. +@interface GIDUserAuth () + +// Private initializer for |GIDUserAuth|. +// @param user The current GIDGoogleUser. +// @param severAuthCode The one-time authorization code for backend to exchange +// access and refresh tokens. +- (instancetype)initWithGoogleUser:(GIDGoogleUser *)user + serverAuthCode:(nullable NSString *)serverAuthCode; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDUserAuth.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDUserAuth.h new file mode 100644 index 00000000..0d91b8cd --- /dev/null +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDUserAuth.h @@ -0,0 +1,40 @@ +/* +* Copyright 2021 Google LLC +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#import + +@class GIDGoogleUser; + +NS_ASSUME_NONNULL_BEGIN + +/// A helper object that contains the outcome of a successful signIn or addScopes flow. +@interface GIDUserAuth : NSObject + +/// The updated `GIDGoogleUser` instance for the user who just completed the flow. +@property(nonatomic, readonly) GIDGoogleUser *user; + +/// An OAuth2 authorization code for the home server. +@property(nonatomic, readonly, nullable) NSString *serverAuthCode; + +/// Unsupported. ++ (instancetype)new NS_UNAVAILABLE; + +/// Unsupported. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END From 1f54000cd580d556e716c582c760f0e9f2822936 Mon Sep 17 00:00:00 2001 From: pinlu Date: Fri, 15 Jul 2022 23:25:21 -0700 Subject: [PATCH 03/17] Replace GIDSignInCallback (#179) Replace GIDSignInCallback with block void (^)(GIDUserAuth *_Nullable userAuth, NSError *_Nullable error) --- GoogleSignIn/Sources/GIDSignIn.m | 46 ++++++++---- .../Sources/GIDSignInInternalOptions.h | 21 +++--- .../Sources/GIDSignInInternalOptions.m | 15 ++-- GoogleSignIn/Sources/GIDSignIn_Private.h | 4 ++ .../Sources/Public/GoogleSignIn/GIDSignIn.h | 70 ++++++++++--------- .../Public/GoogleSignIn/GoogleSignIn.h | 1 + .../Tests/Unit/GIDSignInInternalOptionsTest.m | 11 +-- GoogleSignIn/Tests/Unit/GIDSignInTest.m | 27 ++++--- .../Source/SignInViewController.m | 10 +-- .../Services/GoogleSignInAuthenticator.swift | 24 +++---- 10 files changed, 139 insertions(+), 90 deletions(-) diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index 7a810445..a8bbb47a 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -20,6 +20,7 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDProfileData.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDUserAuth.h" #import "GoogleSignIn/Sources/GIDSignInInternalOptions.h" #import "GoogleSignIn/Sources/GIDSignInPreferences.h" @@ -34,6 +35,7 @@ #import "GoogleSignIn/Sources/GIDAuthentication_Private.h" #import "GoogleSignIn/Sources/GIDGoogleUser_Private.h" #import "GoogleSignIn/Sources/GIDProfileData_Private.h" +#import "GoogleSignIn/Sources/GIDUserAuth_Private.h" #ifdef SWIFT_PACKAGE @import AppAuth; @@ -187,8 +189,16 @@ - (BOOL)hasPreviousSignIn { return [authState isAuthorized]; } -- (void)restorePreviousSignInWithCompletion:(nullable GIDSignInCompletion)completion { - [self signInWithOptions:[GIDSignInInternalOptions silentOptionsWithCompletion:completion]]; +- (void)restorePreviousSignInWithCompletion:(nullable void (^)(GIDGoogleUser *_Nullable user, + NSError *_Nullable error))completion { + [self signInWithOptions:[GIDSignInInternalOptions silentOptionsWithCompletion: + ^(GIDUserAuth *userAuth, NSError *error) { + if (userAuth) { + completion(userAuth.user, nil); + } else { + completion(nil, error); + } + }]]; } - (BOOL)restorePreviousSignInNoRefresh { @@ -217,7 +227,7 @@ - (BOOL)restorePreviousSignInNoRefresh { - (void)signInWithConfiguration:(GIDConfiguration *)configuration presentingViewController:(UIViewController *)presentingViewController hint:(nullable NSString *)hint - completion:(nullable GIDSignInCompletion)completion { + completion:(nullable GIDUserAuthCompletion)completion { GIDSignInInternalOptions *options = [GIDSignInInternalOptions defaultOptionsWithConfiguration:configuration presentingViewController:presentingViewController @@ -231,7 +241,7 @@ - (void)signInWithConfiguration:(GIDConfiguration *)configuration presentingViewController:(UIViewController *)presentingViewController hint:(nullable NSString *)hint additionalScopes:(nullable NSArray *)additionalScopes - completion:(nullable GIDSignInCompletion)completion { + completion:(nullable GIDUserAuthCompletion)completion { GIDSignInInternalOptions *options = [GIDSignInInternalOptions defaultOptionsWithConfiguration:configuration presentingViewController:presentingViewController @@ -244,7 +254,7 @@ - (void)signInWithConfiguration:(GIDConfiguration *)configuration - (void)signInWithConfiguration:(GIDConfiguration *)configuration presentingViewController:(UIViewController *)presentingViewController - completion:(nullable GIDSignInCompletion)completion { + completion:(nullable GIDUserAuthCompletion)completion { [self signInWithConfiguration:configuration presentingViewController:presentingViewController hint:nil @@ -253,7 +263,7 @@ - (void)signInWithConfiguration:(GIDConfiguration *)configuration - (void)addScopes:(NSArray *)scopes presentingViewController:(UIViewController *)presentingViewController - completion:(nullable GIDSignInCompletion)completion { + completion:(nullable GIDUserAuthCompletion)completion { // A currentUser must be available in order to complete this flow. if (!self.currentUser) { // No currentUser is set, notify callback of failure. @@ -310,7 +320,7 @@ - (void)addScopes:(NSArray *)scopes - (void)signInWithConfiguration:(GIDConfiguration *)configuration presentingWindow:(NSWindow *)presentingWindow hint:(nullable NSString *)hint - completion:(nullable GIDSignInCompletion)completion { + completion:(nullable GIDUserAuthCompletion)completion { GIDSignInInternalOptions *options = [GIDSignInInternalOptions defaultOptionsWithConfiguration:configuration presentingWindow:presentingWindow @@ -322,7 +332,7 @@ - (void)signInWithConfiguration:(GIDConfiguration *)configuration - (void)signInWithConfiguration:(GIDConfiguration *)configuration presentingWindow:(NSWindow *)presentingWindow - completion:(nullable GIDSignInCompletion)completion { + completion:(nullable GIDUserAuthCompletion)completion { [self signInWithConfiguration:configuration presentingWindow:presentingWindow hint:nil @@ -333,7 +343,7 @@ - (void)signInWithConfiguration:(GIDConfiguration *)configuration presentingWindow:(NSWindow *)presentingWindow hint:(nullable NSString *)hint additionalScopes:(nullable NSArray *)additionalScopes - completion:(nullable GIDSignInCompletion)completion { + completion:(nullable GIDUserAuthCompletion)completion { GIDSignInInternalOptions *options = [GIDSignInInternalOptions defaultOptionsWithConfiguration:configuration presentingWindow:presentingWindow @@ -346,7 +356,7 @@ - (void)signInWithConfiguration:(GIDConfiguration *)configuration - (void)addScopes:(NSArray *)scopes presentingWindow:(NSWindow *)presentingWindow - completion:(nullable GIDSignInCompletion)completion { + completion:(nullable GIDUserAuthCompletion)completion { // A currentUser must be available in order to complete this flow. if (!self.currentUser) { // No currentUser is set, notify callback of failure. @@ -541,7 +551,8 @@ - (void)signInWithOptions:(GIDSignInInternalOptions *)options { if (options.completion) { self->_currentOptions = nil; dispatch_async(dispatch_get_main_queue(), ^{ - options.completion(self->_currentUser, nil); + GIDUserAuth *userAuth = [[GIDUserAuth alloc] initWithGoogleUser:self->_currentUser serverAuthCode:nil]; + options.completion(userAuth, nil); }); } } @@ -601,7 +612,7 @@ - (void)authenticateInteractivelyWithOptions:(GIDSignInInternalOptions *)options _currentAuthorizationFlow = [OIDAuthorizationService presentAuthorizationRequest:request presentingViewController:options.presentingViewController - callback:^(OIDAuthorizationResponse *_Nullable authorizationResponse, + callback:^(OIDAuthorizationResponse *_Nullable authorizationResponse, NSError *_Nullable error) { [self processAuthorizationResponse:authorizationResponse error:error @@ -882,10 +893,17 @@ - (void)addCompletionCallback:(GIDAuthFlow *)authFlow { [authFlow addCallback:^() { GIDAuthFlow *handlerAuthFlow = weakAuthFlow; if (self->_currentOptions.completion) { - GIDSignInCompletion completion = self->_currentOptions.completion; + GIDUserAuthCompletion completion = self->_currentOptions.completion; self->_currentOptions = nil; dispatch_async(dispatch_get_main_queue(), ^{ - completion(self->_currentUser, handlerAuthFlow.error); + if (handlerAuthFlow.error) { + completion(nil, handlerAuthFlow.error); + } else { + OIDAuthState *authState = handlerAuthFlow.authState; + NSString *_Nullable serverAuthCode = [authState.lastTokenResponse.additionalParameters[@"server_code"] copy]; + GIDUserAuth *userAuth = [[GIDUserAuth alloc] initWithGoogleUser:self->_currentUser serverAuthCode:serverAuthCode]; + completion(userAuth, nil); + } }); } }]; diff --git a/GoogleSignIn/Sources/GIDSignInInternalOptions.h b/GoogleSignIn/Sources/GIDSignInInternalOptions.h index d104246e..a51bfd95 100644 --- a/GoogleSignIn/Sources/GIDSignInInternalOptions.h +++ b/GoogleSignIn/Sources/GIDSignInInternalOptions.h @@ -22,9 +22,8 @@ #import #endif -#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h" - @class GIDConfiguration; +@class GIDUserAuth; NS_ASSUME_NONNULL_BEGIN @@ -55,7 +54,8 @@ NS_ASSUME_NONNULL_BEGIN #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST /// The completion block to be called at the completion of the flow. -@property(nonatomic, readonly, nullable) GIDSignInCompletion completion; +@property(nonatomic, readonly, nullable) void (^completion)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error); /// The scopes to be used during the flow. @property(nonatomic, copy, nullable) NSArray *scopes; @@ -69,32 +69,37 @@ NS_ASSUME_NONNULL_BEGIN presentingViewController:(nullable UIViewController *)presentingViewController loginHint:(nullable NSString *)loginHint addScopesFlow:(BOOL)addScopesFlow - completion:(nullable GIDSignInCompletion)completion; + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion; + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)configuration presentingViewController:(nullable UIViewController *)presentingViewController loginHint:(nullable NSString *)loginHint addScopesFlow:(BOOL)addScopesFlow scopes:(nullable NSArray *)scopes - completion:(nullable GIDSignInCompletion)completion; + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion; #elif TARGET_OS_OSX + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)configuration presentingWindow:(nullable NSWindow *)presentingWindow loginHint:(nullable NSString *)loginHint addScopesFlow:(BOOL)addScopesFlow - completion:(nullable GIDSignInCompletion)completion; + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion; + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)configuration presentingWindow:(nullable NSWindow *)presentingWindow loginHint:(nullable NSString *)loginHint addScopesFlow:(BOOL)addScopesFlow scopes:(nullable NSArray *)scopes - completion:(nullable GIDSignInCompletion)completion; + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion; #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST /// Creates the options to sign in silently. -+ (instancetype)silentOptionsWithCompletion:(GIDSignInCompletion)completion; ++ (instancetype)silentOptionsWithCompletion:(void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion; /// Creates options with the same values as the receiver, except for the "extra parameters", and /// continuation flag, which are replaced by the arguments passed to this method. diff --git a/GoogleSignIn/Sources/GIDSignInInternalOptions.m b/GoogleSignIn/Sources/GIDSignInInternalOptions.m index 06db24ab..745cfa70 100644 --- a/GoogleSignIn/Sources/GIDSignInInternalOptions.m +++ b/GoogleSignIn/Sources/GIDSignInInternalOptions.m @@ -31,14 +31,16 @@ + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)con loginHint:(nullable NSString *)loginHint addScopesFlow:(BOOL)addScopesFlow scopes:(nullable NSArray *)scopes - completion:(nullable GIDSignInCompletion)completion { + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion { #elif TARGET_OS_OSX + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)configuration presentingWindow:(nullable NSWindow *)presentingWindow loginHint:(nullable NSString *)loginHint addScopesFlow:(BOOL)addScopesFlow scopes:(nullable NSArray *)scopes - completion:(nullable GIDSignInCompletion)completion { + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion { #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST GIDSignInInternalOptions *options = [[GIDSignInInternalOptions alloc] init]; @@ -64,13 +66,15 @@ + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)con presentingViewController:(nullable UIViewController *)presentingViewController loginHint:(nullable NSString *)loginHint addScopesFlow:(BOOL)addScopesFlow - completion:(nullable GIDSignInCompletion)completion { + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion { #elif TARGET_OS_OSX + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)configuration presentingWindow:(nullable NSWindow *)presentingWindow loginHint:(nullable NSString *)loginHint addScopesFlow:(BOOL)addScopesFlow - completion:(nullable GIDSignInCompletion)completion { + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion { #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST GIDSignInInternalOptions *options = [self defaultOptionsWithConfiguration:configuration #if TARGET_OS_IOS || TARGET_OS_MACCATALYST @@ -85,7 +89,8 @@ + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)con return options; } -+ (instancetype)silentOptionsWithCompletion:(GIDSignInCompletion)completion { ++ (instancetype)silentOptionsWithCompletion:(void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion { GIDSignInInternalOptions *options = [self defaultOptionsWithConfiguration:nil #if TARGET_OS_IOS || TARGET_OS_MACCATALYST presentingViewController:nil diff --git a/GoogleSignIn/Sources/GIDSignIn_Private.h b/GoogleSignIn/Sources/GIDSignIn_Private.h index 5d1a6da5..5c48f919 100644 --- a/GoogleSignIn/Sources/GIDSignIn_Private.h +++ b/GoogleSignIn/Sources/GIDSignIn_Private.h @@ -21,6 +21,10 @@ NS_ASSUME_NONNULL_BEGIN @class GIDGoogleUser; @class GIDSignInInternalOptions; +// Represents a completion block that takes a `GIDUserAuth` on success or an error if the operation +// was unsuccessful. +typedef void (^GIDUserAuthCompletion)(GIDUserAuth *_Nullable userAuth, NSError *_Nullable error); + // Private |GIDSignIn| methods that are used internally in this SDK and other Google SDKs. @interface GIDSignIn () diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h index 35a8a15d..0a29e15b 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h @@ -25,6 +25,7 @@ @class GIDConfiguration; @class GIDGoogleUser; +@class GIDUserAuth; NS_ASSUME_NONNULL_BEGIN @@ -50,10 +51,6 @@ typedef NS_ERROR_ENUM(kGIDSignInErrorDomain, GIDSignInErrorCode) { kGIDSignInErrorCodeScopesAlreadyGranted = -8, }; -/// Represents a completion block that takes a `GIDGoogleUser` on success or an error if the operation -/// was unsuccessful. -typedef void (^GIDSignInCompletion)(GIDGoogleUser *_Nullable user, NSError *_Nullable error); - /// Represents a completion block that takes an error if the operation was unsuccessful. typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); @@ -91,9 +88,10 @@ typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); /// Attempts to restore a previously authenticated user without interaction. /// -/// @param completion The `GIDSignInCompletion` block that is called on completion. This block will -/// be called asynchronously on the main queue. -- (void)restorePreviousSignInWithCompletion:(nullable GIDSignInCompletion)completion; +/// @param completion The block that is called on completion. This block will be called asynchronously +/// on the main queue. +- (void)restorePreviousSignInWithCompletion:(nullable void (^)(GIDGoogleUser *_Nullable user, + NSError *_Nullable error))completion; /// Marks current user as being in the signed out state. - (void)signOut; @@ -117,11 +115,12 @@ typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); /// @param presentingViewController The view controller used to present `SFSafariViewContoller` on /// iOS 9 and 10 and to supply `presentationContextProvider` for `ASWebAuthenticationSession` on /// iOS 13+. -/// @param completion The `GIDSignInCompletion` block that is called on completion. This block will -/// be called asynchronously on the main queue. +/// @param completion The block that is called on completion. This block will be called asynchronously +/// on the main queue. - (void)signInWithConfiguration:(GIDConfiguration *)configuration presentingViewController:(UIViewController *)presentingViewController - completion:(nullable GIDSignInCompletion)completion + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion NS_EXTENSION_UNAVAILABLE("The sign-in flow is not supported in App Extensions."); /// Starts an interactive sign-in flow on iOS using the provided configuration and a login hint. @@ -137,12 +136,13 @@ typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); /// iOS 13+. /// @param hint An optional hint for the authorization server, for example the user's ID or email /// address, to be prefilled if possible. -/// @param completion The `GIDSignInCompletion` block that is called on completion. This block will -/// be called asynchronously on the main queue. +/// @param completion The block that is called on completion. This block will be called asynchronously +/// on the main queue. - (void)signInWithConfiguration:(GIDConfiguration *)configuration presentingViewController:(UIViewController *)presentingViewController hint:(nullable NSString *)hint - completion:(nullable GIDSignInCompletion)completion + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion NS_EXTENSION_UNAVAILABLE("The sign-in flow is not supported in App Extensions."); /// Starts an interactive sign-in flow on iOS using the provided configuration and a login hint. @@ -158,14 +158,14 @@ typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); /// @param hint An optional hint for the authorization server, for example the user's ID or email /// address, to be prefilled if possible. /// @param additionalScopes An optional array of scopes to request in addition to the basic profile scopes. -/// @param completion The `GIDSignInCompletion` block that is called on completion. This block will -/// be called asynchronously on the main queue. - +/// @param completion The block that is called on completion. This block will be called asynchronously +/// on the main queue. - (void)signInWithConfiguration:(GIDConfiguration *)configuration presentingViewController:(UIViewController *)presentingViewController hint:(nullable NSString *)hint additionalScopes:(nullable NSArray *)additionalScopes - completion:(nullable GIDSignInCompletion)completion; + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion; /// Starts an interactive consent flow on iOS to add scopes to the current user's grants. /// @@ -176,11 +176,12 @@ typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); /// @param presentingViewController The view controller used to present `SFSafariViewContoller` on /// iOS 9 and 10 and to supply `presentationContextProvider` for `ASWebAuthenticationSession` on /// iOS 13+. -/// @param completion The `GIDSignInCompletion` block that is called on completion. This block will -/// be called asynchronously on the main queue. +/// @param completion The block that is called on completion. This block will be called asynchronously +/// on the main queue. - (void)addScopes:(NSArray *)scopes presentingViewController:(UIViewController *)presentingViewController - completion:(nullable GIDSignInCompletion)completion + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion NS_EXTENSION_UNAVAILABLE("The add scopes flow is not supported in App Extensions."); #elif TARGET_OS_OSX @@ -193,11 +194,12 @@ typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); /// /// @param configuration The configuration properties to be used for this flow. /// @param presentingWindow The window used to supply `presentationContextProvider` for `ASWebAuthenticationSession`. -/// @param completion The `GIDSignInCompletion` block that is called on completion. This block will -/// be called asynchronously on the main queue. +/// @param completion The block that is called on completion. This block will be called asynchronously +/// on the main queue. - (void)signInWithConfiguration:(GIDConfiguration *)configuration presentingWindow:(NSWindow *)presentingWindow - completion:(nullable GIDSignInCompletion)completion; + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion; /// Starts an interactive sign-in flow on macOS using the provided configuration and a login hint. /// @@ -210,12 +212,13 @@ typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); /// @param presentingWindow The window used to supply `presentationContextProvider` for `ASWebAuthenticationSession`. /// @param hint An optional hint for the authorization server, for example the user's ID or email /// address, to be prefilled if possible. -/// @param completion The `GIDSignInCompletion` block that is called on completion. This block will -/// be called asynchronously on the main queue. +/// @param completion The block that is called on completion. This block will be called asynchronously +/// on the main queue. - (void)signInWithConfiguration:(GIDConfiguration *)configuration presentingWindow:(NSWindow *)presentingWindow hint:(nullable NSString *)hint - completion:(nullable GIDSignInCompletion)completion; + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion; /// Starts an interactive sign-in flow on macOS using the provided configuration and a login hint. /// @@ -229,14 +232,14 @@ typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); /// @param hint An optional hint for the authorization server, for example the user's ID or email /// address, to be prefilled if possible. /// @param additionalScopes An optional array of scopes to request in addition to the basic profile scopes. -/// @param completion The `GIDSignInCompletion` block that is called on completion. This block will -/// be called asynchronously on the main queue. - +/// @param completion The block that is called on completion. This block will be called asynchronously +/// on the main queue. - (void)signInWithConfiguration:(GIDConfiguration *)configuration presentingWindow:(NSWindow *)presentingWindow hint:(nullable NSString *)hint additionalScopes:(nullable NSArray *)additionalScopes - completion:(nullable GIDSignInCompletion)completion; + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion; /// Starts an interactive consent flow on macOS to add scopes to the current user's grants. /// @@ -245,11 +248,12 @@ typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); /// /// @param scopes An array of scopes to ask the user to consent to. /// @param presentingWindow The window used to supply `presentationContextProvider` for `ASWebAuthenticationSession`. -/// @param completion The `GIDSignInCompletion` block that is called on completion. This block will -/// be called asynchronously on the main queue. +/// @param completion The block that is called on completion. This block will be called asynchronously +/// on the main queue. - (void)addScopes:(NSArray *)scopes presentingWindow:(NSWindow *)presentingWindow - completion:(nullable GIDSignInCompletion)completion; + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion; #endif diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GoogleSignIn.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GoogleSignIn.h index 091f2c1a..df002612 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GoogleSignIn.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GoogleSignIn.h @@ -20,6 +20,7 @@ #import "GIDGoogleUser.h" #import "GIDProfileData.h" #import "GIDSignIn.h" +#import "GIDUserAuth.h" #if TARGET_OS_IOS || TARGET_OS_MACCATALYST #import "GIDSignInButton.h" #endif diff --git a/GoogleSignIn/Tests/Unit/GIDSignInInternalOptionsTest.m b/GoogleSignIn/Tests/Unit/GIDSignInInternalOptionsTest.m index ce98c93a..cc1d63d2 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInInternalOptionsTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInInternalOptionsTest.m @@ -37,8 +37,9 @@ - (void)testDefaultOptions { id presentingWindow = OCMStrictClassMock([NSWindow class]); #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST NSString *loginHint = @"login_hint"; - GIDSignInCompletion completion = ^(GIDGoogleUser * _Nullable user, NSError * _Nullable error) {}; - + + void (^completion)(GIDUserAuth *_Nullable userAuth, NSError *_Nullable error) = + ^(GIDUserAuth *_Nullable userAuth, NSError * _Nullable error) {}; GIDSignInInternalOptions *options = [GIDSignInInternalOptions defaultOptionsWithConfiguration:configuration #if TARGET_OS_IOS || TARGET_OS_MACCATALYST @@ -63,9 +64,9 @@ - (void)testDefaultOptions { } - (void)testSilentOptions { - GIDSignInCompletion completion = ^(GIDGoogleUser * _Nullable user, NSError * _Nullable error) {}; - GIDSignInInternalOptions *options = [GIDSignInInternalOptions - silentOptionsWithCompletion:completion]; + void (^completion)(GIDUserAuth *_Nullable userAuth, NSError *_Nullable error) = + ^(GIDUserAuth *_Nullable userAuth, NSError * _Nullable error) {}; + GIDSignInInternalOptions *options = [GIDSignInInternalOptions silentOptionsWithCompletion:completion]; XCTAssertFalse(options.interactive); XCTAssertFalse(options.continuation); XCTAssertNil(options.extraParams); diff --git a/GoogleSignIn/Tests/Unit/GIDSignInTest.m b/GoogleSignIn/Tests/Unit/GIDSignInTest.m index 0a74e01c..3449eb34 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInTest.m @@ -241,7 +241,7 @@ @interface GIDSignInTest : XCTestCase { NSString *_hint; // The completion to be used when testing |GIDSignIn|. - GIDSignInCompletion _completion; + GIDUserAuthCompletion _completion; // The saved authorization request. OIDAuthorizationRequest *_savedAuthorizationRequest; @@ -346,10 +346,10 @@ - (void)setUp { _hint = nil; __weak GIDSignInTest *weakSelf = self; - _completion = ^(GIDGoogleUser * _Nullable user, NSError * _Nullable error) { + _completion = ^(GIDUserAuth *_Nullable userAuth, NSError * _Nullable error) { GIDSignInTest *strongSelf = weakSelf; - if (!user) { - XCTAssertNotNil(error, @"should have an error if user is nil"); + if (!userAuth) { + XCTAssertNotNil(error, @"should have an error if the userAuth is nil"); } XCTAssertFalse(strongSelf->_completionCalled, @"callback already called"); strongSelf->_completionCalled = YES; @@ -1073,6 +1073,7 @@ - (void)testTokenEndpointEMMError { NSError *handledError = [NSError errorWithDomain:kGIDSignInErrorDomain code:kGIDSignInErrorCodeEMM userInfo:emmError.userInfo]; + completion(handledError); [self waitForExpectationsWithTimeout:1 handler:nil]; @@ -1220,10 +1221,13 @@ - (void)OAuthLoginWithAddScopesFlow:(BOOL)addScopesFlow } } else { XCTestExpectation *expectation = [self expectationWithDescription:@"Callback called"]; - GIDSignInCompletion completion = ^(GIDGoogleUser * _Nullable user, NSError * _Nullable error) { + GIDUserAuthCompletion completion = + ^(GIDUserAuth *_Nullable userAuth, NSError * _Nullable error) { [expectation fulfill]; - if (!user) { - XCTAssertNotNil(error, @"should have an error if user is nil"); + if (userAuth) { + XCTAssertEqualObjects(userAuth.serverAuthCode, kServerAuthCode); + } else { + XCTAssertNotNil(error, @"Should have an error if the userAuth is nil"); } XCTAssertFalse(self->_completionCalled, @"callback already called"); self->_completionCalled = YES; @@ -1348,6 +1352,11 @@ - (void)OAuthLoginWithAddScopesFlow:(BOOL)addScopesFlow profileData:SAVE_TO_ARG_BLOCK(profileData)]; } } + + // CompletionCallback - mock server auth code parsing + if (!keychainError) { + [[[_authState expect] andReturn:tokenResponse] lastTokenResponse]; + } if (restoredSignIn && !oldAccessToken) { XCTestExpectation *expectation = [self expectationWithDescription:@"Callback should be called"]; @@ -1361,11 +1370,13 @@ - (void)OAuthLoginWithAddScopesFlow:(BOOL)addScopesFlow _savedTokenCallback(tokenResponse, nil); } - [_authState verify]; if (keychainError) { return; } [self waitForExpectationsWithTimeout:1 handler:nil]; + + [_authState verify]; + XCTAssertTrue(_keychainSaved, @"should save to keychain"); XCTAssertNotNil(authState); // Check fat ID token decoding diff --git a/Samples/ObjC/SignInSample/Source/SignInViewController.m b/Samples/ObjC/SignInSample/Source/SignInViewController.m index 009e698c..d3fad276 100644 --- a/Samples/ObjC/SignInSample/Source/SignInViewController.m +++ b/Samples/ObjC/SignInSample/Source/SignInViewController.m @@ -259,8 +259,8 @@ - (void)updateButtons { - (IBAction)signIn:(id)sender { [GIDSignIn.sharedInstance signInWithConfiguration:_configuration presentingViewController:self - callback:^(GIDGoogleUser * _Nullable user, - NSError * _Nullable error) { + callback:^(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error) { if (error) { self->_signInAuthStatus.text = [NSString stringWithFormat:@"Status: Authentication error: %@", error]; @@ -278,7 +278,7 @@ - (IBAction)signOut:(id)sender { } - (IBAction)disconnect:(id)sender { - [GIDSignIn.sharedInstance disconnectWithCallback:^(NSError * _Nullable error) { + [GIDSignIn.sharedInstance disconnectWithCallback:^(NSError *_Nullable error) { if (error) { self->_signInAuthStatus.text = [NSString stringWithFormat:@"Status: Failed to disconnect: %@", error]; @@ -293,8 +293,8 @@ - (IBAction)disconnect:(id)sender { - (IBAction)addScopes:(id)sender { [GIDSignIn.sharedInstance addScopes:@[ @"https://www.googleapis.com/auth/user.birthday.read" ] presentingViewController:self - callback:^(GIDGoogleUser * _Nullable user, - NSError * _Nullable error) { + callback:^(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error) { if (error) { self->_signInAuthStatus.text = [NSString stringWithFormat:@"Status: Failed to add scopes: %@", error]; diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift index 2a0e88fd..b798fb10 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift @@ -48,12 +48,12 @@ final class GoogleSignInAuthenticator: ObservableObject { } GIDSignIn.sharedInstance.signIn(with: configuration, - presenting: rootViewController) { user, error in - guard let user = user else { + presenting: rootViewController) { userAuth, error in + guard let userAuth = userAuth else { print("Error! \(String(describing: error))") return } - self.authViewModel.state = .signedIn(user) + self.authViewModel.state = .signedIn(userAuth.user) } #elseif os(macOS) @@ -63,12 +63,12 @@ final class GoogleSignInAuthenticator: ObservableObject { } GIDSignIn.sharedInstance.signIn(with: configuration, - presenting: presentingWindow) { user, error in - guard let user = user else { + presenting: presentingWindow) { userAuth, error in + guard let userAuth = userAuth else { print("Error! \(String(describing: error))") return } - self.authViewModel.state = .signedIn(user) + self.authViewModel.state = .signedIn(userAuth.user) } #endif } @@ -102,14 +102,14 @@ final class GoogleSignInAuthenticator: ObservableObject { } GIDSignIn.sharedInstance.addScopes([BirthdayLoader.birthdayReadScope], - presenting: rootViewController) { user, error in + presenting: rootViewController) { userAuth, error in if let error = error { print("Found error while adding birthday read scope: \(error).") return } - guard let currentUser = user else { return } - self.authViewModel.state = .signedIn(currentUser) + guard let userAuth = userAuth else { return } + self.authViewModel.state = .signedIn(userAuth.user) completion() } @@ -119,14 +119,14 @@ final class GoogleSignInAuthenticator: ObservableObject { } GIDSignIn.sharedInstance.addScopes([BirthdayLoader.birthdayReadScope], - presenting: presentingWindow) { user, error in + presenting: presentingWindow) { userAuth, error in if let error = error { print("Found error while adding birthday read scope: \(error).") return } - guard let currentUser = user else { return } - self.authViewModel.state = .signedIn(currentUser) + guard let userAuth = userAuth else { return } + self.authViewModel.state = .signedIn(userAuth.user) completion() } From 4094422bd5a5073685ef387bb2ff40507ccc3e58 Mon Sep 17 00:00:00 2001 From: pinlu Date: Mon, 18 Jul 2022 11:46:28 -0700 Subject: [PATCH 04/17] Add GIDToken Class (#181) Add GIDToken class --- .../Sources/GIDSignInInternalOptions.m | 1 - GoogleSignIn/Sources/GIDToken.m | 58 +++++++++++++++++++ GoogleSignIn/Sources/GIDToken_Private.h | 32 ++++++++++ .../Sources/Public/GoogleSignIn/GIDToken.h | 38 ++++++++++++ .../Public/GoogleSignIn/GoogleSignIn.h | 1 + GoogleSignIn/Tests/Unit/GIDTokenTest.m | 56 ++++++++++++++++++ 6 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 GoogleSignIn/Sources/GIDToken.m create mode 100644 GoogleSignIn/Sources/GIDToken_Private.h create mode 100644 GoogleSignIn/Sources/Public/GoogleSignIn/GIDToken.h create mode 100644 GoogleSignIn/Tests/Unit/GIDTokenTest.m diff --git a/GoogleSignIn/Sources/GIDSignInInternalOptions.m b/GoogleSignIn/Sources/GIDSignInInternalOptions.m index 745cfa70..dfa39aa1 100644 --- a/GoogleSignIn/Sources/GIDSignInInternalOptions.m +++ b/GoogleSignIn/Sources/GIDSignInInternalOptions.m @@ -42,7 +42,6 @@ + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)con completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, NSError *_Nullable error))completion { #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST - GIDSignInInternalOptions *options = [[GIDSignInInternalOptions alloc] init]; if (options) { options->_interactive = YES; diff --git a/GoogleSignIn/Sources/GIDToken.m b/GoogleSignIn/Sources/GIDToken.m new file mode 100644 index 00000000..05d3f1dc --- /dev/null +++ b/GoogleSignIn/Sources/GIDToken.m @@ -0,0 +1,58 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDToken.h" + +#import "GoogleSignIn/Sources/GIDToken_Private.h" + +// Key constants used for encode and decode. +static NSString *const kTokenStringKey = @"tokenString"; +static NSString *const kExpirationDateKey = @"expirationDate"; + +@implementation GIDToken + +- (instancetype)initWithTokenString:(NSString *)tokenString + expirationDate:(NSDate *)expirationDate { + self = [super init]; + if (self) { + _tokenString = tokenString; + _expirationDate = expirationDate; + } + + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)decoder { + self = [super init]; + if (self) { + _tokenString = [decoder decodeObjectOfClass:[NSString class] forKey:kTokenStringKey]; + _expirationDate = [decoder decodeObjectOfClass:[NSDate class] forKey:kExpirationDateKey]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)encoder { + [encoder encodeObject:_tokenString forKey:kTokenStringKey]; + [encoder encodeObject:_expirationDate forKey:kExpirationDateKey]; +} + +@end diff --git a/GoogleSignIn/Sources/GIDToken_Private.h b/GoogleSignIn/Sources/GIDToken_Private.h new file mode 100644 index 00000000..b078cb5a --- /dev/null +++ b/GoogleSignIn/Sources/GIDToken_Private.h @@ -0,0 +1,32 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDUserAuth.h" + +NS_ASSUME_NONNULL_BEGIN + +// Private |GIDToken| methods that are used in this SDK. +@interface GIDToken () + +// Private initializer for |GIDToken|. +// @param token The token String. +// @param expirationDate The expiration date of the token. +- (instancetype)initWithTokenString:(NSString *)tokenString + expirationDate:(NSDate *)expirationDate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDToken.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDToken.h new file mode 100644 index 00000000..29f5d3b9 --- /dev/null +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDToken.h @@ -0,0 +1,38 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// This class represents the basic information of a token. +@interface GIDToken : NSObject + +/// The token string. +@property(nonatomic, copy, readonly) NSString *tokenString; + +/// The estimated expiration date of the token. +@property(nonatomic, readonly, nullable) NSDate *expirationDate; + +/// Unsupported. ++ (instancetype)new NS_UNAVAILABLE; + +/// Unsupported. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GoogleSignIn.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GoogleSignIn.h index df002612..d1b7afda 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GoogleSignIn.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GoogleSignIn.h @@ -20,6 +20,7 @@ #import "GIDGoogleUser.h" #import "GIDProfileData.h" #import "GIDSignIn.h" +#import "GIDToken.h" #import "GIDUserAuth.h" #if TARGET_OS_IOS || TARGET_OS_MACCATALYST #import "GIDSignInButton.h" diff --git a/GoogleSignIn/Tests/Unit/GIDTokenTest.m b/GoogleSignIn/Tests/Unit/GIDTokenTest.m new file mode 100644 index 00000000..aa9d1b1a --- /dev/null +++ b/GoogleSignIn/Tests/Unit/GIDTokenTest.m @@ -0,0 +1,56 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDToken.h" + +#import "GoogleSignIn/Sources/GIDToken_Private.h" + +static NSString * const tokenString = @"tokenString"; + +@interface GIDTokenTest : XCTestCase { + NSDate *_date; +} +@end + +@implementation GIDTokenTest + +- (void)setUP { + [super setUp]; + _date = [[NSDate alloc]initWithTimeIntervalSince1970:1000]; +} + +- (void)testInitializer { + GIDToken *token = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:_date]; + XCTAssertEqualObjects(token.tokenString, tokenString); + XCTAssertEqualObjects(token.expirationDate, _date); +} + +- (void)testCoding { + if (@available(iOS 11, macOS 10.13, *)) { + GIDToken *token = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:_date]; + NSData *data = [NSKeyedArchiver archivedDataWithRootObject:token requiringSecureCoding:YES error:nil]; + GIDToken *newToken = [NSKeyedUnarchiver unarchivedObjectOfClass:[GIDToken class] + fromData:data + error:nil]; + XCTAssertEqualObjects(token.tokenString, newToken.tokenString); + XCTAssertEqualObjects(token.expirationDate, newToken.expirationDate); + + XCTAssertTrue([GIDToken supportsSecureCoding]); + } else { + XCTSkip(@"Required API is not available for this test."); + } +} + +@end From be4f6fa1f9c033bae397c42c64412e64fa3802f7 Mon Sep 17 00:00:00 2001 From: pinlu Date: Mon, 25 Jul 2022 15:01:49 -0700 Subject: [PATCH 05/17] Add the property `configuration` to `GIDGoogleUser` (#183) * Add the property GIDConfiguration to GIDGoogleUser - Add a GIDConfiguration to replace hostedDomain, serverClientID, openRealm. - Remove the property serverAuthCode. --- GoogleSignIn/Sources/GIDGoogleUser.m | 66 ++++++++++++------- GoogleSignIn/Sources/GIDSignIn.m | 12 +--- .../Public/GoogleSignIn/GIDGoogleUser.h | 15 +---- .../Tests/Unit/GIDConfiguration+Testing.m | 6 ++ .../Tests/Unit/GIDGoogleUser+Testing.m | 9 +-- GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m | 5 +- GoogleSignIn/Tests/Unit/GIDSignInTest.m | 27 +++++--- .../Tests/Unit/OIDTokenResponse+Testing.m | 2 +- 8 files changed, 79 insertions(+), 63 deletions(-) diff --git a/GoogleSignIn/Sources/GIDGoogleUser.m b/GoogleSignIn/Sources/GIDGoogleUser.m index 34e636d6..8cefa6fa 100644 --- a/GoogleSignIn/Sources/GIDGoogleUser.m +++ b/GoogleSignIn/Sources/GIDGoogleUser.m @@ -12,8 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h" + #import "GoogleSignIn/Sources/GIDGoogleUser_Private.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" + #import "GoogleSignIn/Sources/GIDAuthentication_Private.h" #import "GoogleSignIn/Sources/GIDProfileData_Private.h" @@ -39,6 +43,7 @@ @implementation GIDGoogleUser { OIDAuthState *_authState; + GIDConfiguration *_cachedConfiguration; } - (nullable NSString *)userID { @@ -53,30 +58,6 @@ - (nullable NSString *)userID { return nil; } -- (nullable NSString *)hostedDomain { - NSString *idToken = [self idToken]; - if (idToken) { - OIDIDToken *idTokenDecoded = [[OIDIDToken alloc] initWithIDTokenString:idToken]; - if (idTokenDecoded && idTokenDecoded.claims[kHostedDomainIDTokenClaimKey]) { - return [idTokenDecoded.claims[kHostedDomainIDTokenClaimKey] copy]; - } - } - - return nil; -} - -- (nullable NSString *)serverAuthCode { - return [_authState.lastTokenResponse.additionalParameters[@"server_code"] copy]; -} - -- (nullable NSString *)serverClientID { - return [_authState.lastTokenResponse.request.additionalParameters[kAudienceParameter] copy]; -} - -- (nullable NSString *)openIDRealm { - return [_authState.lastTokenResponse.request.additionalParameters[kOpenIDRealmParameter] copy]; -} - - (nullable NSArray *)grantedScopes { NSArray *grantedScopes; NSString *grantedScopeString = _authState.lastTokenResponse.scope; @@ -95,6 +76,20 @@ - (nullable NSString *)openIDRealm { return grantedScopes; } +- (GIDConfiguration *)configuration { + @synchronized(self) { + // Caches the configuration since it would not change for one GIDGoogleUser instance. + if (!_cachedConfiguration) { + _cachedConfiguration = [[GIDConfiguration alloc] initWithClientID:[self clientID] + serverClientID:[self serverClientID] + hostedDomain:[self hostedDomain] + openIDRealm:[self openIDRealm]]; + }; + } + + return _cachedConfiguration; +} + #pragma mark - Private Methods - (instancetype)initWithAuthState:(OIDAuthState *)authState @@ -115,10 +110,33 @@ - (void)updateAuthState:(OIDAuthState *)authState #pragma mark - Helpers +- (NSString *)clientID { + return _authState.lastAuthorizationResponse.request.clientID; +} + +- (nullable NSString *)hostedDomain { + NSString *idToken = [self idToken]; + if (idToken) { + OIDIDToken *idTokenDecoded = [[OIDIDToken alloc] initWithIDTokenString:idToken]; + if (idTokenDecoded && idTokenDecoded.claims[kHostedDomainIDTokenClaimKey]) { + return [idTokenDecoded.claims[kHostedDomainIDTokenClaimKey] copy]; + } + } + return nil; +} + - (NSString *)idToken { return _authState ? _authState.lastTokenResponse.idToken : nil; } +- (nullable NSString *)serverClientID { + return [_authState.lastTokenResponse.request.additionalParameters[kAudienceParameter] copy]; +} + +- (nullable NSString *)openIDRealm { + return [_authState.lastTokenResponse.request.additionalParameters[kOpenIDRealmParameter] copy]; +} + #pragma mark - NSSecureCoding + (BOOL)supportsSecureCoding { diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index a8bbb47a..093e7a85 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -278,11 +278,7 @@ - (void)addScopes:(NSArray *)scopes return; } - GIDConfiguration *configuration = - [[GIDConfiguration alloc] initWithClientID:self.currentUser.authentication.clientID - serverClientID:self.currentUser.serverClientID - hostedDomain:self.currentUser.hostedDomain - openIDRealm:self.currentUser.openIDRealm]; + GIDConfiguration *configuration = self.currentUser.configuration; GIDSignInInternalOptions *options = [GIDSignInInternalOptions defaultOptionsWithConfiguration:configuration presentingViewController:presentingViewController @@ -371,11 +367,7 @@ - (void)addScopes:(NSArray *)scopes return; } - GIDConfiguration *configuration = - [[GIDConfiguration alloc] initWithClientID:self.currentUser.authentication.clientID - serverClientID:self.currentUser.serverClientID - hostedDomain:self.currentUser.hostedDomain - openIDRealm:self.currentUser.openIDRealm]; + GIDConfiguration *configuration = self.currentUser.configuration; GIDSignInInternalOptions *options = [GIDSignInInternalOptions defaultOptionsWithConfiguration:configuration presentingWindow:presentingWindow diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h index f5f130df..9a17af70 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h @@ -19,6 +19,7 @@ NS_ASSUME_NONNULL_BEGIN @class GIDAuthentication; +@class GIDConfiguration; @class GIDProfileData; /// This class represents a user account. @@ -36,18 +37,8 @@ NS_ASSUME_NONNULL_BEGIN /// The API scopes granted to the app in an array of `NSString`. @property(nonatomic, readonly, nullable) NSArray *grantedScopes; -/// For Google Apps hosted accounts, the domain of the user. -@property(nonatomic, readonly, nullable) NSString *hostedDomain; - -/// The client ID of the home server. -@property(nonatomic, readonly, nullable) NSString *serverClientID; - -/// An OAuth2 authorization code for the home server. -@property(nonatomic, readonly, nullable) NSString *serverAuthCode; - -/// The OpenID2 realm of the home server. -@property(nonatomic, readonly, nullable) NSString *openIDRealm; - +/// The configuration that was used to sign in this user. +@property(nonatomic, readonly) GIDConfiguration *configuration; @end diff --git a/GoogleSignIn/Tests/Unit/GIDConfiguration+Testing.m b/GoogleSignIn/Tests/Unit/GIDConfiguration+Testing.m index 8fd52fc1..72bc9106 100644 --- a/GoogleSignIn/Tests/Unit/GIDConfiguration+Testing.m +++ b/GoogleSignIn/Tests/Unit/GIDConfiguration+Testing.m @@ -46,6 +46,12 @@ - (BOOL)isEqualToConfiguration:(GIDConfiguration *)other { self.openIDRealm == other.openIDRealm); } +// Not the hash implemention you want to use on prod, but just to match |isEqual:| here. +- (NSUInteger)hash { + return [self.clientID hash] ^ [self.serverClientID hash] ^ [self.hostedDomain hash] ^ + [self.openIDRealm hash]; +} + + (instancetype)testInstance { return [[GIDConfiguration alloc] initWithClientID:OIDAuthorizationRequestTestingClientID serverClientID:kServerClientID diff --git a/GoogleSignIn/Tests/Unit/GIDGoogleUser+Testing.m b/GoogleSignIn/Tests/Unit/GIDGoogleUser+Testing.m index 64e00fed..de89f8d3 100644 --- a/GoogleSignIn/Tests/Unit/GIDGoogleUser+Testing.m +++ b/GoogleSignIn/Tests/Unit/GIDGoogleUser+Testing.m @@ -14,7 +14,9 @@ #import "GoogleSignIn/Tests/Unit/GIDGoogleUser+Testing.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" #import "GoogleSignIn/Tests/Unit/GIDAuthentication+Testing.h" +#import "GoogleSignIn/Tests/Unit/GIDConfiguration+Testing.h" #import "GoogleSignIn/Tests/Unit/GIDProfileData+Testing.h" @implementation GIDGoogleUser (Testing) @@ -32,15 +34,14 @@ - (BOOL)isEqual:(id)object { - (BOOL)isEqualToGoogleUser:(GIDGoogleUser *)other { return [self.authentication isEqual:other.authentication] && [self.userID isEqual:other.userID] && - [self.serverAuthCode isEqual:other.serverAuthCode] && [self.profile isEqual:other.profile] && - [self.hostedDomain isEqual:other.hostedDomain]; + [self.configuration isEqual:other.configuration]; } // Not the hash implemention you want to use on prod, but just to match |isEqual:| here. - (NSUInteger)hash { - return [self.authentication hash] ^ [self.userID hash] ^ [self.serverAuthCode hash] ^ - [self.profile hash] ^ [self.hostedDomain hash]; + return [self.authentication hash] ^ [self.userID hash] ^ [self.configuration hash] ^ + [self.profile hash] ; } @end diff --git a/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m b/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m index 6dee9267..dea0abad 100644 --- a/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m +++ b/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m @@ -17,6 +17,7 @@ #import #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDAuthentication.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDProfileData.h" #import "GoogleSignIn/Sources/GIDAuthentication_Private.h" @@ -49,8 +50,8 @@ - (void)testInitWithAuthState { XCTAssertEqualObjects(user.authentication, authentication); XCTAssertEqualObjects(user.grantedScopes, @[ OIDAuthorizationRequestTestingScope2 ]); XCTAssertEqualObjects(user.userID, kUserID); - XCTAssertEqualObjects(user.hostedDomain, kHostedDomain); - XCTAssertEqualObjects(user.serverAuthCode, kServerAuthCode); + XCTAssertEqualObjects(user.configuration.hostedDomain, kHostedDomain); + XCTAssertEqualObjects(user.configuration.clientID, OIDAuthorizationRequestTestingClientID); XCTAssertEqualObjects(user.profile, [GIDProfileData testInstance]); } diff --git a/GoogleSignIn/Tests/Unit/GIDSignInTest.m b/GoogleSignIn/Tests/Unit/GIDSignInTest.m index 3449eb34..84c2cece 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInTest.m @@ -397,22 +397,29 @@ - (void)testShareInstance { - (void)testRestorePreviousSignInNoRefresh_hasPreviousUser { [[[_authorization expect] andReturn:_authState] authState]; OCMStub([_authState lastTokenResponse]).andReturn(_tokenResponse); - OCMStub([_tokenResponse scope]).andReturn(nil); - OCMStub([_tokenResponse additionalParameters]).andReturn(nil); - OCMStub([_tokenResponse idToken]).andReturn(kFakeIDToken); - OCMStub([_tokenResponse request]).andReturn(_tokenRequest); - OCMStub([_tokenRequest additionalParameters]).andReturn(nil); id idTokenDecoded = OCMClassMock([OIDIDToken class]); OCMStub([idTokenDecoded alloc]).andReturn(idTokenDecoded); OCMStub([idTokenDecoded initWithIDTokenString:OCMOCK_ANY]).andReturn(idTokenDecoded); OCMStub([idTokenDecoded subject]).andReturn(kFakeGaiaID); + + // Mock generating a GIDConfiguration when initializing GIDGoogleUser. + OIDAuthorizationResponse *authResponse = + [OIDAuthorizationResponse testInstanceWithAdditionalParameters:nil + errorString:nil]; + + OCMStub([_authState lastAuthorizationResponse]).andReturn(authResponse); + OCMStub([_tokenResponse idToken]).andReturn(kFakeIDToken); + OCMStub([_tokenResponse request]).andReturn(_tokenRequest); + OCMStub([_tokenRequest additionalParameters]).andReturn(nil); [_signIn restorePreviousSignInNoRefresh]; [_authorization verify]; [_authState verify]; [_tokenResponse verify]; + [_tokenRequest verify]; + [idTokenDecoded verify]; XCTAssertEqual(_signIn.currentUser.userID, kFakeGaiaID); [idTokenDecoded stopMocking]; @@ -569,11 +576,9 @@ - (void)testAddScopes { OCMStub([profile email]).andReturn(kUserEmail); OCMStub([_user authentication]).andReturn(_authentication); - OCMStub([_authentication clientID]).andReturn(kClientId); - OCMStub([_user serverClientID]).andReturn(nil); - OCMStub([_user hostedDomain]).andReturn(nil); - - OCMStub([_user openIDRealm]).andReturn(kOpenIDRealm); + + // Mock for the method `addScopes`. + OCMStub([_user configuration]).andReturn(_configuration); OCMStub([_user profile]).andReturn(profile); OCMStub([_user grantedScopes]).andReturn(@[kGrantedScope]); @@ -603,6 +608,8 @@ - (void)testAddScopes { NSArray *expectedScopes = @[kNewScope, kGrantedScope]; XCTAssertEqualObjects(grantedScopes, expectedScopes); + [_user verify]; + [profile verify]; [profile stopMocking]; } diff --git a/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.m b/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.m index b8a5974d..1e1b95bf 100644 --- a/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.m +++ b/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.m @@ -112,7 +112,7 @@ + (NSString *)idTokenWithSub:(NSString *)sub exp:(NSNumber *)exp fat:(BOOL)fat { NSMutableDictionary *payloadContents = [NSMutableDictionary dictionaryWithDictionary:@{ @"sub" : sub, - @"hd" : kHostedDomain, + @"hd" : kHostedDomain, @"iss" : kIssuer, @"aud" : kAudience, @"exp" : exp, From 71f82c0c75b694059a63920e97b0039c16241918 Mon Sep 17 00:00:00 2001 From: pinlu Date: Fri, 15 Jul 2022 23:25:21 -0700 Subject: [PATCH 06/17] Replace GIDSignInCallback (#179) Replace GIDSignInCallback with block void (^)(GIDUserAuth *_Nullable userAuth, NSError *_Nullable error) --- GoogleSignIn/Sources/GIDSignInInternalOptions.h | 1 + 1 file changed, 1 insertion(+) diff --git a/GoogleSignIn/Sources/GIDSignInInternalOptions.h b/GoogleSignIn/Sources/GIDSignInInternalOptions.h index a51bfd95..03596504 100644 --- a/GoogleSignIn/Sources/GIDSignInInternalOptions.h +++ b/GoogleSignIn/Sources/GIDSignInInternalOptions.h @@ -88,6 +88,7 @@ NS_ASSUME_NONNULL_BEGIN completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, NSError *_Nullable error))completion; + + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)configuration presentingWindow:(nullable NSWindow *)presentingWindow loginHint:(nullable NSString *)loginHint From 02d37363541182078d45e89ce962cc371c251e7f Mon Sep 17 00:00:00 2001 From: pinlu Date: Thu, 28 Jul 2022 15:03:19 -0700 Subject: [PATCH 07/17] Add three tokens in GIDGoogleUser API --- GoogleSignIn/Sources/GIDGoogleUser.m | 49 ++++++++++++++++--- GoogleSignIn/Sources/GIDToken.m | 35 ++++++++++++- GoogleSignIn/Sources/GIDToken_Private.h | 4 +- .../Public/GoogleSignIn/GIDGoogleUser.h | 12 +++++ .../Tests/Unit/GIDGoogleUser+Testing.m | 10 +++- GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m | 3 ++ GoogleSignIn/Tests/Unit/GIDSignInTest.m | 7 ++- GoogleSignIn/Tests/Unit/GIDTokenTest.m | 13 ++++- 8 files changed, 117 insertions(+), 16 deletions(-) diff --git a/GoogleSignIn/Sources/GIDGoogleUser.m b/GoogleSignIn/Sources/GIDGoogleUser.m index 8cefa6fa..50fbd00b 100644 --- a/GoogleSignIn/Sources/GIDGoogleUser.m +++ b/GoogleSignIn/Sources/GIDGoogleUser.m @@ -20,6 +20,7 @@ #import "GoogleSignIn/Sources/GIDAuthentication_Private.h" #import "GoogleSignIn/Sources/GIDProfileData_Private.h" +#import "GoogleSignIn/Sources/GIDToken_Private.h" #ifdef SWIFT_PACKAGE @import AppAuth; @@ -47,7 +48,7 @@ @implementation GIDGoogleUser { } - (nullable NSString *)userID { - NSString *idToken = [self idToken]; + NSString *idToken = [self idTokenString]; if (idToken) { OIDIDToken *idTokenDecoded = [[OIDIDToken alloc] initWithIDTokenString:idToken]; if (idTokenDecoded && idTokenDecoded.subject) { @@ -106,6 +107,7 @@ - (void)updateAuthState:(OIDAuthState *)authState _authState = authState; _authentication = [[GIDAuthentication alloc] initWithAuthState:authState]; _profile = profileData; + [self updateTokens]; } #pragma mark - Helpers @@ -115,9 +117,9 @@ - (NSString *)clientID { } - (nullable NSString *)hostedDomain { - NSString *idToken = [self idToken]; - if (idToken) { - OIDIDToken *idTokenDecoded = [[OIDIDToken alloc] initWithIDTokenString:idToken]; + NSString *idTokenString = [self idTokenString]; + if (idTokenString) { + OIDIDToken *idTokenDecoded = [[OIDIDToken alloc] initWithIDTokenString:idTokenString]; if (idTokenDecoded && idTokenDecoded.claims[kHostedDomainIDTokenClaimKey]) { return [idTokenDecoded.claims[kHostedDomainIDTokenClaimKey] copy]; } @@ -125,10 +127,6 @@ - (nullable NSString *)hostedDomain { return nil; } -- (NSString *)idToken { - return _authState ? _authState.lastTokenResponse.idToken : nil; -} - - (nullable NSString *)serverClientID { return [_authState.lastTokenResponse.request.additionalParameters[kAudienceParameter] copy]; } @@ -137,6 +135,40 @@ - (nullable NSString *)openIDRealm { return [_authState.lastTokenResponse.request.additionalParameters[kOpenIDRealmParameter] copy]; } +- (NSString *)idTokenString { + return _authState.lastTokenResponse.idToken; +} + +- (nullable NSDate *)idTokenExpirationDate { + return [[[OIDIDToken alloc] initWithIDTokenString:self.idTokenString] expiresAt]; +} + +- (NSString *)accessTokenString { + return _authState.lastTokenResponse.accessToken; +} + +- (NSDate *)accessTokenExpirationDate { + return _authState.lastTokenResponse.accessTokenExpirationDate; +} + +- (NSString *)refreshTokenString { + return _authState.refreshToken; +} + +- (void)updateTokens { + _accessToken = [[GIDToken alloc] initWithTokenString:[self accessTokenString] + expirationDate:[self accessTokenExpirationDate]]; + _refreshToken = [[GIDToken alloc] initWithTokenString:[self refreshTokenString] + expirationDate:nil]; + NSString *idTokenString = [self idTokenString]; + if (idTokenString) { + _idToken = [[GIDToken alloc] initWithTokenString:[self idTokenString] + expirationDate:[self idTokenExpirationDate]]; + } else { + _idToken = nil; + } +} + #pragma mark - NSSecureCoding + (BOOL)supportsSecureCoding { @@ -155,6 +187,7 @@ - (nullable instancetype)initWithCoder:(NSCoder *)decoder { _authState = authentication.authState; } _authentication = [[GIDAuthentication alloc] initWithAuthState:_authState]; + [self updateTokens]; } return self; } diff --git a/GoogleSignIn/Sources/GIDToken.m b/GoogleSignIn/Sources/GIDToken.m index 05d3f1dc..2db0c794 100644 --- a/GoogleSignIn/Sources/GIDToken.m +++ b/GoogleSignIn/Sources/GIDToken.m @@ -25,7 +25,7 @@ @implementation GIDToken - (instancetype)initWithTokenString:(NSString *)tokenString - expirationDate:(NSDate *)expirationDate { + expirationDate:(nullable NSDate *)expirationDate { self = [super init]; if (self) { _tokenString = tokenString; @@ -55,4 +55,37 @@ - (void)encodeWithCoder:(NSCoder *)encoder { [encoder encodeObject:_expirationDate forKey:kExpirationDateKey]; } +#pragma mark - isEqual + +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[GIDToken class]]) { + return NO; + } + return [self isEqualToGIDToken:(GIDToken *)object]; +} + +- (BOOL)isEqualToGIDToken:(GIDToken *)other { + return [_tokenString isEqual:other.tokenString] && + [self isTheSameDateWithDate1:_expirationDate date2:other.expirationDate]; +} + +- (BOOL)isTheSameDateWithDate1:(NSDate *)date1 + date2:(NSDate *)date2 { + // The date is nullable. Two `null` date is equal. + if (!date1 && !date2) { + return YES; + } + if (!date1 || !date2) { + return NO; + } + return [date1 isEqualToDate:date2]; +} + +- (NSUInteger)hash { + return [self.tokenString hash] ^ [self.expirationDate hash]; +} + @end diff --git a/GoogleSignIn/Sources/GIDToken_Private.h b/GoogleSignIn/Sources/GIDToken_Private.h index b078cb5a..0ce94af4 100644 --- a/GoogleSignIn/Sources/GIDToken_Private.h +++ b/GoogleSignIn/Sources/GIDToken_Private.h @@ -14,7 +14,7 @@ * limitations under the License. */ -#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDUserAuth.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDToken.h" NS_ASSUME_NONNULL_BEGIN @@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN // @param token The token String. // @param expirationDate The expiration date of the token. - (instancetype)initWithTokenString:(NSString *)tokenString - expirationDate:(NSDate *)expirationDate; + expirationDate:(nullable NSDate *)expirationDate; @end diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h index 9a17af70..4d6a6a80 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h @@ -20,6 +20,7 @@ NS_ASSUME_NONNULL_BEGIN @class GIDAuthentication; @class GIDConfiguration; +@class GIDToken; @class GIDProfileData; /// This class represents a user account. @@ -40,6 +41,17 @@ NS_ASSUME_NONNULL_BEGIN /// The configuration that was used to sign in this user. @property(nonatomic, readonly) GIDConfiguration *configuration; +/// The OAuth2 access token to access Google services. +@property(nonatomic, readonly) GIDToken *accessToken; + +/// The OAuth2 refresh token to exchange for new access tokens. +@property(nonatomic, readonly) GIDToken *refreshToken; + +/// An OpenID Connect ID token that identifies the user. Send this token to your server to +/// authenticate the user there. For more information on this topic, see +/// https://developers.google.com/identity/sign-in/ios/backend-auth +@property(nonatomic, readonly, nullable) GIDToken *idToken; + @end NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Tests/Unit/GIDGoogleUser+Testing.m b/GoogleSignIn/Tests/Unit/GIDGoogleUser+Testing.m index de89f8d3..f6db0e85 100644 --- a/GoogleSignIn/Tests/Unit/GIDGoogleUser+Testing.m +++ b/GoogleSignIn/Tests/Unit/GIDGoogleUser+Testing.m @@ -15,6 +15,8 @@ #import "GoogleSignIn/Tests/Unit/GIDGoogleUser+Testing.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDToken.h" + #import "GoogleSignIn/Tests/Unit/GIDAuthentication+Testing.h" #import "GoogleSignIn/Tests/Unit/GIDConfiguration+Testing.h" #import "GoogleSignIn/Tests/Unit/GIDProfileData+Testing.h" @@ -35,13 +37,17 @@ - (BOOL)isEqualToGoogleUser:(GIDGoogleUser *)other { return [self.authentication isEqual:other.authentication] && [self.userID isEqual:other.userID] && [self.profile isEqual:other.profile] && - [self.configuration isEqual:other.configuration]; + [self.configuration isEqual:other.configuration] && + [self.idToken isEqual:other.idToken] && + [self.refreshToken isEqual:other.refreshToken] && + [self.accessToken isEqual:other.accessToken]; } // Not the hash implemention you want to use on prod, but just to match |isEqual:| here. - (NSUInteger)hash { return [self.authentication hash] ^ [self.userID hash] ^ [self.configuration hash] ^ - [self.profile hash] ; + [self.profile hash] ^ [self.idToken hash] ^ [self.refreshToken hash] ^ + [self.accessToken hash]; } @end diff --git a/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m b/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m index dea0abad..9a3935c4 100644 --- a/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m +++ b/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m @@ -19,6 +19,7 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDAuthentication.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDProfileData.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDToken.h" #import "GoogleSignIn/Sources/GIDAuthentication_Private.h" #import "GoogleSignIn/Sources/GIDGoogleUser_Private.h" @@ -53,6 +54,8 @@ - (void)testInitWithAuthState { XCTAssertEqualObjects(user.configuration.hostedDomain, kHostedDomain); XCTAssertEqualObjects(user.configuration.clientID, OIDAuthorizationRequestTestingClientID); XCTAssertEqualObjects(user.profile, [GIDProfileData testInstance]); + XCTAssertEqualObjects(user.accessToken.tokenString, kAccessToken); + XCTAssertEqualObjects(user.refreshToken.tokenString, kRefreshToken); } - (void)testCoding { diff --git a/GoogleSignIn/Tests/Unit/GIDSignInTest.m b/GoogleSignIn/Tests/Unit/GIDSignInTest.m index 84c2cece..ec473207 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInTest.m @@ -397,7 +397,8 @@ - (void)testShareInstance { - (void)testRestorePreviousSignInNoRefresh_hasPreviousUser { [[[_authorization expect] andReturn:_authState] authState]; OCMStub([_authState lastTokenResponse]).andReturn(_tokenResponse); - + OCMStub([_authState refreshToken]).andReturn(kRefreshToken); + id idTokenDecoded = OCMClassMock([OIDIDToken class]); OCMStub([idTokenDecoded alloc]).andReturn(idTokenDecoded); OCMStub([idTokenDecoded initWithIDTokenString:OCMOCK_ANY]).andReturn(idTokenDecoded); @@ -412,6 +413,10 @@ - (void)testRestorePreviousSignInNoRefresh_hasPreviousUser { OCMStub([_tokenResponse idToken]).andReturn(kFakeIDToken); OCMStub([_tokenResponse request]).andReturn(_tokenRequest); OCMStub([_tokenRequest additionalParameters]).andReturn(nil); + OCMStub([_tokenResponse accessToken]).andReturn(kAccessToken); + OCMStub([_tokenResponse accessTokenExpirationDate]).andReturn(nil); + + [_signIn restorePreviousSignInNoRefresh]; diff --git a/GoogleSignIn/Tests/Unit/GIDTokenTest.m b/GoogleSignIn/Tests/Unit/GIDTokenTest.m index aa9d1b1a..06d627f2 100644 --- a/GoogleSignIn/Tests/Unit/GIDTokenTest.m +++ b/GoogleSignIn/Tests/Unit/GIDTokenTest.m @@ -36,6 +36,16 @@ - (void)testInitializer { XCTAssertEqualObjects(token.tokenString, tokenString); XCTAssertEqualObjects(token.expirationDate, _date); } + +- (void)testIsEqual { + GIDToken *token = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:_date]; + GIDToken *token2 = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:_date]; + XCTAssertEqualObjects(token, token2); + + GIDToken *refreshToken = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:nil]; + GIDToken *refreshToken2 = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:nil]; + XCTAssertEqualObjects(refreshToken, refreshToken2); +} - (void)testCoding { if (@available(iOS 11, macOS 10.13, *)) { @@ -44,8 +54,7 @@ - (void)testCoding { GIDToken *newToken = [NSKeyedUnarchiver unarchivedObjectOfClass:[GIDToken class] fromData:data error:nil]; - XCTAssertEqualObjects(token.tokenString, newToken.tokenString); - XCTAssertEqualObjects(token.expirationDate, newToken.expirationDate); + XCTAssertEqualObjects(token, newToken); XCTAssertTrue([GIDToken supportsSecureCoding]); } else { From b320b0755d64a0c923e83bb0e61c59dd6b710c2d Mon Sep 17 00:00:00 2001 From: pinlu Date: Sat, 30 Jul 2022 11:35:06 -0700 Subject: [PATCH 08/17] Resolve comments --- GoogleSignIn/Sources/GIDToken.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GoogleSignIn/Sources/GIDToken.m b/GoogleSignIn/Sources/GIDToken.m index 2db0c794..4c68b827 100644 --- a/GoogleSignIn/Sources/GIDToken.m +++ b/GoogleSignIn/Sources/GIDToken.m @@ -69,11 +69,11 @@ - (BOOL)isEqual:(id)object { - (BOOL)isEqualToGIDToken:(GIDToken *)other { return [_tokenString isEqual:other.tokenString] && - [self isTheSameDateWithDate1:_expirationDate date2:other.expirationDate]; + [self isTheSameDate:_expirationDate with:other.expirationDate]; } -- (BOOL)isTheSameDateWithDate1:(NSDate *)date1 - date2:(NSDate *)date2 { +- (BOOL)isTheSameDate:(NSDate *)date1 + with:(NSDate *)date2 { // The date is nullable. Two `null` date is equal. if (!date1 && !date2) { return YES; From 6111126adca5cc8556dedd6d6d0f7b371fe74c8f Mon Sep 17 00:00:00 2001 From: pinlu Date: Mon, 1 Aug 2022 12:18:40 -0700 Subject: [PATCH 09/17] Resolve comments --- GoogleSignIn/Sources/GIDGoogleUser.m | 28 +++++++--------- GoogleSignIn/Sources/GIDToken.m | 13 ++++---- .../Public/GoogleSignIn/GIDGoogleUser.h | 7 ++-- GoogleSignIn/Tests/Unit/GIDTokenTest.m | 32 ++++++++++++++++--- 4 files changed, 50 insertions(+), 30 deletions(-) diff --git a/GoogleSignIn/Sources/GIDGoogleUser.m b/GoogleSignIn/Sources/GIDGoogleUser.m index 50fbd00b..c880a554 100644 --- a/GoogleSignIn/Sources/GIDGoogleUser.m +++ b/GoogleSignIn/Sources/GIDGoogleUser.m @@ -48,7 +48,7 @@ @implementation GIDGoogleUser { } - (nullable NSString *)userID { - NSString *idToken = [self idTokenString]; + NSString *idToken = [self lastTokenResponseToken]; if (idToken) { OIDIDToken *idTokenDecoded = [[OIDIDToken alloc] initWithIDTokenString:idToken]; if (idTokenDecoded && idTokenDecoded.subject) { @@ -117,9 +117,9 @@ - (NSString *)clientID { } - (nullable NSString *)hostedDomain { - NSString *idTokenString = [self idTokenString]; - if (idTokenString) { - OIDIDToken *idTokenDecoded = [[OIDIDToken alloc] initWithIDTokenString:idTokenString]; + NSString *lastTokenResponseToken = [self lastTokenResponseToken]; + if (lastTokenResponseToken) { + OIDIDToken *idTokenDecoded = [[OIDIDToken alloc] initWithIDTokenString:lastTokenResponseToken]; if (idTokenDecoded && idTokenDecoded.claims[kHostedDomainIDTokenClaimKey]) { return [idTokenDecoded.claims[kHostedDomainIDTokenClaimKey] copy]; } @@ -135,15 +135,15 @@ - (nullable NSString *)openIDRealm { return [_authState.lastTokenResponse.request.additionalParameters[kOpenIDRealmParameter] copy]; } -- (NSString *)idTokenString { +- (NSString *)lastTokenResponseToken { return _authState.lastTokenResponse.idToken; } - (nullable NSDate *)idTokenExpirationDate { - return [[[OIDIDToken alloc] initWithIDTokenString:self.idTokenString] expiresAt]; + return [[[OIDIDToken alloc] initWithIDTokenString:[self lastTokenResponseToken]] expiresAt]; } -- (NSString *)accessTokenString { +- (NSString *)lastTokenResponseAccessToken { return _authState.lastTokenResponse.accessToken; } @@ -151,18 +151,14 @@ - (NSDate *)accessTokenExpirationDate { return _authState.lastTokenResponse.accessTokenExpirationDate; } -- (NSString *)refreshTokenString { - return _authState.refreshToken; -} - - (void)updateTokens { - _accessToken = [[GIDToken alloc] initWithTokenString:[self accessTokenString] + _accessToken = [[GIDToken alloc] initWithTokenString:[self lastTokenResponseAccessToken] expirationDate:[self accessTokenExpirationDate]]; - _refreshToken = [[GIDToken alloc] initWithTokenString:[self refreshTokenString] + _refreshToken = [[GIDToken alloc] initWithTokenString:_authState.refreshToken expirationDate:nil]; - NSString *idTokenString = [self idTokenString]; - if (idTokenString) { - _idToken = [[GIDToken alloc] initWithTokenString:[self idTokenString] + NSString *lastTokenResponseToken = [self lastTokenResponseToken]; + if (lastTokenResponseToken) { + _idToken = [[GIDToken alloc] initWithTokenString:lastTokenResponseToken expirationDate:[self idTokenExpirationDate]]; } else { _idToken = nil; diff --git a/GoogleSignIn/Sources/GIDToken.m b/GoogleSignIn/Sources/GIDToken.m index 4c68b827..e94a27fb 100644 --- a/GoogleSignIn/Sources/GIDToken.m +++ b/GoogleSignIn/Sources/GIDToken.m @@ -74,14 +74,15 @@ - (BOOL)isEqualToGIDToken:(GIDToken *)other { - (BOOL)isTheSameDate:(NSDate *)date1 with:(NSDate *)date2 { - // The date is nullable. Two `null` date is equal. - if (!date1 && !date2) { + + if (date1 || date2) { + return [date1 isEqualToDate:date2]; + } else { + // The date is nullable in GIDToken. Two `nil` dates are considered equal so + // token equality check succeeds if token strings are equal and have no expiration. return YES; } - if (!date1 || !date2) { - return NO; - } - return [date1 isEqualToDate:date2]; + } - (NSUInteger)hash { diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h index 4d6a6a80..0a2aa0f6 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h @@ -47,9 +47,10 @@ NS_ASSUME_NONNULL_BEGIN /// The OAuth2 refresh token to exchange for new access tokens. @property(nonatomic, readonly) GIDToken *refreshToken; -/// An OpenID Connect ID token that identifies the user. Send this token to your server to -/// authenticate the user there. For more information on this topic, see -/// https://developers.google.com/identity/sign-in/ios/backend-auth +/// An OpenID Connect ID token that identifies the user. +/// +/// Send this token to your server to authenticate the user there. For more information on this topic, +/// see https://developers.google.com/identity/sign-in/ios/backend-auth. @property(nonatomic, readonly, nullable) GIDToken *idToken; @end diff --git a/GoogleSignIn/Tests/Unit/GIDTokenTest.m b/GoogleSignIn/Tests/Unit/GIDTokenTest.m index 06d627f2..b1ce4cbb 100644 --- a/GoogleSignIn/Tests/Unit/GIDTokenTest.m +++ b/GoogleSignIn/Tests/Unit/GIDTokenTest.m @@ -18,6 +18,7 @@ #import "GoogleSignIn/Sources/GIDToken_Private.h" static NSString * const tokenString = @"tokenString"; +static NSString * const tokenString2 = @"tokenString2"; @interface GIDTokenTest : XCTestCase { NSDate *_date; @@ -26,7 +27,7 @@ @interface GIDTokenTest : XCTestCase { @implementation GIDTokenTest -- (void)setUP { +- (void)setUp { [super setUp]; _date = [[NSDate alloc]initWithTimeIntervalSince1970:1000]; } @@ -37,23 +38,44 @@ - (void)testInitializer { XCTAssertEqualObjects(token.expirationDate, _date); } -- (void)testIsEqual { +- (void)testTokensWithSameTokenStringAndExpirationDateAreEqual { GIDToken *token = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:_date]; GIDToken *token2 = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:_date]; XCTAssertEqualObjects(token, token2); - +} + +- (void)testTokensWithDifferentTokenStringsAreNotEqual { + GIDToken *token = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:_date]; + GIDToken *token2 = [[GIDToken alloc]initWithTokenString:tokenString2 expirationDate:_date]; + XCTAssertNotEqualObjects(token, token2); +} + +- (void)testTokensWithSameTokenStringAndNoExpirationDateAreEqual { GIDToken *refreshToken = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:nil]; GIDToken *refreshToken2 = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:nil]; XCTAssertEqualObjects(refreshToken, refreshToken2); } + +- (void)testTokensWithSameTokenStringAndDifferentExpirationDateAreNotEqual { + GIDToken *token = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:_date]; + NSDate *date2 = [[NSDate alloc]initWithTimeIntervalSince1970:2000]; + GIDToken *token2 = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:date2]; + XCTAssertNotEqualObjects(token, token2); +} + +- (void)testTokensWithSameTokenStringAndOneHasNoExpirationDateAreNotEqual { + GIDToken *token = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:_date]; + GIDToken *token2 = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:nil]; + XCTAssertNotEqualObjects(token, token2); +} - (void)testCoding { if (@available(iOS 11, macOS 10.13, *)) { GIDToken *token = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:_date]; NSData *data = [NSKeyedArchiver archivedDataWithRootObject:token requiringSecureCoding:YES error:nil]; GIDToken *newToken = [NSKeyedUnarchiver unarchivedObjectOfClass:[GIDToken class] - fromData:data - error:nil]; + fromData:data + error:nil]; XCTAssertEqualObjects(token, newToken); XCTAssertTrue([GIDToken supportsSecureCoding]); From 59886e4ba3ce2f3eb246e4d94e139d93a52bfe2b Mon Sep 17 00:00:00 2001 From: pinlu Date: Mon, 1 Aug 2022 12:29:13 -0700 Subject: [PATCH 10/17] Resolve comment --- GoogleSignIn/Sources/GIDToken.m | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/GoogleSignIn/Sources/GIDToken.m b/GoogleSignIn/Sources/GIDToken.m index e94a27fb..dee1aa0e 100644 --- a/GoogleSignIn/Sources/GIDToken.m +++ b/GoogleSignIn/Sources/GIDToken.m @@ -64,10 +64,10 @@ - (BOOL)isEqual:(id)object { if (![object isKindOfClass:[GIDToken class]]) { return NO; } - return [self isEqualToGIDToken:(GIDToken *)object]; + return [self isEqualToToken:(GIDToken *)object]; } -- (BOOL)isEqualToGIDToken:(GIDToken *)other { +- (BOOL)isEqualToToken:(GIDToken *)other { return [_tokenString isEqual:other.tokenString] && [self isTheSameDate:_expirationDate with:other.expirationDate]; } @@ -82,7 +82,6 @@ - (BOOL)isTheSameDate:(NSDate *)date1 // token equality check succeeds if token strings are equal and have no expiration. return YES; } - } - (NSUInteger)hash { From be0b9657f363107070a9b5fc1f043b26e0f67e7c Mon Sep 17 00:00:00 2001 From: pinlu Date: Mon, 1 Aug 2022 21:00:41 -0700 Subject: [PATCH 11/17] Add NS_ASSUME_NONNULL_BEGIN(END) --- GoogleSignIn/Sources/GIDToken.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/GoogleSignIn/Sources/GIDToken.m b/GoogleSignIn/Sources/GIDToken.m index dee1aa0e..caa480c7 100644 --- a/GoogleSignIn/Sources/GIDToken.m +++ b/GoogleSignIn/Sources/GIDToken.m @@ -22,6 +22,8 @@ static NSString *const kTokenStringKey = @"tokenString"; static NSString *const kExpirationDateKey = @"expirationDate"; +NS_ASSUME_NONNULL_BEGIN + @implementation GIDToken - (instancetype)initWithTokenString:(NSString *)tokenString @@ -89,3 +91,5 @@ - (NSUInteger)hash { } @end + +NS_ASSUME_NONNULL_END From d86d5a9df7cf635725d7af4a78d228b09b740a72 Mon Sep 17 00:00:00 2001 From: pinlu Date: Wed, 3 Aug 2022 07:43:46 -0700 Subject: [PATCH 12/17] Resolve comments --- GoogleSignIn/Sources/GIDToken.m | 15 ++++++++------- .../Sources/Public/GoogleSignIn/GIDToken.h | 5 +++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/GoogleSignIn/Sources/GIDToken.m b/GoogleSignIn/Sources/GIDToken.m index caa480c7..b1f3281d 100644 --- a/GoogleSignIn/Sources/GIDToken.m +++ b/GoogleSignIn/Sources/GIDToken.m @@ -59,7 +59,10 @@ - (void)encodeWithCoder:(NSCoder *)encoder { #pragma mark - isEqual -- (BOOL)isEqual:(id)object { +- (BOOL)isEqual:(nullable id)object { + if (object == nil) { + return NO; + } if (self == object) { return YES; } @@ -74,16 +77,14 @@ - (BOOL)isEqualToToken:(GIDToken *)other { [self isTheSameDate:_expirationDate with:other.expirationDate]; } +// The date is nullable in GIDToken. Two `nil` dates are considered equal so +// token equality check succeeds if token strings are equal and have no expiration. - (BOOL)isTheSameDate:(NSDate *)date1 with:(NSDate *)date2 { - - if (date1 || date2) { - return [date1 isEqualToDate:date2]; - } else { - // The date is nullable in GIDToken. Two `nil` dates are considered equal so - // token equality check succeeds if token strings are equal and have no expiration. + if (!date1 && !date2) { return YES; } + return [date1 isEqualToDate:date2]; } - (NSUInteger)hash { diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDToken.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDToken.h index 29f5d3b9..508b6d12 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDToken.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDToken.h @@ -27,6 +27,11 @@ NS_ASSUME_NONNULL_BEGIN /// The estimated expiration date of the token. @property(nonatomic, readonly, nullable) NSDate *expirationDate; +/// Check if current token is equal to another one. +/// +/// @param other - Another token to compare. +- (BOOL)isEqualToToken:(GIDToken *)other; + /// Unsupported. + (instancetype)new NS_UNAVAILABLE; From 5b7b0def5cd2885afb7e2b9fff50a65f4a6ba0a1 Mon Sep 17 00:00:00 2001 From: pinlu Date: Thu, 4 Aug 2022 09:57:02 -0700 Subject: [PATCH 13/17] Resolve comments --- GoogleSignIn/Sources/GIDGoogleUser.m | 50 +++++++++---------- GoogleSignIn/Sources/GIDToken.m | 10 ++-- .../Sources/Public/GoogleSignIn/GIDToken.h | 4 +- GoogleSignIn/Tests/Unit/GIDTokenTest.m | 7 +++ 4 files changed, 38 insertions(+), 33 deletions(-) diff --git a/GoogleSignIn/Sources/GIDGoogleUser.m b/GoogleSignIn/Sources/GIDGoogleUser.m index c880a554..c8aa1209 100644 --- a/GoogleSignIn/Sources/GIDGoogleUser.m +++ b/GoogleSignIn/Sources/GIDGoogleUser.m @@ -48,9 +48,10 @@ @implementation GIDGoogleUser { } - (nullable NSString *)userID { - NSString *idToken = [self lastTokenResponseToken]; - if (idToken) { - OIDIDToken *idTokenDecoded = [[OIDIDToken alloc] initWithIDTokenString:idToken]; + NSString *idTokenString = self.idToken.tokenString; + if (idTokenString) { + OIDIDToken *idTokenDecoded = + [[OIDIDToken alloc] initWithIDTokenString:idTokenString]; if (idTokenDecoded && idTokenDecoded.subject) { return [idTokenDecoded.subject copy]; } @@ -107,7 +108,17 @@ - (void)updateAuthState:(OIDAuthState *)authState _authState = authState; _authentication = [[GIDAuthentication alloc] initWithAuthState:authState]; _profile = profileData; - [self updateTokens]; + _accessToken = [[GIDToken alloc] initWithTokenString:[self lastTokenResponseAccessToken] + expirationDate:[self accessTokenExpirationDate]]; + _refreshToken = [[GIDToken alloc] initWithTokenString:_authState.refreshToken + expirationDate:nil]; + NSString *lastTokenResponseToken = [self lastTokenResponseToken]; + if (lastTokenResponseToken) { + _idToken = [[GIDToken alloc] initWithTokenString:lastTokenResponseToken + expirationDate:[self idTokenExpirationDate]]; + } else { + _idToken = nil; + } } #pragma mark - Helpers @@ -117,9 +128,9 @@ - (NSString *)clientID { } - (nullable NSString *)hostedDomain { - NSString *lastTokenResponseToken = [self lastTokenResponseToken]; - if (lastTokenResponseToken) { - OIDIDToken *idTokenDecoded = [[OIDIDToken alloc] initWithIDTokenString:lastTokenResponseToken]; + NSString *idTokenString = self.idToken.tokenString; + if (idTokenString) { + OIDIDToken *idTokenDecoded = [[OIDIDToken alloc] initWithIDTokenString:idTokenString]; if (idTokenDecoded && idTokenDecoded.claims[kHostedDomainIDTokenClaimKey]) { return [idTokenDecoded.claims[kHostedDomainIDTokenClaimKey] copy]; } @@ -151,20 +162,6 @@ - (NSDate *)accessTokenExpirationDate { return _authState.lastTokenResponse.accessTokenExpirationDate; } -- (void)updateTokens { - _accessToken = [[GIDToken alloc] initWithTokenString:[self lastTokenResponseAccessToken] - expirationDate:[self accessTokenExpirationDate]]; - _refreshToken = [[GIDToken alloc] initWithTokenString:_authState.refreshToken - expirationDate:nil]; - NSString *lastTokenResponseToken = [self lastTokenResponseToken]; - if (lastTokenResponseToken) { - _idToken = [[GIDToken alloc] initWithTokenString:lastTokenResponseToken - expirationDate:[self idTokenExpirationDate]]; - } else { - _idToken = nil; - } -} - #pragma mark - NSSecureCoding + (BOOL)supportsSecureCoding { @@ -174,16 +171,17 @@ + (BOOL)supportsSecureCoding { - (nullable instancetype)initWithCoder:(NSCoder *)decoder { self = [super init]; if (self) { - _profile = [decoder decodeObjectOfClass:[GIDProfileData class] forKey:kProfileDataKey]; + GIDProfileData *profileData = + [decoder decodeObjectOfClass:[GIDProfileData class] forKey:kProfileDataKey]; + OIDAuthState *authState; if ([decoder containsValueForKey:kAuthState]) { // Current encoding - _authState = [decoder decodeObjectOfClass:[OIDAuthState class] forKey:kAuthState]; + authState = [decoder decodeObjectOfClass:[OIDAuthState class] forKey:kAuthState]; } else { // Old encoding GIDAuthentication *authentication = [decoder decodeObjectOfClass:[GIDAuthentication class] forKey:kAuthenticationKey]; - _authState = authentication.authState; + authState = authentication.authState; } - _authentication = [[GIDAuthentication alloc] initWithAuthState:_authState]; - [self updateTokens]; + [self updateAuthState:authState profileData:profileData]; } return self; } diff --git a/GoogleSignIn/Sources/GIDToken.m b/GoogleSignIn/Sources/GIDToken.m index b1f3281d..4ac1cdbf 100644 --- a/GoogleSignIn/Sources/GIDToken.m +++ b/GoogleSignIn/Sources/GIDToken.m @@ -72,15 +72,15 @@ - (BOOL)isEqual:(nullable id)object { return [self isEqualToToken:(GIDToken *)object]; } -- (BOOL)isEqualToToken:(GIDToken *)other { - return [_tokenString isEqual:other.tokenString] && - [self isTheSameDate:_expirationDate with:other.expirationDate]; +- (BOOL)isEqualToToken:(GIDToken *)otherToken { + return [_tokenString isEqual:otherToken.tokenString] && + [self isTheSameDate:_expirationDate with:otherToken.expirationDate]; } // The date is nullable in GIDToken. Two `nil` dates are considered equal so // token equality check succeeds if token strings are equal and have no expiration. -- (BOOL)isTheSameDate:(NSDate *)date1 - with:(NSDate *)date2 { +- (BOOL)isTheSameDate:(nullable NSDate *)date1 + with:(nullable NSDate *)date2 { if (!date1 && !date2) { return YES; } diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDToken.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDToken.h index 508b6d12..866ede4c 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDToken.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDToken.h @@ -29,8 +29,8 @@ NS_ASSUME_NONNULL_BEGIN /// Check if current token is equal to another one. /// -/// @param other - Another token to compare. -- (BOOL)isEqualToToken:(GIDToken *)other; +/// @param otherToken - Another token to compare. +- (BOOL)isEqualToToken:(GIDToken *)otherToken; /// Unsupported. + (instancetype)new NS_UNAVAILABLE; diff --git a/GoogleSignIn/Tests/Unit/GIDTokenTest.m b/GoogleSignIn/Tests/Unit/GIDTokenTest.m index b1ce4cbb..94a8ba06 100644 --- a/GoogleSignIn/Tests/Unit/GIDTokenTest.m +++ b/GoogleSignIn/Tests/Unit/GIDTokenTest.m @@ -44,6 +44,13 @@ - (void)testTokensWithSameTokenStringAndExpirationDateAreEqual { XCTAssertEqualObjects(token, token2); } +- (void)testEqualTokensHaveTheSameHash { + GIDToken *token = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:_date]; + GIDToken *token2 = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:_date]; + XCTAssertEqualObjects(token, token2); + XCTAssertEqual(token.hash, token2.hash); +} + - (void)testTokensWithDifferentTokenStringsAreNotEqual { GIDToken *token = [[GIDToken alloc]initWithTokenString:tokenString expirationDate:_date]; GIDToken *token2 = [[GIDToken alloc]initWithTokenString:tokenString2 expirationDate:_date]; From c70498c1c67827d7a45da2e0e686290d8c0f698e Mon Sep 17 00:00:00 2001 From: pinlu Date: Mon, 8 Aug 2022 12:29:05 -0700 Subject: [PATCH 14/17] Resolve comments 1. Add property getters in GIDGoogleUser to match the pattern of GIDConfiguration 2. Use copy on the string parsed from authState. --- GoogleSignIn/Sources/GIDGoogleUser.m | 80 +++++++++++++-------- GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m | 3 + 2 files changed, 52 insertions(+), 31 deletions(-) diff --git a/GoogleSignIn/Sources/GIDGoogleUser.m b/GoogleSignIn/Sources/GIDGoogleUser.m index c8aa1209..51cd86dc 100644 --- a/GoogleSignIn/Sources/GIDGoogleUser.m +++ b/GoogleSignIn/Sources/GIDGoogleUser.m @@ -28,8 +28,6 @@ #import #endif -NS_ASSUME_NONNULL_BEGIN - // The ID Token claim key for the hosted domain value. static NSString *const kHostedDomainIDTokenClaimKey = @"hd"; @@ -42,11 +40,17 @@ static NSString *const kAudienceParameter = @"audience"; static NSString *const kOpenIDRealmParameter = @"openid.realm"; +NS_ASSUME_NONNULL_BEGIN + @implementation GIDGoogleUser { OIDAuthState *_authState; GIDConfiguration *_cachedConfiguration; } +@synthesize accessToken = _accessToken; +@synthesize refreshToken = _refreshToken; +@synthesize idToken = _idToken; + - (nullable NSString *)userID { NSString *idTokenString = self.idToken.tokenString; if (idTokenString) { @@ -92,6 +96,40 @@ - (GIDConfiguration *)configuration { return _cachedConfiguration; } +- (GIDToken *)accessToken { + @synchronized(self) { + if (!_accessToken) { + _accessToken = [[GIDToken alloc] initWithTokenString:[_authState.lastTokenResponse.accessToken copy] + expirationDate:_authState.lastTokenResponse.accessTokenExpirationDate]; + } + } + return _accessToken; +} + +- (GIDToken *)refreshToken { + @synchronized(self) { + if (!_refreshToken) { + _refreshToken = [[GIDToken alloc] initWithTokenString:[_authState.refreshToken copy] + expirationDate:nil]; + } + } + return _refreshToken; +} + +- (nullable GIDToken *)idToken { + @synchronized(self) { + NSString *idTokenString = [_authState.lastTokenResponse.idToken copy]; + if (!_idToken && idTokenString) { + NSDate *idTokenExpirationDate = [[[OIDIDToken alloc] + initWithIDTokenString:idTokenString] expiresAt]; + _idToken = [[GIDToken alloc] initWithTokenString:idTokenString + expirationDate:idTokenExpirationDate]; + } + } + return _idToken; +} + + #pragma mark - Private Methods - (instancetype)initWithAuthState:(OIDAuthState *)authState @@ -105,18 +143,14 @@ - (instancetype)initWithAuthState:(OIDAuthState *)authState - (void)updateAuthState:(OIDAuthState *)authState profileData:(nullable GIDProfileData *)profileData { - _authState = authState; - _authentication = [[GIDAuthentication alloc] initWithAuthState:authState]; - _profile = profileData; - _accessToken = [[GIDToken alloc] initWithTokenString:[self lastTokenResponseAccessToken] - expirationDate:[self accessTokenExpirationDate]]; - _refreshToken = [[GIDToken alloc] initWithTokenString:_authState.refreshToken - expirationDate:nil]; - NSString *lastTokenResponseToken = [self lastTokenResponseToken]; - if (lastTokenResponseToken) { - _idToken = [[GIDToken alloc] initWithTokenString:lastTokenResponseToken - expirationDate:[self idTokenExpirationDate]]; - } else { + @synchronized(self) { + _authState = authState; + _authentication = [[GIDAuthentication alloc] initWithAuthState:authState]; + _profile = profileData; + + // These three tokens will be generated in the getter and cached . + _accessToken = nil; + _refreshToken = nil; _idToken = nil; } } @@ -124,7 +158,7 @@ - (void)updateAuthState:(OIDAuthState *)authState #pragma mark - Helpers - (NSString *)clientID { - return _authState.lastAuthorizationResponse.request.clientID; + return [_authState.lastAuthorizationResponse.request.clientID copy]; } - (nullable NSString *)hostedDomain { @@ -146,22 +180,6 @@ - (nullable NSString *)openIDRealm { return [_authState.lastTokenResponse.request.additionalParameters[kOpenIDRealmParameter] copy]; } -- (NSString *)lastTokenResponseToken { - return _authState.lastTokenResponse.idToken; -} - -- (nullable NSDate *)idTokenExpirationDate { - return [[[OIDIDToken alloc] initWithIDTokenString:[self lastTokenResponseToken]] expiresAt]; -} - -- (NSString *)lastTokenResponseAccessToken { - return _authState.lastTokenResponse.accessToken; -} - -- (NSDate *)accessTokenExpirationDate { - return _authState.lastTokenResponse.accessTokenExpirationDate; -} - #pragma mark - NSSecureCoding + (BOOL)supportsSecureCoding { diff --git a/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m b/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m index 9a3935c4..4d39bdd8 100644 --- a/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m +++ b/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m @@ -56,6 +56,9 @@ - (void)testInitWithAuthState { XCTAssertEqualObjects(user.profile, [GIDProfileData testInstance]); XCTAssertEqualObjects(user.accessToken.tokenString, kAccessToken); XCTAssertEqualObjects(user.refreshToken.tokenString, kRefreshToken); + + NSDate *expectedExpirationDate = [NSDate dateWithTimeIntervalSince1970:kIDTokenExpires]; + XCTAssertEqualObjects(user.idToken.expirationDate, expectedExpirationDate); } - (void)testCoding { From 8b9d15be59ed8a52b0c5843a7e9ed774953a6d06 Mon Sep 17 00:00:00 2001 From: pinlu Date: Mon, 8 Aug 2022 14:09:25 -0700 Subject: [PATCH 15/17] Minor improve on tests. --- GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m b/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m index 4d39bdd8..8196da40 100644 --- a/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m +++ b/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m @@ -57,8 +57,9 @@ - (void)testInitWithAuthState { XCTAssertEqualObjects(user.accessToken.tokenString, kAccessToken); XCTAssertEqualObjects(user.refreshToken.tokenString, kRefreshToken); - NSDate *expectedExpirationDate = [NSDate dateWithTimeIntervalSince1970:kIDTokenExpires]; - XCTAssertEqualObjects(user.idToken.expirationDate, expectedExpirationDate); + OIDIDToken *idToken = [[OIDIDToken alloc] + initWithIDTokenString:authState.lastTokenResponse.idToken]; + XCTAssertEqualObjects(user.idToken.expirationDate, [idToken expiresAt]); } - (void)testCoding { From 288671bc7bb5561c0e5f9cc5d9a34016b28ee59b Mon Sep 17 00:00:00 2001 From: pinlu Date: Tue, 9 Aug 2022 13:59:17 -0700 Subject: [PATCH 16/17] Resolve comments. --- GoogleSignIn/Sources/GIDGoogleUser.m | 45 ++++++++----------- GoogleSignIn/Sources/GIDToken.m | 2 +- .../Public/GoogleSignIn/GIDGoogleUser.h | 2 +- 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/GoogleSignIn/Sources/GIDGoogleUser.m b/GoogleSignIn/Sources/GIDGoogleUser.m index 51cd86dc..05eb1770 100644 --- a/GoogleSignIn/Sources/GIDGoogleUser.m +++ b/GoogleSignIn/Sources/GIDGoogleUser.m @@ -1,4 +1,4 @@ -// Copyright 2021 Google LLC +// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -45,12 +45,11 @@ @implementation GIDGoogleUser { OIDAuthState *_authState; GIDConfiguration *_cachedConfiguration; + GIDToken *_accessToken; + GIDToken *_refreshToken; + GIDToken *_idToken; } -@synthesize accessToken = _accessToken; -@synthesize refreshToken = _refreshToken; -@synthesize idToken = _idToken; - - (nullable NSString *)userID { NSString *idTokenString = self.idToken.tokenString; if (idTokenString) { @@ -86,10 +85,16 @@ - (GIDConfiguration *)configuration { @synchronized(self) { // Caches the configuration since it would not change for one GIDGoogleUser instance. if (!_cachedConfiguration) { - _cachedConfiguration = [[GIDConfiguration alloc] initWithClientID:[self clientID] - serverClientID:[self serverClientID] + NSString *clientID = _authState.lastAuthorizationResponse.request.clientID; + NSString *serverClientID = + _authState.lastTokenResponse.request.additionalParameters[kAudienceParameter]; + NSString *openIDRealm = + _authState.lastTokenResponse.request.additionalParameters[kOpenIDRealmParameter]; + + _cachedConfiguration = [[GIDConfiguration alloc] initWithClientID:clientID + serverClientID:serverClientID hostedDomain:[self hostedDomain] - openIDRealm:[self openIDRealm]]; + openIDRealm:openIDRealm]; }; } @@ -99,8 +104,9 @@ - (GIDConfiguration *)configuration { - (GIDToken *)accessToken { @synchronized(self) { if (!_accessToken) { - _accessToken = [[GIDToken alloc] initWithTokenString:[_authState.lastTokenResponse.accessToken copy] - expirationDate:_authState.lastTokenResponse.accessTokenExpirationDate]; + _accessToken = [[GIDToken alloc] initWithTokenString:_authState.lastTokenResponse.accessToken + expirationDate:_authState.lastTokenResponse. + accessTokenExpirationDate]; } } return _accessToken; @@ -109,7 +115,7 @@ - (GIDToken *)accessToken { - (GIDToken *)refreshToken { @synchronized(self) { if (!_refreshToken) { - _refreshToken = [[GIDToken alloc] initWithTokenString:[_authState.refreshToken copy] + _refreshToken = [[GIDToken alloc] initWithTokenString:_authState.refreshToken expirationDate:nil]; } } @@ -118,7 +124,7 @@ - (GIDToken *)refreshToken { - (nullable GIDToken *)idToken { @synchronized(self) { - NSString *idTokenString = [_authState.lastTokenResponse.idToken copy]; + NSString *idTokenString = _authState.lastTokenResponse.idToken; if (!_idToken && idTokenString) { NSDate *idTokenExpirationDate = [[[OIDIDToken alloc] initWithIDTokenString:idTokenString] expiresAt]; @@ -129,7 +135,6 @@ - (nullable GIDToken *)idToken { return _idToken; } - #pragma mark - Private Methods - (instancetype)initWithAuthState:(OIDAuthState *)authState @@ -157,29 +162,17 @@ - (void)updateAuthState:(OIDAuthState *)authState #pragma mark - Helpers -- (NSString *)clientID { - return [_authState.lastAuthorizationResponse.request.clientID copy]; -} - - (nullable NSString *)hostedDomain { NSString *idTokenString = self.idToken.tokenString; if (idTokenString) { OIDIDToken *idTokenDecoded = [[OIDIDToken alloc] initWithIDTokenString:idTokenString]; if (idTokenDecoded && idTokenDecoded.claims[kHostedDomainIDTokenClaimKey]) { - return [idTokenDecoded.claims[kHostedDomainIDTokenClaimKey] copy]; + return idTokenDecoded.claims[kHostedDomainIDTokenClaimKey]; } } return nil; } -- (nullable NSString *)serverClientID { - return [_authState.lastTokenResponse.request.additionalParameters[kAudienceParameter] copy]; -} - -- (nullable NSString *)openIDRealm { - return [_authState.lastTokenResponse.request.additionalParameters[kOpenIDRealmParameter] copy]; -} - #pragma mark - NSSecureCoding + (BOOL)supportsSecureCoding { diff --git a/GoogleSignIn/Sources/GIDToken.m b/GoogleSignIn/Sources/GIDToken.m index 4ac1cdbf..2702a952 100644 --- a/GoogleSignIn/Sources/GIDToken.m +++ b/GoogleSignIn/Sources/GIDToken.m @@ -30,7 +30,7 @@ - (instancetype)initWithTokenString:(NSString *)tokenString expirationDate:(nullable NSDate *)expirationDate { self = [super init]; if (self) { - _tokenString = tokenString; + _tokenString = [tokenString copy]; _expirationDate = expirationDate; } diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h index 0a2aa0f6..1d3f09c6 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h @@ -1,5 +1,5 @@ /* - * Copyright 2021 Google LLC + * Copyright 2022 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From a54bf30f504225ff47123ef29380ce33ffb32f12 Mon Sep 17 00:00:00 2001 From: pinlu Date: Thu, 11 Aug 2022 11:20:46 -0700 Subject: [PATCH 17/17] Update ivar naming --- GoogleSignIn/Sources/GIDGoogleUser.m | 38 ++++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/GoogleSignIn/Sources/GIDGoogleUser.m b/GoogleSignIn/Sources/GIDGoogleUser.m index 05eb1770..b03bd55d 100644 --- a/GoogleSignIn/Sources/GIDGoogleUser.m +++ b/GoogleSignIn/Sources/GIDGoogleUser.m @@ -45,9 +45,9 @@ @implementation GIDGoogleUser { OIDAuthState *_authState; GIDConfiguration *_cachedConfiguration; - GIDToken *_accessToken; - GIDToken *_refreshToken; - GIDToken *_idToken; + GIDToken *_cachedAccessToken; + GIDToken *_cachedRefreshToken; + GIDToken *_cachedIdToken; } - (nullable NSString *)userID { @@ -103,36 +103,36 @@ - (GIDConfiguration *)configuration { - (GIDToken *)accessToken { @synchronized(self) { - if (!_accessToken) { - _accessToken = [[GIDToken alloc] initWithTokenString:_authState.lastTokenResponse.accessToken - expirationDate:_authState.lastTokenResponse. - accessTokenExpirationDate]; + if (!_cachedAccessToken) { + _cachedAccessToken = [[GIDToken alloc] initWithTokenString:_authState.lastTokenResponse.accessToken + expirationDate:_authState.lastTokenResponse. + accessTokenExpirationDate]; } } - return _accessToken; + return _cachedAccessToken; } - (GIDToken *)refreshToken { @synchronized(self) { - if (!_refreshToken) { - _refreshToken = [[GIDToken alloc] initWithTokenString:_authState.refreshToken - expirationDate:nil]; + if (!_cachedRefreshToken) { + _cachedRefreshToken = [[GIDToken alloc] initWithTokenString:_authState.refreshToken + expirationDate:nil]; } } - return _refreshToken; + return _cachedRefreshToken; } - (nullable GIDToken *)idToken { @synchronized(self) { NSString *idTokenString = _authState.lastTokenResponse.idToken; - if (!_idToken && idTokenString) { + if (!_cachedIdToken && idTokenString) { NSDate *idTokenExpirationDate = [[[OIDIDToken alloc] initWithIDTokenString:idTokenString] expiresAt]; - _idToken = [[GIDToken alloc] initWithTokenString:idTokenString - expirationDate:idTokenExpirationDate]; + _cachedIdToken = [[GIDToken alloc] initWithTokenString:idTokenString + expirationDate:idTokenExpirationDate]; } } - return _idToken; + return _cachedIdToken; } #pragma mark - Private Methods @@ -154,9 +154,9 @@ - (void)updateAuthState:(OIDAuthState *)authState _profile = profileData; // These three tokens will be generated in the getter and cached . - _accessToken = nil; - _refreshToken = nil; - _idToken = nil; + _cachedAccessToken = nil; + _cachedRefreshToken = nil; + _cachedIdToken = nil; } }