• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.libraries.entitlement;
18 
19 import android.content.Context;
20 
21 import androidx.annotation.NonNull;
22 import androidx.annotation.Nullable;
23 import androidx.annotation.VisibleForTesting;
24 
25 import com.android.libraries.entitlement.eapaka.EapAkaApi;
26 import com.android.libraries.entitlement.http.HttpResponse;
27 import com.android.libraries.entitlement.utils.DebugUtils;
28 import com.android.libraries.entitlement.utils.Ts43Constants;
29 
30 import com.google.common.collect.ImmutableList;
31 import com.google.common.collect.ImmutableMap;
32 
33 import java.util.List;
34 
35 /**
36  * Implements protocol for carrier service entitlement configuration query and operation, based on
37  * GSMA TS.43 spec.
38  */
39 public class ServiceEntitlement {
40     /**
41      * App ID for Voice-Over-LTE entitlement.
42      */
43     public static final String APP_VOLTE = Ts43Constants.APP_VOLTE;
44     /**
45      * App ID for Voice-Over-WiFi entitlement.
46      */
47     public static final String APP_VOWIFI = Ts43Constants.APP_VOWIFI;
48     /**
49      * App ID for SMS-Over-IP entitlement.
50      */
51     public static final String APP_SMSOIP = Ts43Constants.APP_SMSOIP;
52     /**
53      * App ID for on device service activation (ODSA) for companion device.
54      */
55     public static final String APP_ODSA_COMPANION = Ts43Constants.APP_ODSA_COMPANION;
56     /**
57      * App ID for on device service activation (ODSA) for primary device.
58      */
59     public static final String APP_ODSA_PRIMARY = Ts43Constants.APP_ODSA_PRIMARY;
60     /**
61      * App ID for data plan information entitlement.
62      */
63     public static final String APP_DATA_PLAN_BOOST = Ts43Constants.APP_DATA_PLAN_BOOST;
64 
65     /**
66      * App ID for server initiated requests, entitlement and activation.
67      */
68     public static final String APP_ODSA_SERVER_INITIATED_REQUESTS =
69             Ts43Constants.APP_ODSA_SERVER_INITIATED_REQUESTS;
70 
71     /**
72      * App ID for direct carrier billing.
73      */
74     public static final String APP_DIRECT_CARRIER_BILLING =
75             Ts43Constants.APP_DIRECT_CARRIER_BILLING;
76 
77     /**
78      * App ID for private user identity.
79      */
80     public static final String APP_PRIVATE_USER_IDENTITY = Ts43Constants.APP_PRIVATE_USER_IDENTITY;
81 
82     /**
83      * App ID for phone number information.
84      */
85     public static final String APP_PHONE_NUMBER_INFORMATION =
86             Ts43Constants.APP_PHONE_NUMBER_INFORMATION;
87 
88     /**
89      * App ID for satellite entitlement.
90      */
91     public static final String APP_SATELLITE_ENTITLEMENT = Ts43Constants.APP_SATELLITE_ENTITLEMENT;
92 
93     /**
94      * App ID for ODSA for Cross-TS.43 platform device, Entitlement and Activation.
95      */
96     public static final String APP_ODSA_CROSS_TS43 = Ts43Constants.APP_ODSA_CROSS_TS43;
97 
98     private final CarrierConfig carrierConfig;
99     private final EapAkaApi eapAkaApi;
100     @Nullable
101     private ServiceEntitlementRequest mOidcRequest;
102     /**
103      * Creates an instance for service entitlement configuration query and operation for the
104      * carrier.
105      *
106      * @param context           context of application
107      * @param carrierConfig     carrier specific configs used in the queries and operations.
108      * @param simSubscriptionId the subscription ID of the carrier's SIM on device. This indicates
109      *                          which SIM to retrieve IMEI/IMSI from and perform EAP-AKA
110      *                          authentication with. See
111      *                          {@link android.telephony.SubscriptionManager}
112      *                          for how to get the subscription ID.
113      */
ServiceEntitlement(Context context, CarrierConfig carrierConfig, int simSubscriptionId)114     public ServiceEntitlement(Context context, CarrierConfig carrierConfig, int simSubscriptionId) {
115         this(context, carrierConfig, simSubscriptionId, /* saveHttpHistory= */ false);
116     }
117 
118     /**
119      * Creates an instance for service entitlement configuration query and operation for the
120      * carrier.
121      *
122      * @param context context of application
123      * @param carrierConfig carrier specific configs used in the queries and operations.
124      * @param simSubscriptionId the subscription ID of the carrier's SIM on device. This indicates
125      *     which SIM to retrieve IMEI/IMSI from and perform EAP-AKA authentication with. See {@link
126      *     android.telephony.SubscriptionManager} for how to get the subscription ID.
127      * @param saveHttpHistory set to {@code true} to save the history of request and response which
128      *     can later be retrieved by {@code getHistory()}. Intended for debugging.
129      */
ServiceEntitlement( Context context, CarrierConfig carrierConfig, int simSubscriptionId, boolean saveHttpHistory)130     public ServiceEntitlement(
131             Context context,
132             CarrierConfig carrierConfig,
133             int simSubscriptionId,
134             boolean saveHttpHistory) {
135         this(
136                 context,
137                 carrierConfig,
138                 simSubscriptionId,
139                 saveHttpHistory,
140                 DebugUtils.getBypassEapAkaResponse());
141     }
142 
143     /**
144      * Creates an instance for service entitlement configuration query and operation for the
145      * carrier.
146      *
147      * @param context context of application
148      * @param carrierConfig carrier specific configs used in the queries and operations.
149      * @param simSubscriptionId the subscription ID of the carrier's SIM on device. This indicates
150      *     which SIM to retrieve IMEI/IMSI from and perform EAP-AKA authentication with. See {@link
151      *     android.telephony.SubscriptionManager} for how to get the subscription ID.
152      * @param saveHttpHistory set to {@code true} to save the history of request and response which
153      *     can later be retrieved by {@code getHistory()}. Intended for debugging.
154      * @param bypassEapAkaResponse set to non empty string to bypass EAP-AKA authentication.
155      *     The client will accept any challenge from the server and return this string as a
156      *     response. Must not be {@code null}. Intended for testing.
157      */
ServiceEntitlement( Context context, CarrierConfig carrierConfig, int simSubscriptionId, boolean saveHttpHistory, String bypassEapAkaResponse)158     public ServiceEntitlement(
159             Context context,
160             CarrierConfig carrierConfig,
161             int simSubscriptionId,
162             boolean saveHttpHistory,
163             String bypassEapAkaResponse) {
164         this.carrierConfig = carrierConfig;
165         this.eapAkaApi =
166                 new EapAkaApi(context, simSubscriptionId, saveHttpHistory, bypassEapAkaResponse);
167     }
168 
169     @VisibleForTesting
ServiceEntitlement(CarrierConfig carrierConfig, EapAkaApi eapAkaApi)170     ServiceEntitlement(CarrierConfig carrierConfig, EapAkaApi eapAkaApi) {
171         this.carrierConfig = carrierConfig;
172         this.eapAkaApi = eapAkaApi;
173     }
174 
175     /**
176      * Retrieves service entitlement configuration. For on device service activation (ODSA) of eSIM
177      * for companion/primary devices, use {@link #performEsimOdsa} instead.
178      *
179      * <p>Supported {@code appId}: {@link #APP_VOLTE}, {@link #APP_VOWIFI}, {@link #APP_SMSOIP}.
180      *
181      * <p>This method sends an HTTP GET request to entitlement server, responds to EAP-AKA
182      * challenge if needed, and returns the raw configuration doc as a string. The following
183      * parameters are set in the HTTP request:
184      *
185      * <ul>
186      * <li>"app": {@code appId}
187      * <li>"vers": 0, or {@code request.configurationVersion()} if it's not 0.
188      * <li>"entitlement_version": "2.0", or {@code request.entitlementVersion()} if it's not empty.
189      * <li>"token": not set, or {@code request.authenticationToken()} if it's not empty.
190      * <li>"IMSI": if "token" is set, set to {@link android.telephony.TelephonyManager#getImei}.
191      * <li>"EAP_ID": if "token" is not set, set this parameter to trigger embedded EAP-AKA
192      * authentication as described in TS.43 section 2.6.1. Its value is derived from IMSI as per
193      * GSMA spec RCC.14 section C.2.
194      * <li>"terminal_id": IMEI, or {@code request.terminalId()} if it's not empty.
195      * <li>"terminal_vendor": {@link android.os.Build#MANUFACTURER}, or {@code
196      * request.terminalVendor()} if it's not empty.
197      * <li>"terminal_model": {@link android.os.Build#MODEL}, or {@code request.terminalModel()} if
198      * it's not empty.
199      * <li>"terminal_sw_version": {@link android.os.Build.VERSION#BASE_OS}, or {@code
200      * request.terminalSoftwareVersion()} if it's not empty.
201      * <li>"app_name": not set, or {@code request.appName()} if it's not empty.
202      * <li>"app_version": not set, or {@code request.appVersion()} if it's not empty.
203      * <li>"notif_token": not set, or {@code request.notificationToken()} if it's not empty.
204      * <li>"notif_action": {@code request.notificationAction()} if "notif_token" is set, otherwise
205      * not set.
206      * </ul>
207      *
208      * <p>Requires permission: READ_PRIVILEGED_PHONE_STATE, or carrier privilege.
209      *
210      * @param appId   an app ID string defined in TS.43 section 2.2, e.g. {@link #APP_VOWIFI}.
211      * @param request contains parameters that can be used in the HTTP request.
212      */
213     @NonNull
queryEntitlementStatus(String appId, ServiceEntitlementRequest request)214     public String queryEntitlementStatus(String appId, ServiceEntitlementRequest request)
215             throws ServiceEntitlementException {
216         return queryEntitlementStatus(ImmutableList.of(appId), request);
217     }
218 
219     /**
220      * Retrieves service entitlement configurations for multiple app IDs in one HTTP
221      * request/response. For on device service activation (ODSA) of eSIM for companion/primary
222      * devices, use {@link #performEsimOdsa} instead.
223      *
224      * <p>Same as {@link #queryEntitlementStatus(String, ServiceEntitlementRequest)} except that
225      * multiple "app" parameters will be set in the HTTP request, in the order as they appear in
226      * parameter {@code appIds}.
227      */
228     @NonNull
queryEntitlementStatus( ImmutableList<String> appIds, ServiceEntitlementRequest request)229     public String queryEntitlementStatus(
230             ImmutableList<String> appIds, ServiceEntitlementRequest request)
231             throws ServiceEntitlementException {
232         return getEntitlementStatusResponse(appIds, request).body();
233     }
234 
235     /**
236      * Retrieves service entitlement configurations for multiple app IDs in one HTTP
237      * request/response. For on device service activation (ODSA) of eSIM for companion/primary
238      * devices, use {@link #performEsimOdsa} instead.
239      *
240      * <p>Same as {@link #queryEntitlementStatus(String, ServiceEntitlementRequest)} except that
241      * multiple "app" parameters will be set in the HTTP request, in the order as they appear in
242      * parameter {@code appIds}. Additional parameters from {@code additionalHeaders} are set to the
243      * HTTP request.
244      */
245     @NonNull
queryEntitlementStatus( ImmutableList<String> appIds, ServiceEntitlementRequest request, ImmutableMap<String, String> additionalHeaders)246     public String queryEntitlementStatus(
247             ImmutableList<String> appIds,
248             ServiceEntitlementRequest request,
249             ImmutableMap<String, String> additionalHeaders)
250             throws ServiceEntitlementException {
251         return getEntitlementStatusResponse(appIds, request, additionalHeaders).body();
252     }
253 
254     /**
255      * Retrieves service entitlement configurations for multiple app IDs in one HTTP
256      * request/response. For on device service activation (ODSA) of eSIM for companion/primary
257      * devices, use {@link #performEsimOdsa} instead.
258      *
259      * <p>Same as {@link #queryEntitlementStatus(ImmutableList, ServiceEntitlementRequest)}
260      * except that it returns the full HTTP response instead of just the body.
261      */
262     @NonNull
getEntitlementStatusResponse(ImmutableList<String> appIds, ServiceEntitlementRequest request)263     public HttpResponse getEntitlementStatusResponse(ImmutableList<String> appIds,
264             ServiceEntitlementRequest request)
265             throws ServiceEntitlementException {
266         return getEntitlementStatusResponse(appIds, request, ImmutableMap.of());
267     }
268 
269     /**
270      * Retrieves service entitlement configurations for multiple app IDs in one HTTP
271      * request/response. For on device service activation (ODSA) of eSIM for companion/primary
272      * devices, use {@link #performEsimOdsa} instead.
273      */
274     @NonNull
getEntitlementStatusResponse( ImmutableList<String> appIds, ServiceEntitlementRequest request, ImmutableMap<String, String> additionalHeaders)275     public HttpResponse getEntitlementStatusResponse(
276             ImmutableList<String> appIds,
277             ServiceEntitlementRequest request,
278             ImmutableMap<String, String> additionalHeaders)
279             throws ServiceEntitlementException {
280         return eapAkaApi.queryEntitlementStatus(appIds, carrierConfig, request, additionalHeaders);
281     }
282 
283     /**
284      * Performs on device service activation (ODSA) of eSIM for companion/primary devices.
285      *
286      * <p>Supported {@code appId}: {@link #APP_ODSA_COMPANION}, {@link #APP_ODSA_PRIMARY}.
287      *
288      * <p>Similar to {@link #queryEntitlementStatus(String, ServiceEntitlementRequest)}, this method
289      * sends an HTTP GET request to entitlement server, responds to EAP-AKA challenge if needed, and
290      * returns the raw configuration doc as a string. Additional parameters from {@code operation}
291      * are set to the HTTP request. See {@link EsimOdsaOperation} for details.
292      */
293     @NonNull
performEsimOdsa( String appId, ServiceEntitlementRequest request, EsimOdsaOperation operation)294     public String performEsimOdsa(
295             String appId, ServiceEntitlementRequest request, EsimOdsaOperation operation)
296             throws ServiceEntitlementException {
297         return performEsimOdsa(appId, request, operation, ImmutableMap.of());
298     }
299 
300     /**
301      * Performs on device service activation (ODSA) of eSIM for companion/primary devices.
302      *
303      * <p>Supported {@code appId}: {@link #APP_ODSA_COMPANION}, {@link #APP_ODSA_PRIMARY}.
304      *
305      * <p>Similar to {@link #queryEntitlementStatus(String, ServiceEntitlementRequest)}, this method
306      * sends an HTTP GET request to entitlement server, responds to EAP-AKA challenge if needed, and
307      * returns the raw configuration doc as a string. Additional parameters from {@code operation}
308      * are set to the HTTP request. See {@link EsimOdsaOperation} for details. Additional parameters
309      * from {@code additionalHeaders} are set to the HTTP request.
310      */
311     @NonNull
performEsimOdsa( String appId, ServiceEntitlementRequest request, EsimOdsaOperation operation, ImmutableMap<String, String> additionalHeaders)312     public String performEsimOdsa(
313             String appId,
314             ServiceEntitlementRequest request,
315             EsimOdsaOperation operation,
316             ImmutableMap<String, String> additionalHeaders)
317             throws ServiceEntitlementException {
318         return getEsimOdsaResponse(appId, request, operation, additionalHeaders).body();
319     }
320 
321     /**
322      * Retrieves the HTTP response after performing on device service activation (ODSA) of eSIM for
323      * companion/primary devices.
324      *
325      * <p>Same as {@link #performEsimOdsa(String, ServiceEntitlementRequest, EsimOdsaOperation)}
326      * except that it returns the full HTTP response instead of just the body.
327      */
328     @NonNull
getEsimOdsaResponse( String appId, ServiceEntitlementRequest request, EsimOdsaOperation operation)329     public HttpResponse getEsimOdsaResponse(
330             String appId, ServiceEntitlementRequest request, EsimOdsaOperation operation)
331             throws ServiceEntitlementException {
332         return getEsimOdsaResponse(appId, request, operation, ImmutableMap.of());
333     }
334 
335     /**
336      * Retrieves the HTTP response after performing on device service activation (ODSA) of eSIM for
337      * companion/primary devices.
338      *
339      * <p>Same as {@link #performEsimOdsa(String, ServiceEntitlementRequest, EsimOdsaOperation)}
340      * except that it returns the full HTTP response instead of just the body. Additional parameters
341      * from {@code additionalHeaders} are set to the HTTP request.
342      */
343     @NonNull
getEsimOdsaResponse( String appId, ServiceEntitlementRequest request, EsimOdsaOperation operation, ImmutableMap<String, String> additionalHeaders)344     public HttpResponse getEsimOdsaResponse(
345             String appId,
346             ServiceEntitlementRequest request,
347             EsimOdsaOperation operation,
348             ImmutableMap<String, String> additionalHeaders)
349             throws ServiceEntitlementException {
350         return eapAkaApi.performEsimOdsaOperation(
351                 appId, carrierConfig, request, operation, additionalHeaders);
352     }
353 
354     /**
355      * Retrieves the endpoint for OpenID Connect(OIDC) authentication.
356      *
357      * <p>Implementation based on section 2.8.2 of TS.43
358      *
359      * <p>The user should call {@link #queryEntitlementStatusFromOidc(String url)} with the
360      * authentication result to retrieve the service entitlement configuration.
361      *
362      * @param appId an app ID string defined in TS.43 section 2.2
363      * @param request contains parameters that can be used in the HTTP request
364      */
365     @NonNull
acquireOidcAuthenticationEndpoint(String appId, ServiceEntitlementRequest request)366     public String acquireOidcAuthenticationEndpoint(String appId, ServiceEntitlementRequest request)
367             throws ServiceEntitlementException {
368         return acquireOidcAuthenticationEndpoint(appId, request, ImmutableMap.of());
369     }
370 
371     /**
372      * Retrieves the endpoint for OpenID Connect(OIDC) authentication.
373      *
374      * <p>Implementation based on section 2.8.2 of TS.43
375      *
376      * <p>The user should call {@link #queryEntitlementStatusFromOidc(String url)} with the
377      * authentication result to retrieve the service entitlement configuration.
378      *
379      * @param appId an app ID string defined in TS.43 section 2.2
380      * @param request contains parameters that can be used in the HTTP request
381      * @param additionalHeaders additional headers to be set in the HTTP request
382      */
383     @NonNull
acquireOidcAuthenticationEndpoint( String appId, ServiceEntitlementRequest request, ImmutableMap<String, String> additionalHeaders)384     public String acquireOidcAuthenticationEndpoint(
385             String appId,
386             ServiceEntitlementRequest request,
387             ImmutableMap<String, String> additionalHeaders)
388             throws ServiceEntitlementException {
389         mOidcRequest = request;
390         return eapAkaApi.acquireOidcAuthenticationEndpoint(
391                 appId, carrierConfig, request, additionalHeaders);
392     }
393 
394     /**
395      * Retrieves the service entitlement configuration from OIDC authentication result.
396      *
397      * <p>Implementation based on section 2.8.2 of TS.43.
398      *
399      * <p>{@link #acquireOidcAuthenticationEndpoint} must be called before calling this method.
400      *
401      * @param url the redirect url from OIDC authentication result.
402      */
403     @NonNull
queryEntitlementStatusFromOidc(String url)404     public String queryEntitlementStatusFromOidc(String url) throws ServiceEntitlementException {
405         return getEntitlementStatusResponseFromOidc(url).body();
406     }
407 
408     /**
409      * Retrieves the HTTP response containing the service entitlement configuration from
410      * OIDC authentication result.
411      *
412      * <p>Same as {@link #queryEntitlementStatusFromOidc(String)} except that it returns the
413      * full HTTP response instead of just the body.
414      *
415      * @param url the redirect url from OIDC authentication result.
416      */
417     @NonNull
getEntitlementStatusResponseFromOidc(String url)418     public HttpResponse getEntitlementStatusResponseFromOidc(String url)
419             throws ServiceEntitlementException {
420         return getEntitlementStatusResponseFromOidc(url, ImmutableMap.of());
421     }
422 
423     /**
424      * Retrieves the HTTP response containing the service entitlement configuration from OIDC
425      * authentication result.
426      *
427      * <p>Same as {@link #queryEntitlementStatusFromOidc(String)} except that it returns the full
428      * HTTP response instead of just the body.
429      *
430      * @param url the redirect url from OIDC authentication result.
431      * @param additionalHeaders additional headers to be set in the HTTP request
432      */
433     @NonNull
getEntitlementStatusResponseFromOidc( String url, ImmutableMap<String, String> additionalHeaders)434     public HttpResponse getEntitlementStatusResponseFromOidc(
435             String url, ImmutableMap<String, String> additionalHeaders)
436             throws ServiceEntitlementException {
437         if (mOidcRequest == null) {
438             throw new IllegalStateException(
439                     "acquireOidcAuthenticationEndpoint must be called before calling this method.");
440         }
441         return eapAkaApi.queryEntitlementStatusFromOidc(
442                 url, carrierConfig, mOidcRequest, additionalHeaders);
443     }
444 
445     /**
446      * Retrieves the history of past HTTP request and responses if {@code saveHttpHistory} was set
447      * in constructor.
448      */
449     @NonNull
getHistory()450     public List<String> getHistory() {
451         return eapAkaApi.getHistory();
452     }
453 
454     /**
455      * Clears the history of past HTTP request and responses.
456      */
clearHistory()457     public void clearHistory() {
458         eapAkaApi.clearHistory();
459     }
460 }
461