Skip to content

Commit

Permalink
Use sign up endpoint for link with email password (resubmit #11925) (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
renkelvin committed Nov 1, 2023
1 parent 86ef7d8 commit 6673e7c
Show file tree
Hide file tree
Showing 11 changed files with 223 additions and 77 deletions.
3 changes: 3 additions & 0 deletions FirebaseAuth/CHANGELOG.md
@@ -1,3 +1,6 @@
# 10.18.0
- [fixed] Fix a bug where anonymous account can't be linked with email password credential. (#11911)

# 10.16.0
- [added] Added custom auth domain support in recaptcha v2 authentication flows. (#7553)

Expand Down
7 changes: 1 addition & 6 deletions FirebaseAuth/Sources/Auth/FIRAuth.m
Expand Up @@ -35,7 +35,6 @@
#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h"
#import "FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h"
#import "FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h"
#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h"
#import "FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h"
#import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h"
#import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h"
Expand Down Expand Up @@ -165,11 +164,6 @@
*/
static NSString *const kRevertSecondFactorAdditionRequestType = @"REVERT_SECOND_FACTOR_ADDITION";

/** @var kMissingRecaptchaTokenErrorPrefix
@brief The prefix of the error message of missing recaptcha token during authenticating.
*/
static NSString *const kMissingRecaptchaTokenErrorPrefix = @"MISSING_RECAPTCHA_TOKEN";

/** @var kMissingPasswordReason
@brief The reason why the @c FIRAuthErrorCodeWeakPassword error is thrown.
@remarks This error message will be localized in the future.
Expand Down Expand Up @@ -1994,6 +1988,7 @@ - (void)internalCreateUserWithEmail:(NSString *)email
[[FIRSignUpNewUserRequest alloc] initWithEmail:email
password:password
displayName:nil
idToken:nil
requestConfiguration:_requestConfiguration];
if (![request.password length]) {
completion(
Expand Down
1 change: 1 addition & 0 deletions FirebaseAuth/Sources/Auth/FIRAuth_Internal.h
Expand Up @@ -16,6 +16,7 @@

#import <Foundation/Foundation.h>
#import "FirebaseAuth/Interop/FIRAuthInterop.h"
#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h"
#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h"
#import "FirebaseCore/Extension/FIRLogger.h"

Expand Down
6 changes: 6 additions & 0 deletions FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h
Expand Up @@ -38,6 +38,11 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property(nonatomic, copy, nullable) NSString *displayName;

/** @property idToken
@brief The idToken of the user.
*/
@property(nonatomic, copy, nullable) NSString *idToken;

/** @property captchaResponse
@brief Response to the captcha.
*/
Expand Down Expand Up @@ -74,6 +79,7 @@ NS_ASSUME_NONNULL_BEGIN
- (nullable instancetype)initWithEmail:(nullable NSString *)email
password:(nullable NSString *)password
displayName:(nullable NSString *)displayName
idToken:(nullable NSString *)idToken
requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration
NS_DESIGNATED_INITIALIZER;

Expand Down
11 changes: 11 additions & 0 deletions FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.m
Expand Up @@ -38,6 +38,11 @@
*/
static NSString *const kDisplayNameKey = @"displayName";

/** @var kIDToken
@brief The key for the "kIDToken" value in the request.
*/
static NSString *const kIDToken = @"idToken";

/** @var kCaptchaResponseKey
@brief The key for the "captchaResponse" value in the request.
*/
Expand Down Expand Up @@ -68,12 +73,14 @@ @implementation FIRSignUpNewUserRequest
- (nullable instancetype)initWithEmail:(nullable NSString *)email
password:(nullable NSString *)password
displayName:(nullable NSString *)displayName
idToken:(nullable NSString *)idToken
requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration {
self = [super initWithEndpoint:kSignupNewUserEndpoint requestConfiguration:requestConfiguration];
if (self) {
_email = [email copy];
_password = [password copy];
_displayName = [displayName copy];
_idToken = [idToken copy];
_returnSecureToken = YES;
}
return self;
Expand All @@ -84,6 +91,7 @@ - (nullable instancetype)initWithRequestConfiguration:
self = [self initWithEmail:nil
password:nil
displayName:nil
idToken:nil
requestConfiguration:requestConfiguration];
return self;
}
Expand All @@ -99,6 +107,9 @@ - (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)
if (_displayName) {
postBody[kDisplayNameKey] = _displayName;
}
if (_idToken) {
postBody[kIDToken] = _idToken;
}
if (_captchaResponse) {
postBody[kCaptchaResponseKey] = _captchaResponse;
}
Expand Down
122 changes: 110 additions & 12 deletions FirebaseAuth/Sources/User/FIRUser.m
Expand Up @@ -43,6 +43,8 @@
#import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h"
#import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h"
#import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h"
#import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h"
#import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h"
#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h"
#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h"
#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h"
Expand All @@ -61,9 +63,9 @@
#import "FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h"

#if TARGET_OS_IOS
#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h"

#import "FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h"
#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h"
#import "FirebaseAuth/Sources/Utilities/FIRAuthRecaptchaVerifier.h"
#endif

NS_ASSUME_NONNULL_BEGIN
Expand Down Expand Up @@ -582,7 +584,6 @@ - (void)setTokenService:(FIRSecureTokenService *)tokenService
}

#pragma mark -

/** @fn updateEmail:password:callback:
@brief Updates email address and/or password for the current user.
@remarks May fail if there is already an email/password-based account for the same email
Expand Down Expand Up @@ -1079,6 +1080,109 @@ - (void)internalVerifyBeforeUpdateEmailWithNewEmail:(NSString *)newEmail
});
}

- (void)linkWithEmailPassword:(FIREmailPasswordAuthCredential *)credential
authResult:(FIRAuthDataResult *)authResult
completion:(nullable FIRAuthDataResultCallback)completion {
[self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) {
FIRAuthRequestConfiguration *requestConfiguration = self.auth.requestConfiguration;
FIRSignUpNewUserRequest *request =
[[FIRSignUpNewUserRequest alloc] initWithEmail:credential.email
password:credential.password
displayName:nil
idToken:accessToken
requestConfiguration:requestConfiguration];
FIRSignupNewUserCallback signUpNewUserCallback = ^(FIRSignUpNewUserResponse *_Nullable response,
NSError *_Nullable error) {
if (error) {
[self signOutIfTokenIsInvalidWithError:error];
callInMainThreadWithAuthDataResultAndError(completion, nil, error);
} else {
// Update the new token and refresh user info again.
self->_tokenService = [[FIRSecureTokenService alloc]
initWithRequestConfiguration:requestConfiguration
accessToken:response.IDToken
accessTokenExpirationDate:response.approximateExpirationDate
refreshToken:response.refreshToken];

[self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
NSError *_Nullable error) {
if (error) {
callInMainThreadWithAuthDataResultAndError(completion, nil, error);
return;
}
FIRGetAccountInfoRequest *getAccountInfoRequest =
[[FIRGetAccountInfoRequest alloc] initWithAccessToken:accessToken
requestConfiguration:requestConfiguration];
[FIRAuthBackend
getAccountInfo:getAccountInfoRequest
callback:^(FIRGetAccountInfoResponse *_Nullable response,
NSError *_Nullable error) {
if (error) {
[self signOutIfTokenIsInvalidWithError:error];
callInMainThreadWithAuthDataResultAndError(completion, nil, error);
return;
}
self.anonymous = NO;
[self updateWithGetAccountInfoResponse:response];
NSError *keychainError;
if (![self updateKeychain:&keychainError]) {
callInMainThreadWithAuthDataResultAndError(completion, nil, keychainError);
return;
}
[self signOutIfTokenIsInvalidWithError:error];
callInMainThreadWithAuthDataResultAndError(completion, authResult, nil);
}];
}];
}
};

#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST && (!defined(TARGET_OS_VISION) || !TARGET_OS_VISION)
if ([[FIRAuthRecaptchaVerifier sharedRecaptchaVerifier:self.auth]
enablementStatusForProvider:FIRAuthRecaptchaProviderPassword]) {
[[FIRAuthRecaptchaVerifier sharedRecaptchaVerifier:self.auth]
injectRecaptchaFields:request
provider:FIRAuthRecaptchaProviderPassword
action:FIRAuthRecaptchaActionSignUpPassword
completion:^(
FIRIdentityToolkitRequest<FIRAuthRPCRequest> *requestWithRecaptchaToken) {
[FIRAuthBackend
signUpNewUser:(FIRSignUpNewUserRequest *)requestWithRecaptchaToken
callback:signUpNewUserCallback];
}];
} else {
[FIRAuthBackend
signUpNewUser:request
callback:^(FIRSignUpNewUserResponse *_Nullable response, NSError *_Nullable error) {
if (!error) {
signUpNewUserCallback(response, nil);
return;
}
NSError *underlyingError = [error.userInfo objectForKey:NSUnderlyingErrorKey];
if (error.code == FIRAuthErrorCodeInternalError &&
[[underlyingError.userInfo
objectForKey:FIRAuthErrorUserInfoDeserializedResponseKey][@"message"]
hasPrefix:kMissingRecaptchaTokenErrorPrefix]) {
[[FIRAuthRecaptchaVerifier sharedRecaptchaVerifier:self.auth]
injectRecaptchaFields:request
provider:FIRAuthRecaptchaProviderPassword
action:FIRAuthRecaptchaActionSignUpPassword
completion:^(FIRIdentityToolkitRequest<FIRAuthRPCRequest>
*requestWithRecaptchaToken) {
[FIRAuthBackend signUpNewUser:(FIRSignUpNewUserRequest *)
requestWithRecaptchaToken
callback:signUpNewUserCallback];
}];
} else {
signUpNewUserCallback(nil, error);
}
}];
}
#else
[FIRAuthBackend signUpNewUser:request callback:signUpNewUserCallback];
#endif
}];
}

- (void)linkWithCredential:(FIRAuthCredential *)credential
completion:(nullable FIRAuthDataResultCallback)completion {
dispatch_async(FIRAuthGlobalWorkQueue(), ^{
Expand All @@ -1098,15 +1202,9 @@ - (void)linkWithCredential:(FIRAuthCredential *)credential
FIREmailPasswordAuthCredential *emailPasswordCredential =
(FIREmailPasswordAuthCredential *)credential;
if (emailPasswordCredential.password) {
[self updateEmail:emailPasswordCredential.email
password:emailPasswordCredential.password
callback:^(NSError *error) {
if (error) {
callInMainThreadWithAuthDataResultAndError(completion, nil, error);
} else {
callInMainThreadWithAuthDataResultAndError(completion, result, nil);
}
}];
[self linkWithEmailPassword:emailPasswordCredential
authResult:result
completion:completion];
} else {
[self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
NSError *_Nullable error) {
Expand Down
5 changes: 5 additions & 0 deletions FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h
Expand Up @@ -23,6 +23,11 @@

NS_ASSUME_NONNULL_BEGIN

/** @var kMissingRecaptchaTokenErrorPrefix
@brief The prefix of the error message of missing recaptcha token during authenticating.
*/
static NSString *const kMissingRecaptchaTokenErrorPrefix = @"MISSING_RECAPTCHA_TOKEN";

/** @class FIRAuthErrorUtils
@brief Utility class used to construct @c NSError instances.
*/
Expand Down
7 changes: 7 additions & 0 deletions FirebaseAuth/Tests/Unit/FIRAuthTests.m
Expand Up @@ -138,6 +138,11 @@
*/
static NSString *const kDisplayName = @"User Doe";

/** @var kIDToken
@brief The fake id token.
*/
static NSString *const kIDToken = @"IDToken";

/** @var kFakeGivenName
@brief The fake user given name.
*/
Expand Down Expand Up @@ -1818,6 +1823,7 @@ - (void)testCreateUserWithEmailPasswordWithRecaptchaVerificationSuccess {
[[FIRSignUpNewUserRequest alloc] initWithEmail:kEmail
password:kFakePassword
displayName:kDisplayName
idToken:kIDToken
requestConfiguration:[FIRAuth auth].requestConfiguration];
[constRequestWithRecaptchaToken injectRecaptchaFields:kFakeRecaptchaResponse
recaptchaVersion:kFakeRecaptchaVersion];
Expand Down Expand Up @@ -1867,6 +1873,7 @@ - (void)testCreateUserWithEmailPasswordWithRecaptchaFallbackSuccess {
[[FIRSignUpNewUserRequest alloc] initWithEmail:kEmail
password:kFakePassword
displayName:kDisplayName
idToken:kIDToken
requestConfiguration:[FIRAuth auth].requestConfiguration];
[constRequestWithRecaptchaToken injectRecaptchaFields:kFakeRecaptchaResponse
recaptchaVersion:kFakeRecaptchaVersion];
Expand Down
12 changes: 12 additions & 0 deletions FirebaseAuth/Tests/Unit/FIRSignUpNewUserRequestTests.m
Expand Up @@ -60,6 +60,16 @@
*/
static NSString *const kTestDisplayName = @"DisplayName";

/** @var kIDTokenKey
@brief the name of the "kIDTokenKey" property in the request.
*/
static NSString *const kIDTokenKey = @"idToken";

/** @var kTestIDToken
@brief Testing id token.
*/
static NSString *const kTestIDToken = @"testIDToken";

/** @var kPasswordKey
@brief the name of the "password" property in the request.
*/
Expand Down Expand Up @@ -167,6 +177,7 @@ - (void)testSignUpNewUserRequestNotAnonymous {
[[FIRSignUpNewUserRequest alloc] initWithEmail:kTestEmail
password:kTestPassword
displayName:kTestDisplayName
idToken:kTestIDToken
requestConfiguration:_requestConfiguration];
[FIRAuthBackend
signUpNewUser:request
Expand All @@ -190,6 +201,7 @@ - (void)testSignUpNewUserRequestOptionalFields {
[[FIRSignUpNewUserRequest alloc] initWithEmail:kTestEmail
password:kTestPassword
displayName:kTestDisplayName
idToken:kTestIDToken
requestConfiguration:_requestConfiguration];
request.captchaResponse = kTestCaptchaResponse;
request.clientType = kTestClientType;
Expand Down
1 change: 1 addition & 0 deletions FirebaseAuth/Tests/Unit/FIRSignUpNewUserResponseTests.m
Expand Up @@ -159,6 +159,7 @@ - (void)testSuccessfulSignUp {
[[FIRSignUpNewUserRequest alloc] initWithEmail:kTestEmail
password:kTestPassword
displayName:kTestDisplayName
idToken:kTestIDToken
requestConfiguration:_requestConfiguration];

__block BOOL callbackInvoked;
Expand Down

0 comments on commit 6673e7c

Please sign in to comment.