aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKiwon Park <kiwonp@google.com>2023-03-18 00:04:44 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-03-18 00:04:44 +0000
commit9f6f01d27afb594593222c26272d00f1240f7789 (patch)
treed851a394fcc6429f9c9b2058cb776df65e71e16c
parentd54d1cda6eae03dad31ff481e4434774cc43bc96 (diff)
parentd6487bda8e2ec3bd64201f99896e406c1bd07c4c (diff)
downloadservice_entitlement-9f6f01d27afb594593222c26272d00f1240f7789.tar.gz
Respond to second and third challenge during EAP-AKA. am: d6487bda8e
Original change: https://android-review.googlesource.com/c/platform/frameworks/libs/service_entitlement/+/2494696 Change-Id: I3e74094fb53b0cff2ca38c4733acfc823658e8f1 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--java/com/android/libraries/entitlement/ServiceEntitlementException.java5
-rw-r--r--java/com/android/libraries/entitlement/eapaka/EapAkaApi.java136
-rw-r--r--tests/src/com/android/libraries/entitlement/eapaka/EapAkaApiTest.java305
3 files changed, 406 insertions, 40 deletions
diff --git a/java/com/android/libraries/entitlement/ServiceEntitlementException.java b/java/com/android/libraries/entitlement/ServiceEntitlementException.java
index 45b1b9b..b1cb50f 100644
--- a/java/com/android/libraries/entitlement/ServiceEntitlementException.java
+++ b/java/com/android/libraries/entitlement/ServiceEntitlementException.java
@@ -43,6 +43,11 @@ public class ServiceEntitlementException extends Exception {
* synchronization" procedure as defined in RFC 4187.
*/
public static final int ERROR_EAP_AKA_SYNCHRONIZATION_FAILURE = 21;
+ /**
+ * EAP-AKA failure that happens when the client fails to authenticate within the maximum number
+ * of attempts
+ */
+ public static final int ERROR_EAP_AKA_FAILURE = 21;
// HTTP related failures
/**
diff --git a/java/com/android/libraries/entitlement/eapaka/EapAkaApi.java b/java/com/android/libraries/entitlement/eapaka/EapAkaApi.java
index 2847c16..dc3c518 100644
--- a/java/com/android/libraries/entitlement/eapaka/EapAkaApi.java
+++ b/java/com/android/libraries/entitlement/eapaka/EapAkaApi.java
@@ -16,6 +16,7 @@
package com.android.libraries.entitlement.eapaka;
+import static com.android.libraries.entitlement.ServiceEntitlementException.ERROR_EAP_AKA_FAILURE;
import static com.android.libraries.entitlement.ServiceEntitlementException.ERROR_EAP_AKA_SYNCHRONIZATION_FAILURE;
import static com.android.libraries.entitlement.ServiceEntitlementException.ERROR_MALFORMED_HTTP_RESPONSE;
@@ -33,6 +34,7 @@ import com.android.libraries.entitlement.EsimOdsaOperation;
import com.android.libraries.entitlement.ServiceEntitlementException;
import com.android.libraries.entitlement.ServiceEntitlementRequest;
import com.android.libraries.entitlement.http.HttpClient;
+import com.android.libraries.entitlement.http.HttpConstants.ContentType;
import com.android.libraries.entitlement.http.HttpConstants.RequestMethod;
import com.android.libraries.entitlement.http.HttpRequest;
import com.android.libraries.entitlement.http.HttpResponse;
@@ -91,8 +93,9 @@ public class EapAkaApi {
private static final String NETWORK_IDENTIFIER = "network_identifier";
- // In case of EAP-AKA synchronization failure, we try to recover for at most two times.
- private static final int FOLLOW_SYNC_FAILURE_MAX_COUNT = 2;
+ // In case of EAP-AKA synchronization failure or another challenge, we try to authenticate for
+ // at most three times.
+ private static final int MAX_EAP_AKA_ATTEMPTS = 3;
private final Context mContext;
private final int mSimSubscriptionId;
@@ -145,10 +148,17 @@ public class EapAkaApi {
urlBuilder.toString(),
carrierConfig,
ServiceEntitlementRequest.ACCEPT_CONTENT_TYPE_JSON);
+ String eapAkaChallenge = getEapAkaChallenge(challengeResponse);
+ if (eapAkaChallenge == null) {
+ throw new ServiceEntitlementException(
+ ERROR_MALFORMED_HTTP_RESPONSE,
+ "Failed to parse EAP-AKA challenge: " + challengeResponse.body());
+ }
return respondToEapAkaChallenge(
carrierConfig,
- challengeResponse,
- FOLLOW_SYNC_FAILURE_MAX_COUNT,
+ eapAkaChallenge,
+ challengeResponse.cookies(),
+ MAX_EAP_AKA_ATTEMPTS,
request.acceptContentType())
.body();
}
@@ -158,62 +168,79 @@ public class EapAkaApi {
* Sends a follow-up HTTP request to the HTTP {@code response} using the same cookie, and
* returns the follow-up HTTP response.
*
- * <p>The {@code response} should contain a EAP-AKA challenge from server, and the
- * follow-up request could contain:
+ * <p>The {@code eapAkaChallenge} should be the EAP-AKA challenge from server, and the follow-up
+ * request could contain:
*
* <ul>
- * <li>The EAP-AKA response message, and the follow-up response should contain the
- * service entitlement configuration; or,
- * <li>The EAP-AKA synchronization failure message, and the follow-up response should
- * contain the new EAP-AKA challenge. Then this method calls itself to follow-up
- * the new challenge and return a new response, if {@code followSyncFailureCount}
- * is greater than zero. When this method call itself {@code followSyncFailureCount} is
- * reduced by one to prevent infinite loop (unlikely in practice, but just in case).
+ * <li>The EAP-AKA response message, and the follow-up response should contain the service
+ * entitlement configuration, or another EAP-AKA challenge in which case the method calls
+ * if {@code remainingAttempts} is greater than zero (If {@code remainingAttempts} reaches
+ * 0, the method will throw ServiceEntitlementException) ; or
+ * <li>The EAP-AKA synchronization failure message, and the follow-up response should contain
+ * the new EAP-AKA challenge. Then this method calls itself to follow-up the new challenge
+ * and return a new response, as long as {@code remainingAttempts} is greater than zero.
* </ul>
*
* @param response Challenge response from server which its content type is JSON
*/
private HttpResponse respondToEapAkaChallenge(
CarrierConfig carrierConfig,
- HttpResponse response,
- int followSyncFailureCount,
+ String eapAkaChallenge,
+ ImmutableList<String> cookies,
+ int remainingAttempts,
String contentType)
throws ServiceEntitlementException {
- String eapAkaChallenge;
- try {
- eapAkaChallenge = new JSONObject(response.body()).getString(EAP_CHALLENGE_RESPONSE);
- } catch (JSONException jsonException) {
- throw new ServiceEntitlementException(
- ERROR_MALFORMED_HTTP_RESPONSE, "Failed to parse json object", jsonException);
- }
if (!mBypassEapAkaResponse.isEmpty()) {
- return challengeResponse(
- mBypassEapAkaResponse,
- carrierConfig,
- response.cookies(),
- contentType);
+ return challengeResponse(mBypassEapAkaResponse, carrierConfig, cookies, contentType);
}
+
EapAkaChallenge challenge = EapAkaChallenge.parseEapAkaChallenge(eapAkaChallenge);
EapAkaResponse eapAkaResponse =
EapAkaResponse.respondToEapAkaChallenge(mContext, mSimSubscriptionId, challenge);
- // This could be a successful authentication, or synchronization failure.
- if (eapAkaResponse.response() != null) { // successful authentication
- return challengeResponse(
- eapAkaResponse.response(),
- carrierConfig,
- response.cookies(),
- contentType);
+ // This could be a successful authentication, another challenge, or synchronization failure.
+ if (eapAkaResponse.response() != null) {
+ HttpResponse response =
+ challengeResponse(
+ eapAkaResponse.response(), carrierConfig, cookies, contentType);
+ String nextEapAkaChallenge = getEapAkaChallenge(response);
+ // successful authentication
+ if (nextEapAkaChallenge == null) {
+ return response;
+ }
+ // another challenge
+ Log.d(TAG, "Received another challenge");
+ if (remainingAttempts > 0) {
+ return respondToEapAkaChallenge(
+ carrierConfig,
+ nextEapAkaChallenge,
+ cookies,
+ remainingAttempts - 1,
+ contentType);
+ } else {
+ throw new ServiceEntitlementException(
+ ERROR_EAP_AKA_FAILURE, "Unable to EAP-AKA authenticate");
+ }
} else if (eapAkaResponse.synchronizationFailureResponse() != null) {
Log.d(TAG, "synchronization failure");
HttpResponse newChallenge =
challengeResponse(
eapAkaResponse.synchronizationFailureResponse(),
carrierConfig,
- response.cookies(),
+ cookies,
ServiceEntitlementRequest.ACCEPT_CONTENT_TYPE_JSON);
- if (followSyncFailureCount > 0) {
+ String nextEapAkaChallenge = getEapAkaChallenge(newChallenge);
+ if (nextEapAkaChallenge == null) {
+ throw new ServiceEntitlementException(
+ ERROR_MALFORMED_HTTP_RESPONSE,
+ "Failed to parse EAP-AKA challenge: " + newChallenge.body());
+ }
+ if (remainingAttempts > 0) {
return respondToEapAkaChallenge(
- carrierConfig, newChallenge, followSyncFailureCount - 1, contentType);
+ carrierConfig,
+ nextEapAkaChallenge,
+ cookies,
+ remainingAttempts - 1,
+ contentType);
} else {
throw new ServiceEntitlementException(
ERROR_EAP_AKA_SYNCHRONIZATION_FAILURE,
@@ -281,10 +308,17 @@ public class EapAkaApi {
urlBuilder.toString(),
carrierConfig,
ServiceEntitlementRequest.ACCEPT_CONTENT_TYPE_JSON);
+ String eapAkaChallenge = getEapAkaChallenge(challengeResponse);
+ if (eapAkaChallenge == null) {
+ throw new ServiceEntitlementException(
+ ERROR_MALFORMED_HTTP_RESPONSE,
+ "Failed to parse EAP-AKA challenge: " + challengeResponse.body());
+ }
return respondToEapAkaChallenge(
carrierConfig,
- challengeResponse,
- FOLLOW_SYNC_FAILURE_MAX_COUNT,
+ eapAkaChallenge,
+ challengeResponse.cookies(),
+ MAX_EAP_AKA_ATTEMPTS,
request.acceptContentType())
.body();
}
@@ -405,6 +439,30 @@ public class EapAkaApi {
}
}
+ @Nullable
+ private String getEapAkaChallenge(HttpResponse response) throws ServiceEntitlementException {
+ String eapAkaChallenge = null;
+ String responseBody = response.body();
+ if (response.contentType() == ContentType.JSON) {
+ try {
+ eapAkaChallenge =
+ new JSONObject(responseBody).optString(EAP_CHALLENGE_RESPONSE, null);
+ } catch (JSONException jsonException) {
+ throw new ServiceEntitlementException(
+ ERROR_MALFORMED_HTTP_RESPONSE,
+ "Failed to parse json object",
+ jsonException);
+ }
+ } else if (response.contentType() == ContentType.XML) {
+ // TODO: possibly support parsing eap-relay-packet in XML format
+ return null;
+ } else {
+ throw new ServiceEntitlementException(
+ ERROR_MALFORMED_HTTP_RESPONSE, "Unknown HTTP content type");
+ }
+ return eapAkaChallenge;
+ }
+
/**
* Returns the IMSI EAP value. The resulting realm part of the Root NAI in 3GPP TS 23.003 clause
* 19.3.2 will be in the form:
diff --git a/tests/src/com/android/libraries/entitlement/eapaka/EapAkaApiTest.java b/tests/src/com/android/libraries/entitlement/eapaka/EapAkaApiTest.java
index 8e331f3..aff8f4b 100644
--- a/tests/src/com/android/libraries/entitlement/eapaka/EapAkaApiTest.java
+++ b/tests/src/com/android/libraries/entitlement/eapaka/EapAkaApiTest.java
@@ -67,6 +67,8 @@ public class EapAkaApiTest {
private static final String TEST_URL = "https://test.url/test-path";
private static final String EAP_AKA_CHALLENGE =
"{\"eap-relay-packet\":\"" + EAP_AKA_CHALLENGE_REQUEST + "\"}";
+ private static final String INVALID_EAP_AKA_CHALLENGE =
+ "{\"invalid-eap-relay-packet\":\"" + EAP_AKA_CHALLENGE_REQUEST + "\"}";
// com.google.common.net.HttpHeaders.COOKIE
private static final String HTTP_HEADER_COOKIE = "Cookie";
private static final String COOKIE_VALUE = "COOKIE=abcdefg";
@@ -169,8 +171,137 @@ public class EapAkaApiTest {
ImmutableList.of(ServiceEntitlement.APP_VOWIFI), carrierConfig, request);
assertThat(respopnse).isEqualTo(RESPONSE_XML);
- // Verify that the 2nd request has cookies set by the 1st response
verify(mMockHttpClient, times(2)).request(mHttpRequestCaptor.capture());
+ // Verify that the 2nd request has cookies set by the 1st response
+ assertThat(mHttpRequestCaptor.getAllValues().get(1).requestProperties())
+ .containsAtLeast(HTTP_HEADER_COOKIE, COOKIE_VALUE,
+ HTTP_HEADER_COOKIE, COOKIE_VALUE_1);
+ assertThat(mHttpRequestCaptor.getAllValues().get(0).timeoutInSec())
+ .isEqualTo(CarrierConfig.DEFAULT_TIMEOUT_IN_SEC);
+ assertThat(mHttpRequestCaptor.getAllValues().get(0).network()).isNull();
+ assertThat(mHttpRequestCaptor.getAllValues().get(1).timeoutInSec())
+ .isEqualTo(CarrierConfig.DEFAULT_TIMEOUT_IN_SEC);
+ assertThat(mHttpRequestCaptor.getAllValues().get(1).network()).isNull();
+ }
+
+ @Test
+ public void queryEntitlementStatus_noAuthenticationToken_invalidChallenge() throws Exception {
+ when(mMockTelephonyManagerForSubId.getIccAuthentication(
+ TelephonyManager.APPTYPE_USIM,
+ TelephonyManager.AUTHTYPE_EAP_AKA,
+ EAP_AKA_SECURITY_CONTEXT_REQUEST_EXPECTED))
+ .thenReturn(EAP_AKA_SECURITY_CONTEXT_RESPONSE_SUCCESS);
+ HttpResponse eapChallengeResponse =
+ HttpResponse.builder()
+ .setContentType(ContentType.JSON)
+ .setBody(INVALID_EAP_AKA_CHALLENGE)
+ .setCookies(ImmutableList.of(COOKIE_VALUE, COOKIE_VALUE_1))
+ .build();
+ HttpResponse xmlResponse =
+ HttpResponse.builder().setContentType(ContentType.XML).setBody(RESPONSE_XML)
+ .build();
+ when(mMockHttpClient.request(any()))
+ .thenReturn(eapChallengeResponse).thenReturn(xmlResponse);
+ CarrierConfig carrierConfig = CarrierConfig.builder().setServerUrl(TEST_URL).build();
+ ServiceEntitlementRequest request = ServiceEntitlementRequest.builder().build();
+
+ ServiceEntitlementException exception =
+ expectThrows(
+ ServiceEntitlementException.class,
+ () ->
+ mEapAkaApi.queryEntitlementStatus(
+ ImmutableList.of(ServiceEntitlement.APP_VOWIFI),
+ carrierConfig,
+ request));
+
+ assertThat(exception.getErrorCode())
+ .isEqualTo(ServiceEntitlementException.ERROR_MALFORMED_HTTP_RESPONSE);
+ assertThat(exception.getMessage())
+ .isEqualTo("Failed to parse EAP-AKA challenge: " + INVALID_EAP_AKA_CHALLENGE);
+ assertThat(exception.getCause()).isNull();
+ assertThat(exception.getHttpStatus()).isEqualTo(0);
+ assertThat(exception.getRetryAfter()).isEmpty();
+ }
+
+ @Test
+ public void queryEntitlementStatus_noAuthenticationToken_secondChallenge() throws Exception {
+ when(mMockTelephonyManagerForSubId.getIccAuthentication(
+ TelephonyManager.APPTYPE_USIM,
+ TelephonyManager.AUTHTYPE_EAP_AKA,
+ EAP_AKA_SECURITY_CONTEXT_REQUEST_EXPECTED))
+ .thenReturn(EAP_AKA_SECURITY_CONTEXT_RESPONSE_SUCCESS);
+ HttpResponse eapChallengeResponse =
+ HttpResponse.builder()
+ .setContentType(ContentType.JSON)
+ .setBody(EAP_AKA_CHALLENGE)
+ .setCookies(ImmutableList.of(COOKIE_VALUE, COOKIE_VALUE_1))
+ .build();
+ HttpResponse xmlResponse =
+ HttpResponse.builder()
+ .setContentType(ContentType.XML)
+ .setBody(RESPONSE_XML)
+ .build();
+ when(mMockHttpClient.request(any()))
+ .thenReturn(eapChallengeResponse)
+ .thenReturn(eapChallengeResponse)
+ .thenReturn(xmlResponse);
+ CarrierConfig carrierConfig = CarrierConfig.builder().setServerUrl(TEST_URL).build();
+ ServiceEntitlementRequest request = ServiceEntitlementRequest.builder().build();
+
+ String respopnse =
+ mEapAkaApi.queryEntitlementStatus(
+ ImmutableList.of(ServiceEntitlement.APP_VOWIFI), carrierConfig, request);
+
+ assertThat(respopnse).isEqualTo(RESPONSE_XML);
+ // Verify that the subsequent requests have cookies set by the 1st response
+ verify(mMockHttpClient, times(3)).request(mHttpRequestCaptor.capture());
+ assertThat(mHttpRequestCaptor.getAllValues().get(1).requestProperties())
+ .containsAtLeast(HTTP_HEADER_COOKIE, COOKIE_VALUE,
+ HTTP_HEADER_COOKIE, COOKIE_VALUE_1);
+ assertThat(mHttpRequestCaptor.getAllValues().get(0).timeoutInSec())
+ .isEqualTo(CarrierConfig.DEFAULT_TIMEOUT_IN_SEC);
+ assertThat(mHttpRequestCaptor.getAllValues().get(0).network()).isNull();
+ assertThat(mHttpRequestCaptor.getAllValues().get(1).timeoutInSec())
+ .isEqualTo(CarrierConfig.DEFAULT_TIMEOUT_IN_SEC);
+ assertThat(mHttpRequestCaptor.getAllValues().get(1).network()).isNull();
+ assertThat(mHttpRequestCaptor.getAllValues().get(2).timeoutInSec())
+ .isEqualTo(CarrierConfig.DEFAULT_TIMEOUT_IN_SEC);
+ assertThat(mHttpRequestCaptor.getAllValues().get(2).network()).isNull();
+ }
+
+ @Test
+ public void queryEntitlementStatus_noAuthenticationToken_thirdChallenge() throws Exception {
+ when(mMockTelephonyManagerForSubId.getIccAuthentication(
+ TelephonyManager.APPTYPE_USIM,
+ TelephonyManager.AUTHTYPE_EAP_AKA,
+ EAP_AKA_SECURITY_CONTEXT_REQUEST_EXPECTED))
+ .thenReturn(EAP_AKA_SECURITY_CONTEXT_RESPONSE_SUCCESS);
+ HttpResponse eapChallengeResponse =
+ HttpResponse.builder()
+ .setContentType(ContentType.JSON)
+ .setBody(EAP_AKA_CHALLENGE)
+ .setCookies(ImmutableList.of(COOKIE_VALUE, COOKIE_VALUE_1))
+ .build();
+ HttpResponse xmlResponse =
+ HttpResponse.builder()
+ .setContentType(ContentType.XML)
+ .setBody(RESPONSE_XML)
+ .build();
+ when(mMockHttpClient.request(any()))
+ .thenReturn(eapChallengeResponse)
+ .thenReturn(eapChallengeResponse)
+ .thenReturn(eapChallengeResponse)
+ .thenReturn(xmlResponse);
+ CarrierConfig carrierConfig = CarrierConfig.builder().setServerUrl(TEST_URL).build();
+ ServiceEntitlementRequest request = ServiceEntitlementRequest.builder().build();
+
+ String respopnse =
+ mEapAkaApi.queryEntitlementStatus(
+ ImmutableList.of(ServiceEntitlement.APP_VOWIFI), carrierConfig, request);
+
+ assertThat(respopnse).isEqualTo(RESPONSE_XML);
+ // Verify that the subsequent requests have cookies set by the 1st response
+ verify(mMockHttpClient, times(4)).request(mHttpRequestCaptor.capture());
assertThat(mHttpRequestCaptor.getAllValues().get(1).requestProperties())
.containsAtLeast(HTTP_HEADER_COOKIE, COOKIE_VALUE,
HTTP_HEADER_COOKIE, COOKIE_VALUE_1);
@@ -180,6 +311,51 @@ public class EapAkaApiTest {
assertThat(mHttpRequestCaptor.getAllValues().get(1).timeoutInSec())
.isEqualTo(CarrierConfig.DEFAULT_TIMEOUT_IN_SEC);
assertThat(mHttpRequestCaptor.getAllValues().get(1).network()).isNull();
+ assertThat(mHttpRequestCaptor.getAllValues().get(2).timeoutInSec())
+ .isEqualTo(CarrierConfig.DEFAULT_TIMEOUT_IN_SEC);
+ assertThat(mHttpRequestCaptor.getAllValues().get(2).network()).isNull();
+ assertThat(mHttpRequestCaptor.getAllValues().get(3).timeoutInSec())
+ .isEqualTo(CarrierConfig.DEFAULT_TIMEOUT_IN_SEC);
+ assertThat(mHttpRequestCaptor.getAllValues().get(3).network()).isNull();
+ }
+
+ @Test
+ public void queryEntitlementStatus_noAuthenticationToken_fourthChallenge_throwException()
+ throws Exception {
+ when(mMockTelephonyManagerForSubId.getIccAuthentication(
+ TelephonyManager.APPTYPE_USIM,
+ TelephonyManager.AUTHTYPE_EAP_AKA,
+ EAP_AKA_SECURITY_CONTEXT_REQUEST_EXPECTED))
+ .thenReturn(EAP_AKA_SECURITY_CONTEXT_RESPONSE_SUCCESS);
+ HttpResponse eapChallengeResponse =
+ HttpResponse.builder()
+ .setContentType(ContentType.JSON)
+ .setBody(EAP_AKA_CHALLENGE)
+ .setCookies(ImmutableList.of(COOKIE_VALUE, COOKIE_VALUE_1))
+ .build();
+ when(mMockHttpClient.request(any()))
+ .thenReturn(eapChallengeResponse)
+ .thenReturn(eapChallengeResponse)
+ .thenReturn(eapChallengeResponse)
+ .thenReturn(eapChallengeResponse);
+ CarrierConfig carrierConfig = CarrierConfig.builder().setServerUrl(TEST_URL).build();
+ ServiceEntitlementRequest request = ServiceEntitlementRequest.builder().build();
+
+ ServiceEntitlementException exception =
+ expectThrows(
+ ServiceEntitlementException.class,
+ () ->
+ mEapAkaApi.queryEntitlementStatus(
+ ImmutableList.of(ServiceEntitlement.APP_VOWIFI),
+ carrierConfig,
+ request));
+
+ assertThat(exception.getErrorCode())
+ .isEqualTo(ServiceEntitlementException.ERROR_EAP_AKA_FAILURE);
+ assertThat(exception.getMessage()).isEqualTo("Unable to EAP-AKA authenticate");
+ assertThat(exception.getCause()).isNull();
+ assertThat(exception.getHttpStatus()).isEqualTo(0);
+ assertThat(exception.getRetryAfter()).isEmpty();
}
@Test
@@ -266,6 +442,89 @@ public class EapAkaApiTest {
}
@Test
+ public void queryEntitlementStatus_noAuthenticationToken_eapAkaSyncFailure_invalidChallenge()
+ throws Exception {
+ when(mMockTelephonyManagerForSubId.getIccAuthentication(
+ TelephonyManager.APPTYPE_USIM,
+ TelephonyManager.AUTHTYPE_EAP_AKA,
+ EAP_AKA_SECURITY_CONTEXT_REQUEST_EXPECTED))
+ .thenReturn(EAP_AKA_SECURITY_CONTEXT_RESPONSE_SYNC_FAILURE);
+ HttpResponse eapChallengeResponse =
+ HttpResponse
+ .builder().setContentType(ContentType.JSON).setBody(EAP_AKA_CHALLENGE)
+ .setCookies(ImmutableList.of(COOKIE_VALUE)).build();
+ HttpResponse invalidEapChallengeResponse =
+ HttpResponse.builder()
+ .setContentType(ContentType.JSON)
+ .setBody(INVALID_EAP_AKA_CHALLENGE)
+ .setCookies(ImmutableList.of(COOKIE_VALUE))
+ .build();
+ when(mMockHttpClient.request(any()))
+ .thenReturn(eapChallengeResponse)
+ .thenReturn(invalidEapChallengeResponse);
+ CarrierConfig carrierConfig = CarrierConfig.builder().setServerUrl(TEST_URL).build();
+ ServiceEntitlementRequest request = ServiceEntitlementRequest.builder().build();
+
+ ServiceEntitlementException exception =
+ expectThrows(
+ ServiceEntitlementException.class,
+ () ->
+ mEapAkaApi.queryEntitlementStatus(
+ ImmutableList.of(ServiceEntitlement.APP_VOWIFI),
+ carrierConfig,
+ request));
+
+ assertThat(exception.getErrorCode())
+ .isEqualTo(ServiceEntitlementException.ERROR_MALFORMED_HTTP_RESPONSE);
+ assertThat(exception.getMessage())
+ .isEqualTo("Failed to parse EAP-AKA challenge: " + INVALID_EAP_AKA_CHALLENGE);
+ assertThat(exception.getCause()).isNull();
+ assertThat(exception.getHttpStatus()).isEqualTo(0);
+ assertThat(exception.getRetryAfter()).isEmpty();
+ }
+
+ @Test
+ public void queryEntitlementStatus_noAuthenticationToken_fourthEapAkaSyncFailure()
+ throws Exception {
+ when(mMockTelephonyManagerForSubId.getIccAuthentication(
+ TelephonyManager.APPTYPE_USIM,
+ TelephonyManager.AUTHTYPE_EAP_AKA,
+ EAP_AKA_SECURITY_CONTEXT_REQUEST_EXPECTED))
+ .thenReturn(EAP_AKA_SECURITY_CONTEXT_RESPONSE_SYNC_FAILURE)
+ .thenReturn(EAP_AKA_SECURITY_CONTEXT_RESPONSE_SYNC_FAILURE)
+ .thenReturn(EAP_AKA_SECURITY_CONTEXT_RESPONSE_SYNC_FAILURE)
+ .thenReturn(EAP_AKA_SECURITY_CONTEXT_RESPONSE_SYNC_FAILURE);
+ HttpResponse eapChallengeResponse =
+ HttpResponse
+ .builder().setContentType(ContentType.JSON).setBody(EAP_AKA_CHALLENGE)
+ .setCookies(ImmutableList.of(COOKIE_VALUE)).build();
+ when(mMockHttpClient.request(any()))
+ .thenReturn(eapChallengeResponse)
+ .thenReturn(eapChallengeResponse)
+ .thenReturn(eapChallengeResponse)
+ .thenReturn(eapChallengeResponse);
+ CarrierConfig carrierConfig = CarrierConfig.builder().setServerUrl(TEST_URL).build();
+ ServiceEntitlementRequest request = ServiceEntitlementRequest.builder().build();
+
+ ServiceEntitlementException exception =
+ expectThrows(
+ ServiceEntitlementException.class,
+ () ->
+ mEapAkaApi.queryEntitlementStatus(
+ ImmutableList.of(ServiceEntitlement.APP_VOWIFI),
+ carrierConfig,
+ request));
+
+ assertThat(exception.getErrorCode())
+ .isEqualTo(ServiceEntitlementException.ERROR_EAP_AKA_SYNCHRONIZATION_FAILURE);
+ assertThat(exception.getMessage())
+ .isEqualTo("Unable to recover from EAP-AKA synchroinization failure");
+ assertThat(exception.getCause()).isNull();
+ assertThat(exception.getHttpStatus()).isEqualTo(0);
+ assertThat(exception.getRetryAfter()).isEmpty();
+ }
+
+ @Test
public void queryEntitlementStatus_hasNoAuthenticationToken_bypassAuthentication()
throws Exception {
HttpResponse eapChallengeResponse =
@@ -398,4 +657,48 @@ public class EapAkaApiTest {
assertThat(response).isEqualTo(RESPONSE_XML);
verify(mMockHttpClient, times(1)).request(any());
}
+
+ @Test
+ public void performEsimOdsaOperation_noAuthenticationToken_invalidChallenge() throws Exception {
+ when(mMockTelephonyManagerForSubId.getIccAuthentication(
+ TelephonyManager.APPTYPE_USIM,
+ TelephonyManager.AUTHTYPE_EAP_AKA,
+ EAP_AKA_SECURITY_CONTEXT_REQUEST_EXPECTED))
+ .thenReturn(EAP_AKA_SECURITY_CONTEXT_RESPONSE_SUCCESS);
+ HttpResponse eapChallengeResponse =
+ HttpResponse.builder()
+ .setContentType(ContentType.JSON)
+ .setBody(INVALID_EAP_AKA_CHALLENGE)
+ .setCookies(ImmutableList.of(COOKIE_VALUE))
+ .build();
+ HttpResponse xmlResponse =
+ HttpResponse.builder()
+ .setContentType(ContentType.XML)
+ .setBody(RESPONSE_XML)
+ .build();
+ when(mMockHttpClient.request(any()))
+ .thenReturn(eapChallengeResponse)
+ .thenReturn(xmlResponse);
+ CarrierConfig carrierConfig = CarrierConfig.builder().setServerUrl(TEST_URL).build();
+ ServiceEntitlementRequest request = ServiceEntitlementRequest.builder().build();
+ EsimOdsaOperation operation = EsimOdsaOperation.builder().build();
+
+ ServiceEntitlementException exception =
+ expectThrows(
+ ServiceEntitlementException.class,
+ () ->
+ mEapAkaApi.performEsimOdsaOperation(
+ ServiceEntitlement.APP_ODSA_COMPANION,
+ carrierConfig,
+ request,
+ operation));
+
+ assertThat(exception.getErrorCode())
+ .isEqualTo(ServiceEntitlementException.ERROR_MALFORMED_HTTP_RESPONSE);
+ assertThat(exception.getMessage())
+ .isEqualTo("Failed to parse EAP-AKA challenge: " + INVALID_EAP_AKA_CHALLENGE);
+ assertThat(exception.getCause()).isNull();
+ assertThat(exception.getHttpStatus()).isEqualTo(0);
+ assertThat(exception.getRetryAfter()).isEmpty();
+ }
}