From f6f3c3a8b5797fabef9cdc299443e57f94b74a58 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 20:05:19 +0000 Subject: [PATCH 1/2] Implement Firebase Auth UseUserAccessGroup for C++ SDK This commit adds the UseUserAccessGroup method to the Firebase C++ Auth SDK. This method is only functional on iOS and acts as a no-op stub on other platforms (Android, desktop). It wraps the [FIRAuth useUserAccessGroup:error:] Objective-C method on iOS, allowing C++ developers to specify a keychain access group for sharing authentication data between apps. Key changes: - Added UseUserAccessGroup to the public Auth class in auth.h. - Implemented the iOS-specific logic in auth_ios.mm. - Provided stub implementations in auth_stub.cc (for desktop) and auth_android.cc (for Android). --- auth/src/android/auth_android.cc | 9 ++++++++ auth/src/auth.cc | 13 ++++++++++++ auth/src/include/firebase/auth.h | 17 ++++++++++++++++ auth/src/ios/auth_ios.mm | 12 +++++++++++ auth/src/stub/auth_stub.cc | 35 ++++++++++++++++++++++++++++++++ 5 files changed, 86 insertions(+) create mode 100644 auth/src/stub/auth_stub.cc diff --git a/auth/src/android/auth_android.cc b/auth/src/android/auth_android.cc index e0a9a669cb..0757e92acb 100644 --- a/auth/src/android/auth_android.cc +++ b/auth/src/android/auth_android.cc @@ -676,5 +676,14 @@ void DisableTokenAutoRefresh(AuthData* auth_data) {} void InitializeTokenRefresher(AuthData* auth_data) {} void DestroyTokenRefresher(AuthData* auth_data) {} +// Stub implementation for UseUserAccessGroupInternal on Android. +AuthError UseUserAccessGroupInternal(AuthData* auth_data, + const char* group_id) { + // This function is a no-op on Android. + (void)auth_data; + (void)group_id; + return kAuthErrorNone; +} + } // namespace auth } // namespace firebase diff --git a/auth/src/auth.cc b/auth/src/auth.cc index b1417f63f1..755bb8e21c 100644 --- a/auth/src/auth.cc +++ b/auth/src/auth.cc @@ -373,5 +373,18 @@ AUTH_RESULT_FN(Auth, SignInWithEmailAndPassword, AuthResult) AUTH_RESULT_FN(Auth, CreateUserWithEmailAndPassword, AuthResult) +// Platform-specific implementation of UseUserAccessGroup. +// This is defined in auth_ios.mm for iOS, and auth_stub.cc for other +// platforms. +AuthError UseUserAccessGroupInternal(AuthData* auth_data, + const char* group_id); + +AuthError Auth::UseUserAccessGroup(const char* group_id) { + if (!auth_data_) { + return kAuthErrorUninitialized; + } + return UseUserAccessGroupInternal(auth_data_, group_id); +} + } // namespace auth } // namespace firebase diff --git a/auth/src/include/firebase/auth.h b/auth/src/include/firebase/auth.h index f6809c4a57..e72a64ceb8 100644 --- a/auth/src/include/firebase/auth.h +++ b/auth/src/include/firebase/auth.h @@ -517,6 +517,23 @@ class Auth { /// not available on the current device. static Auth* GetAuth(App* app, InitResult* init_result_out = nullptr); + /// @brief Sets the user access group to use for data sharing for the app. + /// + /// This method is only applicable to iOS. On other platforms, it's a no-op + /// and will return `kAuthErrorNone`. + /// + /// Sets the user access group to use for data sharing for the app. This + /// should be used to share authentication data between apps that have the + /// same access group. + /// + /// @param[in] group_id The user access group to use. For example, + /// `com.example.accessgroup`. Set to `nullptr` or an empty string to clear + /// a previously set value and use the default keychain group. + /// + /// @return Returns `kAuthErrorNone` on success, or an `AuthError` code if an + /// error occurred. + AuthError UseUserAccessGroup(const char* group_id); + private: /// @cond FIREBASE_APP_INTERNAL friend class ::firebase::App; diff --git a/auth/src/ios/auth_ios.mm b/auth/src/ios/auth_ios.mm index a0292ba3b8..2ffbb9cb83 100644 --- a/auth/src/ios/auth_ios.mm +++ b/auth/src/ios/auth_ios.mm @@ -608,5 +608,17 @@ void DisableTokenAutoRefresh(AuthData *auth_data) {} void InitializeTokenRefresher(AuthData *auth_data) {} void DestroyTokenRefresher(AuthData *auth_data) {} +AuthError UseUserAccessGroupInternal(AuthData* auth_data, + const char* group_id) { + NSString* group_id_nsstring = nil; + if (group_id != nullptr && strlen(group_id) > 0) { + group_id_nsstring = [NSString stringWithUTF8String:group_id]; + } + + NSError* ns_error = nil; + [AuthImpl(auth_data) useUserAccessGroup:group_id_nsstring error:&ns_error]; + return AuthErrorFromNSError(ns_error); +} + } // namespace auth } // namespace firebase diff --git a/auth/src/stub/auth_stub.cc b/auth/src/stub/auth_stub.cc new file mode 100644 index 0000000000..7a041fc250 --- /dev/null +++ b/auth/src/stub/auth_stub.cc @@ -0,0 +1,35 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "auth/src/include/firebase/auth_error.h" +#include "auth/src/common.h" // For AuthData + +namespace firebase { +namespace auth { + +// Stub implementation for UseUserAccessGroupInternal on non-iOS platforms. +AuthError UseUserAccessGroupInternal(AuthData* auth_data, + const char* group_id) { + // This function is a no-op on non-iOS platforms. + (void)auth_data; + (void)group_id; + return kAuthErrorNone; +} + +// Other stub functions that are not implemented on desktop/non-mobile +// should also go here. For example, if there were other iOS or Android +// specific internal functions called from auth.cc + +} // namespace auth +} // namespace firebase From 582010b858b17f8538da19bc4703f9ed94d682e6 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 20:11:00 +0000 Subject: [PATCH 2/2] Address review comments for UseUserAccessGroup - Moved stub implementations from auth_stub.cc to auth_desktop.cc and auth_android.cc. - Removed auth_stub.cc. - Removed unnecessary forward declaration for UseUserAccessGroupInternal from auth.cc. - Added a basic integration test for UseUserAccessGroup to ensure it doesn't crash on any platform. --- auth/integration_test/src/integration_test.cc | 43 +++++++++++++++++++ auth/src/auth.cc | 6 --- auth/src/desktop/auth_desktop.cc | 9 ++++ auth/src/stub/auth_stub.cc | 35 --------------- 4 files changed, 52 insertions(+), 41 deletions(-) delete mode 100644 auth/src/stub/auth_stub.cc diff --git a/auth/integration_test/src/integration_test.cc b/auth/integration_test/src/integration_test.cc index eef1301adc..96a83a3c0b 100644 --- a/auth/integration_test/src/integration_test.cc +++ b/auth/integration_test/src/integration_test.cc @@ -1513,4 +1513,47 @@ TEST_F(FirebaseAuthTest, TestLinkFederatedProviderBadProviderIdFails) { #endif // defined(ENABLE_OAUTH_TESTS) +TEST_F(FirebaseAuthTest, TestUseUserAccessGroup) { + // This test simply calls the UseUserAccessGroup method to ensure it doesn't + // crash. It doesn't verify the underlying keychain behavior. + // On non-iOS platforms, this is a no-op and should return kAuthErrorNone. + // On iOS, it will call the underlying OS method. + + LogDebug("Calling UseUserAccessGroup with a test group ID."); + firebase::auth::AuthError error = + auth_->UseUserAccessGroup("com.firebase.test.accessgroup"); + +#if TARGET_OS_IPHONE + // On iOS, the actual error code depends on keychain access and provisioning. + // For this test, we just ensure it doesn't crash. + // A specific error like kAuthErrorMissingIOSBundleID might occur if the + // environment isn't set up for keychain sharing, or kAuthErrorNone on + // success. For a simple "does not crash" test, we don't strictly check + // the error code, but kAuthErrorNone is the ideal outcome if keychain is + // usable. + LogDebug("UseUserAccessGroup returned %d on iOS.", error); +#else + // On other platforms, it should be a no-op. + EXPECT_EQ(error, firebase::auth::kAuthErrorNone); +#endif + + LogDebug("Calling UseUserAccessGroup with nullptr to clear the group."); + error = auth_->UseUserAccessGroup(nullptr); + +#if TARGET_OS_IPHONE + LogDebug("UseUserAccessGroup(nullptr) returned %d on iOS.", error); +#else + EXPECT_EQ(error, firebase::auth::kAuthErrorNone); +#endif + + LogDebug("Calling UseUserAccessGroup with empty string to clear the group."); + error = auth_->UseUserAccessGroup(""); + +#if TARGET_OS_IPHONE + LogDebug("UseUserAccessGroup(\"\") returned %d on iOS.", error); +#else + EXPECT_EQ(error, firebase::auth::kAuthErrorNone); +#endif +} + } // namespace firebase_testapp_automated diff --git a/auth/src/auth.cc b/auth/src/auth.cc index 755bb8e21c..9981aaacde 100644 --- a/auth/src/auth.cc +++ b/auth/src/auth.cc @@ -373,12 +373,6 @@ AUTH_RESULT_FN(Auth, SignInWithEmailAndPassword, AuthResult) AUTH_RESULT_FN(Auth, CreateUserWithEmailAndPassword, AuthResult) -// Platform-specific implementation of UseUserAccessGroup. -// This is defined in auth_ios.mm for iOS, and auth_stub.cc for other -// platforms. -AuthError UseUserAccessGroupInternal(AuthData* auth_data, - const char* group_id); - AuthError Auth::UseUserAccessGroup(const char* group_id) { if (!auth_data_) { return kAuthErrorUninitialized; diff --git a/auth/src/desktop/auth_desktop.cc b/auth/src/desktop/auth_desktop.cc index dc9aca2950..6ed47c60f1 100644 --- a/auth/src/desktop/auth_desktop.cc +++ b/auth/src/desktop/auth_desktop.cc @@ -768,5 +768,14 @@ void IdTokenRefreshThread::DisableAuthRefresh() { ref_count_--; } +// Stub implementation for UseUserAccessGroupInternal on desktop. +AuthError UseUserAccessGroupInternal(AuthData* auth_data, + const char* group_id) { + // This function is a no-op on desktop platforms. + (void)auth_data; + (void)group_id; + return kAuthErrorNone; +} + } // namespace auth } // namespace firebase diff --git a/auth/src/stub/auth_stub.cc b/auth/src/stub/auth_stub.cc deleted file mode 100644 index 7a041fc250..0000000000 --- a/auth/src/stub/auth_stub.cc +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "auth/src/include/firebase/auth_error.h" -#include "auth/src/common.h" // For AuthData - -namespace firebase { -namespace auth { - -// Stub implementation for UseUserAccessGroupInternal on non-iOS platforms. -AuthError UseUserAccessGroupInternal(AuthData* auth_data, - const char* group_id) { - // This function is a no-op on non-iOS platforms. - (void)auth_data; - (void)group_id; - return kAuthErrorNone; -} - -// Other stub functions that are not implemented on desktop/non-mobile -// should also go here. For example, if there were other iOS or Android -// specific internal functions called from auth.cc - -} // namespace auth -} // namespace firebase