diff options
author | Meng Wang <mewan@google.com> | 2021-05-25 17:47:52 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-05-25 17:47:52 +0000 |
commit | c987171036cf68df973d20fdb0301b6f3ef291f8 (patch) | |
tree | 0909cfc97f66cbd81b43d7005885fe13b5a284ba | |
parent | 04517003517b29f25cc8dc69b455b1cbcfd451aa (diff) | |
parent | db18ed256b703a0d61c436fa3d42f3eb4bf7fc82 (diff) | |
download | service_entitlement-c987171036cf68df973d20fdb0301b6f3ef291f8.tar.gz |
Merge "Support specifying accept configuration document type XML or JSON" into sc-dev am: 8f2bf45bd0 am: adc146b7af am: db18ed256b
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/libs/service_entitlement/+/14623351
Change-Id: I9e29da60352844e3333858cf5e6199da493fca58
3 files changed, 149 insertions, 79 deletions
diff --git a/java/com/android/libraries/entitlement/ServiceEntitlementRequest.java b/java/com/android/libraries/entitlement/ServiceEntitlementRequest.java index 9db5246..c7b0ad3 100644 --- a/java/com/android/libraries/entitlement/ServiceEntitlementRequest.java +++ b/java/com/android/libraries/entitlement/ServiceEntitlementRequest.java @@ -26,14 +26,23 @@ import com.google.auto.value.AutoValue; */ @AutoValue public abstract class ServiceEntitlementRequest { - /** - * Disables notification token. - */ + /** Disables notification token. */ public static final int NOTICATION_ACTION_DISABLE = 0; - /** - * Enables FCM notification token. - */ + /** Enables FCM notification token. */ public static final int NOTICATION_ACTION_ENABLE_FCM = 2; + /** Accepts the content type in XML format. */ + public static final String ACCEPT_CONTENT_TYPE_XML = "text/vnd.wap.connectivity-xml"; + /** Accepts the content type in JSON format. */ + public static final String ACCEPT_CONTENT_TYPE_JSON = + "application/vnd.gsma.eap-relay.v1.0+json"; + /** Accepts the content type in JSON or XML format. */ + public static final String ACCEPT_CONTENT_TYPE_JSON_AND_XML = + "application/vnd.gsma.eap-relay.v1.0+json, text/vnd.wap.connectivity-xml"; + /** Default value of configuration version. */ + public static final int DEFAULT_CONFIGURATION_VERSION = 0; + /** Default value of entitlement version. */ + public static final String DEFAULT_ENTITLEMENT_VERSION = "2.0"; + /** * Returns the version of configuration currently stored on the client. Used by HTTP parameter @@ -100,12 +109,21 @@ public abstract class ServiceEntitlementRequest { public abstract int notificationAction(); /** + * Returns the accepted content type of http response. + * + * @see #ACCEPT_CONTENT_TYPE_XML + * @see #ACCEPT_CONTENT_TYPE_JSON + * @see #ACCEPT_CONTENT_TYPE_JSON_AND_XML + */ + public abstract String acceptContentType(); + + /** * Returns a new {@link Builder} object. */ public static Builder builder() { return new AutoValue_ServiceEntitlementRequest.Builder() - .setConfigurationVersion(0) - .setEntitlementVersion("2.0") + .setConfigurationVersion(DEFAULT_CONFIGURATION_VERSION) + .setEntitlementVersion(DEFAULT_ENTITLEMENT_VERSION) .setAuthenticationToken("") .setTerminalId("") .setTerminalVendor(Build.MANUFACTURER) @@ -114,7 +132,8 @@ public abstract class ServiceEntitlementRequest { .setAppName("") .setAppVersion("") .setNotificationToken("") - .setNotificationAction(NOTICATION_ACTION_ENABLE_FCM); + .setNotificationAction(NOTICATION_ACTION_ENABLE_FCM) + .setAcceptContentType(ACCEPT_CONTENT_TYPE_JSON_AND_XML); } /** @@ -126,7 +145,8 @@ public abstract class ServiceEntitlementRequest { * Sets the version of configuration currently stored on the client. Used by HTTP parameter * "vers". * - * <p>If not set, default to 0 indicating no existing configuration. + * <p>If not set, default to {@link #DEFAULT_CONFIGURATION_VERSION} indicating no existing + * configuration. */ public abstract Builder setConfigurationVersion(int value); @@ -134,7 +154,7 @@ public abstract class ServiceEntitlementRequest { * Sets the current version of the entitlement specification. Used by HTTP parameter * "entitlement_version". * - * <p>If not set, default to "2.0" base on TS.43-v5.0. + * <p>If not set, default to {@link #DEFAULT_ENTITLEMENT_VERSION} base on TS.43-v5.0. */ public abstract Builder setEntitlementVersion(String value); @@ -211,6 +231,18 @@ public abstract class ServiceEntitlementRequest { */ public abstract Builder setNotificationAction(int value); + /** + * Sets the configuration document format the caller accepts, e.g. XML or JSON. Used by HTTP + * request header "Accept". + * + * <p>If not set, will use {@link #ACCEPT_CONTENT_TYPE_JSON_AND_XML}. + * + * @see #ACCEPT_CONTENT_TYPE_XML + * @see #ACCEPT_CONTENT_TYPE_JSON + * @see #ACCEPT_CONTENT_TYPE_JSON_AND_XML + */ + public abstract Builder setAcceptContentType(String contentType); + public abstract ServiceEntitlementRequest build(); } } diff --git a/java/com/android/libraries/entitlement/eapaka/EapAkaApi.java b/java/com/android/libraries/entitlement/eapaka/EapAkaApi.java index bf53d87..2e337e4 100644 --- a/java/com/android/libraries/entitlement/eapaka/EapAkaApi.java +++ b/java/com/android/libraries/entitlement/eapaka/EapAkaApi.java @@ -33,7 +33,6 @@ 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; @@ -64,11 +63,6 @@ public class EapAkaApi { private static final String APP_VERSION = "app_version"; private static final String APP_NAME = "app_name"; - private static final String ACCEPT_CONTENT_TYPE_JSON_AND_XML = - "application/vnd.gsma.eap-relay.v1.0+json, text/vnd.wap.connectivity-xml"; - private static final String REQUEST_CONTENT_TYPE_JSON = - "application/vnd.gsma.eap-relay.v1.0+json"; - private static final String OPERATION = "operation"; private static final String OPERATION_TYPE = "operation_type"; private static final String COMPANION_TERMINAL_ID = "companion_terminal_id"; @@ -119,16 +113,26 @@ public class EapAkaApi { throws ServiceEntitlementException { Uri.Builder urlBuilder = Uri.parse(carrierConfig.serverUrl()).buildUpon(); appendParametersForServiceEntitlementRequest(urlBuilder, appIds, request); - HttpResponse response = httpGet(urlBuilder.toString(), carrierConfig); - if (!request.authenticationToken().isEmpty()) { + if (!TextUtils.isEmpty(request.authenticationToken())) { // Fast Re-Authentication flow with pre-existing auth token Log.d(TAG, "Fast Re-Authentication"); - return response.body(); + return httpGet( + urlBuilder.toString(), carrierConfig, request.acceptContentType()).body(); + } else { + // Full Authentication flow + Log.d(TAG, "Full Authentication"); + HttpResponse challengeResponse = + httpGet( + urlBuilder.toString(), + carrierConfig, + ServiceEntitlementRequest.ACCEPT_CONTENT_TYPE_JSON); + return respondToEapAkaChallenge( + carrierConfig, + challengeResponse, + FOLLOW_SYNC_FAILURE_MAX_COUNT, + request.acceptContentType()) + .body(); } - // Full Authentication flow - Log.d(TAG, "Full Authentication"); - return respondToEapAkaChallenge(carrierConfig, response, FOLLOW_SYNC_FAILURE_MAX_COUNT) - .body(); } /** @@ -147,14 +151,15 @@ public class EapAkaApi { * 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). * </ul> + * + * @param response Challenge response from server which its content type is JSON */ private HttpResponse respondToEapAkaChallenge( - CarrierConfig carrierConfig, HttpResponse response, int followSyncFailureCount) + CarrierConfig carrierConfig, + HttpResponse response, + int followSyncFailureCount, + String contentType) throws ServiceEntitlementException { - if (response.contentType() != ContentType.JSON) { - throw new ServiceEntitlementException( - ERROR_MALFORMED_HTTP_RESPONSE, "Unexpected http ContentType"); - } String eapAkaChallenge; try { eapAkaChallenge = new JSONObject(response.body()).getString(EAP_CHALLENGE_RESPONSE); @@ -167,17 +172,22 @@ public class EapAkaApi { 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.cookie()); + return challengeResponse( + eapAkaResponse.response(), + carrierConfig, + response.cookie(), + contentType); } else if (eapAkaResponse.synchronizationFailureResponse() != null) { Log.d(TAG, "synchronization failure"); HttpResponse newChallenge = challengeResponse( eapAkaResponse.synchronizationFailureResponse(), carrierConfig, - response.cookie()); + response.cookie(), + ServiceEntitlementRequest.ACCEPT_CONTENT_TYPE_JSON); if (followSyncFailureCount > 0) { return respondToEapAkaChallenge( - carrierConfig, newChallenge, followSyncFailureCount - 1); + carrierConfig, newChallenge, followSyncFailureCount - 1, contentType); } else { throw new ServiceEntitlementException( ERROR_EAP_AKA_SYNCHRONIZATION_FAILURE, @@ -189,7 +199,10 @@ public class EapAkaApi { } private HttpResponse challengeResponse( - String eapAkaChallengeResponse, CarrierConfig carrierConfig, String cookie) + String eapAkaChallengeResponse, + CarrierConfig carrierConfig, + String cookie, + String contentType) throws ServiceEntitlementException { Log.d(TAG, "challengeResponse"); JSONObject postData = new JSONObject(); @@ -204,8 +217,10 @@ public class EapAkaApi { .setUrl(carrierConfig.serverUrl()) .setRequestMethod(RequestMethod.POST) .setPostData(postData) - .addRequestProperty(HttpHeaders.ACCEPT, ACCEPT_CONTENT_TYPE_JSON_AND_XML) - .addRequestProperty(HttpHeaders.CONTENT_TYPE, REQUEST_CONTENT_TYPE_JSON) + .addRequestProperty(HttpHeaders.ACCEPT, contentType) + .addRequestProperty( + HttpHeaders.CONTENT_TYPE, + ServiceEntitlementRequest.ACCEPT_CONTENT_TYPE_JSON) .addRequestProperty(HttpHeaders.COOKIE, cookie) .setTimeoutInSec(carrierConfig.timeoutInSec()) .setNetwork(carrierConfig.network()) @@ -226,16 +241,26 @@ public class EapAkaApi { appendParametersForServiceEntitlementRequest(urlBuilder, ImmutableList.of(appId), request); appendParametersForEsimOdsaOperation(urlBuilder, odsaOperation); - HttpResponse response = httpGet(urlBuilder.toString(), carrierConfig); - if (!request.authenticationToken().isEmpty()) { + if (!TextUtils.isEmpty(request.authenticationToken())) { // Fast Re-Authentication flow with pre-existing auth token Log.d(TAG, "Fast Re-Authentication"); - return response.body(); + return httpGet( + urlBuilder.toString(), carrierConfig, request.acceptContentType()).body(); + } else { + // Full Authentication flow + Log.d(TAG, "Full Authentication"); + HttpResponse challengeResponse = + httpGet( + urlBuilder.toString(), + carrierConfig, + ServiceEntitlementRequest.ACCEPT_CONTENT_TYPE_JSON); + return respondToEapAkaChallenge( + carrierConfig, + challengeResponse, + FOLLOW_SYNC_FAILURE_MAX_COUNT, + request.acceptContentType()) + .body(); } - // Full Authentication flow - Log.d(TAG, "Full Authentication"); - return respondToEapAkaChallenge(carrierConfig, response, FOLLOW_SYNC_FAILURE_MAX_COUNT) - .body(); } private void appendParametersForServiceEntitlementRequest( @@ -322,13 +347,13 @@ public class EapAkaApi { odsaOperation.targetTerminalEid()); } - private HttpResponse httpGet(String url, CarrierConfig carrierConfig) + private HttpResponse httpGet(String url, CarrierConfig carrierConfig, String contentType) throws ServiceEntitlementException { HttpRequest httpRequest = HttpRequest.builder() .setUrl(url) .setRequestMethod(RequestMethod.GET) - .addRequestProperty(HttpHeaders.ACCEPT, ACCEPT_CONTENT_TYPE_JSON_AND_XML) + .addRequestProperty(HttpHeaders.ACCEPT, contentType) .setTimeoutInSec(carrierConfig.timeoutInSec()) .setNetwork(carrierConfig.network()) .build(); diff --git a/tests/src/com/android/libraries/entitlement/eapaka/EapAkaApiTest.java b/tests/src/com/android/libraries/entitlement/eapaka/EapAkaApiTest.java index 99e8cfa..f289c04 100644 --- a/tests/src/com/android/libraries/entitlement/eapaka/EapAkaApiTest.java +++ b/tests/src/com/android/libraries/entitlement/eapaka/EapAkaApiTest.java @@ -48,6 +48,7 @@ import com.android.libraries.entitlement.http.HttpRequest; import com.android.libraries.entitlement.http.HttpResponse; import com.google.common.collect.ImmutableList; +import com.google.common.net.HttpHeaders; import org.json.JSONException; import org.junit.Before; @@ -93,19 +94,13 @@ public class EapAkaApiTest { private static final String ACCEPT_CONTENT_TYPE_JSON_AND_XML = "application/vnd.gsma.eap-relay.v1.0+json, text/vnd.wap.connectivity-xml"; - @Rule - public final MockitoRule rule = MockitoJUnit.rule(); + @Rule public final MockitoRule rule = MockitoJUnit.rule(); - @Mock - private HttpClient mMockHttpClient; - @Mock - private Network mMockNetwork; - @Mock - private TelephonyManager mMockTelephonyManager; - @Mock - private TelephonyManager mMockTelephonyManagerForSubId; - @Captor - private ArgumentCaptor<HttpRequest> mHttpRequestCaptor; + @Mock private HttpClient mMockHttpClient; + @Mock private Network mMockNetwork; + @Mock private TelephonyManager mMockTelephonyManager; + @Mock private TelephonyManager mMockTelephonyManagerForSubId; + @Captor private ArgumentCaptor<HttpRequest> mHttpRequestCaptor; private Context mContext; private EapAkaApi mEapAkaApi; @@ -203,29 +198,6 @@ public class EapAkaApiTest { } @Test - public void queryEntitlementStatus_noAuthenticationToken_contentTypeNotJson_throwException() - throws Exception { - HttpResponse xmlResponse = - HttpResponse.builder().setContentType(ContentType.XML).setBody(RESPONSE_XML) - .build(); - when(mMockHttpClient.request(any())).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("Unexpected http ContentType"); - } - - @Test public void queryEntitlementStatus_noAuthenticationToken_emptyResponseBody_throwException() throws Exception { HttpResponse eapChallengeResponse = @@ -285,6 +257,47 @@ public class EapAkaApiTest { } @Test + public void queryEntitlementStatus_acceptContentTypeSpecified_verfityAcceptContentType() + throws Exception { + HttpResponse response = HttpResponse.builder().setBody(RESPONSE_XML).build(); + when(mMockHttpClient.request(any())).thenReturn(response); + CarrierConfig carrierConfig = CarrierConfig.builder().build(); + ServiceEntitlementRequest request = + ServiceEntitlementRequest + .builder() + .setAuthenticationToken(TOKEN) + .setAcceptContentType(ServiceEntitlementRequest.ACCEPT_CONTENT_TYPE_XML) + .build(); + + mEapAkaApi.queryEntitlementStatus( + ImmutableList.of(ServiceEntitlement.APP_VOWIFI), carrierConfig, request); + + verify(mMockHttpClient).request(mHttpRequestCaptor.capture()); + assertThat(mHttpRequestCaptor.getValue().requestProperties().get(HttpHeaders.ACCEPT)) + .isEqualTo(ServiceEntitlementRequest.ACCEPT_CONTENT_TYPE_XML); + } + + @Test + public void queryEntitlementStatus_acceptContentTypeNotSpecified_defaultAcceptContentType() + throws Exception { + HttpResponse response = HttpResponse.builder().setBody(RESPONSE_XML).build(); + when(mMockHttpClient.request(any())).thenReturn(response); + CarrierConfig carrierConfig = CarrierConfig.builder().build(); + ServiceEntitlementRequest request = + ServiceEntitlementRequest + .builder() + .setAuthenticationToken(TOKEN) + .build(); + + mEapAkaApi.queryEntitlementStatus( + ImmutableList.of(ServiceEntitlement.APP_VOWIFI), carrierConfig, request); + + verify(mMockHttpClient).request(mHttpRequestCaptor.capture()); + assertThat(mHttpRequestCaptor.getValue().requestProperties().get(HttpHeaders.ACCEPT)) + .isEqualTo(ServiceEntitlementRequest.ACCEPT_CONTENT_TYPE_JSON_AND_XML); + } + + @Test public void performEsimOdsaOperation_noAuthenticationToken_returnsResult() throws Exception { when(mMockTelephonyManagerForSubId.getIccAuthentication( TelephonyManager.APPTYPE_USIM, |