Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use sign up endpoint for link with email password #11925

Merged
merged 13 commits into from
Oct 13, 2023
3 changes: 3 additions & 0 deletions FirebaseAuth/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# 10.17.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
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading
Loading