FIRStorageTokenAuthorizer.m 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // Copyright 2017 Google
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #import "FirebaseStorageInternal/Sources/FIRStorageTokenAuthorizer.h"
  15. #import "FirebaseStorageInternal/Sources/Public/FirebaseStorageInternal/FIRStorage.h"
  16. #import "FirebaseStorageInternal/Sources/Public/FirebaseStorageInternal/FIRStorageConstants.h"
  17. #import "FirebaseStorageInternal/Sources/FIRStorageConstants_Private.h"
  18. #import "FirebaseStorageInternal/Sources/FIRStorageErrors.h"
  19. #import "FirebaseStorageInternal/Sources/FIRStorageLogger.h"
  20. #import "FirebaseCore/Extension/FirebaseCoreInternal.h"
  21. #import "FirebaseAppCheck/Interop/FIRAppCheckInterop.h"
  22. #import "FirebaseAppCheck/Interop/FIRAppCheckTokenResultInterop.h"
  23. #import "FirebaseAuth/Interop/FIRAuthInterop.h"
  24. static NSString *const kAppCheckTokenHeader = @"X-Firebase-AppCheck";
  25. static NSString *const kAuthHeader = @"Authorization";
  26. @implementation FIRStorageTokenAuthorizer {
  27. @private
  28. /// Google App ID to pass along with each request.
  29. NSString *_googleAppID;
  30. /// Auth provider.
  31. id<FIRAuthInterop> _auth;
  32. id<FIRAppCheckInterop> _appCheck;
  33. }
  34. @synthesize fetcherService = _fetcherService;
  35. - (instancetype)initWithGoogleAppID:(NSString *)googleAppID
  36. fetcherService:(GTMSessionFetcherService *)service
  37. authProvider:(nullable id<FIRAuthInterop>)auth
  38. appCheck:(nullable id<FIRAppCheckInterop>)appCheck {
  39. self = [super init];
  40. if (self) {
  41. _googleAppID = googleAppID;
  42. _fetcherService = service;
  43. _auth = auth;
  44. _appCheck = appCheck;
  45. }
  46. return self;
  47. }
  48. #pragma mark - GTMFetcherAuthorizationProtocol methods
  49. #pragma clang diagnostic push
  50. #pragma clang diagnostic ignored "-Wdeprecated-implementations"
  51. - (void)authorizeRequest:(NSMutableURLRequest *)request
  52. delegate:(id)delegate
  53. didFinishSelector:(SEL)sel {
  54. #pragma clang diagnostic push
  55. // Set version header on each request
  56. NSString *versionString = [NSString stringWithFormat:@"ios/%@", FIRFirebaseVersion()];
  57. [request setValue:versionString forHTTPHeaderField:@"x-firebase-storage-version"];
  58. // Set GMP ID on each request
  59. [request setValue:_googleAppID forHTTPHeaderField:@"x-firebase-gmpid"];
  60. if (delegate && sel) {
  61. id selfParam = self;
  62. NSMethodSignature *sig = [delegate methodSignatureForSelector:sel];
  63. NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
  64. [invocation setSelector:sel];
  65. [invocation setTarget:delegate];
  66. [invocation setArgument:&selfParam atIndex:2];
  67. [invocation setArgument:&request atIndex:3];
  68. dispatch_queue_t callbackQueue = self.fetcherService.callbackQueue;
  69. if (!callbackQueue) {
  70. callbackQueue = dispatch_get_main_queue();
  71. }
  72. [invocation retainArguments];
  73. dispatch_group_t fetchTokenGroup = dispatch_group_create();
  74. if (_auth) {
  75. dispatch_group_enter(fetchTokenGroup);
  76. [_auth getTokenForcingRefresh:NO
  77. withCallback:^(NSString *_Nullable token, NSError *_Nullable error) {
  78. if (error) {
  79. NSMutableDictionary *errorDictionary =
  80. [NSMutableDictionary dictionaryWithDictionary:error.userInfo];
  81. errorDictionary[kFIRStorageResponseErrorDomain] = error.domain;
  82. errorDictionary[kFIRStorageResponseErrorCode] = @(error.code);
  83. NSError *tokenError = [FIRStorageErrors
  84. errorWithCode:FIRIMPLStorageErrorCodeUnauthenticated
  85. infoDictionary:errorDictionary];
  86. [invocation setArgument:&tokenError atIndex:4];
  87. } else if (token) {
  88. NSString *firebaseToken =
  89. [NSString stringWithFormat:kFIRStorageAuthTokenFormat, token];
  90. [request setValue:firebaseToken forHTTPHeaderField:kAuthHeader];
  91. }
  92. dispatch_group_leave(fetchTokenGroup);
  93. }];
  94. }
  95. if (_appCheck) {
  96. dispatch_group_enter(fetchTokenGroup);
  97. [_appCheck getTokenForcingRefresh:NO
  98. completion:^(id<FIRAppCheckTokenResultInterop> tokenResult) {
  99. [request setValue:tokenResult.token
  100. forHTTPHeaderField:kAppCheckTokenHeader];
  101. if (tokenResult.error) {
  102. FIRLogDebug(kFIRLoggerStorage, kFIRStorageMessageCodeAppCheckError,
  103. @"Failed to fetch AppCheck token. Error: %@",
  104. tokenResult.error);
  105. }
  106. dispatch_group_leave(fetchTokenGroup);
  107. }];
  108. }
  109. dispatch_group_notify(fetchTokenGroup, callbackQueue, ^{
  110. [invocation invoke];
  111. });
  112. }
  113. }
  114. // Note that stopAuthorization, isAuthorizingRequest, and userEmail
  115. // aren't relevant with the Firebase App/Auth implementation of tokens,
  116. // and thus aren't implemented. Token refresh is handled transparently
  117. // for us, and we don't allow the auth request to be stopped.
  118. // Auth is also not required so the world doesn't stop.
  119. - (void)stopAuthorization {
  120. // Noop
  121. }
  122. - (void)stopAuthorizationForRequest:(NSURLRequest *)request {
  123. // Noop
  124. }
  125. - (BOOL)isAuthorizingRequest:(NSURLRequest *)request {
  126. return NO;
  127. }
  128. - (BOOL)isAuthorizedRequest:(NSURLRequest *)request {
  129. NSString *authHeader = request.allHTTPHeaderFields[@"Authorization"];
  130. BOOL isFirebaseToken = [authHeader hasPrefix:@"Firebase"];
  131. return isFirebaseToken;
  132. }
  133. - (NSString *)userEmail {
  134. // Noop
  135. return nil;
  136. }
  137. @end