aboutsummaryrefslogtreecommitdiff
path: root/java/com/android/libraries/entitlement/ServiceEntitlement.java
blob: 398e0a9aa7c3e23b49496a6221b037f4a0171b40 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * 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.android.libraries.entitlement;

import android.content.Context;

import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;

import com.android.libraries.entitlement.eapaka.EapAkaApi;
import com.android.libraries.entitlement.http.HttpResponse;
import com.android.libraries.entitlement.utils.Ts43Constants;

import com.google.common.collect.ImmutableList;

import java.util.List;

/**
 * Implements protocol for carrier service entitlement configuration query and operation, based on
 * GSMA TS.43 spec.
 */
public class ServiceEntitlement {
    /**
     * App ID for Voice-Over-LTE entitlement.
     */
    public static final String APP_VOLTE = Ts43Constants.APP_VOLTE;
    /**
     * App ID for Voice-Over-WiFi entitlement.
     */
    public static final String APP_VOWIFI = Ts43Constants.APP_VOWIFI;
    /**
     * App ID for SMS-Over-IP entitlement.
     */
    public static final String APP_SMSOIP = Ts43Constants.APP_SMSOIP;
    /**
     * App ID for on device service activation (ODSA) for companion device.
     */
    public static final String APP_ODSA_COMPANION = Ts43Constants.APP_ODSA_COMPANION;
    /**
     * App ID for on device service activation (ODSA) for primary device.
     */
    public static final String APP_ODSA_PRIMARY = Ts43Constants.APP_ODSA_PRIMARY;
    /**
     * App ID for data plan information entitlement.
     */
    public static final String APP_DATA_PLAN_BOOST = Ts43Constants.APP_DATA_PLAN_BOOST;

    /**
     * App ID for server initiated requests, entitlement and activation.
     */
    public static final String APP_ODSA_SERVER_INITIATED_REQUESTS =
            Ts43Constants.APP_ODSA_SERVER_INITIATED_REQUESTS;

    /**
     * App ID for direct carrier billing.
     */
    public static final String APP_DIRECT_CARRIER_BILLING =
            Ts43Constants.APP_DIRECT_CARRIER_BILLING;

    /**
     * App ID for private user identity.
     */
    public static final String APP_PRIVATE_USER_IDENTITY = Ts43Constants.APP_PRIVATE_USER_IDENTITY;

    /**
     * App ID for phone number information.
     */
    public static final String APP_PHONE_NUMBER_INFORMATION =
            Ts43Constants.APP_PHONE_NUMBER_INFORMATION;

    private final CarrierConfig carrierConfig;
    private final EapAkaApi eapAkaApi;
    private String mOidcAcceptContentType;
    /**
     * Creates an instance for service entitlement configuration query and operation for the
     * carrier.
     *
     * @param context           context of application
     * @param carrierConfig     carrier specific configs used in the queries and operations.
     * @param simSubscriptionId the subscription ID of the carrier's SIM on device. This indicates
     *                          which SIM to retrieve IMEI/IMSI from and perform EAP-AKA
     *                          authentication with. See
     *                          {@link android.telephony.SubscriptionManager}
     *                          for how to get the subscription ID.
     */
    public ServiceEntitlement(Context context, CarrierConfig carrierConfig, int simSubscriptionId) {
        this(
                context,
                carrierConfig,
                simSubscriptionId,
                /* saveHttpHistory= */ false,
                /* bypassEapAkaResponse= */ "");
    }

    /**
     * Creates an instance for service entitlement configuration query and operation for the
     * carrier.
     *
     * @param context context of application
     * @param carrierConfig carrier specific configs used in the queries and operations.
     * @param simSubscriptionId the subscription ID of the carrier's SIM on device. This indicates
     *     which SIM to retrieve IMEI/IMSI from and perform EAP-AKA authentication with. See {@link
     *     android.telephony.SubscriptionManager} for how to get the subscription ID.
     * @param saveHttpHistory set to {@code true} to save the history of request and response which
     *     can later be retrieved by {@code getHistory()}. Intended for debugging.
     */
    public ServiceEntitlement(
            Context context,
            CarrierConfig carrierConfig,
            int simSubscriptionId,
            boolean saveHttpHistory) {
        this(
                context,
                carrierConfig,
                simSubscriptionId,
                saveHttpHistory,
                /* bypassEapAkaResponse= */ "");
    }

    /**
     * Creates an instance for service entitlement configuration query and operation for the
     * carrier.
     *
     * @param context context of application
     * @param carrierConfig carrier specific configs used in the queries and operations.
     * @param simSubscriptionId the subscription ID of the carrier's SIM on device. This indicates
     *     which SIM to retrieve IMEI/IMSI from and perform EAP-AKA authentication with. See {@link
     *     android.telephony.SubscriptionManager} for how to get the subscription ID.
     * @param saveHttpHistory set to {@code true} to save the history of request and response which
     *     can later be retrieved by {@code getHistory()}. Intended for debugging.
     * @param bypassEapAkaResponse set to non empty string to bypass EAP-AKA authentication.
     *     The client will accept any challenge from the server and return this string as a
     *     response. Must not be {@code null}. Intended for testing.
     */
    public ServiceEntitlement(
            Context context,
            CarrierConfig carrierConfig,
            int simSubscriptionId,
            boolean saveHttpHistory,
            String bypassEapAkaResponse) {
        this.carrierConfig = carrierConfig;
        this.eapAkaApi =
                new EapAkaApi(context, simSubscriptionId, saveHttpHistory, bypassEapAkaResponse);
    }

    @VisibleForTesting
    ServiceEntitlement(CarrierConfig carrierConfig, EapAkaApi eapAkaApi) {
        this.carrierConfig = carrierConfig;
        this.eapAkaApi = eapAkaApi;
    }

    /**
     * Retrieves service entitlement configuration. For on device service activation (ODSA) of eSIM
     * for companion/primary devices, use {@link #performEsimOdsa} instead.
     *
     * <p>Supported {@code appId}: {@link #APP_VOLTE}, {@link #APP_VOWIFI}, {@link #APP_SMSOIP}.
     *
     * <p>This method sends an HTTP GET request to entitlement server, responds to EAP-AKA
     * challenge if needed, and returns the raw configuration doc as a string. The following
     * parameters are set in the HTTP request:
     *
     * <ul>
     * <li>"app": {@code appId}
     * <li>"vers": 0, or {@code request.configurationVersion()} if it's not 0.
     * <li>"entitlement_version": "2.0", or {@code request.entitlementVersion()} if it's not empty.
     * <li>"token": not set, or {@code request.authenticationToken()} if it's not empty.
     * <li>"IMSI": if "token" is set, set to {@link android.telephony.TelephonyManager#getImei}.
     * <li>"EAP_ID": if "token" is not set, set this parameter to trigger embedded EAP-AKA
     * authentication as described in TS.43 section 2.6.1. Its value is derived from IMSI as per
     * GSMA spec RCC.14 section C.2.
     * <li>"terminal_id": IMEI, or {@code request.terminalId()} if it's not empty.
     * <li>"terminal_vendor": {@link android.os.Build#MANUFACTURER}, or {@code
     * request.terminalVendor()} if it's not empty.
     * <li>"terminal_model": {@link android.os.Build#MODEL}, or {@code request.terminalModel()} if
     * it's not empty.
     * <li>"terminal_sw_version": {@link android.os.Build.VERSION#BASE_OS}, or {@code
     * request.terminalSoftwareVersion()} if it's not empty.
     * <li>"app_name": not set, or {@code request.appName()} if it's not empty.
     * <li>"app_version": not set, or {@code request.appVersion()} if it's not empty.
     * <li>"notif_token": not set, or {@code request.notificationToken()} if it's not empty.
     * <li>"notif_action": {@code request.notificationAction()} if "notif_token" is set, otherwise
     * not set.
     * </ul>
     *
     * <p>Requires permission: READ_PRIVILEGED_PHONE_STATE, or carrier privilege.
     *
     * @param appId   an app ID string defined in TS.43 section 2.2, e.g. {@link #APP_VOWIFI}.
     * @param request contains parameters that can be used in the HTTP request.
     */
    @NonNull
    public String queryEntitlementStatus(String appId, ServiceEntitlementRequest request)
            throws ServiceEntitlementException {
        return queryEntitlementStatus(ImmutableList.of(appId), request);
    }

    /**
     * Retrieves service entitlement configurations for multiple app IDs in one HTTP
     * request/response. For on device service activation (ODSA) of eSIM for companion/primary
     * devices, use {@link #performEsimOdsa} instead.
     *
     * <p>Same as {@link #queryEntitlementStatus(String, ServiceEntitlementRequest)} except that
     * multiple "app" parameters will be set in the HTTP request, in the order as they appear in
     * parameter {@code appIds}.
     */
    @NonNull
    public String queryEntitlementStatus(ImmutableList<String> appIds,
            ServiceEntitlementRequest request)
            throws ServiceEntitlementException {
        return getEntitlementStatusResponse(appIds, request).body();
    }

    /**
     * Retrieves service entitlement configurations for multiple app IDs in one HTTP
     * request/response. For on device service activation (ODSA) of eSIM for companion/primary
     * devices, use {@link #performEsimOdsa} instead.
     *
     * <p>Same as {@link #queryEntitlementStatus(ImmutableList, ServiceEntitlementRequest)}
     * except that it returns the full HTTP response instead of just the body.
     */
    @NonNull
    public HttpResponse getEntitlementStatusResponse(ImmutableList<String> appIds,
            ServiceEntitlementRequest request)
            throws ServiceEntitlementException {
        return eapAkaApi.queryEntitlementStatus(appIds, carrierConfig, request);
    }

    /**
     * Performs on device service activation (ODSA) of eSIM for companion/primary devices.
     *
     * <p>Supported {@code appId}: {@link #APP_ODSA_COMPANION}, {@link #APP_ODSA_PRIMARY}.
     *
     * <p>Similar to {@link #queryEntitlementStatus(String, ServiceEntitlementRequest)}, this
     * method sends an HTTP GET request to entitlement server, responds to EAP-AKA challenge if
     * needed, and returns the raw configuration doc as a string. Additional parameters from {@code
     * operation} are set to the HTTP request. See {@link EsimOdsaOperation} for details.
     */
    @NonNull
    public String performEsimOdsa(
            String appId, ServiceEntitlementRequest request, EsimOdsaOperation operation)
            throws ServiceEntitlementException {
        return getEsimOdsaResponse(appId, request, operation).body();
    }

    /**
     * Retrieves the HTTP response after performing on device service activation (ODSA) of eSIM for
     * companion/primary devices.
     *
     * <p>Same as {@link #performEsimOdsa(String, ServiceEntitlementRequest, EsimOdsaOperation)}
     * except that it returns the full HTTP response instead of just the body.
     */
    @NonNull
    public HttpResponse getEsimOdsaResponse(
            String appId, ServiceEntitlementRequest request, EsimOdsaOperation operation)
            throws ServiceEntitlementException {
        return eapAkaApi.performEsimOdsaOperation(appId, carrierConfig, request, operation);
    }

    /**
     * Retrieves the endpoint for OpenID Connect(OIDC) authentication.
     *
     * <p>Implementation based on section 2.8.2 of TS.43
     *
     * <p>The user should call {@link #queryEntitlementStatusFromOidc(String url)} with the
     * authentication result to retrieve the service entitlement configuration.
     *
     * @param appId an app ID string defined in TS.43 section 2.2
     * @param request contains parameters that can be used in the HTTP request
     */
    @NonNull
    public String acquireOidcAuthenticationEndpoint(String appId, ServiceEntitlementRequest request)
            throws ServiceEntitlementException {
        mOidcAcceptContentType = request.acceptContentType();
        return eapAkaApi.acquireOidcAuthenticationEndpoint(appId, carrierConfig, request);
    }

    /**
     * Retrieves the service entitlement configuration from OIDC authentication result.
     *
     * <p>Implementation based on section 2.8.2 of TS.43.
     *
     * <p>{@link #acquireOidcAuthenticationEndpoint} must be called before calling this method.
     *
     * @param url the redirect url from OIDC authentication result.
     */
    @NonNull
    public String queryEntitlementStatusFromOidc(String url) throws ServiceEntitlementException {
        return getEntitlementStatusResponseFromOidc(url).body();
    }

    /**
     * Retrieves the HTTP response containing the service entitlement configuration from
     * OIDC authentication result.
     *
     * <p>Same as {@link #queryEntitlementStatusFromOidc(String)} except that it returns the
     * full HTTP response instead of just the body.
     *
     * @param url the redirect url from OIDC authentication result.
     */
    @NonNull
    public HttpResponse getEntitlementStatusResponseFromOidc(String url)
            throws ServiceEntitlementException {
        return eapAkaApi.queryEntitlementStatusFromOidc(url, carrierConfig, mOidcAcceptContentType);
    }

    /**
     * Retrieves the history of past HTTP request and responses if {@code saveHttpHistory} was set
     * in constructor.
     */
    @NonNull
    public List<String> getHistory() {
        return eapAkaApi.getHistory();
    }

    /**
     * Clears the history of past HTTP request and responses.
     */
    public void clearHistory() {
        eapAkaApi.clearHistory();
    }
}