Skip to content

Commit 20d0b8d

Browse files
Fix credential.is_valid() crash on iOS (#1309)
* Add test for credential.is_valid(). * Handle PhoneAuthCredentialFromImpl and others - Handle null `impl_` for PhoneAuthCredentialFromImpl - Handle API receiving invalid `Credential` - Add a basic test to just verify if the app crashes. * format code * Explicitly ignore return value of is_valid to prevent build warning. * Add release note. * Clean up release note. --------- Co-authored-by: Shawn Kuang <[email protected]>
1 parent 041257c commit 20d0b8d

File tree

5 files changed

+64
-4
lines changed

5 files changed

+64
-4
lines changed

Diff for: auth/integration_test/src/integration_test.cc

+7
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,9 @@ bool FirebaseAuthTest::WaitForCompletion(
273273
EXPECT_TRUE(auth_->current_user().is_valid());
274274
EXPECT_EQ(future.result()->user.uid(), auth_->current_user().uid())
275275
<< "User returned by Future doesn't match User in Auth";
276+
// Expect no crash.
277+
// TODO(b/281590792): Properly validate AuthResult fields case-by-case.
278+
(void)future.result()->credential.is_valid();
276279
succeeded = future.result()->user.is_valid() &&
277280
auth_->current_user().is_valid();
278281
}
@@ -310,6 +313,9 @@ bool FirebaseAuthTest::WaitForCompletion(
310313
EXPECT_EQ(result_ptr->additional_user_info.provider_id, provider_id);
311314
EXPECT_EQ(result_ptr->user.uid(), auth_->current_user().uid());
312315
EXPECT_TRUE(auth_->current_user().is_valid());
316+
// Expect no crash.
317+
// TODO(b/281590792): Properly validate AuthResult fields case-by-case.
318+
(void)result_ptr->credential.is_valid();
313319
}
314320
return succeeded;
315321
}
@@ -368,6 +374,7 @@ TEST_F(FirebaseAuthTest, TestInitialization) {
368374

369375
TEST_F(FirebaseAuthTest, TestAnonymousSignin) {
370376
// Test notification on SignIn().
377+
371378
WaitForCompletion(auth_->SignInAnonymously(), "SignInAnonymously");
372379
EXPECT_TRUE(auth_->current_user().is_valid());
373380
EXPECT_TRUE(auth_->current_user().is_anonymous());

Diff for: auth/src/ios/auth_ios.mm

+16
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,10 @@ void SignInResultCallback(FIRAuthDataResult *_Nullable auth_result, NSError *_Nu
455455
Future<User> Auth::SignInWithCredential(const Credential &credential) {
456456
ReferenceCountedFutureImpl &futures = auth_data_->future_impl;
457457
const auto handle = futures.SafeAlloc<User>(kAuthFn_SignInWithCredential, User());
458+
if (!credential.is_valid()) {
459+
futures.Complete(handle, kAuthErrorInvalidCredential, "Invalid credential is not allowed.");
460+
return MakeFuture(&futures, handle);
461+
}
458462

459463
[AuthImpl(auth_data_)
460464
signInWithCredential:CredentialFromImpl(credential.impl_)
@@ -468,6 +472,10 @@ void SignInResultCallback(FIRAuthDataResult *_Nullable auth_result, NSError *_Nu
468472
Future<User *> Auth::SignInWithCredential_DEPRECATED(const Credential &credential) {
469473
ReferenceCountedFutureImpl &futures = auth_data_->future_impl;
470474
const auto handle = futures.SafeAlloc<User *>(kAuthFn_SignInWithCredential_DEPRECATED, nullptr);
475+
if (!credential.is_valid()) {
476+
futures.Complete(handle, kAuthErrorInvalidCredential, "Invalid credential is not allowed.");
477+
return MakeFuture(&futures, handle);
478+
}
471479

472480
[AuthImpl(auth_data_)
473481
signInWithCredential:CredentialFromImpl(credential.impl_)
@@ -482,6 +490,10 @@ void SignInResultCallback(FIRAuthDataResult *_Nullable auth_result, NSError *_Nu
482490
ReferenceCountedFutureImpl &futures = auth_data_->future_impl;
483491
const auto handle =
484492
futures.SafeAlloc<AuthResult>(kAuthFn_SignInAndRetrieveDataWithCredential, AuthResult());
493+
if (!credential.is_valid()) {
494+
futures.Complete(handle, kAuthErrorInvalidCredential, "Invalid credential is not allowed.");
495+
return MakeFuture(&futures, handle);
496+
}
485497

486498
[AuthImpl(auth_data_)
487499
signInWithCredential:CredentialFromImpl(credential.impl_)
@@ -497,6 +509,10 @@ void SignInResultCallback(FIRAuthDataResult *_Nullable auth_result, NSError *_Nu
497509
ReferenceCountedFutureImpl &futures = auth_data_->future_impl;
498510
const auto handle = futures.SafeAlloc<SignInResult>(
499511
kAuthFn_SignInAndRetrieveDataWithCredential_DEPRECATED, SignInResult());
512+
if (!credential.is_valid()) {
513+
futures.Complete(handle, kAuthErrorInvalidCredential, "Invalid credential is not allowed.");
514+
return MakeFuture(&futures, handle);
515+
}
500516

501517
[AuthImpl(auth_data_)
502518
signInWithCredential:CredentialFromImpl(credential.impl_)

Diff for: auth/src/ios/common_ios.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,14 @@ static inline FIRAuth *_Nonnull AuthImpl(AuthData *_Nonnull auth_data) {
9191

9292
/// Convert from the void* credential implementation pointer into the Obj-C
9393
/// FIRAuthCredential pointer.
94-
static inline FIRAuthCredential *_Nonnull CredentialFromImpl(void *_Nonnull impl) {
95-
return static_cast<FIRAuthCredentialPointer *>(impl)->get();
94+
static inline FIRAuthCredential *_Nullable CredentialFromImpl(void *_Nullable impl) {
95+
return impl ? static_cast<FIRAuthCredentialPointer *>(impl)->get() : nil;
9696
}
9797

9898
/// Convert from the void* credential implementation pointer into the Obj-C
9999
/// FIRPhoneAuthCredential pointer.
100-
static inline FIRPhoneAuthCredential *_Nonnull PhoneAuthCredentialFromImpl(void *_Nonnull impl) {
101-
return static_cast<FIRPhoneAuthCredentialPointer *>(impl)->get();
100+
static inline FIRPhoneAuthCredential *_Nullable PhoneAuthCredentialFromImpl(void *_Nullable impl) {
101+
return impl ? static_cast<FIRPhoneAuthCredentialPointer *>(impl)->get() : nil;
102102
}
103103

104104
AuthError AuthErrorFromNSError(NSError *_Nullable error);

Diff for: auth/src/ios/user_ios.mm

+32
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,10 @@ explicit IOSWrappedUserInfo(id<FIRUserInfo> user_info) : user_info_(user_info) {
194194
}
195195
ReferenceCountedFutureImpl &futures = auth_data_->future_impl;
196196
const auto handle = futures.SafeAlloc<AuthResult>(kUserFn_LinkWithCredential, AuthResult());
197+
if (!credential.is_valid()) {
198+
futures.Complete(handle, kAuthErrorInvalidCredential, "Invalid credential is not allowed.");
199+
return MakeFuture(&futures, handle);
200+
}
197201
AuthData *auth_data = auth_data_;
198202
[UserImpl(auth_data)
199203
linkWithCredential:CredentialFromImpl(credential.impl_)
@@ -209,6 +213,10 @@ explicit IOSWrappedUserInfo(id<FIRUserInfo> user_info) : user_info_(user_info) {
209213
}
210214
ReferenceCountedFutureImpl &futures = auth_data_->future_impl;
211215
const auto handle = futures.SafeAlloc<User *>(kUserFn_LinkWithCredential_DEPRECATED);
216+
if (!credential.is_valid()) {
217+
futures.Complete(handle, kAuthErrorInvalidCredential, "Invalid credential is not allowed.");
218+
return MakeFuture(&futures, handle);
219+
}
212220
[UserImpl(auth_data_)
213221
linkWithCredential:CredentialFromImpl(credential.impl_)
214222
completion:^(FIRAuthDataResult *_Nullable auth_result, NSError *_Nullable error) {
@@ -224,6 +232,10 @@ explicit IOSWrappedUserInfo(id<FIRUserInfo> user_info) : user_info_(user_info) {
224232
ReferenceCountedFutureImpl &futures = auth_data_->future_impl;
225233
const auto handle = auth_data_->future_impl.SafeAlloc<SignInResult>(
226234
kUserFn_LinkAndRetrieveDataWithCredential, SignInResult());
235+
if (!credential.is_valid()) {
236+
futures.Complete(handle, kAuthErrorInvalidCredential, "Invalid credential is not allowed.");
237+
return MakeFuture(&futures, handle);
238+
}
227239
AuthData *auth_data = auth_data_;
228240
[UserImpl(auth_data)
229241
linkWithCredential:CredentialFromImpl(credential.impl_)
@@ -279,6 +291,10 @@ explicit IOSWrappedUserInfo(id<FIRUserInfo> user_info) : user_info_(user_info) {
279291
const auto handle = futures.SafeAlloc<User>(kUserFn_UpdatePhoneNumberCredential);
280292

281293
#if FIREBASE_PLATFORM_IOS
294+
if (!credential.is_valid()) {
295+
futures.Complete(handle, kAuthErrorInvalidCredential, "Invalid credential is not allowed.");
296+
return MakeFuture(&futures, handle);
297+
}
282298
FIRPhoneAuthCredential *objc_credential = PhoneAuthCredentialFromImpl(credential.impl_);
283299
[UserImpl(auth_data_)
284300
updatePhoneNumberCredential:objc_credential
@@ -302,6 +318,10 @@ explicit IOSWrappedUserInfo(id<FIRUserInfo> user_info) : user_info_(user_info) {
302318
const auto handle = futures.SafeAlloc<User *>(kUserFn_UpdatePhoneNumberCredential_DEPRECATED);
303319

304320
#if FIREBASE_PLATFORM_IOS
321+
if (!credential.is_valid()) {
322+
futures.Complete(handle, kAuthErrorInvalidCredential, "Invalid credential is not allowed.");
323+
return MakeFuture(&futures, handle);
324+
}
305325
FIRAuthCredential *objc_credential = CredentialFromImpl(credential.impl_);
306326
if ([objc_credential isKindOfClass:[FIRPhoneAuthCredential class]]) {
307327
[UserImpl(auth_data_)
@@ -341,6 +361,10 @@ explicit IOSWrappedUserInfo(id<FIRUserInfo> user_info) : user_info_(user_info) {
341361
}
342362
ReferenceCountedFutureImpl &futures = auth_data_->future_impl;
343363
const auto handle = futures.SafeAlloc<void>(kUserFn_Reauthenticate);
364+
if (!credential.is_valid()) {
365+
futures.Complete(handle, kAuthErrorInvalidCredential, "Invalid credential is not allowed.");
366+
return MakeFuture(&futures, handle);
367+
}
344368

345369
[UserImpl(auth_data_)
346370
reauthenticateWithCredential:CredentialFromImpl(credential.impl_)
@@ -359,6 +383,10 @@ explicit IOSWrappedUserInfo(id<FIRUserInfo> user_info) : user_info_(user_info) {
359383
ReferenceCountedFutureImpl &futures = auth_data_->future_impl;
360384
const auto handle = auth_data_->future_impl.SafeAlloc<AuthResult>(
361385
kUserFn_ReauthenticateAndRetrieveData, AuthResult());
386+
if (!credential.is_valid()) {
387+
futures.Complete(handle, kAuthErrorInvalidCredential, "Invalid credential is not allowed.");
388+
return MakeFuture(&futures, handle);
389+
}
362390
AuthData *auth_data = auth_data_;
363391
[UserImpl(auth_data)
364392
reauthenticateWithCredential:CredentialFromImpl(credential.impl_)
@@ -376,6 +404,10 @@ explicit IOSWrappedUserInfo(id<FIRUserInfo> user_info) : user_info_(user_info) {
376404
ReferenceCountedFutureImpl &futures = auth_data_->future_impl;
377405
const auto handle = auth_data_->future_impl.SafeAlloc<SignInResult>(
378406
kUserFn_ReauthenticateAndRetrieveData_DEPRECATED, SignInResult());
407+
if (!credential.is_valid()) {
408+
futures.Complete(handle, kAuthErrorInvalidCredential, "Invalid credential is not allowed.");
409+
return MakeFuture(&futures, handle);
410+
}
379411
AuthData *auth_data = auth_data_;
380412
[UserImpl(auth_data)
381413
reauthenticateWithCredential:CredentialFromImpl(credential.impl_)

Diff for: release_build_files/readme.md

+5
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,11 @@ workflow use only during the development of your app, not for publicly shipping
627627
code.
628628

629629
## Release Notes
630+
### 11.0.1
631+
- Changes
632+
- Auth (iOS): Fixed a crash in `Credential::is_valid()` when an `AuthResult`
633+
contains an invalid credential, such as when signing in anonymously.
634+
630635
### 11.0.0
631636
- Changes
632637
- General: Update minimum supported C++ standard to C++14.

0 commit comments

Comments
 (0)