Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions appcheck/firebase-appcheck-debug-testing/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Unreleased

- [unchanged] Updated to keep [app_check] SDK versions aligned.

# 19.0.2

- [unchanged] Updated to keep [app_check] SDK versions aligned.
Expand Down
2 changes: 1 addition & 1 deletion appcheck/firebase-appcheck-debug-testing/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version=19.0.3
version=19.1.0
latestReleasedVersion=19.0.2
2 changes: 2 additions & 0 deletions appcheck/firebase-appcheck-debug/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Unreleased

- [fixed] Fixed issue preventing limited use tokens from being correctly generated. (#8204)

# 19.0.2

- [unchanged] Updated to keep [app_check] SDK versions aligned.
Expand Down
2 changes: 1 addition & 1 deletion appcheck/firebase-appcheck-debug/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version=19.0.3
version=19.1.0
latestReleasedVersion=19.0.2
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,22 @@ static Task<String> determineDebugSecret(
@NonNull
@Override
public Task<AppCheckToken> getToken() {
return getToken(/* isLimitedUseToken= */ false);
}

@NonNull
@Override
public Task<AppCheckToken> getLimitedUseToken() {
return getToken(/* isLimitedUseToken= */ true);
}

private Task<AppCheckToken> getToken(boolean isLimitedUseToken) {
return debugSecretTask
.onSuccessTask(
liteExecutor,
debugSecret -> {
ExchangeDebugTokenRequest request = new ExchangeDebugTokenRequest(debugSecret);
ExchangeDebugTokenRequest request =
new ExchangeDebugTokenRequest(debugSecret, isLimitedUseToken);
return Tasks.call(
blockingExecutor,
() ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,23 @@
*/
public class ExchangeDebugTokenRequest {
@VisibleForTesting static final String DEBUG_TOKEN_KEY = "debugToken";
@VisibleForTesting static final String LIMITED_USE_TOKEN_KEY = "limited_use";
Comment thread
rlazo marked this conversation as resolved.

private final String debugToken;
private final boolean isLimitedUseToken;

public ExchangeDebugTokenRequest(@NonNull String debugToken) {
public ExchangeDebugTokenRequest(@NonNull String debugToken, boolean isLimitedUseToken) {
this.debugToken = debugToken;
this.isLimitedUseToken = isLimitedUseToken;
}

@NonNull
public String toJsonString() throws JSONException {
JSONObject jsonObject = new JSONObject();
jsonObject.put(DEBUG_TOKEN_KEY, debugToken);

if (isLimitedUseToken) {
jsonObject.put(LIMITED_USE_TOKEN_KEY, true);
}
return jsonObject.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,13 @@
import com.google.firebase.concurrent.TestOnlyExecutors;
import java.io.IOException;
import java.util.concurrent.Executor;
import org.json.JSONObject;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
Expand Down Expand Up @@ -70,6 +73,7 @@ public class DebugAppCheckProviderTest {
@Mock NetworkClient mockNetworkClient;
@Mock RetryManager mockRetryManager;
@Mock AppCheckTokenResponse mockAppCheckTokenResponse;
@Captor ArgumentCaptor<byte[]> requestBytesCaptor;

private StorageHelper storageHelper;
private SharedPreferences sharedPreferences;
Expand Down Expand Up @@ -173,4 +177,31 @@ public void exchangeDebugToken_onFailure_setsTaskException() throws Exception {
Exception exception = task.getException();
assertThat(exception).isInstanceOf(IOException.class);
}

@Test
public void getLimitedUseToken_onSuccess_setsTaskResult() throws Exception {
when(mockNetworkClient.exchangeAttestationForAppCheckToken(
any(), eq(NetworkClient.DEBUG), eq(mockRetryManager)))
.thenReturn(mockAppCheckTokenResponse);
when(mockAppCheckTokenResponse.getToken()).thenReturn(APP_CHECK_TOKEN);
when(mockAppCheckTokenResponse.getTimeToLive()).thenReturn(TIME_TO_LIVE);

DebugAppCheckProvider provider =
new DebugAppCheckProvider(
DEBUG_SECRET, mockNetworkClient, liteExecutor, blockingExecutor, mockRetryManager);
Task<AppCheckToken> task = provider.getLimitedUseToken();

verify(mockNetworkClient)
.exchangeAttestationForAppCheckToken(
requestBytesCaptor.capture(), eq(NetworkClient.DEBUG), eq(mockRetryManager));

byte[] capturedBytes = requestBytesCaptor.getValue();
JSONObject jsonObject = new JSONObject(new String(capturedBytes, "UTF-8"));
assertThat(jsonObject.opt(ExchangeDebugTokenRequest.DEBUG_TOKEN_KEY)).isEqualTo(DEBUG_SECRET);
assertThat(jsonObject.opt(ExchangeDebugTokenRequest.LIMITED_USE_TOKEN_KEY)).isEqualTo(true);

AppCheckToken token = task.getResult();
assertThat(token).isInstanceOf(DefaultAppCheckToken.class);
assertThat(token.getToken()).isEqualTo(APP_CHECK_TOKEN);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,26 @@ public class ExchangeDebugTokenRequestTest {
@Test
public void toJsonString_expectSerialized() throws Exception {
ExchangeDebugTokenRequest exchangeDebugTokenRequest =
new ExchangeDebugTokenRequest(DEBUG_TOKEN);
new ExchangeDebugTokenRequest(DEBUG_TOKEN, false);

String jsonString = exchangeDebugTokenRequest.toJsonString();
JSONObject jsonObject = new JSONObject(jsonString);

assertThat(jsonObject.getString(ExchangeDebugTokenRequest.DEBUG_TOKEN_KEY))
.isEqualTo(DEBUG_TOKEN);
assertThat(jsonObject.opt(ExchangeDebugTokenRequest.LIMITED_USE_TOKEN_KEY)).isNull();
}

@Test
public void toJsonString_limitedUse_expectSerialized() throws Exception {
ExchangeDebugTokenRequest exchangeDebugTokenRequest =
new ExchangeDebugTokenRequest(DEBUG_TOKEN, true);

String jsonString = exchangeDebugTokenRequest.toJsonString();
JSONObject jsonObject = new JSONObject(jsonString);

assertThat(jsonObject.getString(ExchangeDebugTokenRequest.DEBUG_TOKEN_KEY))
.isEqualTo(DEBUG_TOKEN);
assertThat(jsonObject.getBoolean(ExchangeDebugTokenRequest.LIMITED_USE_TOKEN_KEY)).isTrue();
}
}
2 changes: 2 additions & 0 deletions appcheck/firebase-appcheck-playintegrity/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Unreleased

- [fixed] Fixed issue preventing limited use tokens from being correctly generated. (#8204)

# 19.0.2

- [unchanged] Updated to keep [app_check] SDK versions aligned.
Expand Down
2 changes: 1 addition & 1 deletion appcheck/firebase-appcheck-playintegrity/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version=19.0.3
version=19.1.0
latestReleasedVersion=19.0.2
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,24 @@
class ExchangePlayIntegrityTokenRequest {

@VisibleForTesting static final String PLAY_INTEGRITY_TOKEN_KEY = "playIntegrityToken";
@VisibleForTesting static final String LIMITED_USE_TOKEN_KEY = "limited_use";

private final String playIntegrityToken;
private final boolean isLimitedUseToken;

public ExchangePlayIntegrityTokenRequest(@NonNull String playIntegrityToken) {
public ExchangePlayIntegrityTokenRequest(
@NonNull String playIntegrityToken, boolean isLimitedUseToken) {
this.playIntegrityToken = playIntegrityToken;
this.isLimitedUseToken = isLimitedUseToken;
}

@NonNull
public String toJsonString() throws JSONException {
JSONObject jsonObject = new JSONObject();
jsonObject.put(PLAY_INTEGRITY_TOKEN_KEY, playIntegrityToken);
if (isLimitedUseToken) {
jsonObject.put(LIMITED_USE_TOKEN_KEY, true);
}

return jsonObject.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,23 @@ public PlayIntegrityAppCheckProvider(
@NonNull
@Override
public Task<AppCheckToken> getToken() {
return getToken(/* isLimitedUseToken= */ false);
}

@NonNull
@Override
public Task<AppCheckToken> getLimitedUseToken() {
return getToken(/* isLimitedUseToken= */ true);
}

private Task<AppCheckToken> getToken(boolean isLimitedUseToken) {
return getPlayIntegrityAttestation()
.onSuccessTask(
liteExecutor,
integrityTokenResponse -> {
ExchangePlayIntegrityTokenRequest request =
new ExchangePlayIntegrityTokenRequest(integrityTokenResponse.token());
new ExchangePlayIntegrityTokenRequest(
integrityTokenResponse.token(), isLimitedUseToken);
return Tasks.call(
blockingExecutor,
() ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,27 @@ public class ExchangePlayIntegrityTokenRequestTest {
@Test
public void toJsonString_expectSerialized() throws Exception {
ExchangePlayIntegrityTokenRequest exchangePlayIntegrityTokenRequest =
new ExchangePlayIntegrityTokenRequest(PLAY_INTEGRITY_TOKEN);
new ExchangePlayIntegrityTokenRequest(PLAY_INTEGRITY_TOKEN, /* isLimitedUseToken= */ false);

String jsonString = exchangePlayIntegrityTokenRequest.toJsonString();
JSONObject jsonObject = new JSONObject(jsonString);

assertThat(jsonObject.getString(ExchangePlayIntegrityTokenRequest.PLAY_INTEGRITY_TOKEN_KEY))
.isEqualTo(PLAY_INTEGRITY_TOKEN);
assertThat(jsonObject.opt(ExchangePlayIntegrityTokenRequest.LIMITED_USE_TOKEN_KEY)).isNull();
}

@Test
public void toJsonString_limitedUse_expectSerialized() throws Exception {
ExchangePlayIntegrityTokenRequest exchangePlayIntegrityTokenRequest =
new ExchangePlayIntegrityTokenRequest(PLAY_INTEGRITY_TOKEN, /* isLimitedUseToken= */ true);

String jsonString = exchangePlayIntegrityTokenRequest.toJsonString();
JSONObject jsonObject = new JSONObject(jsonString);

assertThat(jsonObject.getString(ExchangePlayIntegrityTokenRequest.PLAY_INTEGRITY_TOKEN_KEY))
.isEqualTo(PLAY_INTEGRITY_TOKEN);
assertThat(jsonObject.optBoolean(ExchangePlayIntegrityTokenRequest.LIMITED_USE_TOKEN_KEY))
.isTrue();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ public void getToken_onSuccess_setsTaskResult() throws Exception {
String exchangePlayIntegrityTokenRequestJsonString =
new String(exchangePlayIntegrityTokenRequestCaptor.getValue());
assertThat(exchangePlayIntegrityTokenRequestJsonString).contains(INTEGRITY_TOKEN);
JSONObject jsonObject = new JSONObject(exchangePlayIntegrityTokenRequestJsonString);
assertThat(jsonObject.opt(ExchangePlayIntegrityTokenRequest.LIMITED_USE_TOKEN_KEY)).isNull();
}

@Test
Expand Down Expand Up @@ -226,6 +228,50 @@ public void getToken_tokenExchangeFails_setsTaskException() throws Exception {
assertThat(exchangePlayIntegrityTokenRequestJsonString).contains(INTEGRITY_TOKEN);
}

@Test
public void getLimitedUseToken_onSuccess_setsTaskResult() throws Exception {
when(mockNetworkClient.generatePlayIntegrityChallenge(any(), eq(mockRetryManager)))
.thenReturn(createGeneratePlayIntegrityChallengeResponse());
when(mockIntegrityManager.requestIntegrityToken(any()))
.thenReturn(Tasks.forResult(mockIntegrityTokenResponse));
when(mockNetworkClient.exchangeAttestationForAppCheckToken(
any(), eq(NetworkClient.PLAY_INTEGRITY), eq(mockRetryManager)))
.thenReturn(mockAppCheckTokenResponse);

PlayIntegrityAppCheckProvider provider =
new PlayIntegrityAppCheckProvider(
PROJECT_NUMBER,
mockIntegrityManager,
mockNetworkClient,
liteExecutor,
blockingExecutor,
mockRetryManager);
Task<AppCheckToken> task = provider.getLimitedUseToken();

AppCheckToken token = task.getResult();
assertThat(token).isInstanceOf(DefaultAppCheckToken.class);
assertThat(token.getToken()).isEqualTo(APP_CHECK_TOKEN);

verify(mockNetworkClient).generatePlayIntegrityChallenge(any(), eq(mockRetryManager));

verify(mockIntegrityManager).requestIntegrityToken(integrityTokenRequestCaptor.capture());
assertThat(integrityTokenRequestCaptor.getValue().cloudProjectNumber())
.isEqualTo(Long.parseLong(PROJECT_NUMBER));
assertThat(integrityTokenRequestCaptor.getValue().nonce()).isEqualTo(CHALLENGE);

verify(mockNetworkClient)
.exchangeAttestationForAppCheckToken(
exchangePlayIntegrityTokenRequestCaptor.capture(),
eq(NetworkClient.PLAY_INTEGRITY),
eq(mockRetryManager));
String exchangePlayIntegrityTokenRequestJsonString =
new String(exchangePlayIntegrityTokenRequestCaptor.getValue());
assertThat(exchangePlayIntegrityTokenRequestJsonString).contains(INTEGRITY_TOKEN);
JSONObject jsonObject = new JSONObject(exchangePlayIntegrityTokenRequestJsonString);
assertThat(jsonObject.opt(ExchangePlayIntegrityTokenRequest.LIMITED_USE_TOKEN_KEY))
.isEqualTo(true);
}

private static String createGeneratePlayIntegrityChallengeResponse() throws Exception {
JSONObject responseBodyJson = new JSONObject();
responseBodyJson.put(GeneratePlayIntegrityChallengeResponse.CHALLENGE_KEY, CHALLENGE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,24 @@ public class ExchangeRecaptchaEnterpriseTokenRequest {
@VisibleForTesting
static final String RECAPTCHA_ENTERPRISE_TOKEN_KEY = "recaptchaEnterpriseToken";

@VisibleForTesting static final String LIMITED_USE_TOKEN_KEY = "limited_use";

private final String recaptchaEnterpriseToken;
private final boolean isLimitedUseToken;

public ExchangeRecaptchaEnterpriseTokenRequest(@NonNull String recaptchaEnterpriseToken) {
public ExchangeRecaptchaEnterpriseTokenRequest(
@NonNull String recaptchaEnterpriseToken, boolean isLimitedUseToken) {
this.recaptchaEnterpriseToken = recaptchaEnterpriseToken;
this.isLimitedUseToken = isLimitedUseToken;
}

@NonNull
public String toJsonString() throws JSONException {
JSONObject jsonObject = new JSONObject();
jsonObject.put(RECAPTCHA_ENTERPRISE_TOKEN_KEY, recaptchaEnterpriseToken);
if (isLimitedUseToken) {
jsonObject.put(LIMITED_USE_TOKEN_KEY, true);
}

return jsonObject.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,23 @@ public void initializeRecaptchaClient() {
@NonNull
@Override
public Task<AppCheckToken> getToken() {
return getToken(/* isLimitedUseToken= */ false);
}

@NonNull
@Override
public Task<AppCheckToken> getLimitedUseToken() {
return getToken(/* isLimitedUseToken= */ true);
}

private Task<AppCheckToken> getToken(boolean isLimitedUseToken) {
return getRecaptchaEnterpriseAttestation()
.onSuccessTask(
liteExecutor,
recaptchaEnterpriseToken -> {
ExchangeRecaptchaEnterpriseTokenRequest request =
new ExchangeRecaptchaEnterpriseTokenRequest(recaptchaEnterpriseToken);
new ExchangeRecaptchaEnterpriseTokenRequest(
recaptchaEnterpriseToken, isLimitedUseToken);
return Tasks.call(
blockingExecutor,
() ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public class ExchangeRecaptchaEnterpriseTokenRequestTest {
@Test
public void toJsonString_expectSerialized() throws Exception {
ExchangeRecaptchaEnterpriseTokenRequest exchangeRecaptchaEnterpriseTokenRequest =
new ExchangeRecaptchaEnterpriseTokenRequest(RECAPTCHA_ENTERPRISE_TOKEN);
new ExchangeRecaptchaEnterpriseTokenRequest(
RECAPTCHA_ENTERPRISE_TOKEN, /* isLimitedUseToken= */ false);

String jsonString = exchangeRecaptchaEnterpriseTokenRequest.toJsonString();
JSONObject jsonObject = new JSONObject(jsonString);
Expand All @@ -35,5 +36,24 @@ public void toJsonString_expectSerialized() throws Exception {
jsonObject.getString(
ExchangeRecaptchaEnterpriseTokenRequest.RECAPTCHA_ENTERPRISE_TOKEN_KEY))
.isEqualTo(RECAPTCHA_ENTERPRISE_TOKEN);
assertThat(jsonObject.opt(ExchangeRecaptchaEnterpriseTokenRequest.LIMITED_USE_TOKEN_KEY))
.isNull();
}

@Test
public void toJsonString_limitedUse_expectSerialized() throws Exception {
ExchangeRecaptchaEnterpriseTokenRequest exchangeRecaptchaEnterpriseTokenRequest =
new ExchangeRecaptchaEnterpriseTokenRequest(
RECAPTCHA_ENTERPRISE_TOKEN, /* isLimitedUseToken= */ true);

String jsonString = exchangeRecaptchaEnterpriseTokenRequest.toJsonString();
JSONObject jsonObject = new JSONObject(jsonString);

assertThat(
jsonObject.getString(
ExchangeRecaptchaEnterpriseTokenRequest.RECAPTCHA_ENTERPRISE_TOKEN_KEY))
.isEqualTo(RECAPTCHA_ENTERPRISE_TOKEN);
assertThat(jsonObject.optBoolean(ExchangeRecaptchaEnterpriseTokenRequest.LIMITED_USE_TOKEN_KEY))
.isTrue();
}
}
Loading
Loading