From da1495b612cc490fe083844ce50fc1fa9c688b2e Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 12 May 2023 12:56:05 -0700 Subject: [PATCH] Add FAC getLimitedUseToken to internal interop interface (#4979) * Add FAC getLimitedUseToken to internal interop interface * Typo * Changelog * Formatting * PR feedback --- .../interop/InteropAppCheckTokenProvider.java | 9 ++++++ appcheck/firebase-appcheck/CHANGELOG.md | 2 +- .../firebase-appcheck.gradle | 2 +- .../internal/DefaultFirebaseAppCheck.java | 22 +++++++++++++++ .../internal/DefaultFirebaseAppCheckTest.java | 28 +++++++++++++++++++ .../TestInteropAppCheckTokenProvider.java | 6 ++++ 6 files changed, 67 insertions(+), 2 deletions(-) diff --git a/appcheck/firebase-appcheck-interop/src/main/java/com/google/firebase/appcheck/interop/InteropAppCheckTokenProvider.java b/appcheck/firebase-appcheck-interop/src/main/java/com/google/firebase/appcheck/interop/InteropAppCheckTokenProvider.java index 38b2a8aed32..1fde5c7c8cb 100644 --- a/appcheck/firebase-appcheck-interop/src/main/java/com/google/firebase/appcheck/interop/InteropAppCheckTokenProvider.java +++ b/appcheck/firebase-appcheck-interop/src/main/java/com/google/firebase/appcheck/interop/InteropAppCheckTokenProvider.java @@ -29,6 +29,15 @@ public interface InteropAppCheckTokenProvider { @NonNull Task getToken(boolean forceRefresh); + /** + * Requests an {@link AppCheckTokenResult} from the installed {@code AppCheckFactory}. This will + * always return a successful task, with an {@link AppCheckTokenResult} that contains either a + * valid token, or a dummy token and an error string. The token returned from this method will be + * a one-time use token. + */ + @NonNull + Task getLimitedUseToken(); + /** * Registers a listener to changes in the token state. There can be more than one listener * registered at the same time for one or more FirebaseAppAuth instances. The listeners call back diff --git a/appcheck/firebase-appcheck/CHANGELOG.md b/appcheck/firebase-appcheck/CHANGELOG.md index eda4e0a1ceb..2f6299ee233 100644 --- a/appcheck/firebase-appcheck/CHANGELOG.md +++ b/appcheck/firebase-appcheck/CHANGELOG.md @@ -1,5 +1,5 @@ # Unreleased - +* [changed] Internal updates to allow Firebase SDKs to obtain limited-use tokens. # 17.0.0 * [feature] Added [`getLimitedUseAppCheckToken()`](/docs/reference/android/com/google/firebase/appcheck/FirebaseAppCheck#getLimitedUseAppCheckToken()) diff --git a/appcheck/firebase-appcheck/firebase-appcheck.gradle b/appcheck/firebase-appcheck/firebase-appcheck.gradle index 2439f8087a7..4d9d6de480f 100644 --- a/appcheck/firebase-appcheck/firebase-appcheck.gradle +++ b/appcheck/firebase-appcheck/firebase-appcheck.gradle @@ -46,7 +46,7 @@ dependencies { implementation 'com.google.firebase:firebase-annotations:16.2.0' implementation 'com.google.firebase:firebase-common:20.3.1' implementation 'com.google.firebase:firebase-components:17.1.0' - implementation 'com.google.firebase:firebase-appcheck-interop:17.0.0' + implementation project(':appcheck:firebase-appcheck-interop') implementation 'com.google.android.gms:play-services-base:18.0.1' implementation 'com.google.android.gms:play-services-tasks:18.0.1' diff --git a/appcheck/firebase-appcheck/src/main/java/com/google/firebase/appcheck/internal/DefaultFirebaseAppCheck.java b/appcheck/firebase-appcheck/src/main/java/com/google/firebase/appcheck/internal/DefaultFirebaseAppCheck.java index fa363983184..58e0fdd0ac8 100644 --- a/appcheck/firebase-appcheck/src/main/java/com/google/firebase/appcheck/internal/DefaultFirebaseAppCheck.java +++ b/appcheck/firebase-appcheck/src/main/java/com/google/firebase/appcheck/internal/DefaultFirebaseAppCheck.java @@ -213,6 +213,28 @@ public Task getToken(boolean forceRefresh) { }); } + @NonNull + @Override + public Task getLimitedUseToken() { + return getLimitedUseAppCheckToken() + .continueWithTask( + liteExecutor, + appCheckTokenTask -> { + if (appCheckTokenTask.isSuccessful()) { + return Tasks.forResult( + DefaultAppCheckTokenResult.constructFromAppCheckToken( + appCheckTokenTask.getResult())); + } + // If the token exchange failed, return a dummy token for integrators to attach + // in their headers. + return Tasks.forResult( + DefaultAppCheckTokenResult.constructFromError( + new FirebaseException( + appCheckTokenTask.getException().getMessage(), + appCheckTokenTask.getException()))); + }); + } + @NonNull @Override public Task getAppCheckToken(boolean forceRefresh) { diff --git a/appcheck/firebase-appcheck/src/test/java/com/google/firebase/appcheck/internal/DefaultFirebaseAppCheckTest.java b/appcheck/firebase-appcheck/src/test/java/com/google/firebase/appcheck/internal/DefaultFirebaseAppCheckTest.java index 1d458c85dec..5d5974036e6 100644 --- a/appcheck/firebase-appcheck/src/test/java/com/google/firebase/appcheck/internal/DefaultFirebaseAppCheckTest.java +++ b/appcheck/firebase-appcheck/src/test/java/com/google/firebase/appcheck/internal/DefaultFirebaseAppCheckTest.java @@ -235,6 +235,15 @@ public void testGetLimitedUseAppCheckToken_noFactoryInstalled_taskFails() throws assertThat(tokenTask.isSuccessful()).isFalse(); } + @Test + public void testGetLimitedUseToken_noFactoryInstalled_returnResultWithError() throws Exception { + Task tokenTask = defaultFirebaseAppCheck.getLimitedUseToken(); + assertThat(tokenTask.isComplete()).isTrue(); + assertThat(tokenTask.isSuccessful()).isTrue(); + assertThat(tokenTask.getResult().getToken()).isNotNull(); + assertThat(tokenTask.getResult().getError()).isNotNull(); + } + @Test public void testGetToken_factoryInstalled_proxiesToAppCheckFactory() { defaultFirebaseAppCheck.installAppCheckProviderFactory(mockAppCheckProviderFactory); @@ -422,4 +431,23 @@ public void testGetLimitedUseAppCheckToken_existingToken_requestsNewToken() { verify(mockAppCheckProvider).getToken(); } + + @Test + public void testGetLimitedUseToken_noExistingToken_requestsNewToken() { + defaultFirebaseAppCheck.installAppCheckProviderFactory(mockAppCheckProviderFactory); + + defaultFirebaseAppCheck.getLimitedUseToken(); + + verify(mockAppCheckProvider).getToken(); + } + + @Test + public void testGetLimitedUseToken_existingToken_requestsNewToken() { + defaultFirebaseAppCheck.setCachedToken(validDefaultAppCheckToken); + defaultFirebaseAppCheck.installAppCheckProviderFactory(mockAppCheckProviderFactory); + + defaultFirebaseAppCheck.getLimitedUseToken(); + + verify(mockAppCheckProvider).getToken(); + } } diff --git a/firebase-functions/src/androidTest/java/com/google/firebase/functions/TestInteropAppCheckTokenProvider.java b/firebase-functions/src/androidTest/java/com/google/firebase/functions/TestInteropAppCheckTokenProvider.java index 9ed0a508e20..5342ec91e4c 100644 --- a/firebase-functions/src/androidTest/java/com/google/firebase/functions/TestInteropAppCheckTokenProvider.java +++ b/firebase-functions/src/androidTest/java/com/google/firebase/functions/TestInteropAppCheckTokenProvider.java @@ -66,6 +66,12 @@ public Task getToken(boolean forceRefresh) { return Tasks.forResult(testToken); } + @NonNull + @Override + public Task getLimitedUseToken() { + return Tasks.forResult(testToken); + } + @Override public void addAppCheckTokenListener(@NonNull AppCheckTokenListener listener) {}