Skip to content

Commit

Permalink
Email enumeration protection related error and doc updates (#12081)
Browse files Browse the repository at this point in the history
  • Loading branch information
renkelvin authored Nov 17, 2023
1 parent 2aa184c commit 7605a18
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 15 deletions.
9 changes: 8 additions & 1 deletion FirebaseAuth/Sources/Backend/FIRAuthBackend.m
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,12 @@
*/
static NSString *const kInvalidRecaptchaVersion = @"INVALID_RECAPTCHA_VERSION";

/** @var kInvalidLoginCredentials
@brief This is the error message the server will respond with if the login credentials is
invalid. in the request.
*/
static NSString *const kInvalidLoginCredentials = @"INVALID_LOGIN_CREDENTIALS";

/** @var gBackendImplementation
@brief The singleton FIRAuthBackendImplementation instance to use.
*/
Expand Down Expand Up @@ -1404,7 +1410,8 @@ + (nullable NSError *)clientErrorWithServerErrorMessage:(NSString *)serverErrorM
}

if ([shortErrorMessage isEqualToString:kInvalidCredentialErrorMessage] ||
[shortErrorMessage isEqualToString:kInvalidPendingToken]) {
[shortErrorMessage isEqualToString:kInvalidPendingToken] ||
[shortErrorMessage isEqualToString:kInvalidLoginCredentials]) {
return [FIRAuthErrorUtils invalidCredentialErrorWithMessage:serverDetailErrorMessage];
}

Expand Down
19 changes: 14 additions & 5 deletions FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,9 @@ NS_SWIFT_NAME(Auth)

/** @fn fetchSignInMethodsForEmail:completion:
@brief Fetches the list of all sign-in methods previously used for the provided email address.
This method returns an empty list when [Email Enumeration
Protection](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection)
is enabled, irrespective of the number of authentication methods available for the given email.
@param email The email address for which to obtain a list of sign-in methods.
@param completion Optionally; a block which is invoked when the list of sign in methods for the
specified email address is ready or an error was encountered. Invoked asynchronously on the
Expand All @@ -393,10 +395,15 @@ NS_SWIFT_NAME(Auth)

- (void)fetchSignInMethodsForEmail:(NSString *)email
completion:(nullable void (^)(NSArray<NSString *> *_Nullable,
NSError *_Nullable))completion;
NSError *_Nullable))completion
DEPRECATED_MSG_ATTRIBUTE(
"This method returns an empty list when Email Enumeration Protection is enabled.");

/** @fn signInWithEmail:password:completion:
@brief Signs in using an email address and password.
@brief Signs in using an email address and password. When [Email Enumeration
Protection](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection)
is enabled, this method fails with FIRAuthErrorCodeInvalidCredentials in case of an invalid
email/password.
@param email The user's email address.
@param password The user's password.
Expand Down Expand Up @@ -663,8 +670,10 @@ NS_SWIFT_NAME(Auth)
- (void)applyActionCode:(NSString *)code completion:(void (^)(NSError *_Nullable error))completion;

/** @fn sendPasswordResetWithEmail:completion:
@brief Initiates a password reset for the given email address.
@brief Initiates a password reset for the given email address. This method does not throw an
error when there's no user account with the given email address and [Email Enumeration
Protection](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection)
is enabled.
@param email The email address of the user.
@param completion Optionally; a block which is invoked when the request finishes. Invoked
asynchronously on the main thread in the future.
Expand Down
7 changes: 5 additions & 2 deletions FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ NS_SWIFT_NAME(User)

/** @fn updateEmail:completion:
@brief Updates the email address for the user. On success, the cached user profile data is
updated.
updated. Throws FIRAuthErrorCodeInvalidCredentials error when [Email Enumeration
Protection](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection)
is enabled.
@remarks May fail if there is already an account with this email address that was created using
email and password authentication.
Expand Down Expand Up @@ -160,7 +162,8 @@ NS_SWIFT_NAME(User)
*/
- (void)updateEmail:(NSString *)email
completion:(nullable void (^)(NSError *_Nullable error))completion
NS_SWIFT_NAME(updateEmail(to:completion:));
NS_SWIFT_NAME(updateEmail(to:completion:))
DEPRECATED_MSG_ATTRIBUTE("Use sendEmailVerificationBeforeUpdatingEmail: instead.");

/** @fn updatePassword:completion:
@brief Updates the password for the user. On success, the cached user profile data is updated.
Expand Down
4 changes: 4 additions & 0 deletions FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,10 @@
@"The reCAPTCHA SDK is not linked to your app. See "
@"https://cloud.google.com/recaptcha-enterprise/docs/instrument-ios-apps";

static NSString *const kFIRAuthErrorMessageInvalidLoginCredentials =
@"Login credentials invalid. It is possible that the email/password combination does not "
@"exist.";

/** @var FIRAuthErrorDescription
@brief The error descrioption, based on the error code.
@remarks No default case so that we get a compiler warning if a new value was added to the enum.
Expand Down
6 changes: 6 additions & 0 deletions FirebaseAuth/Tests/Unit/FIRAuthTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,8 @@ - (void)testFetchSignInMethodsForEmailSuccess {
});
});
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[[FIRAuth auth] fetchSignInMethodsForEmail:kEmail
completion:^(NSArray<NSString *> *_Nullable signInMethods,
NSError *_Nullable error) {
Expand All @@ -442,6 +444,7 @@ - (void)testFetchSignInMethodsForEmailSuccess {
XCTAssertNil(error);
[expectation fulfill];
}];
#pragma clang diagnostic pop
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
Expand All @@ -453,6 +456,8 @@ - (void)testFetchSignInMethodsForEmailFailure {
OCMExpect([_mockBackend createAuthURI:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils tooManyRequestsErrorWithMessage:nil]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[[FIRAuth auth] fetchSignInMethodsForEmail:kEmail
completion:^(NSArray<NSString *> *_Nullable signInMethods,
NSError *_Nullable error) {
Expand All @@ -462,6 +467,7 @@ - (void)testFetchSignInMethodsForEmailFailure {
XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
[expectation fulfill];
}];
#pragma clang diagnostic pop
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
Expand Down
12 changes: 12 additions & 0 deletions FirebaseAuth/Tests/Unit/FIRUserTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,8 @@ - (void)testUpdateEmailSuccess {
callback(mockSetAccountInfoResponse, nil);
});
});
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[user updateEmail:kNewEmail
completion:^(NSError *_Nullable error) {
XCTAssertNil(error);
Expand All @@ -777,6 +779,7 @@ - (void)testUpdateEmailSuccess {
kNewDisplayName);
[expectation fulfill];
}];
#pragma clang diagnostic pop
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
Expand Down Expand Up @@ -829,6 +832,8 @@ - (void)testUpdateEmailWithAuthLinkAccountSuccess {
callback(mockSetAccountInfoResponse, nil);
});
});
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[user updateEmail:kNewEmail
completion:^(NSError *_Nullable error) {
XCTAssertNil(error);
Expand All @@ -838,6 +843,7 @@ - (void)testUpdateEmailWithAuthLinkAccountSuccess {
XCTAssertFalse(user.isAnonymous);
[expectation fulfill];
}];
#pragma clang diagnostic pop
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
Expand All @@ -862,6 +868,8 @@ - (void)testUpdateEmailFailure {
callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils
invalidEmailErrorWithMessage:nil]);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[user
updateEmail:kNewEmail
completion:^(NSError *_Nullable error) {
Expand All @@ -876,6 +884,7 @@ - (void)testUpdateEmailFailure {
user);
[expectation fulfill];
}];
#pragma clang diagnostic pop
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
Expand All @@ -900,6 +909,8 @@ - (void)testUpdateEmailAutoSignOut {
callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils
invalidUserTokenErrorWithMessage:nil]);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[user updateEmail:kNewEmail
completion:^(NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
Expand All @@ -913,6 +924,7 @@ - (void)testUpdateEmailAutoSignOut {
XCTAssertNil([FIRAuth auth].currentUser);
[expectation fulfill];
}];
#pragma clang diagnostic pop
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
Expand Down
7 changes: 0 additions & 7 deletions FirebaseAuth/Tests/Unit/SwiftAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,9 @@ class AuthAPI_hOnlyTests: XCTestCase {

func FIRAuth_h(credential: AuthCredential) throws {
let auth = FirebaseAuth.Auth.auth()
let authApp = FirebaseAuth.Auth.auth(app: FirebaseApp.app()!)
let user = auth.currentUser!
auth.updateCurrentUser(user) { _ in
}
authApp.fetchSignInMethods(forEmail: "[email protected]") { string, error in
}
auth.signIn(withEmail: "[email protected]", password: "password") { result, error in
}
auth.signIn(withEmail: "[email protected]", link: "link") { result, error in
Expand Down Expand Up @@ -173,7 +170,6 @@ class AuthAPI_hOnlyTests: XCTestCase {
let auth = FirebaseAuth.Auth.auth()
let user = auth.currentUser!
try await auth.updateCurrentUser(user)
_ = try await auth.fetchSignInMethods(forEmail: "[email protected]")
_ = try await auth.signIn(withEmail: "[email protected]", password: "password")
_ = try await auth.signIn(withEmail: "[email protected]", link: "link")
_ = try await auth.signIn(with: credential)
Expand Down Expand Up @@ -574,8 +570,6 @@ class AuthAPI_hOnlyTests: XCTestCase {
let auth = FirebaseAuth.Auth.auth()
let user = auth.currentUser!
let credential = GoogleAuthProvider.credential(withIDToken: "token", accessToken: "aToken")
user.updateEmail(to: "email") { _ in
}
user.updatePassword(to: "password") { _ in
}
let changeRequest = user.createProfileChangeRequest()
Expand Down Expand Up @@ -648,7 +642,6 @@ class AuthAPI_hOnlyTests: XCTestCase {
let auth = FirebaseAuth.Auth.auth()
let user = auth.currentUser!
let credential = GoogleAuthProvider.credential(withIDToken: "token", accessToken: "aToken")
try await user.updateEmail(to: "email")
try await user.updatePassword(to: "password")
let changeRequest = user.createProfileChangeRequest()
try await user.reload()
Expand Down

0 comments on commit 7605a18

Please sign in to comment.