Skip to content

Commit

Permalink
App Check and Storage, Functions, and RtDb support (firebase#2601)
Browse files Browse the repository at this point in the history
Open-sourcing ongoing App Check SDK work. Changes in this PR have been reviewed in separate PRs in the private repo.

Co-authored-by: Malcolm Deck <mdeck@google.com>
Co-authored-by: Vladimir Kryachko <vkryachko@google.com>
Co-authored-by: Sebastian Schmidt <mrschmidt@google.com>
  • Loading branch information
4 people authored Apr 22, 2021
1 parent 1275ceb commit 6da8617
Show file tree
Hide file tree
Showing 158 changed files with 6,561 additions and 133 deletions.
18 changes: 18 additions & 0 deletions appcheck/appcheck.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2020 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.


configure(subprojects) {
group = 'com.google.firebase'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright 2021 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.

plugins {
id 'firebase-library'
}

firebaseLibrary {
testLab.enabled = true
publishSources = true
}

android {
adbOptions {
timeOutInMs 60 * 1000
}

compileSdkVersion project.targetSdkVersion
defaultConfig {
targetSdkVersion project.targetSdkVersion
minSdkVersion project.minSdkVersion
versionName version
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// TODO: Uncomment the line below once we configure the debug secret environment variable in the public repo.
// testInstrumentationRunnerArgument "firebaseAppCheckDebugSecret", System.getenv("FIREBASE_APP_CHECK_DEBUG_SECRET") ?: ''
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

testOptions.unitTests.includeAndroidResources = true
}

dependencies {
implementation project(':firebase-common')
implementation project(':firebase-components')
implementation project(':appcheck:firebase-appcheck')
implementation project(':appcheck:firebase-appcheck-debug')
implementation project(':appcheck:firebase-appcheck-interop')
implementation 'com.google.android.gms:play-services-base:17.1.0'
implementation 'com.google.android.gms:play-services-tasks:17.0.0'
implementation 'androidx.test:core:1.2.0'

testImplementation 'junit:junit:4.13-beta-2'
testImplementation 'org.mockito:mockito-core:2.25.0'
testImplementation "org.robolectric:robolectric:$robolectricVersion"
testImplementation "com.google.truth:truth:$googleTruthVersion"
testImplementation 'androidx.test:core:1.2.0'
testImplementation project(':appcheck:firebase-appcheck-safetynet')

androidTestImplementation project(':firebase-storage')
androidTestImplementation 'junit:junit:4.13-beta-2'
androidTestImplementation "com.google.truth:truth:$googleTruthVersion"
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'org.mockito:mockito-core:2.25.0'
}

// ==========================================================================
// Copy from here down if you want to use the google-services plugin in your
// androidTest integration tests.
// ==========================================================================
ext.packageName = "com.google.firebase.appcheck.debug.testing"
apply from: '../../gradle/googleServices.gradle'
1 change: 1 addition & 0 deletions appcheck/firebase-appcheck-debug-testing/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
version=0.1.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2021 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.

package com.google.firebase.appcheck.debug.testing;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;

import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;
import com.google.firebase.FirebaseApp;
import com.google.firebase.appcheck.AppCheckTokenResult;
import com.google.firebase.appcheck.FirebaseAppCheck;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.ListResult;
import java.util.concurrent.ExecutionException;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
@Ignore("TODO: Re-enable after setting up debug secret environment variable in public repo.")
public class FirebaseAppCheckTest {
private final DebugAppCheckTestHelper debugAppCheckTestHelper =
DebugAppCheckTestHelper.fromInstrumentationArgs();

private FirebaseAppCheck firebaseAppCheck;

@Before
public void setUp() {
FirebaseApp.initializeApp(ApplicationProvider.getApplicationContext());
firebaseAppCheck = FirebaseAppCheck.getInstance();
}

@After
public void tearDown() {
FirebaseApp.clearInstancesForTest();
}

@Test
public void exchangeDebugSecretForAppCheckToken() throws Exception {
debugAppCheckTestHelper.withDebugProvider(
() -> {
Task<AppCheckTokenResult> tokenResultTask = firebaseAppCheck.getToken(true);
Tasks.await(tokenResultTask);
AppCheckTokenResult result = tokenResultTask.getResult();
assertThat(result.getToken()).isNotEmpty();
assertThat(result.getError()).isNull();
});
}

@Test
@Ignore("TODO: Enable once we have a project with enforcement enabled in CI.")
public void firebaseStorageListFiles_withValidAppCheckToken_success() throws Exception {
debugAppCheckTestHelper.withDebugProvider(
() -> {
FirebaseStorage firebaseStorage = FirebaseStorage.getInstance();
Task<ListResult> listResultTask = firebaseStorage.getReference().listAll();

Tasks.await(listResultTask);
});
}

@Test
@Ignore("TODO: Enable once we have a project with enforcement enabled in CI.")
public void firebaseStorageListFiles_withAppCheckDummyHeader_fails() throws Exception {
FirebaseStorage firebaseStorage = FirebaseStorage.getInstance();
Task<ListResult> listResultTask = firebaseStorage.getReference().listAll();
assertThrows(ExecutionException.class, () -> Tasks.await(listResultTask));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2021 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. -->

<manifest package="com.google.firebase.appcheck.debug.testing">
<!--Although the *SdkVersion is captured in gradle build files, this is required for non gradle builds-->
<!--<uses-sdk android:minSdkVersion="16"/>-->
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2021 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.

package com.google.firebase.appcheck.debug;

import androidx.annotation.NonNull;

/**
* Helper class used by {@link com.google.firebase.appcheck.debug.testing.DebugAppCheckTestHelper}
* in order to access the package-private {@link DebugAppCheckProviderFactory} constructor that
* takes in a debug secret.
*
* @hide
*/
public class DebugAppCheckProviderFactoryHelper {
@NonNull
public static DebugAppCheckProviderFactory createDebugAppCheckProviderFactory(
@NonNull String debugSecret) {
return new DebugAppCheckProviderFactory(debugSecret);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Copyright 2021 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.

package com.google.firebase.appcheck.debug.testing;

import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.test.platform.app.InstrumentationRegistry;
import com.google.firebase.FirebaseApp;
import com.google.firebase.appcheck.AppCheckProviderFactory;
import com.google.firebase.appcheck.FirebaseAppCheck;
import com.google.firebase.appcheck.debug.DebugAppCheckProviderFactory;
import com.google.firebase.appcheck.debug.DebugAppCheckProviderFactoryHelper;
import com.google.firebase.appcheck.internal.DefaultFirebaseAppCheck;

/**
* Helper class for using {@link DebugAppCheckProviderFactory} in integration tests.
*
* <p>Example Usage:
*
* <pre>{@code
* @RunWith(AndroidJunit4.class)
* public class MyTests {
* private final DebugAppCheckTestHelper debugAppCheckTestHelper =
* DebugAppCheckTestHelper.fromInstrumentationArgs();
*
* @Test
* public testWithDefaultApp() {
* debugAppCheckTestHelper.withDebugProvider(() -> {
* // Test code that requires a debug AppCheckToken
* });
* }
*
* @Test
* public testWithNonDefaultApp() {
* debugAppCheckTestHelper.withDebugProvider(
* FirebaseApp.getInstance("nonDefaultApp"),
* () -> {
* // Test code that requires a debug AppCheckToken
* });
* }
* }
* }</pre>
*
* <pre>{@code
* // In build.gradle.kts
* android {
* defaultConfig {
* System.getenv("FIREBASE_APP_CHECK_DEBUG_SECRET")?.let { token ->
* testInstrumentationRunnerArguments(
* mapOf("firebaseAppCheckDebugSecret" to token))
* }
* }
* }
* }</pre>
*/
public final class DebugAppCheckTestHelper {
private static final String DEBUG_SECRET_KEY = "firebaseAppCheckDebugSecret";

private final String debugSecret;

/**
* Create a {@link DebugAppCheckTestHelper} instance with the debug secret obtained from {@link
* InstrumentationRegistry} arguments.
*/
@NonNull
public static DebugAppCheckTestHelper fromInstrumentationArgs() {
String debugSecret = InstrumentationRegistry.getArguments().getString(DEBUG_SECRET_KEY);
return new DebugAppCheckTestHelper(debugSecret);
}

@VisibleForTesting
static DebugAppCheckTestHelper fromString(String debugSecret) {
return new DebugAppCheckTestHelper(debugSecret);
}

private DebugAppCheckTestHelper(String debugSecret) {
this.debugSecret = debugSecret;
}

/**
* Installs a {@link DebugAppCheckProviderFactory} to the default {@link FirebaseApp} and runs the
* test code in {@code runnable}.
*/
public <E extends Throwable> void withDebugProvider(@NonNull MaybeThrowingRunnable<E> runnable)
throws E {
FirebaseApp firebaseApp = FirebaseApp.getInstance();
withDebugProvider(firebaseApp, runnable);
}

/**
* Installs a {@link DebugAppCheckProviderFactory} to the provided {@link FirebaseApp} and runs
* the test code in {@code runnable}.
*/
public <E extends Throwable> void withDebugProvider(
@NonNull FirebaseApp firebaseApp, @NonNull MaybeThrowingRunnable<E> runnable) throws E {
DefaultFirebaseAppCheck firebaseAppCheck =
(DefaultFirebaseAppCheck) FirebaseAppCheck.getInstance(firebaseApp);
AppCheckProviderFactory currentAppCheckProviderFactory =
firebaseAppCheck.getInstalledAppCheckProviderFactory();
firebaseAppCheck.installAppCheckProviderFactory(
DebugAppCheckProviderFactoryHelper.createDebugAppCheckProviderFactory(debugSecret));
try {
runnable.run();
} catch (Throwable throwable) {
E e = (E) throwable;
throw e;
} finally {
firebaseAppCheck.resetAppCheckState();
// Restore the previous AppCheckProviderFactory
if (currentAppCheckProviderFactory != null) {
firebaseAppCheck.installAppCheckProviderFactory(currentAppCheckProviderFactory);
}
}
}

public interface MaybeThrowingRunnable<E extends Throwable> {
void run() throws E;
}
}
Loading

0 comments on commit 6da8617

Please sign in to comment.