1/*
2 * Copyright (C) 2016 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
17package android.net.wifi.hotspot2.omadm;
18
19import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertTrue;
21
22import android.net.wifi.hotspot2.omadm.PpsMoParser;
23import android.net.wifi.hotspot2.PasspointConfiguration;
24import android.net.wifi.hotspot2.pps.Credential;
25import android.net.wifi.hotspot2.pps.HomeSp;
26import android.net.wifi.hotspot2.pps.Policy;
27import android.net.wifi.hotspot2.pps.UpdateParameter;
28import android.support.test.filters.SmallTest;
29import android.text.TextUtils;
30
31import org.junit.Test;
32
33import java.io.BufferedReader;
34import java.io.IOException;
35import java.io.InputStream;
36import java.io.InputStreamReader;
37import java.text.DateFormat;
38import java.text.SimpleDateFormat;
39import java.util.ArrayList;
40import java.util.Arrays;
41import java.util.HashMap;
42import java.util.List;
43import java.util.Map;
44
45/**
46 * Unit tests for {@link android.net.wifi.hotspot2.omadm.PpsMoParser}.
47 */
48@SmallTest
49public class PpsMoParserTest {
50    private static final String VALID_PPS_MO_XML_FILE = "assets/pps/PerProviderSubscription.xml";
51    private static final String PPS_MO_XML_FILE_DUPLICATE_HOMESP =
52            "assets/pps/PerProviderSubscription_DuplicateHomeSP.xml";
53    private static final String PPS_MO_XML_FILE_DUPLICATE_VALUE =
54            "assets/pps/PerProviderSubscription_DuplicateValue.xml";
55    private static final String PPS_MO_XML_FILE_MISSING_VALUE =
56            "assets/pps/PerProviderSubscription_MissingValue.xml";
57    private static final String PPS_MO_XML_FILE_MISSING_NAME =
58            "assets/pps/PerProviderSubscription_MissingName.xml";
59    private static final String PPS_MO_XML_FILE_INVALID_NODE =
60            "assets/pps/PerProviderSubscription_InvalidNode.xml";
61    private static final String PPS_MO_XML_FILE_INVALID_NAME =
62            "assets/pps/PerProviderSubscription_InvalidName.xml";
63
64    /**
65     * Read the content of the given resource file into a String.
66     *
67     * @param filename String name of the file
68     * @return String
69     * @throws IOException
70     */
71    private String loadResourceFile(String filename) throws IOException {
72        InputStream in = getClass().getClassLoader().getResourceAsStream(filename);
73        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
74        StringBuilder builder = new StringBuilder();
75        String line;
76        while ((line = reader.readLine()) != null) {
77            builder.append(line).append("\n");
78        }
79
80        return builder.toString();
81    }
82
83    /**
84     * Generate a {@link PasspointConfiguration} that matches the configuration specified in the
85     * XML file {@link #VALID_PPS_MO_XML_FILE}.
86     *
87     * @return {@link PasspointConfiguration}
88     */
89    private PasspointConfiguration generateConfigurationFromPPSMOTree() throws Exception {
90        DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
91        byte[] certFingerprint = new byte[32];
92        Arrays.fill(certFingerprint, (byte) 0x1f);
93
94        PasspointConfiguration config = new PasspointConfiguration();
95        config.setUpdateIdentifier(12);
96        config.setCredentialPriority(99);
97
98        // AAA Server trust root.
99        Map<String, byte[]> trustRootCertList = new HashMap<>();
100        trustRootCertList.put("server1.trust.root.com", certFingerprint);
101        config.setTrustRootCertList(trustRootCertList);
102
103        // Subscription update.
104        UpdateParameter subscriptionUpdate = new UpdateParameter();
105        subscriptionUpdate.setUpdateIntervalInMinutes(120);
106        subscriptionUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_SSP);
107        subscriptionUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_ROAMING_PARTNER);
108        subscriptionUpdate.setServerUri("subscription.update.com");
109        subscriptionUpdate.setUsername("subscriptionUser");
110        subscriptionUpdate.setBase64EncodedPassword("subscriptionPass");
111        subscriptionUpdate.setTrustRootCertUrl("subscription.update.cert.com");
112        subscriptionUpdate.setTrustRootCertSha256Fingerprint(certFingerprint);
113        config.setSubscriptionUpdate(subscriptionUpdate);
114
115        // Subscription parameters.
116        config.setSubscriptionCreationTimeInMillis(format.parse("2016-02-01T10:00:00Z").getTime());
117        config.setSubscriptionExpirationTimeInMillis(format.parse("2016-03-01T10:00:00Z").getTime());
118        config.setSubscriptionType("Gold");
119        config.setUsageLimitDataLimit(921890);
120        config.setUsageLimitStartTimeInMillis(format.parse("2016-12-01T10:00:00Z").getTime());
121        config.setUsageLimitTimeLimitInMinutes(120);
122        config.setUsageLimitUsageTimePeriodInMinutes(99910);
123
124        // HomeSP configuration.
125        HomeSp homeSp = new HomeSp();
126        homeSp.setFriendlyName("Century House");
127        homeSp.setFqdn("mi6.co.uk");
128        homeSp.setRoamingConsortiumOis(new long[] {0x112233L, 0x445566L});
129        homeSp.setIconUrl("icon.test.com");
130        Map<String, Long> homeNetworkIds = new HashMap<>();
131        homeNetworkIds.put("TestSSID", 0x12345678L);
132        homeNetworkIds.put("NullHESSID", null);
133        homeSp.setHomeNetworkIds(homeNetworkIds);
134        homeSp.setMatchAllOis(new long[] {0x11223344});
135        homeSp.setMatchAnyOis(new long[] {0x55667788});
136        homeSp.setOtherHomePartners(new String[] {"other.fqdn.com"});
137        config.setHomeSp(homeSp);
138
139        // Credential configuration.
140        Credential credential = new Credential();
141        credential.setCreationTimeInMillis(format.parse("2016-01-01T10:00:00Z").getTime());
142        credential.setExpirationTimeInMillis(format.parse("2016-02-01T10:00:00Z").getTime());
143        credential.setRealm("shaken.stirred.com");
144        credential.setCheckAaaServerCertStatus(true);
145        Credential.UserCredential userCredential = new Credential.UserCredential();
146        userCredential.setUsername("james");
147        userCredential.setPassword("Ym9uZDAwNw==");
148        userCredential.setMachineManaged(true);
149        userCredential.setSoftTokenApp("TestApp");
150        userCredential.setAbleToShare(true);
151        userCredential.setEapType(21);
152        userCredential.setNonEapInnerMethod("MS-CHAP-V2");
153        credential.setUserCredential(userCredential);
154        Credential.CertificateCredential certCredential = new Credential.CertificateCredential();
155        certCredential.setCertType("x509v3");
156        certCredential.setCertSha256Fingerprint(certFingerprint);
157        credential.setCertCredential(certCredential);
158        Credential.SimCredential simCredential = new Credential.SimCredential();
159        simCredential.setImsi("imsi");
160        simCredential.setEapType(24);
161        credential.setSimCredential(simCredential);
162        config.setCredential(credential);
163
164        // Policy configuration.
165        Policy policy = new Policy();
166        List<Policy.RoamingPartner> preferredRoamingPartnerList = new ArrayList<>();
167        Policy.RoamingPartner partner1 = new Policy.RoamingPartner();
168        partner1.setFqdn("test1.fqdn.com");
169        partner1.setFqdnExactMatch(true);
170        partner1.setPriority(127);
171        partner1.setCountries("us,fr");
172        Policy.RoamingPartner partner2 = new Policy.RoamingPartner();
173        partner2.setFqdn("test2.fqdn.com");
174        partner2.setFqdnExactMatch(false);
175        partner2.setPriority(200);
176        partner2.setCountries("*");
177        preferredRoamingPartnerList.add(partner1);
178        preferredRoamingPartnerList.add(partner2);
179        policy.setPreferredRoamingPartnerList(preferredRoamingPartnerList);
180        policy.setMinHomeDownlinkBandwidth(23412);
181        policy.setMinHomeUplinkBandwidth(9823);
182        policy.setMinRoamingDownlinkBandwidth(9271);
183        policy.setMinRoamingUplinkBandwidth(2315);
184        policy.setExcludedSsidList(new String[] {"excludeSSID"});
185        Map<Integer, String> requiredProtoPortMap = new HashMap<>();
186        requiredProtoPortMap.put(12, "34,92,234");
187        policy.setRequiredProtoPortMap(requiredProtoPortMap);
188        policy.setMaximumBssLoadValue(23);
189        UpdateParameter policyUpdate = new UpdateParameter();
190        policyUpdate.setUpdateIntervalInMinutes(120);
191        policyUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_OMADM);
192        policyUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_HOMESP);
193        policyUpdate.setServerUri("policy.update.com");
194        policyUpdate.setUsername("updateUser");
195        policyUpdate.setBase64EncodedPassword("updatePass");
196        policyUpdate.setTrustRootCertUrl("update.cert.com");
197        policyUpdate.setTrustRootCertSha256Fingerprint(certFingerprint);
198        policy.setPolicyUpdate(policyUpdate);
199        config.setPolicy(policy);
200        return config;
201    }
202
203    /**
204     * Parse and verify all supported fields under PPS MO tree.
205     *
206     * @throws Exception
207     */
208    @Test
209    public void parseValidPPSMOTree() throws Exception {
210        String ppsMoTree = loadResourceFile(VALID_PPS_MO_XML_FILE);
211        PasspointConfiguration expectedConfig = generateConfigurationFromPPSMOTree();
212        PasspointConfiguration actualConfig = PpsMoParser.parseMoText(ppsMoTree);
213        assertTrue(actualConfig.equals(expectedConfig));
214    }
215
216    @Test
217    public void parseNullPPSMOTree() throws Exception {
218        assertEquals(null, PpsMoParser.parseMoText(null));
219    }
220
221    @Test
222    public void parseEmptyPPSMOTree() throws Exception {
223        assertEquals(null, PpsMoParser.parseMoText(new String()));
224    }
225
226    @Test
227    public void parsePPSMOTreeWithDuplicateHomeSP() throws Exception {
228        assertEquals(null, PpsMoParser.parseMoText(
229                loadResourceFile(PPS_MO_XML_FILE_DUPLICATE_HOMESP)));
230    }
231
232    @Test
233    public void parsePPSMOTreeWithDuplicateValue() throws Exception {
234        assertEquals(null, PpsMoParser.parseMoText(
235                loadResourceFile(PPS_MO_XML_FILE_DUPLICATE_VALUE)));
236    }
237
238    @Test
239    public void parsePPSMOTreeWithMissingValue() throws Exception {
240        assertEquals(null, PpsMoParser.parseMoText(
241                loadResourceFile(PPS_MO_XML_FILE_MISSING_VALUE)));
242    }
243
244    @Test
245    public void parsePPSMOTreeWithMissingName() throws Exception {
246        assertEquals(null, PpsMoParser.parseMoText(
247                loadResourceFile(PPS_MO_XML_FILE_MISSING_NAME)));
248    }
249
250    @Test
251    public void parsePPSMOTreeWithInvalidNode() throws Exception {
252        assertEquals(null, PpsMoParser.parseMoText(
253                loadResourceFile(PPS_MO_XML_FILE_INVALID_NODE)));
254    }
255
256    @Test
257    public void parsePPSMOTreeWithInvalidName() throws Exception {
258        assertEquals(null, PpsMoParser.parseMoText(
259                loadResourceFile(PPS_MO_XML_FILE_INVALID_NAME)));
260    }
261}
262