Skip to content

Commit abbb2ae

Browse files
committed
Flush out the implementation for limited use tokens
1 parent 6dc6d56 commit abbb2ae

15 files changed

Lines changed: 243 additions & 0 deletions

app_check/integration_test/src/integration_test.cc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,27 @@ TEST_F(FirebaseAppCheckTest, TestGetTokenLastResult) {
516516
future2.result()->expire_time_millis);
517517
}
518518

519+
TEST_F(FirebaseAppCheckTest, TestGetLimitedUseAppCheckToken) {
520+
InitializeAppCheckWithDebug();
521+
InitializeApp();
522+
::firebase::app_check::AppCheck* app_check =
523+
::firebase::app_check::AppCheck::GetInstance(app_);
524+
ASSERT_NE(app_check, nullptr);
525+
526+
firebase::Future<::firebase::app_check::AppCheckToken> future =
527+
app_check->GetLimitedUseAppCheckToken();
528+
EXPECT_TRUE(WaitForCompletion(future, "GetLimitedUseAppCheckToken"));
529+
::firebase::app_check::AppCheckToken token = *future.result();
530+
EXPECT_NE(token.token, "");
531+
EXPECT_NE(token.expire_time_millis, 0);
532+
533+
firebase::Future<::firebase::app_check::AppCheckToken> future2 =
534+
app_check->GetLimitedUseAppCheckTokenLastResult();
535+
EXPECT_TRUE(WaitForCompletion(future2, "GetLimitedUseAppCheckTokenLastResult"));
536+
EXPECT_EQ(future.result()->expire_time_millis,
537+
future2.result()->expire_time_millis);
538+
}
539+
519540
TEST_F(FirebaseAppCheckTest, TestAddTokenChangedListener) {
520541
InitializeAppCheckWithDebug();
521542
InitializeApp();

app_check/src/android/app_check_android.cc

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ namespace internal {
4747
"(Z)V"), \
4848
X(GetToken, "getAppCheckToken", \
4949
"(Z)Lcom/google/android/gms/tasks/Task;"), \
50+
X(GetLimitedUseToken, "getLimitedUseAppCheckToken", \
51+
"()Lcom/google/android/gms/tasks/Task;"), \
5052
X(AddAppCheckListener, "addAppCheckListener", \
5153
"(Lcom/google/firebase/appcheck/FirebaseAppCheck$AppCheckListener;)V"), \
5254
X(RemoveAppCheckListener, "removeAppCheckListener", \
@@ -486,6 +488,33 @@ Future<AppCheckToken> AppCheckInternal::GetAppCheckTokenLastResult() {
486488
future()->LastResult(kAppCheckFnGetAppCheckToken));
487489
}
488490

491+
Future<AppCheckToken> AppCheckInternal::GetLimitedUseAppCheckToken() {
492+
JNIEnv* env = app_->GetJNIEnv();
493+
auto handle =
494+
future()->SafeAlloc<AppCheckToken>(kAppCheckFnGetLimitedUseAppCheckToken);
495+
jobject j_task = env->CallObjectMethod(
496+
app_check_impl_, app_check::GetMethodId(app_check::kGetLimitedUseToken));
497+
498+
std::string error = util::GetAndClearExceptionMessage(env);
499+
if (error.empty()) {
500+
auto data_handle = new FutureDataHandle(future(), handle);
501+
util::RegisterCallbackOnTask(env, j_task, TokenResultCallback,
502+
reinterpret_cast<void*>(data_handle),
503+
jni_task_id_.c_str());
504+
} else {
505+
AppCheckToken empty_token;
506+
future()->CompleteWithResult(handle, kAppCheckErrorUnknown, error.c_str(),
507+
empty_token);
508+
}
509+
env->DeleteLocalRef(j_task);
510+
return MakeFuture(future(), handle);
511+
}
512+
513+
Future<AppCheckToken> AppCheckInternal::GetLimitedUseAppCheckTokenLastResult() {
514+
return static_cast<const Future<AppCheckToken>&>(
515+
future()->LastResult(kAppCheckFnGetLimitedUseAppCheckToken));
516+
}
517+
489518
void AppCheckInternal::AddAppCheckListener(AppCheckListener* listener) {
490519
MutexLock lock(listeners_mutex_);
491520
auto it = std::find(listeners_.begin(), listeners_.end(), listener);

app_check/src/android/app_check_android.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ class AppCheckInternal {
4545

4646
Future<AppCheckToken> GetAppCheckTokenLastResult();
4747

48+
Future<AppCheckToken> GetLimitedUseAppCheckToken();
49+
50+
Future<AppCheckToken> GetLimitedUseAppCheckTokenLastResult();
51+
4852
void AddAppCheckListener(AppCheckListener* listener);
4953

5054
void RemoveAppCheckListener(AppCheckListener* listener);

app_check/src/android/common_android.cc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,30 @@ void AndroidAppCheckProvider::GetToken(
161161
env->DeleteLocalRef(j_task);
162162
}
163163

164+
void AndroidAppCheckProvider::GetLimitedUseToken(
165+
std::function<void(AppCheckToken, int, const std::string&)>
166+
completion_callback) {
167+
JNIEnv* env = GetJniEnv();
168+
169+
jobject j_task = env->CallObjectMethod(
170+
android_provider_, app_check_provider::GetMethodId(
171+
app_check_provider::kGetLimitedUseToken));
172+
std::string error = util::GetAndClearExceptionMessage(env);
173+
if (error.empty()) {
174+
// Create an object to wrap the callback function
175+
TokenResultCallbackData* completion_callback_data =
176+
new TokenResultCallbackData(completion_callback);
177+
util::RegisterCallbackOnTask(
178+
env, j_task, TokenResultCallback,
179+
reinterpret_cast<void*>(completion_callback_data),
180+
jni_task_id_.c_str());
181+
} else {
182+
AppCheckToken empty_token;
183+
completion_callback(empty_token, kAppCheckErrorUnknown, error.c_str());
184+
}
185+
env->DeleteLocalRef(j_task);
186+
}
187+
164188
} // namespace internal
165189
} // namespace app_check
166190
} // namespace firebase

app_check/src/android/common_android.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ namespace internal {
3333
// clang-format off
3434
#define APP_CHECK_PROVIDER_METHODS(X) \
3535
X(GetToken, "getToken", \
36+
"()Lcom/google/android/gms/tasks/Task;"), \
37+
X(GetLimitedUseToken, "getLimitedUseToken", \
3638
"()Lcom/google/android/gms/tasks/Task;")
3739
// clang-format on
3840

@@ -59,6 +61,13 @@ class AndroidAppCheckProvider : public AppCheckProvider {
5961
void GetToken(std::function<void(AppCheckToken, int, const std::string&)>
6062
completion_callback) override;
6163

64+
/// Fetches an AppCheckToken suitable for consumption in limited-use scenarios
65+
/// and then calls the provided callback function with the token or with an
66+
/// error code and error message.
67+
void GetLimitedUseToken(
68+
std::function<void(AppCheckToken, int, const std::string&)>
69+
completion_callback) override;
70+
6271
private:
6372
jobject android_provider_;
6473

app_check/src/common/app_check.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,16 @@ Future<AppCheckToken> AppCheck::GetAppCheckTokenLastResult() {
161161
: Future<AppCheckToken>();
162162
}
163163

164+
Future<AppCheckToken> AppCheck::GetLimitedUseAppCheckToken() {
165+
return internal_ ? internal_->GetLimitedUseAppCheckToken()
166+
: Future<AppCheckToken>();
167+
}
168+
169+
Future<AppCheckToken> AppCheck::GetLimitedUseAppCheckTokenLastResult() {
170+
return internal_ ? internal_->GetLimitedUseAppCheckTokenLastResult()
171+
: Future<AppCheckToken>();
172+
}
173+
164174
void AppCheck::AddAppCheckListener(AppCheckListener* listener) {
165175
if (!internal_) return;
166176
internal_->AddAppCheckListener(listener);

app_check/src/common/common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ namespace internal {
2323
enum AppCheckFn {
2424
kAppCheckFnGetAppCheckToken = 0,
2525
kAppCheckFnGetAppCheckStringInternal,
26+
kAppCheckFnGetLimitedUseAppCheckToken,
2627
kAppCheckFnCount,
2728
};
2829

app_check/src/desktop/app_check_desktop.cc

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,36 @@ Future<AppCheckToken> AppCheckInternal::GetAppCheckTokenLastResult() {
120120
future()->LastResult(kAppCheckFnGetAppCheckToken));
121121
}
122122

123+
Future<AppCheckToken> AppCheckInternal::GetLimitedUseAppCheckToken() {
124+
auto handle =
125+
future()->SafeAlloc<AppCheckToken>(kAppCheckFnGetLimitedUseAppCheckToken);
126+
// Get a new token, and pass the result into the future.
127+
AppCheckProvider* provider = GetProvider();
128+
if (provider != nullptr) {
129+
auto token_callback{
130+
[this, handle](firebase::app_check::AppCheckToken token, int error_code,
131+
const std::string& error_message) {
132+
if (error_code == firebase::app_check::kAppCheckErrorNone) {
133+
// Note that we do NOT update the cached token for limited-use tokens.
134+
future()->CompleteWithResult(handle, 0, token);
135+
} else {
136+
future()->Complete(handle, error_code, error_message.c_str());
137+
}
138+
}};
139+
provider->GetLimitedUseToken(token_callback);
140+
} else {
141+
future()->Complete(
142+
handle, firebase::app_check::kAppCheckErrorInvalidConfiguration,
143+
"No AppCheckProvider installed.");
144+
}
145+
return MakeFuture(future(), handle);
146+
}
147+
148+
Future<AppCheckToken> AppCheckInternal::GetLimitedUseAppCheckTokenLastResult() {
149+
return static_cast<const Future<AppCheckToken>&>(
150+
future()->LastResult(kAppCheckFnGetLimitedUseAppCheckToken));
151+
}
152+
123153
Future<std::string> AppCheckInternal::GetAppCheckTokenStringInternal() {
124154
auto handle =
125155
future()->SafeAlloc<std::string>(kAppCheckFnGetAppCheckStringInternal);

app_check/src/desktop/app_check_desktop.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ class AppCheckInternal {
6262

6363
Future<AppCheckToken> GetAppCheckTokenLastResult();
6464

65+
Future<AppCheckToken> GetLimitedUseAppCheckToken();
66+
67+
Future<AppCheckToken> GetLimitedUseAppCheckTokenLastResult();
68+
6569
// Gets the App Check token as just the string, to be used by
6670
// internal methods to not conflict with the publicly returned future.
6771
Future<std::string> GetAppCheckTokenStringInternal();

app_check/src/include/firebase/app_check.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,14 @@ class AppCheck {
153153
/// Returns the result of the most recent call to GetAppCheckToken();
154154
Future<AppCheckToken> GetAppCheckTokenLastResult();
155155

156+
/// Requests a limited-use Firebase App Check token. This method should be used
157+
/// ONLY if you need to authorize requests to a non-Firebase backend. Requests
158+
/// to Firebase backends are authorized automatically if configured.
159+
Future<AppCheckToken> GetLimitedUseAppCheckToken();
160+
161+
/// Returns the result of the most recent call to GetLimitedUseAppCheckToken();
162+
Future<AppCheckToken> GetLimitedUseAppCheckTokenLastResult();
163+
156164
/// Registers an {@link AppCheckListener} to changes in the token state. This
157165
/// method should be used ONLY if you need to authorize requests to a
158166
/// non-Firebase backend. Requests to Firebase backends are authorized

0 commit comments

Comments
 (0)