Skip to content

Commit

Permalink
Multi-app fix (#10805)
Browse files Browse the repository at this point in the history
  • Loading branch information
chuanr authored Feb 10, 2023
1 parent 6d1e7f5 commit 0216c1a
Show file tree
Hide file tree
Showing 14 changed files with 156 additions and 15 deletions.
2 changes: 2 additions & 0 deletions FirebaseAuth.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ supports email and password accounts, as well as several 3rd party authenticatio
'FirebaseAuth/Tests/Unit/FIRVerifyClient*',
'FirebaseAuth/Tests/Unit/FIRVerifyPhoneNumber*',
'FirebaseAuth/Tests/Unit/FIROAuthProviderTests.m',
'FirebaseAuth/Tests/Unit/FIRMultiFactorResolverTests.m',
]
unit_tests.tvos.exclude_files = [
'FirebaseAuth/Tests/Unit/FIRAuthAPNSTokenManagerTests.m',
Expand All @@ -93,6 +94,7 @@ supports email and password accounts, as well as several 3rd party authenticatio
'FirebaseAuth/Tests/Unit/FIRVerifyClient*',
'FirebaseAuth/Tests/Unit/FIRVerifyPhoneNumber*',
'FirebaseAuth/Tests/Unit/FIROAuthProviderTests.m',
'FirebaseAuth/Tests/Unit/FIRMultiFactorResolverTests.m',
]
# app_host is needed for tests with keychain
unit_tests.requires_app_host = true
Expand Down
4 changes: 4 additions & 0 deletions FirebaseAuth/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 10.6.0
- [fixed] Fixed a bug where user is created in a specific tenant although tenantID was not specified. (#10748)
- [fixed] Fixed a bug where the resolver exposed in MFA is not associated to the correct app. (#10690)

# 10.5.0
- [fixed] Use team player ID, game player ID and fetchItems for signature verification. (#10441)
- [fixed] Prevent keychain pop-up when accessing Auth keychain in a Mac
Expand Down
1 change: 1 addition & 0 deletions FirebaseAuth/Sources/Auth/FIRAuth.m
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ - (nullable instancetype)initWithAPIKey:(NSString *)APIKey
_listenerHandles = [NSMutableArray array];
_requestConfiguration = [[FIRAuthRequestConfiguration alloc] initWithAPIKey:APIKey
appID:appID
auth:self
heartbeatLogger:heartbeatLogger];
_firebaseAppName = [appName copy];
#if TARGET_OS_IOS
Expand Down
12 changes: 9 additions & 3 deletions FirebaseAuth/Sources/Backend/FIRAuthBackend.m
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,9 @@ - (void)verifyAssertion:(FIRVerifyAssertionRequest *)request
}
NSError *multiFactorRequiredError = [FIRAuthErrorUtils
secondFactorRequiredErrorWithPendingCredential:response.MFAPendingCredential
hints:multiFactorInfo];
hints:multiFactorInfo
auth:request.requestConfiguration
.auth];
callback(nil, multiFactorRequiredError);
#endif
} else {
Expand Down Expand Up @@ -820,7 +822,9 @@ - (void)verifyPassword:(FIRVerifyPasswordRequest *)request
}
NSError *multiFactorRequiredError = [FIRAuthErrorUtils
secondFactorRequiredErrorWithPendingCredential:response.MFAPendingCredential
hints:multiFactorInfo];
hints:multiFactorInfo
auth:request.requestConfiguration
.auth];
callback(nil, multiFactorRequiredError);
#endif
} else {
Expand Down Expand Up @@ -850,7 +854,9 @@ - (void)emailLinkSignin:(FIREmailLinkSignInRequest *)request
}
NSError *multiFactorRequiredError = [FIRAuthErrorUtils
secondFactorRequiredErrorWithPendingCredential:response.MFAPendingCredential
hints:multiFactorInfo];
hints:multiFactorInfo
auth:request.requestConfiguration
.auth];
callback(nil, multiFactorRequiredError);
#endif
} else {
Expand Down
30 changes: 29 additions & 1 deletion FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#import <Foundation/Foundation.h>

#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h"
#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h"

@protocol FIRHeartbeatLoggerProtocol;

Expand All @@ -37,6 +38,11 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property(nonatomic, copy, readonly) NSString *appID;

/** @property auth
@brief The FIRAuth instance used in the request.
*/
@property(nonatomic, weak, readonly, nullable) FIRAuth *auth;

/** @property heartbeatLogger
@brief The heartbeat logger used to add heartbeats to the corresponding request's header.
*/
Expand Down Expand Up @@ -66,14 +72,36 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (nullable instancetype)initWithAPIKey:(NSString *)APIKey appID:(NSString *)appID;

/** @fn initWithAPIKey:appID:
@brief Convenience initializer.
@param APIKey The API key to be used in the request.
@param appID The Firebase app ID to be passed in the request header.
@param auth The FIRAuth instance used in the request.
*/
- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
appID:(NSString *)appID
auth:(nullable FIRAuth *)auth;

/** @fn initWithAPIKey:appID:heartbeatLogger:
@brief Designated initializer.
@param APIKey The API key to be used in the request.
@param appID The Firebase app ID to be passed in the request header.
@param appID The Firebase app ID to be passed in the request header.
@param heartbeatLogger The heartbeat logger used to add heartbeats to the request header.
*/
- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
appID:(NSString *)appID
heartbeatLogger:(nullable id<FIRHeartbeatLoggerProtocol>)heartbeatLogger;

/** @fn initWithAPIKey:appID:heartbeatLogger:
@brief Designated initializer.
@param APIKey The API key to be used in the request.
@param appID The Firebase app ID to be passed in the request header.
@param auth The FIRAuth instance used in the request.
@param heartbeatLogger The heartbeat logger used to add heartbeats to the request header.
*/
- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
appID:(NSString *)appID
auth:(nullable FIRAuth *)auth
heartbeatLogger:(nullable id<FIRHeartbeatLoggerProtocol>)heartbeatLogger
NS_DESIGNATED_INITIALIZER;

Expand Down
16 changes: 15 additions & 1 deletion FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,30 @@
@implementation FIRAuthRequestConfiguration

- (nullable instancetype)initWithAPIKey:(NSString *)APIKey appID:(NSString *)appID {
return [self initWithAPIKey:APIKey appID:appID heartbeatLogger:nil];
return [self initWithAPIKey:APIKey appID:appID auth:nil heartbeatLogger:nil];
}

- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
appID:(NSString *)appID
auth:(nullable FIRAuth *)auth {
return [self initWithAPIKey:APIKey appID:appID auth:auth heartbeatLogger:nil];
}

- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
appID:(NSString *)appID
heartbeatLogger:(nullable id<FIRHeartbeatLoggerProtocol>)heartbeatLogger {
return [self initWithAPIKey:APIKey appID:appID auth:nil heartbeatLogger:heartbeatLogger];
}

- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
appID:(NSString *)appID
auth:(nullable FIRAuth *)auth
heartbeatLogger:(nullable id<FIRHeartbeatLoggerProtocol>)heartbeatLogger {
self = [super init];
if (self) {
_APIKey = [APIKey copy];
_appID = [appID copy];
_auth = auth;
_heartbeatLogger = heartbeatLogger;
}
return self;
Expand Down
2 changes: 1 addition & 1 deletion FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.m
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ - (nullable instancetype)initWithEndpoint:(NSString *)endpoint
// Automatically set the tenant ID. If the request is initialized before FIRAuth is configured,
// set tenant ID to nil.
@try {
_tenantID = [FIRAuth auth].tenantID;
_tenantID = [self requestConfiguration].auth.tenantID;
} @catch (NSException *e) {
_tenantID = nil;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ NS_ASSUME_NONNULL_BEGIN
@property(nonatomic) NSString *MFAPendingCredential;

- (instancetype)initWithMFAPendingCredential:(NSString *_Nullable)MFAPendingCredential
hints:(NSArray<FIRMultiFactorInfo *> *)hints;
hints:(NSArray<FIRMultiFactorInfo *> *)hints
auth:(FIRAuth *)auth;

@end

Expand Down
5 changes: 3 additions & 2 deletions FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver.m
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,13 @@
@implementation FIRMultiFactorResolver

- (instancetype)initWithMFAPendingCredential:(NSString *_Nullable)MFAPendingCredential
hints:(NSArray<FIRMultiFactorInfo *> *)hints {
hints:(NSArray<FIRMultiFactorInfo *> *)hints
auth:(FIRAuth *)auth {
self = [super init];
if (self) {
_MFAPendingCredential = MFAPendingCredential;
_hints = hints;
_auth = [FIRAuth auth];
_auth = auth;
_session = [[FIRMultiFactorSession alloc] init];
_session.MFAPendingCredential = MFAPendingCredential;
}
Expand Down
1 change: 1 addition & 0 deletions FirebaseAuth/Sources/User/FIRUser.m
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
// The `heartbeatLogger` will be set later via a property update.
_requestConfiguration = [[FIRAuthRequestConfiguration alloc] initWithAPIKey:APIKey
appID:appID
auth:_auth
heartbeatLogger:nil];
#if TARGET_OS_IOS
_multiFactor = multiFactor ?: [[FIRMultiFactor alloc] init];
Expand Down
9 changes: 5 additions & 4 deletions FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
*/

#import <Foundation/Foundation.h>
#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h"
#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h"

#import "FirebaseAuth/Sources/Utilities/FIRAuthInternalErrors.h"

@class FIRAuthCredential;
Expand Down Expand Up @@ -489,9 +489,10 @@ NS_ASSUME_NONNULL_BEGIN
@brief Constructs an @c NSError with the @c FIRAuthErrorCodeSecondFactorRequired code.
@return The NSError instance associated with the given FIRAuthError.
*/
+ (NSError *)secondFactorRequiredErrorWithPendingCredential:(NSString *)MFAPendingCredential
hints:(NSArray<FIRMultiFactorInfo *> *)
multiFactorInfo;
+ (NSError *)
secondFactorRequiredErrorWithPendingCredential:(NSString *)MFAPendingCredential
hints:(NSArray<FIRMultiFactorInfo *> *)multiFactorInfo
auth:(FIRAuth *)auth;
#endif

/** @fn appNotVerifiedErrorWithMessage:
Expand Down
6 changes: 4 additions & 2 deletions FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -1311,12 +1311,14 @@ + (NSError *)gameKitNotLinkedError {

#if TARGET_OS_IOS
+ (NSError *)secondFactorRequiredErrorWithPendingCredential:(NSString *)MFAPendingCredential
hints:(NSArray<FIRMultiFactorInfo *> *)hints {
hints:(NSArray<FIRMultiFactorInfo *> *)hints
auth:(FIRAuth *)auth {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
if (MFAPendingCredential && hints) {
FIRMultiFactorResolver *resolver =
[[FIRMultiFactorResolver alloc] initWithMFAPendingCredential:MFAPendingCredential
hints:hints];
hints:hints
auth:auth];
userInfo[FIRAuthErrorUserInfoMultiFactorResolverKey] = resolver;
}
return [self errorWithCode:FIRAuthInternalErrorCodeSecondFactorRequired userInfo:userInfo];
Expand Down
22 changes: 22 additions & 0 deletions FirebaseAuth/Tests/Unit/FIRIdentityToolkitRequestTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#import <XCTest/XCTest.h>

#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h"
#import "FirebaseAuth/Tests/Unit/FIRApp+FIRAuthUnitTests.h"

/** @var kEndpoint
@brief The endpoint for the requests.
Expand Down Expand Up @@ -158,4 +159,25 @@ - (void)testInitWithEndpointUseIdentityPlatformUseEmulatorExpectedRequestURL {
XCTAssertEqualObjects(expectedURL, request.requestURL.absoluteString);
}

/** @fn testExpectedTenantIDWithNonDefaultFIRApp
@brief Tests the request correctly populated the tenant ID from a non default app.
*/
- (void)testExpectedTenantIDWithNonDefaultFIRApp {
FIRApp *nonDefaultApp = [FIRApp appForAuthUnitTestsWithName:@"nonDefaultApp"];
FIRAuth *nonDefaultAuth = [FIRAuth authWithApp:nonDefaultApp];
nonDefaultAuth.tenantID = @"tenant-id";
FIRAuthRequestConfiguration *requestConfiguration =
[[FIRAuthRequestConfiguration alloc] initWithAPIKey:kAPIKey
appID:kFirebaseAppID
auth:nonDefaultAuth];
requestConfiguration.emulatorHostAndPort = kEmulatorHostAndPort;
FIRIdentityToolkitRequest *request =
[[FIRIdentityToolkitRequest alloc] initWithEndpoint:kEndpoint
requestConfiguration:requestConfiguration
useIdentityPlatform:YES
useStaging:NO];

XCTAssertEqualObjects(@"tenant-id", request.tenantID);
}

@end
58 changes: 58 additions & 0 deletions FirebaseAuth/Tests/Unit/FIRMultiFactorResolverTests.m
Original file line number Diff line number Diff line change
@@ -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 <XCTest/XCTest.h>

#if TARGET_OS_IOS

#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver+Internal.h"
#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h"
#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h"
#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorResolver.h"
#import "FirebaseAuth/Tests/Unit/FIRApp+FIRAuthUnitTests.h"

/** @class FIRMultiFactorResolverTests
@brief Tests for @c FIRMultiFactorResolver.
*/
@interface FIRMultiFactorResolverTests : XCTestCase

@end

@implementation FIRMultiFactorResolverTests

/** @fn testMultifactorResolverCreation
@brief Tests succuessful creation of a @c FIRMultiFactorResolver object.
*/
- (void)testMultifactorResolverCreation {
NSString *fakeMFAPendingCredential = @"fakeMFAPendingCredential";
NSArray<FIRMultiFactorInfo *> *fakeHints = @[];

FIRApp *app = [FIRApp appForAuthUnitTestsWithName:@"app"];
FIRAuth *auth = [FIRAuth authWithApp:app];
auth.tenantID = @"tenant-id";

FIRMultiFactorResolver *resolver =
[[FIRMultiFactorResolver alloc] initWithMFAPendingCredential:fakeMFAPendingCredential
hints:fakeHints
auth:auth];

XCTAssertEqualObjects(resolver.auth, auth);
XCTAssertEqualObjects(resolver.hints, fakeHints);
}

@end

#endif

0 comments on commit 0216c1a

Please sign in to comment.