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 c9cc844b..f6e3280f 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 46e4d36e..c37fed3c 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,