1/*
2 * Copyright (C) 2017 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 com.android.server.wifi.hotspot2;
18
19import static org.junit.Assert.*;
20import static org.mockito.Mockito.*;
21
22import android.net.wifi.hotspot2.PasspointConfiguration;
23import android.net.wifi.hotspot2.pps.Credential;
24import android.net.wifi.hotspot2.pps.HomeSp;
25import android.net.wifi.hotspot2.pps.Policy;
26import android.net.wifi.hotspot2.pps.UpdateParameter;
27import android.test.suitebuilder.annotation.SmallTest;
28import android.util.Xml;
29
30import com.android.internal.util.FastXmlSerializer;
31
32import org.junit.Test;
33import org.xmlpull.v1.XmlPullParser;
34import org.xmlpull.v1.XmlPullParserException;
35import org.xmlpull.v1.XmlSerializer;
36
37import java.io.ByteArrayInputStream;
38import java.io.ByteArrayOutputStream;
39import java.nio.charset.StandardCharsets;
40import java.text.DateFormat;
41import java.text.SimpleDateFormat;
42import java.util.ArrayList;
43import java.util.Arrays;
44import java.util.HashMap;
45import java.util.List;
46import java.util.Map;
47
48/**
49 * Unit tests for {@link com.android.server.wifi.hotspot2.PasspointXmlUtilsTest}.
50 */
51@SmallTest
52public class PasspointXmlUtilsTest {
53
54    /**
55     * Helper function for generating a {@link PasspointConfiguration} for testing the XML
56     * serialization/deserialization logic.
57     *
58     * @return {@link PasspointConfiguration}
59     * @throws Exception
60     */
61    private PasspointConfiguration createFullPasspointConfiguration() throws Exception {
62        DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
63        byte[] certFingerprint = new byte[32];
64        Arrays.fill(certFingerprint, (byte) 0x1f);
65
66        PasspointConfiguration config = new PasspointConfiguration();
67        config.setUpdateIdentifier(12);
68        config.setCredentialPriority(99);
69
70        // AAA Server trust root.
71        Map<String, byte[]> trustRootCertList = new HashMap<>();
72        trustRootCertList.put("server1.trust.root.com", certFingerprint);
73        config.setTrustRootCertList(trustRootCertList);
74
75        // Subscription update.
76        UpdateParameter subscriptionUpdate = new UpdateParameter();
77        subscriptionUpdate.setUpdateIntervalInMinutes(120);
78        subscriptionUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_SSP);
79        subscriptionUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_ROAMING_PARTNER);
80        subscriptionUpdate.setServerUri("subscription.update.com");
81        subscriptionUpdate.setUsername("subscriptionUser");
82        subscriptionUpdate.setBase64EncodedPassword("subscriptionPass");
83        subscriptionUpdate.setTrustRootCertUrl("subscription.update.cert.com");
84        subscriptionUpdate.setTrustRootCertSha256Fingerprint(certFingerprint);
85        config.setSubscriptionUpdate(subscriptionUpdate);
86
87        // Subscription parameters.
88        config.setSubscriptionCreationTimeInMillis(format.parse("2016-02-01T10:00:00Z").getTime());
89        config.setSubscriptionExpirationTimeInMillis(
90                format.parse("2016-03-01T10:00:00Z").getTime());
91        config.setSubscriptionType("Gold");
92        config.setUsageLimitDataLimit(921890);
93        config.setUsageLimitStartTimeInMillis(format.parse("2016-12-01T10:00:00Z").getTime());
94        config.setUsageLimitTimeLimitInMinutes(120);
95        config.setUsageLimitUsageTimePeriodInMinutes(99910);
96
97        // HomeSP configuration.
98        HomeSp homeSp = new HomeSp();
99        homeSp.setFriendlyName("Century House");
100        homeSp.setFqdn("mi6.co.uk");
101        homeSp.setRoamingConsortiumOis(new long[] {0x112233L, 0x445566L});
102        homeSp.setIconUrl("icon.test.com");
103        Map<String, Long> homeNetworkIds = new HashMap<>();
104        homeNetworkIds.put("TestSSID", 0x12345678L);
105        homeNetworkIds.put("NullHESSID", null);
106        homeSp.setHomeNetworkIds(homeNetworkIds);
107        homeSp.setMatchAllOis(new long[] {0x11223344});
108        homeSp.setMatchAnyOis(new long[] {0x55667788});
109        homeSp.setOtherHomePartners(new String[] {"other.fqdn.com"});
110        config.setHomeSp(homeSp);
111
112        // Credential configuration.
113        Credential credential = new Credential();
114        credential.setCreationTimeInMillis(format.parse("2016-01-01T10:00:00Z").getTime());
115        credential.setExpirationTimeInMillis(format.parse("2016-02-01T10:00:00Z").getTime());
116        credential.setRealm("shaken.stirred.com");
117        credential.setCheckAaaServerCertStatus(true);
118        Credential.UserCredential userCredential = new Credential.UserCredential();
119        userCredential.setUsername("james");
120        userCredential.setPassword("Ym9uZDAwNw==");
121        userCredential.setMachineManaged(true);
122        userCredential.setSoftTokenApp("TestApp");
123        userCredential.setAbleToShare(true);
124        userCredential.setEapType(21);
125        userCredential.setNonEapInnerMethod("MS-CHAP-V2");
126        credential.setUserCredential(userCredential);
127        Credential.CertificateCredential certCredential = new Credential.CertificateCredential();
128        certCredential.setCertType("x509v3");
129        certCredential.setCertSha256Fingerprint(certFingerprint);
130        credential.setCertCredential(certCredential);
131        Credential.SimCredential simCredential = new Credential.SimCredential();
132        simCredential.setImsi("imsi");
133        simCredential.setEapType(24);
134        credential.setSimCredential(simCredential);
135        config.setCredential(credential);
136
137        // Policy configuration.
138        Policy policy = new Policy();
139        List<Policy.RoamingPartner> preferredRoamingPartnerList = new ArrayList<>();
140        Policy.RoamingPartner partner1 = new Policy.RoamingPartner();
141        partner1.setFqdn("test1.fqdn.com");
142        partner1.setFqdnExactMatch(true);
143        partner1.setPriority(127);
144        partner1.setCountries("us,fr");
145        Policy.RoamingPartner partner2 = new Policy.RoamingPartner();
146        partner2.setFqdn("test2.fqdn.com");
147        partner2.setFqdnExactMatch(false);
148        partner2.setPriority(200);
149        partner2.setCountries("*");
150        preferredRoamingPartnerList.add(partner1);
151        preferredRoamingPartnerList.add(partner2);
152        policy.setPreferredRoamingPartnerList(preferredRoamingPartnerList);
153        policy.setMinHomeDownlinkBandwidth(23412);
154        policy.setMinHomeUplinkBandwidth(9823);
155        policy.setMinRoamingDownlinkBandwidth(9271);
156        policy.setMinRoamingUplinkBandwidth(2315);
157        policy.setExcludedSsidList(new String[] {"excludeSSID"});
158        Map<Integer, String> requiredProtoPortMap = new HashMap<>();
159        requiredProtoPortMap.put(12, "34,92,234");
160        policy.setRequiredProtoPortMap(requiredProtoPortMap);
161        policy.setMaximumBssLoadValue(23);
162        UpdateParameter policyUpdate = new UpdateParameter();
163        policyUpdate.setUpdateIntervalInMinutes(120);
164        policyUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_OMADM);
165        policyUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_HOMESP);
166        policyUpdate.setServerUri("policy.update.com");
167        policyUpdate.setUsername("updateUser");
168        policyUpdate.setBase64EncodedPassword("updatePass");
169        policyUpdate.setTrustRootCertUrl("update.cert.com");
170        policyUpdate.setTrustRootCertSha256Fingerprint(certFingerprint);
171        policy.setPolicyUpdate(policyUpdate);
172        config.setPolicy(policy);
173        return config;
174    }
175
176    /**
177     * Verify the serialization and deserialization logic of a {@link PasspointConfiguration}.
178     *
179     * 1. Serialize the test config to a XML block
180     * 2. Deserialize the XML block to a {@link PasspointConfiguration}
181     * 3. Verify that the deserialized config is the same as the test config
182     *
183     * @param testConfig The configuration to used for testing
184     * @throws Exception
185     */
186    private void serializeAndDeserializePasspointConfiguration(PasspointConfiguration testConfig)
187            throws Exception {
188        final XmlSerializer out = new FastXmlSerializer();
189        final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
190        out.setOutput(outputStream, StandardCharsets.UTF_8.name());
191        PasspointXmlUtils.serializePasspointConfiguration(out, testConfig);
192        out.flush();
193
194        final XmlPullParser in = Xml.newPullParser();
195        final ByteArrayInputStream inputStream =
196                new ByteArrayInputStream(outputStream.toByteArray());
197        in.setInput(inputStream, StandardCharsets.UTF_8.name());
198
199        PasspointConfiguration deserializedConfig =
200                PasspointXmlUtils.deserializePasspointConfiguration(in, in.getDepth());
201        assertEquals(testConfig, deserializedConfig);
202    }
203
204    /**
205     * Verify that the serialization and deserialization logic for a full
206     * {@link PasspointConfiguration} (all fields are set) works as expected.
207     *
208     * @throws Exception
209     */
210    @Test
211    public void serializeAndDeserializeFullPasspointConfiguration() throws Exception {
212        serializeAndDeserializePasspointConfiguration(createFullPasspointConfiguration());
213    }
214
215    /**
216     * Verify that the serialization and deserialization logic for an empty
217     * {@link PasspointConfiguration} works as expected.
218     *
219     * @throws Exception
220     */
221    @Test
222    public void serializeAndDeserializeEmptyPasspointConfiguration() throws Exception {
223        serializeAndDeserializePasspointConfiguration(new PasspointConfiguration());
224    }
225
226    /**
227     * Verify that a XmlPullParserException will be thrown when deserialize a XML block
228     * for a PasspointConfiguraiton containing an unknown tag.
229     *
230     * @throws Exception
231     */
232    @Test(expected = XmlPullParserException.class)
233    public void deserializePasspointConfigurationWithUnknownTag() throws Exception {
234        String xmlStr = "<UnknownTag>\n"
235                + "</UnknownTag>\n";
236        final XmlPullParser in = Xml.newPullParser();
237        final ByteArrayInputStream inputStream =
238                new ByteArrayInputStream(xmlStr.getBytes(StandardCharsets.UTF_8));
239        in.setInput(inputStream, StandardCharsets.UTF_8.name());
240        PasspointXmlUtils.deserializePasspointConfiguration(in, in.getDepth());
241    }
242}
243