diff --git a/GoogleSignIn/Sources/GIDGoogleUser.m b/GoogleSignIn/Sources/GIDGoogleUser.m index ec300839..0ec2738c 100644 --- a/GoogleSignIn/Sources/GIDGoogleUser.m +++ b/GoogleSignIn/Sources/GIDGoogleUser.m @@ -23,6 +23,7 @@ #import "GoogleSignIn/Sources/GIDEMMSupport.h" #import "GoogleSignIn/Sources/GIDProfileData_Private.h" #import "GoogleSignIn/Sources/GIDSignIn_Private.h" +#import "GoogleSignIn/Sources/GIDSignInConstants.h" #import "GoogleSignIn/Sources/GIDSignInPreferences.h" #import "GoogleSignIn/Sources/GIDToken_Private.h" @@ -43,10 +44,6 @@ static NSString *const kProfileDataKey = @"profileData"; static NSString *const kAuthStateKey = @"authState"; -// Parameters for the token exchange endpoint. -static NSString *const kAudienceParameter = @"audience"; -static NSString *const kOpenIDRealmParameter = @"openid.realm"; - // Additional parameter names for EMM. static NSString *const kEMMSupportParameterName = @"emm_support"; diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index 8ad38645..0452b24f 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -22,6 +22,7 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignInResult.h" #import "GoogleSignIn/Sources/GIDEMMSupport.h" +#import "GoogleSignIn/Sources/GIDSignInConstants.h" #import "GoogleSignIn/Sources/GIDSignInInternalOptions.h" #import "GoogleSignIn/Sources/GIDSignInPreferences.h" #import "GoogleSignIn/Sources/GIDCallbackQueue.h" @@ -69,21 +70,12 @@ // The name of the query parameter used for logging the restart of auth from EMM callback. static NSString *const kEMMRestartAuthParameter = @"emmres"; -// The URL template for the authorization endpoint. -static NSString *const kAuthorizationURLTemplate = @"https://%@/o/oauth2/v2/auth"; - -// The URL template for the token endpoint. -static NSString *const kTokenURLTemplate = @"https://%@/token"; - // The URL template for the URL to get user info. static NSString *const kUserInfoURLTemplate = @"https://%@/oauth2/v3/userinfo?access_token=%@"; // The URL template for the URL to revoke the token. static NSString *const kRevokeTokenURLTemplate = @"https://%@/o/oauth2/revoke?token=%@"; -// Expected path in the URL scheme to be handled. -static NSString *const kBrowserCallbackPath = @"/oauth2callback"; - // Expected path for EMM callback. static NSString *const kEMMCallbackPath = @"/emmcallback"; @@ -124,14 +116,6 @@ // The delay before the new sign-in flow can be presented after the existing one is cancelled. static const NSTimeInterval kPresentationDelayAfterCancel = 1.0; -// Parameters for the auth and token exchange endpoints. -static NSString *const kAudienceParameter = @"audience"; -// See b/11669751 . -static NSString *const kOpenIDRealmParameter = @"openid.realm"; -static NSString *const kIncludeGrantedScopesParameter = @"include_granted_scopes"; -static NSString *const kLoginHintParameter = @"login_hint"; -static NSString *const kHostedDomainParameter = @"hd"; - // Minimum time to expiration for a restored access token. static const NSTimeInterval kMinimumRestoredAccessTokenTimeToExpire = 600.0; diff --git a/GoogleSignIn/Sources/GIDSignInConstants.h b/GoogleSignIn/Sources/GIDSignInConstants.h new file mode 100644 index 00000000..e04db0fa --- /dev/null +++ b/GoogleSignIn/Sources/GIDSignInConstants.h @@ -0,0 +1,41 @@ +/* + * Copyright 2024 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 + +/// The URL template for the authorization endpoint. +extern NSString *const kAuthorizationURLTemplate; + +/// The URL template for the token endpoint. +extern NSString *const kTokenURLTemplate; + +/// Expected path in the URL scheme to be handled. +extern NSString *const kBrowserCallbackPath; + +/// The name of the audience parameter for the auth and token exchange endpoints. +extern NSString *const kAudienceParameter; + +/// The name of the open ID realm parameter for the auth and token exchange endpoints. +extern NSString *const kOpenIDRealmParameter; + +/// The name of the include granted scopes parameter for the auth and token exchange endpoints. +extern NSString *const kIncludeGrantedScopesParameter; + +/// The name of the login hint parameter for the auth and token exchange endpoints. +extern NSString *const kLoginHintParameter; + +/// The name of the hosted domain parameter for the auth and token exchange endpoints. +extern NSString *const kHostedDomainParameter; diff --git a/GoogleSignIn/Sources/GIDSignInConstants.m b/GoogleSignIn/Sources/GIDSignInConstants.m new file mode 100644 index 00000000..bb90d37a --- /dev/null +++ b/GoogleSignIn/Sources/GIDSignInConstants.m @@ -0,0 +1,29 @@ +/* + * Copyright 2024 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/GIDSignInConstants.h" + +NSString *const kAuthorizationURLTemplate = @"https://%@/o/oauth2/v2/auth"; +NSString *const kTokenURLTemplate = @"https://%@/token"; +NSString *const kBrowserCallbackPath = @"/oauth2callback"; + +NSString *const kAudienceParameter = @"audience"; +NSString *const kOpenIDRealmParameter = @"openid.realm"; +NSString *const kIncludeGrantedScopesParameter = @"include_granted_scopes"; +NSString *const kLoginHintParameter = @"login_hint"; +NSString *const kHostedDomainParameter = @"hd"; diff --git a/GoogleSignIn/Sources/GIDSignInInternalOptions.h b/GoogleSignIn/Sources/GIDSignInInternalOptions.h index c722d5d4..7a36e210 100644 --- a/GoogleSignIn/Sources/GIDSignInInternalOptions.h +++ b/GoogleSignIn/Sources/GIDSignInInternalOptions.h @@ -24,9 +24,9 @@ #import "GoogleSignIn/Sources/GIDSignIn_Private.h" -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h" -#endif // TARGET_OS_IOS +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST @class GIDConfiguration; @class GIDSignInResult; @@ -45,10 +45,10 @@ NS_ASSUME_NONNULL_BEGIN /// Whether the sign-in is an addScopes flow. NO means it is a sign in flow. @property(nonatomic, readonly) BOOL addScopesFlow; -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST /// The user account details the Verify with Google flow will verify @property(nonatomic, copy, nullable, readonly) NSArray *accountDetailsToVerify; -#endif // TARGET_OS_IOS +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST /// The extra parameters used in the sign-in URL. @property(nonatomic, readonly, nullable) NSDictionary *extraParams; @@ -67,10 +67,10 @@ NS_ASSUME_NONNULL_BEGIN /// The completion block to be called at the completion of the flow. @property(nonatomic, readonly, nullable) GIDSignInCompletion completion; -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST /// The completion block to be called at the completion of the verify flow. @property(nonatomic, readonly, nullable) GIDVerifyCompletion verifyCompletion; -#endif // TARGET_OS_IOS +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST /// The scopes to be used during the flow. @property(nonatomic, copy, nullable) NSArray *scopes; @@ -79,14 +79,14 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, copy, nullable) NSString *loginHint; /// Creates the default options. -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)configuration presentingViewController:(nullable UIViewController *)presentingViewController loginHint:(nullable NSString *)loginHint addScopesFlow:(BOOL)addScopesFlow accountDetailsToVerify:(NSArray *)accountDetailsToVerify verifyCompletion:(nullable GIDVerifyCompletion)completion; -#endif // TARGET_OS_IOS +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST #if TARGET_OS_IOS || TARGET_OS_MACCATALYST + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)configuration diff --git a/GoogleSignIn/Sources/GIDSignInInternalOptions.m b/GoogleSignIn/Sources/GIDSignInInternalOptions.m index f505eadf..74b271bd 100644 --- a/GoogleSignIn/Sources/GIDSignInInternalOptions.m +++ b/GoogleSignIn/Sources/GIDSignInInternalOptions.m @@ -26,7 +26,7 @@ @implementation GIDSignInInternalOptions -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)configuration presentingViewController:(nullable UIViewController *)presentingViewController loginHint:(nullable NSString *)loginHint @@ -46,7 +46,7 @@ + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)con } return options; } -#endif // TARGET_OS_IOS +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST #if TARGET_OS_IOS || TARGET_OS_MACCATALYST + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)configuration diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index e7b6e7bf..7e192768 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -22,15 +22,39 @@ #import "GoogleSignIn/Sources/GIDSignInInternalOptions.h" #import "GoogleSignIn/Sources/GIDSignInCallbackSchemes.h" +#import "GoogleSignIn/Sources/GIDSignInConstants.h" +#import "GoogleSignIn/Sources/GIDSignInPreferences.h" -#if TARGET_OS_IOS +@import GTMAppAuth; -@implementation GIDVerifyAccountDetail +#ifdef SWIFT_PACKAGE +@import AppAuth; +@import GTMSessionFetcherCore; +#else +#import +#import +#import +#endif + +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST + +@implementation GIDVerifyAccountDetail { + /// AppAuth configuration object. + OIDServiceConfiguration *_appAuthConfiguration; +} - (instancetype)initWithConfig:(GIDConfiguration *)configuration { self = [super init]; if (self) { _configuration = configuration; + + NSString *authorizationEndpointURL = [NSString stringWithFormat:kAuthorizationURLTemplate, + [GIDSignInPreferences googleAuthorizationServer]]; + NSString *tokenEndpointURL = [NSString stringWithFormat:kTokenURLTemplate, + [GIDSignInPreferences googleTokenServer]]; + _appAuthConfiguration = [[OIDServiceConfiguration alloc] + initWithAuthorizationEndpoint:[NSURL URLWithString:authorizationEndpointURL] + tokenEndpoint:[NSURL URLWithString:tokenEndpointURL]]; } return self; } @@ -102,7 +126,7 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * // If the application does not support the required URL schemes tell the developer so. GIDSignInCallbackSchemes *schemes = - [[GIDSignInCallbackSchemes alloc] initWithClientIdentifier:options.configuration.clientID]; + [[GIDSignInCallbackSchemes alloc] initWithClientIdentifier:options.configuration.clientID]; NSArray *unsupportedSchemes = [schemes unsupportedSchemes]; if (unsupportedSchemes.count != 0) { // NOLINTNEXTLINE(google-objc-avoid-throwing-exception) @@ -110,7 +134,39 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * format:@"Your app is missing support for the following URL schemes: %@", [unsupportedSchemes componentsJoinedByString:@", "]]; } - // TODO(#397): Start the incremental authorization flow. + NSString *redirectURI = + [NSString stringWithFormat:@"%@:%@", [schemes clientIdentifierScheme], kBrowserCallbackPath]; + NSURL *redirectURL = [NSURL URLWithString:redirectURI]; + + NSMutableDictionary *additionalParameters = [@{} mutableCopy]; + if (options.configuration.serverClientID) { + additionalParameters[kAudienceParameter] = options.configuration.serverClientID; + } + if (options.loginHint) { + additionalParameters[kLoginHintParameter] = options.loginHint; + } + if (options.configuration.hostedDomain) { + additionalParameters[kHostedDomainParameter] = options.configuration.hostedDomain; + } + additionalParameters[kSDKVersionLoggingParameter] = GIDVersion(); + additionalParameters[kEnvironmentLoggingParameter] = GIDEnvironment(); + + NSMutableArray *scopes; + for (GIDVerifiableAccountDetail *detail in options.accountDetailsToVerify) { + NSString *scopeString = [detail scope]; + if (scopeString) { + [scopes addObject:scopeString]; + } + } + + // TODO(#405): Use request variable to present request and process response. + __unused OIDAuthorizationRequest *request = + [[OIDAuthorizationRequest alloc] initWithConfiguration:_appAuthConfiguration + clientId:options.configuration.clientID + scopes:scopes + redirectURL:redirectURL + responseType:OIDResponseTypeCode + additionalParameters:additionalParameters]; } #pragma mark - Helpers @@ -144,4 +200,4 @@ - (void)assertValidPresentingViewController:(GIDSignInInternalOptions *)options @end -#endif // TARGET_OS_IOS +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h index 6fb68b24..3eb2dea8 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h @@ -16,7 +16,7 @@ #import -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST #import @@ -91,4 +91,4 @@ typedef void (^GIDVerifyCompletion)(GIDVerifiedAccountDetailResult *_Nullable ve NS_ASSUME_NONNULL_END -#endif // TARGET_OS_IOS +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST diff --git a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h index 6ff486de..e25b9bfd 100644 --- a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h +++ b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h @@ -43,6 +43,7 @@ NS_ASSUME_NONNULL_BEGIN * @brief Initializes a GIDFakeMainBundle object with `nil` to all of the designated initializer's parameters. */ - (instancetype)init; + /** * @fn startFaking: * @brief Starts faking [NSBundle mainBundle] diff --git a/GoogleSignIn/Tests/Unit/GIDSignInInternalOptionsTest.m b/GoogleSignIn/Tests/Unit/GIDSignInInternalOptionsTest.m index ac7d47e4..3c2e7fee 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInInternalOptionsTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInInternalOptionsTest.m @@ -33,7 +33,7 @@ @interface GIDSignInInternalOptionsTest : XCTestCase @implementation GIDSignInInternalOptionsTest -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST - (void)testDefaultOptionsForVerificationFlow { GIDConfiguration *configuration = [[GIDConfiguration alloc] initWithClientID:kClientId serverClientID:nil @@ -59,7 +59,7 @@ - (void)testDefaultOptionsForVerificationFlow { XCTAssertEqual(options.presentingViewController, presentingViewController); XCTAssertEqual(options.accountDetailsToVerify, accountDetailsToVerify); } -#endif // TARGET_OS_IOS +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST - (void)testDefaultOptions { id configuration = OCMStrictClassMock([GIDConfiguration class]); diff --git a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m index a9ea0369..a5efdfff 100644 --- a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m +++ b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m @@ -14,7 +14,7 @@ #import -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiableAccountDetail.h" @@ -159,6 +159,8 @@ - (void)testCurrentUserException { } } +// TODO(#405): Write tests for request and response handling. + - (void)testPresentingViewControllerException { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wnonnull" @@ -221,4 +223,4 @@ - (void)testSchemesNotSupportedException { @end -#endif // TARGET_OS_IOS +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST