GIDProfileDataFetcher.m 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /*
  2. * Copyright 2023 Google LLC
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "GoogleSignIn/Sources/GIDProfileDataFetcher/Implementations/GIDProfileDataFetcher.h"
  17. #import "GoogleSignIn/Sources/GIDHTTPFetcher/API/GIDHTTPFetcher.h"
  18. #import "GoogleSignIn/Sources/GIDHTTPFetcher/Implementations/GIDHTTPFetcher.h"
  19. #import "GoogleSignIn/Sources/GIDProfileData_Private.h"
  20. #import "GoogleSignIn/Sources/GIDSignInPreferences.h"
  21. #ifdef SWIFT_PACKAGE
  22. @import AppAuth;
  23. @import GTMAppAuth;
  24. #else
  25. #import <AppAuth/AppAuth.h>
  26. #import <GTMAppAuth/GTMAppAuth.h>
  27. #endif
  28. NS_ASSUME_NONNULL_BEGIN
  29. // The URL template for the URL to get user info.
  30. static NSString *const kUserInfoURLTemplate = @"https://%@/oauth2/v3/userinfo";
  31. // Basic profile (Fat ID Token / userinfo endpoint) keys
  32. static NSString *const kBasicProfileEmailKey = @"email";
  33. static NSString *const kBasicProfilePictureKey = @"picture";
  34. static NSString *const kBasicProfileNameKey = @"name";
  35. static NSString *const kBasicProfileGivenNameKey = @"given_name";
  36. static NSString *const kBasicProfileFamilyNameKey = @"family_name";
  37. @implementation GIDProfileDataFetcher {
  38. id<GIDHTTPFetcher> _httpFetcher;
  39. }
  40. - (instancetype)init {
  41. GIDHTTPFetcher *httpFetcher = [[GIDHTTPFetcher alloc] init];
  42. return [self initWithHTTPFetcher:httpFetcher];
  43. }
  44. - (instancetype)initWithHTTPFetcher:(id<GIDHTTPFetcher>)httpFetcher {
  45. self = [super init];
  46. if (self) {
  47. _httpFetcher = httpFetcher;
  48. }
  49. return self;
  50. }
  51. - (void)fetchProfileDataWithAuthState:(OIDAuthState *)authState
  52. completion:(void (^)(GIDProfileData *_Nullable profileData,
  53. NSError *_Nullable error))completion {
  54. OIDIDToken *idToken =
  55. [[OIDIDToken alloc] initWithIDTokenString:authState.lastTokenResponse.idToken];
  56. if (idToken) {
  57. // If we have an ID token, try to extract profile data from it.
  58. GIDProfileData *profileData = [self fetchProfileDataWithIDToken:idToken];
  59. if (profileData) {
  60. completion(profileData, nil);
  61. return;
  62. }
  63. }
  64. // If we can't retrieve profile data from the ID token, make a UserInfo endpoint request to
  65. // fetch it.
  66. NSString *infoString = [NSString stringWithFormat:kUserInfoURLTemplate,
  67. [GIDSignInPreferences googleUserInfoServer]];
  68. NSURL *infoURL = [NSURL URLWithString:infoString];
  69. NSMutableURLRequest *infoRequest = [NSMutableURLRequest requestWithURL:infoURL];
  70. GTMAppAuthFetcherAuthorization *authorization =
  71. [[GTMAppAuthFetcherAuthorization alloc] initWithAuthState:authState];
  72. [_httpFetcher fetchURLRequest:infoRequest
  73. withAuthorizer:authorization
  74. withComment:@"GIDSignIn: fetch basic profile info"
  75. completion:^(NSData *data, NSError *error) {
  76. if (error) {
  77. completion(nil, error);
  78. return;
  79. }
  80. NSError *jsonDeserializationError;
  81. NSDictionary<NSString *, NSString *> *profileDict =
  82. [NSJSONSerialization JSONObjectWithData:data
  83. options:NSJSONReadingMutableContainers
  84. error:&jsonDeserializationError];
  85. if (jsonDeserializationError) {
  86. completion(nil, jsonDeserializationError);
  87. return;
  88. }
  89. GIDProfileData *profileData = [[GIDProfileData alloc]
  90. initWithEmail:idToken.claims[kBasicProfileEmailKey]
  91. name:profileDict[kBasicProfileNameKey]
  92. givenName:profileDict[kBasicProfileGivenNameKey]
  93. familyName:profileDict[kBasicProfileFamilyNameKey]
  94. imageURL:[NSURL URLWithString:profileDict[kBasicProfilePictureKey]]];
  95. completion(profileData, nil);
  96. }];
  97. }
  98. - (nullable GIDProfileData*)fetchProfileDataWithIDToken:(OIDIDToken *)idToken {
  99. if (!idToken ||
  100. !idToken.claims[kBasicProfilePictureKey] ||
  101. !idToken.claims[kBasicProfileNameKey] ||
  102. !idToken.claims[kBasicProfileGivenNameKey] ||
  103. !idToken.claims[kBasicProfileFamilyNameKey]) {
  104. return nil;
  105. }
  106. return [[GIDProfileData alloc]
  107. initWithEmail:idToken.claims[kBasicProfileEmailKey]
  108. name:idToken.claims[kBasicProfileNameKey]
  109. givenName:idToken.claims[kBasicProfileGivenNameKey]
  110. familyName:idToken.claims[kBasicProfileFamilyNameKey]
  111. imageURL:[NSURL URLWithString:idToken.claims[kBasicProfilePictureKey]]];
  112. }
  113. @end
  114. NS_ASSUME_NONNULL_END