Skip to content

Commit 3830722

Browse files
committed
Feat: Add limited use token suport
1 parent f90e8b7 commit 3830722

File tree

8 files changed

+116
-1
lines changed

8 files changed

+116
-1
lines changed

app_check/src/android/app_check_android.cc

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,17 @@ JNIEXPORT void JNICALL JniAppCheckProvider_nativeGetToken(
109109
JNIEnv* env, jobject j_provider, jlong c_provider,
110110
jobject task_completion_source);
111111

112+
JNIEXPORT void JNICALL JniAppCheckProvider_nativeGetLimitedUseToken(
113+
JNIEnv* env, jobject j_provider, jlong c_provider,
114+
jobject task_completion_source);
115+
112116
static const JNINativeMethod kNativeJniAppCheckProviderMethods[] = {
113117
{"nativeGetToken",
114118
"(JLcom/google/android/gms/tasks/TaskCompletionSource;)V",
115119
reinterpret_cast<void*>(JniAppCheckProvider_nativeGetToken)},
116-
};
120+
{"nativeGetLimitedUseToken",
121+
"(JLcom/google/android/gms/tasks/TaskCompletionSource;)V",
122+
reinterpret_cast<void*>(JniAppCheckProvider_nativeGetLimitedUseToken)}};
117123

118124
// clang-format off
119125
#define JNI_APP_CHECK_LISTENER_METHODS(X) \
@@ -266,6 +272,39 @@ JNIEXPORT void JNICALL JniAppCheckProvider_nativeGetToken(
266272
provider->GetToken(token_callback);
267273
}
268274

275+
JNIEXPORT void JNICALL JniAppCheckProvider_nativeGetLimitedUseToken(
276+
JNIEnv* env, jobject j_provider, jlong c_provider,
277+
jobject task_completion_source) {
278+
// Create GlobalReferences to the provider and task. These references will be
279+
// deleted in the completion callback.
280+
jobject j_provider_global = env->NewGlobalRef(j_provider);
281+
jobject task_completion_source_global =
282+
env->NewGlobalRef(task_completion_source);
283+
284+
// Defines a C++ callback method to call
285+
// JniAppCheckProvider.HandleGetTokenResult with the resulting token
286+
auto token_callback{[j_provider_global, task_completion_source_global](
287+
firebase::app_check::AppCheckToken token,
288+
int error_code, const std::string& error_message) {
289+
// util::GetJNIEnvFromApp returns a threadsafe instance of JNIEnv.
290+
JNIEnv* env = firebase::util::GetJNIEnvFromApp();
291+
jstring error_string = env->NewStringUTF(error_message.c_str());
292+
jstring token_string = env->NewStringUTF(token.token.c_str());
293+
env->CallVoidMethod(
294+
j_provider_global,
295+
jni_provider::GetMethodId(jni_provider::kHandleGetTokenResult),
296+
task_completion_source_global, token_string, token.expire_time_millis,
297+
error_code, error_string);
298+
FIREBASE_ASSERT(!util::CheckAndClearJniExceptions(env));
299+
env->DeleteLocalRef(token_string);
300+
env->DeleteLocalRef(error_string);
301+
env->DeleteGlobalRef(j_provider_global);
302+
env->DeleteGlobalRef(task_completion_source_global);
303+
}};
304+
AppCheckProvider* provider = reinterpret_cast<AppCheckProvider*>(c_provider);
305+
provider->GetLimitedUseToken(token_callback);
306+
}
307+
269308
JNIEXPORT void JNICALL JniAppCheckListener_nativeOnAppCheckTokenChanged(
270309
JNIEnv* env, jobject clazz, jlong c_app_check, jobject token) {
271310
auto app_check_internal = reinterpret_cast<AppCheckInternal*>(c_app_check);

app_check/src/common/app_check.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ static std::map<::firebase::App*, AppCheck*>* g_app_check_map = nullptr;
6767
// Define the destructors for the virtual listener/provider/factory classes.
6868
AppCheckListener::~AppCheckListener() {}
6969
AppCheckProvider::~AppCheckProvider() {}
70+
void AppCheckProvider::GetLimitedUseToken(
71+
std::function<void(AppCheckToken, int, const std::string&)>
72+
completion_callback) {
73+
LogWarning(
74+
"A limited-use token was requested, but the custom provider did not "
75+
"implement the GetLimitedUseToken method. The default implementation is "
76+
"triggered as a result, and GetToken has been invoked instead.");
77+
GetToken(completion_callback);
78+
}
7079
AppCheckProviderFactory::~AppCheckProviderFactory() {}
7180

7281
namespace internal {

app_check/src/desktop/debug_provider_desktop.cc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,16 @@ class DebugAppCheckProvider : public AppCheckProvider {
4141
void GetToken(std::function<void(AppCheckToken, int, const std::string&)>
4242
completion_callback) override;
4343

44+
void GetLimitedUseToken(
45+
std::function<void(AppCheckToken, int, const std::string&)>
46+
completion_callback) override;
47+
4448
private:
49+
void GetTokenInternal(
50+
bool limited_use,
51+
std::function<void(AppCheckToken, int, const std::string&)>
52+
completion_callback);
53+
4554
App* app_;
4655

4756
scheduler::Scheduler scheduler_;
@@ -92,6 +101,19 @@ void GetTokenAsync(std::shared_ptr<DebugTokenRequest> request,
92101
void DebugAppCheckProvider::GetToken(
93102
std::function<void(AppCheckToken, int, const std::string&)>
94103
completion_callback) {
104+
GetTokenInternal(false, completion_callback);
105+
}
106+
107+
void DebugAppCheckProvider::GetLimitedUseToken(
108+
std::function<void(AppCheckToken, int, const std::string&)>
109+
completion_callback) {
110+
GetTokenInternal(true, completion_callback);
111+
}
112+
113+
void DebugAppCheckProvider::GetTokenInternal(
114+
bool limited_use,
115+
std::function<void(AppCheckToken, int, const std::string&)>
116+
completion_callback) {
95117
// Identify the user's debug token
96118
const char* debug_token_cstr;
97119
if (!debug_token_.empty()) {
@@ -109,6 +131,7 @@ void DebugAppCheckProvider::GetToken(
109131
// Exchange debug token with the backend to get a proper attestation token.
110132
auto request = std::make_shared<DebugTokenRequest>(app_);
111133
request->SetDebugToken(debug_token_cstr);
134+
request->SetLimitedUse(limited_use);
112135

113136
// Use an async call, since we don't want to block on the server response.
114137
auto async_call =

app_check/src/desktop/debug_token_request.fbs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace firebase.app_check.fbs;
1616

1717
table DebugTokenRequest {
1818
debug_token:string;
19+
limited_use:bool;
1920
}
2021

2122
root_type DebugTokenRequest;

app_check/src/desktop/debug_token_request.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ class DebugTokenRequest
5555
application_data_->debug_token = std::move(debug_token);
5656
UpdatePostFields();
5757
}
58+
59+
void SetLimitedUse(bool limited_use) {
60+
application_data_->limited_use = limited_use;
61+
UpdatePostFields();
62+
}
5863
};
5964

6065
} // namespace internal

app_check/src/include/firebase/app_check.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,16 @@ class AppCheckProvider {
7878
virtual void GetToken(
7979
std::function<void(AppCheckToken, int, const std::string&)>
8080
completion_callback) = 0;
81+
82+
/// Fetches an AppCheckToken suitable for consumption in limited-use scenarios
83+
/// and then calls the provided callback function with the token or with an
84+
/// error code and error message.
85+
///
86+
/// If you do not implement this method, the default implementation invokes
87+
/// the GetToken method whenever a limited-use token is requested.
88+
virtual void GetLimitedUseToken(
89+
std::function<void(AppCheckToken, int, const std::string&)>
90+
completion_callback);
8191
};
8292

8393
/// Interface for a factory that generates {@link AppCheckProvider}s.

app_check/src/ios/app_check_ios.mm

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,19 @@ - (void)getTokenWithCompletion:(nonnull void (^)(FIRAppCheckToken* _Nullable,
5959
_cppProvider->GetToken(token_callback);
6060
}
6161

62+
- (void)getLimitedUseTokenWithCompletion:(nonnull void (^)(FIRAppCheckToken* _Nullable,
63+
NSError* _Nullable))handler {
64+
auto token_callback{[handler](firebase::app_check::AppCheckToken token, int error_code,
65+
const std::string& error_message) {
66+
NSError* ios_error = firebase::app_check::internal::AppCheckErrorToNSError(
67+
static_cast<firebase::app_check::AppCheckError>(error_code), error_message);
68+
FIRAppCheckToken* ios_token =
69+
firebase::app_check::internal::AppCheckTokenToFIRAppCheckToken(token);
70+
handler(ios_token, ios_error);
71+
}};
72+
_cppProvider->GetLimitedUseToken(token_callback);
73+
}
74+
6275
@end
6376

6477
// Defines an iOS AppCheckProviderFactory that wraps a given C++ Factory.

app_check/src_java/com/google/firebase/appcheck/internal/cpp/JniAppCheckProvider.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ public Task<AppCheckToken> getToken() {
4141
return taskCompletionSource.getTask();
4242
}
4343

44+
public Task<AppCheckToken> getLimitedUseToken() {
45+
TaskCompletionSource<AppCheckToken> taskCompletionSource =
46+
new TaskCompletionSource<AppCheckToken>();
47+
// Call the C++ provider to get an AppCheckToken and set the task result.
48+
// The C++ code will call handleGetTokenResult with the resulting token.
49+
nativeGetLimitedUseToken(cProvider, taskCompletionSource);
50+
return taskCompletionSource.getTask();
51+
}
52+
4453
/**
4554
* Called by C++ with a token in order to complete the java task.
4655
*/
@@ -58,4 +67,10 @@ public void handleGetTokenResult(TaskCompletionSource<AppCheckToken> taskComplet
5867
*/
5968
private native void nativeGetToken(
6069
long cProvider, TaskCompletionSource<AppCheckToken> task_completion_source);
70+
71+
/**
72+
* This function is implemented in the AppCheck C++ library (app_check_android.cc).
73+
*/
74+
private native void nativeGetLimitedUseToken(
75+
long cProvider, TaskCompletionSource<AppCheckToken> task_completion_source);
6176
}

0 commit comments

Comments
 (0)