Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Firestore/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Unreleased
- [fixed] Fix crash while fetching Auth and App Check tokens. (#15281)
- [feature] `Pipeline` support is now available for the `Enterprise edition` as a public review feature. (#15625)
- [fixed] Fixed an issue where the returned object in transaction blocks could not
pass across actor boundaries in Swift 6 (#15467).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ namespace firestore {
namespace credentials {

class FirebaseAppCheckCredentialsProvider
: public CredentialsProvider<std::string, std::string> {
: public CredentialsProvider<std::string, std::string>,
public std::enable_shared_from_this<FirebaseAppCheckCredentialsProvider> {
public:
FirebaseAppCheckCredentialsProvider(FIRApp* app,
id<FIRAppCheckInterop> app_check);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,11 @@

void FirebaseAppCheckCredentialsProvider::GetToken(
TokenListener<std::string> completion) {
std::weak_ptr<Contents> weak_contents = contents_;
if (contents_->app_check) {
// Capture self via a shared_ptr to ensure that the credentials provider
// is not deallocated while the getToken request is outstanding.
std::shared_ptr<FirebaseAppCheckCredentialsProvider> self =
shared_from_this();
if (self->contents_->app_check) {
void (^get_token_callback)(id<FIRAppCheckTokenResultInterop>) =
^(id<FIRAppCheckTokenResultInterop> result) {
if (result.error != nil) {
Expand All @@ -90,13 +93,13 @@

// Retrieve a cached or generate a new FAC Token. If forcingRefresh == YES
// always generates a new token and updates the cache.
[contents_->app_check getTokenForcingRefresh:force_refresh_
completion:get_token_callback];
[self->contents_->app_check getTokenForcingRefresh:self->force_refresh_
completion:get_token_callback];
} else {
// If there's no AppCheck provider, call back immediately with a nil token.
completion(std::string{""});
}
force_refresh_ = false;
self->force_refresh_ = false;
}

void FirebaseAppCheckCredentialsProvider::SetCredentialChangeListener(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ namespace credentials {
* For non-Apple desktop build, this is right now just a stub.
*/
class FirebaseAuthCredentialsProvider
: public CredentialsProvider<AuthToken, User> {
: public CredentialsProvider<AuthToken, User>,
public std::enable_shared_from_this<FirebaseAuthCredentialsProvider> {
public:
// TODO(zxu123): Provide a ctor to accept the C++ Firebase Games App, which
// deals all platforms. Right now, only works for FIRApp*.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,26 +81,23 @@
// fail if there is a token change while the request is outstanding.
int initial_token_counter = contents_->token_counter;

std::weak_ptr<Contents> weak_contents = contents_;
// Capture self via a shared_ptr to ensure that the credentials provider
// is not deallocated while the getToken request is outstanding.
std::shared_ptr<FirebaseAuthCredentialsProvider> self = shared_from_this();
void (^get_token_callback)(NSString*, NSError*) =
^(NSString* _Nullable token, NSError* _Nullable error) {
std::shared_ptr<Contents> contents = weak_contents.lock();
if (!contents) {
return;
}

std::unique_lock<std::mutex> lock(contents->mutex);
if (initial_token_counter != contents->token_counter) {
std::unique_lock<std::mutex> lock(self->contents_->mutex);
if (initial_token_counter != self->contents_->token_counter) {
// Cancel the request since the user changed while the request was
// outstanding so the response is likely for a previous user (which
// user, we can't be sure).
LOG_DEBUG("GetToken aborted due to token change.");
return GetToken(completion);
return self->GetToken(completion);
} else {
if (error == nil) {
if (token != nil) {
completion(
AuthToken{util::MakeString(token), contents->current_user});
completion(AuthToken{util::MakeString(token),
self->contents_->current_user});
} else {
completion(AuthToken::Unauthenticated());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,9 @@ - (nonnull NSString*)tokenDidChangeNotificationName {
auto token_promise = std::make_shared<std::promise<std::string>>();

FIRApp* app = testutil::AppForUnitTesting();
FirebaseAppCheckCredentialsProvider credentials_provider(app, nil);
credentials_provider.GetToken(
auto credentials_provider =
std::make_shared<FirebaseAppCheckCredentialsProvider>(app, nil);
credentials_provider->GetToken(
[token_promise](util::StatusOr<std::string> result) {
EXPECT_TRUE(result.ok());
const std::string& token = result.ValueOrDie();
Expand All @@ -115,8 +116,9 @@ - (nonnull NSString*)tokenDidChangeNotificationName {
FIRApp* app = testutil::AppForUnitTesting();
FSTAppCheckFake* app_check =
[[FSTAppCheckFake alloc] initWithToken:@"fake token"];
FirebaseAppCheckCredentialsProvider credentials_provider(app, app_check);
credentials_provider.GetToken([](util::StatusOr<std::string> result) {
auto credentials_provider =
std::make_shared<FirebaseAppCheckCredentialsProvider>(app, app_check);
credentials_provider->GetToken([](util::StatusOr<std::string> result) {
EXPECT_TRUE(result.ok());
const std::string& token = result.ValueOrDie();
EXPECT_EQ("fake token", token);
Expand All @@ -127,20 +129,22 @@ - (nonnull NSString*)tokenDidChangeNotificationName {
FIRApp* app = testutil::AppForUnitTesting();
FSTAppCheckFake* app_check =
[[FSTAppCheckFake alloc] initWithToken:@"fake token"];
FirebaseAppCheckCredentialsProvider credentials_provider(app, app_check);
credentials_provider.SetCredentialChangeListener(
auto credentials_provider =
std::make_shared<FirebaseAppCheckCredentialsProvider>(app, app_check);
credentials_provider->SetCredentialChangeListener(
[](std::string token) { EXPECT_EQ("", token); });

credentials_provider.SetCredentialChangeListener(nullptr);
credentials_provider->SetCredentialChangeListener(nullptr);
}

TEST(FirebaseAppCheckCredentialsProviderTest, InvalidateToken) {
FIRApp* app = testutil::AppForUnitTesting();
FSTAppCheckFake* app_check =
[[FSTAppCheckFake alloc] initWithToken:@"fake token"];
FirebaseAppCheckCredentialsProvider credentials_provider(app, app_check);
credentials_provider.InvalidateToken();
credentials_provider.GetToken(
auto credentials_provider =
std::make_shared<FirebaseAppCheckCredentialsProvider>(app, app_check);
credentials_provider->InvalidateToken();
credentials_provider->GetToken(
[&app_check](util::StatusOr<std::string> result) {
EXPECT_TRUE(result.ok());
EXPECT_TRUE(app_check.forceRefreshTriggered);
Expand All @@ -154,9 +158,10 @@ - (nonnull NSString*)tokenDidChangeNotificationName {

FIRApp* app = testutil::AppForUnitTesting();
FSTAppCheckFake* app_check = [[FSTAppCheckFake alloc] initWithToken:@""];
FirebaseAppCheckCredentialsProvider credentials_provider(app, app_check);
auto credentials_provider =
std::make_shared<FirebaseAppCheckCredentialsProvider>(app, app_check);

credentials_provider.SetCredentialChangeListener(
credentials_provider->SetCredentialChangeListener(
[token_promise](const std::string& result) {
if (result != "") {
token_promise->set_value(result);
Expand Down Expand Up @@ -186,9 +191,10 @@ - (nonnull NSString*)tokenDidChangeNotificationName {

FIRApp* app = testutil::AppForUnitTesting();
FSTAppCheckFake* app_check = [[FSTAppCheckFake alloc] initWithToken:@""];
FirebaseAppCheckCredentialsProvider credentials_provider(app, app_check);
auto credentials_provider =
std::make_shared<FirebaseAppCheckCredentialsProvider>(app, app_check);

credentials_provider.SetCredentialChangeListener(
credentials_provider->SetCredentialChangeListener(
[token_promise](const std::string& result) {
if (result != "") {
token_promise->set_value(result);
Expand Down Expand Up @@ -227,9 +233,10 @@ - (nonnull NSString*)tokenDidChangeNotificationName {

FIRApp* app = testutil::AppForUnitTesting();
FSTAppCheckFake* app_check = [[FSTAppCheckFake alloc] initWithToken:@""];
FirebaseAppCheckCredentialsProvider credentials_provider(app, app_check);
auto credentials_provider =
std::make_shared<FirebaseAppCheckCredentialsProvider>(app, app_check);

credentials_provider.SetCredentialChangeListener(
credentials_provider->SetCredentialChangeListener(
[token_promise](const std::string& result) {
if (result != "") {
token_promise->set_value(result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ - (void)getTokenForcingRefresh:(BOOL)forceRefresh
auto token_promise = std::make_shared<std::promise<AuthToken>>();

FIRApp* app = testutil::AppForUnitTesting();
FirebaseAuthCredentialsProvider credentials_provider(app, nil);
credentials_provider.GetToken(
auto credentials_provider =
std::make_shared<FirebaseAuthCredentialsProvider>(app, nil);
credentials_provider->GetToken(
[token_promise](util::StatusOr<AuthToken> result) {
EXPECT_TRUE(result.ok());
const AuthToken& token = result.ValueOrDie();
Expand All @@ -99,8 +100,9 @@ - (void)getTokenForcingRefresh:(BOOL)forceRefresh
TEST(FirebaseAuthCredentialsProviderTest, GetTokenUnauthenticated) {
FIRApp* app = testutil::AppForUnitTesting();
FSTAuthFake* auth = [[FSTAuthFake alloc] initWithToken:nil uid:nil];
FirebaseAuthCredentialsProvider credentials_provider(app, auth);
credentials_provider.GetToken([](util::StatusOr<AuthToken> result) {
auto credentials_provider =
std::make_shared<FirebaseAuthCredentialsProvider>(app, auth);
credentials_provider->GetToken([](util::StatusOr<AuthToken> result) {
EXPECT_TRUE(result.ok());
const AuthToken& token = result.ValueOrDie();
EXPECT_ANY_THROW(token.token());
Expand All @@ -114,8 +116,9 @@ - (void)getTokenForcingRefresh:(BOOL)forceRefresh
FIRApp* app = testutil::AppForUnitTesting();
FSTAuthFake* auth = [[FSTAuthFake alloc] initWithToken:@"token for fake uid"
uid:@"fake uid"];
FirebaseAuthCredentialsProvider credentials_provider(app, auth);
credentials_provider.GetToken([](util::StatusOr<AuthToken> result) {
auto credentials_provider =
std::make_shared<FirebaseAuthCredentialsProvider>(app, auth);
credentials_provider->GetToken([](util::StatusOr<AuthToken> result) {
EXPECT_TRUE(result.ok());
const AuthToken& token = result.ValueOrDie();
EXPECT_EQ("token for fake uid", token.token());
Expand All @@ -129,22 +132,24 @@ - (void)getTokenForcingRefresh:(BOOL)forceRefresh
FIRApp* app = testutil::AppForUnitTesting();
FSTAuthFake* auth = [[FSTAuthFake alloc] initWithToken:@"default token"
uid:@"fake uid"];
FirebaseAuthCredentialsProvider credentials_provider(app, auth);
credentials_provider.SetCredentialChangeListener([](User user) {
auto credentials_provider =
std::make_shared<FirebaseAuthCredentialsProvider>(app, auth);
credentials_provider->SetCredentialChangeListener([](User user) {
EXPECT_EQ("fake uid", user.uid());
EXPECT_TRUE(user.is_authenticated());
});

credentials_provider.SetCredentialChangeListener(nullptr);
credentials_provider->SetCredentialChangeListener(nullptr);
}

TEST(FirebaseAuthCredentialsProviderTest, InvalidateToken) {
FIRApp* app = testutil::AppForUnitTesting();
FSTAuthFake* auth = [[FSTAuthFake alloc] initWithToken:@"token for fake uid"
uid:@"fake uid"];
FirebaseAuthCredentialsProvider credentials_provider(app, auth);
credentials_provider.InvalidateToken();
credentials_provider.GetToken([&auth](util::StatusOr<AuthToken> result) {
auto credentials_provider =
std::make_shared<FirebaseAuthCredentialsProvider>(app, auth);
credentials_provider->InvalidateToken();
credentials_provider->GetToken([&auth](util::StatusOr<AuthToken> result) {
EXPECT_TRUE(result.ok());
EXPECT_TRUE(auth.forceRefreshTriggered);
const AuthToken& token = result.ValueOrDie();
Expand All @@ -160,14 +165,15 @@ - (void)getTokenForcingRefresh:(BOOL)forceRefresh
FIRApp* app = testutil::AppForUnitTesting();
FSTAuthFake* auth = [[FSTAuthFake alloc] initWithToken:@"token for fake uid"
uid:@"fake uid"];
FirebaseAuthCredentialsProvider credentials_provider(app, auth);
auto credentials_provider =
std::make_shared<FirebaseAuthCredentialsProvider>(app, auth);

std::thread thread1([&credentials_provider] {
credentials_provider.GetToken(
std::thread thread1([credentials_provider] {
credentials_provider->GetToken(
[](util::StatusOr<AuthToken> result) { EXPECT_TRUE(result.ok()); });
});
std::thread thread2([&credentials_provider] {
credentials_provider.GetToken(
std::thread thread2([credentials_provider] {
credentials_provider->GetToken(
[](util::StatusOr<AuthToken> result) { EXPECT_TRUE(result.ok()); });
});

Expand Down
Loading