Home | History | Annotate | Download | only in config
      1 /*
      2  * Copyright (C) 2015 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 android.security.net.config;
     18 
     19 import android.content.Context;
     20 import android.content.pm.ApplicationInfo;
     21 import android.test.AndroidTestCase;
     22 import android.test.MoreAsserts;
     23 import android.util.ArraySet;
     24 import android.util.Pair;
     25 import java.io.IOException;
     26 import java.net.InetAddress;
     27 import java.net.Socket;
     28 import java.net.URL;
     29 import java.security.KeyStore;
     30 import java.security.Provider;
     31 import java.security.Security;
     32 import java.security.cert.X509Certificate;
     33 import java.util.ArrayList;
     34 import java.util.Collections;
     35 import java.util.Set;
     36 import javax.net.ssl.HttpsURLConnection;
     37 import javax.net.ssl.SSLContext;
     38 import javax.net.ssl.SSLHandshakeException;
     39 import javax.net.ssl.SSLSocket;
     40 import javax.net.ssl.TrustManager;
     41 import javax.net.ssl.TrustManagerFactory;
     42 
     43 public class XmlConfigTests extends AndroidTestCase {
     44 
     45     private final static String DEBUG_CA_SUBJ = "O=AOSP, CN=Test debug CA";
     46 
     47     public void testEmptyConfigFile() throws Exception {
     48         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.empty_config,
     49                 TestUtils.makeApplicationInfo());
     50         ApplicationConfig appConfig = new ApplicationConfig(source);
     51         assertFalse(appConfig.hasPerDomainConfigs());
     52         NetworkSecurityConfig config = appConfig.getConfigForHostname("");
     53         assertNotNull(config);
     54         // Check defaults.
     55         assertTrue(config.isCleartextTrafficPermitted());
     56         assertFalse(config.isHstsEnforced());
     57         assertFalse(config.getTrustAnchors().isEmpty());
     58         PinSet pinSet = config.getPins();
     59         assertTrue(pinSet.pins.isEmpty());
     60         // Try some connections.
     61         SSLContext context = TestUtils.getSSLContext(source);
     62         TestUtils.assertConnectionSucceeds(context, "android.com", 443);
     63         TestUtils.assertConnectionSucceeds(context, "developer.android.com", 443);
     64         TestUtils.assertUrlConnectionSucceeds(context, "google.com", 443);
     65     }
     66 
     67     public void testEmptyAnchors() throws Exception {
     68         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.empty_trust,
     69                 TestUtils.makeApplicationInfo());
     70         ApplicationConfig appConfig = new ApplicationConfig(source);
     71         assertFalse(appConfig.hasPerDomainConfigs());
     72         NetworkSecurityConfig config = appConfig.getConfigForHostname("");
     73         assertNotNull(config);
     74         // Check defaults.
     75         assertTrue(config.isCleartextTrafficPermitted());
     76         assertFalse(config.isHstsEnforced());
     77         assertTrue(config.getTrustAnchors().isEmpty());
     78         PinSet pinSet = config.getPins();
     79         assertTrue(pinSet.pins.isEmpty());
     80         SSLContext context = TestUtils.getSSLContext(source);
     81         TestUtils.assertConnectionFails(context, "android.com", 443);
     82         TestUtils.assertConnectionFails(context, "developer.android.com", 443);
     83         TestUtils.assertUrlConnectionFails(context, "google.com", 443);
     84     }
     85 
     86     public void testBasicDomainConfig() throws Exception {
     87         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.domain1,
     88                 TestUtils.makeApplicationInfo());
     89         ApplicationConfig appConfig = new ApplicationConfig(source);
     90         assertTrue(appConfig.hasPerDomainConfigs());
     91         NetworkSecurityConfig config = appConfig.getConfigForHostname("");
     92         assertNotNull(config);
     93         // Check defaults.
     94         assertTrue(config.isCleartextTrafficPermitted());
     95         assertFalse(config.isHstsEnforced());
     96         assertTrue(config.getTrustAnchors().isEmpty());
     97         PinSet pinSet = config.getPins();
     98         assertTrue(pinSet.pins.isEmpty());
     99         // Check android.com.
    100         config = appConfig.getConfigForHostname("android.com");
    101         assertTrue(config.isCleartextTrafficPermitted());
    102         assertFalse(config.isHstsEnforced());
    103         assertFalse(config.getTrustAnchors().isEmpty());
    104         pinSet = config.getPins();
    105         assertTrue(pinSet.pins.isEmpty());
    106         // Try connections.
    107         SSLContext context = TestUtils.getSSLContext(source);
    108         TestUtils.assertConnectionSucceeds(context, "android.com", 443);
    109         TestUtils.assertConnectionFails(context, "developer.android.com", 443);
    110         TestUtils.assertUrlConnectionFails(context, "google.com", 443);
    111         TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443);
    112         // Check that sockets created without the hostname fail with per-domain configs
    113         SSLSocket socket = (SSLSocket) context.getSocketFactory()
    114                 .createSocket(InetAddress.getByName("android.com"), 443);
    115         try {
    116         socket.startHandshake();
    117         socket.getInputStream();
    118         fail();
    119         } catch (IOException expected) {
    120         }
    121     }
    122 
    123     public void testBasicPinning() throws Exception {
    124         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.pins1,
    125                 TestUtils.makeApplicationInfo());
    126         ApplicationConfig appConfig = new ApplicationConfig(source);
    127         assertTrue(appConfig.hasPerDomainConfigs());
    128         // Check android.com.
    129         NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
    130         PinSet pinSet = config.getPins();
    131         assertFalse(pinSet.pins.isEmpty());
    132         // Try connections.
    133         SSLContext context = TestUtils.getSSLContext(source);
    134         TestUtils.assertConnectionSucceeds(context, "android.com", 443);
    135         TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443);
    136         TestUtils.assertConnectionSucceeds(context, "google.com", 443);
    137     }
    138 
    139     public void testExpiredPin() throws Exception {
    140         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.expired_pin,
    141                 TestUtils.makeApplicationInfo());
    142         ApplicationConfig appConfig = new ApplicationConfig(source);
    143         assertTrue(appConfig.hasPerDomainConfigs());
    144         // Check android.com.
    145         NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
    146         PinSet pinSet = config.getPins();
    147         assertFalse(pinSet.pins.isEmpty());
    148         // Try connections.
    149         SSLContext context = TestUtils.getSSLContext(source);
    150         TestUtils.assertConnectionSucceeds(context, "android.com", 443);
    151         TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443);
    152     }
    153 
    154     public void testOverridesPins() throws Exception {
    155         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.override_pins,
    156                 TestUtils.makeApplicationInfo());
    157         ApplicationConfig appConfig = new ApplicationConfig(source);
    158         assertTrue(appConfig.hasPerDomainConfigs());
    159         // Check android.com.
    160         NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
    161         PinSet pinSet = config.getPins();
    162         assertFalse(pinSet.pins.isEmpty());
    163         // Try connections.
    164         SSLContext context = TestUtils.getSSLContext(source);
    165         TestUtils.assertConnectionSucceeds(context, "android.com", 443);
    166         TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443);
    167     }
    168 
    169     public void testBadPin() throws Exception {
    170         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.bad_pin,
    171                 TestUtils.makeApplicationInfo());
    172         ApplicationConfig appConfig = new ApplicationConfig(source);
    173         assertTrue(appConfig.hasPerDomainConfigs());
    174         // Check android.com.
    175         NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
    176         PinSet pinSet = config.getPins();
    177         assertFalse(pinSet.pins.isEmpty());
    178         // Try connections.
    179         SSLContext context = TestUtils.getSSLContext(source);
    180         TestUtils.assertConnectionFails(context, "android.com", 443);
    181         TestUtils.assertUrlConnectionFails(context, "android.com", 443);
    182         TestUtils.assertConnectionSucceeds(context, "google.com", 443);
    183     }
    184 
    185     public void testMultipleDomains() throws Exception {
    186         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.multiple_domains,
    187                 TestUtils.makeApplicationInfo());
    188         ApplicationConfig appConfig = new ApplicationConfig(source);
    189         assertTrue(appConfig.hasPerDomainConfigs());
    190         NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
    191         assertTrue(config.isCleartextTrafficPermitted());
    192         assertFalse(config.isHstsEnforced());
    193         assertFalse(config.getTrustAnchors().isEmpty());
    194         PinSet pinSet = config.getPins();
    195         assertTrue(pinSet.pins.isEmpty());
    196         // Both android.com and google.com should use the same config
    197         NetworkSecurityConfig other = appConfig.getConfigForHostname("google.com");
    198         assertEquals(config, other);
    199         // Try connections.
    200         SSLContext context = TestUtils.getSSLContext(source);
    201         TestUtils.assertConnectionSucceeds(context, "android.com", 443);
    202         TestUtils.assertConnectionSucceeds(context, "google.com", 443);
    203         TestUtils.assertConnectionFails(context, "developer.android.com", 443);
    204         TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443);
    205     }
    206 
    207     public void testMultipleDomainConfigs() throws Exception {
    208         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.multiple_configs,
    209                 TestUtils.makeApplicationInfo());
    210         ApplicationConfig appConfig = new ApplicationConfig(source);
    211         assertTrue(appConfig.hasPerDomainConfigs());
    212         // Should be two different config objects
    213         NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
    214         NetworkSecurityConfig other = appConfig.getConfigForHostname("google.com");
    215         MoreAsserts.assertNotEqual(config, other);
    216         // Try connections.
    217         SSLContext context = TestUtils.getSSLContext(source);
    218         TestUtils.assertConnectionSucceeds(context, "android.com", 443);
    219         TestUtils.assertConnectionSucceeds(context, "google.com", 443);
    220         TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443);
    221     }
    222 
    223     public void testIncludeSubdomains() throws Exception {
    224         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.subdomains,
    225                 TestUtils.makeApplicationInfo());
    226         ApplicationConfig appConfig = new ApplicationConfig(source);
    227         assertTrue(appConfig.hasPerDomainConfigs());
    228         // Try connections.
    229         SSLContext context = TestUtils.getSSLContext(source);
    230         TestUtils.assertConnectionSucceeds(context, "android.com", 443);
    231         TestUtils.assertConnectionSucceeds(context, "developer.android.com", 443);
    232         TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443);
    233         TestUtils.assertUrlConnectionSucceeds(context, "developer.android.com", 443);
    234         TestUtils.assertConnectionFails(context, "google.com", 443);
    235     }
    236 
    237     public void testAttributes() throws Exception {
    238         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.attributes,
    239                 TestUtils.makeApplicationInfo());
    240         ApplicationConfig appConfig = new ApplicationConfig(source);
    241         assertFalse(appConfig.hasPerDomainConfigs());
    242         NetworkSecurityConfig config = appConfig.getConfigForHostname("");
    243         assertTrue(config.isHstsEnforced());
    244         assertFalse(config.isCleartextTrafficPermitted());
    245     }
    246 
    247     public void testResourcePemCertificateSource() throws Exception {
    248         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.resource_anchors_pem,
    249                 TestUtils.makeApplicationInfo());
    250         ApplicationConfig appConfig = new ApplicationConfig(source);
    251         // Check android.com.
    252         NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
    253         assertTrue(config.isCleartextTrafficPermitted());
    254         assertFalse(config.isHstsEnforced());
    255         assertEquals(2, config.getTrustAnchors().size());
    256         // Try connections.
    257         SSLContext context = TestUtils.getSSLContext(source);
    258         TestUtils.assertConnectionSucceeds(context, "android.com", 443);
    259         TestUtils.assertConnectionFails(context, "developer.android.com", 443);
    260         TestUtils.assertUrlConnectionFails(context, "google.com", 443);
    261         TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443);
    262     }
    263 
    264     public void testResourceDerCertificateSource() throws Exception {
    265         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.resource_anchors_der,
    266                 TestUtils.makeApplicationInfo());
    267         ApplicationConfig appConfig = new ApplicationConfig(source);
    268         // Check android.com.
    269         NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
    270         assertTrue(config.isCleartextTrafficPermitted());
    271         assertFalse(config.isHstsEnforced());
    272         assertEquals(2, config.getTrustAnchors().size());
    273         // Try connections.
    274         SSLContext context = TestUtils.getSSLContext(source);
    275         TestUtils.assertConnectionSucceeds(context, "android.com", 443);
    276         TestUtils.assertConnectionFails(context, "developer.android.com", 443);
    277         TestUtils.assertUrlConnectionFails(context, "google.com", 443);
    278         TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443);
    279     }
    280 
    281     public void testNestedDomainConfigs() throws Exception {
    282         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.nested_domains,
    283                 TestUtils.makeApplicationInfo());
    284         ApplicationConfig appConfig = new ApplicationConfig(source);
    285         assertTrue(appConfig.hasPerDomainConfigs());
    286         NetworkSecurityConfig parent = appConfig.getConfigForHostname("android.com");
    287         NetworkSecurityConfig child = appConfig.getConfigForHostname("developer.android.com");
    288         MoreAsserts.assertNotEqual(parent, child);
    289         MoreAsserts.assertEmpty(parent.getPins().pins);
    290         MoreAsserts.assertNotEmpty(child.getPins().pins);
    291         // Check that the child inherited the cleartext value and anchors.
    292         assertFalse(child.isCleartextTrafficPermitted());
    293         MoreAsserts.assertNotEmpty(child.getTrustAnchors());
    294         // Test connections.
    295         SSLContext context = TestUtils.getSSLContext(source);
    296         TestUtils.assertConnectionSucceeds(context, "android.com", 443);
    297         TestUtils.assertConnectionSucceeds(context, "developer.android.com", 443);
    298     }
    299 
    300     public void testNestedDomainConfigsOverride() throws Exception {
    301         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.nested_domains_override,
    302                 TestUtils.makeApplicationInfo());
    303         ApplicationConfig appConfig = new ApplicationConfig(source);
    304         assertTrue(appConfig.hasPerDomainConfigs());
    305         NetworkSecurityConfig parent = appConfig.getConfigForHostname("android.com");
    306         NetworkSecurityConfig child = appConfig.getConfigForHostname("developer.android.com");
    307         MoreAsserts.assertNotEqual(parent, child);
    308         assertTrue(parent.isCleartextTrafficPermitted());
    309         assertFalse(child.isCleartextTrafficPermitted());
    310     }
    311 
    312     public void testDebugOverridesDisabled() throws Exception {
    313         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.debug_basic,
    314                 TestUtils.makeApplicationInfo());
    315         ApplicationConfig appConfig = new ApplicationConfig(source);
    316         NetworkSecurityConfig config = appConfig.getConfigForHostname("");
    317         Set<TrustAnchor> anchors = config.getTrustAnchors();
    318         MoreAsserts.assertEmpty(anchors);
    319         SSLContext context = TestUtils.getSSLContext(source);
    320         TestUtils.assertConnectionFails(context, "android.com", 443);
    321         TestUtils.assertConnectionFails(context, "developer.android.com", 443);
    322     }
    323 
    324     public void testBasicDebugOverrides() throws Exception {
    325         ApplicationInfo info = TestUtils.makeApplicationInfo();
    326         info.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
    327         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.debug_basic, info);
    328         ApplicationConfig appConfig = new ApplicationConfig(source);
    329         NetworkSecurityConfig config = appConfig.getConfigForHostname("");
    330         Set<TrustAnchor> anchors = config.getTrustAnchors();
    331         MoreAsserts.assertNotEmpty(anchors);
    332         for (TrustAnchor anchor : anchors) {
    333             assertTrue(anchor.overridesPins);
    334         }
    335         SSLContext context = TestUtils.getSSLContext(source);
    336         TestUtils.assertConnectionSucceeds(context, "android.com", 443);
    337         TestUtils.assertConnectionSucceeds(context, "developer.android.com", 443);
    338     }
    339 
    340     public void testDebugOverridesWithDomain() throws Exception {
    341         ApplicationInfo info = TestUtils.makeApplicationInfo();
    342         info.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
    343         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.debug_domain, info);
    344         ApplicationConfig appConfig = new ApplicationConfig(source);
    345         NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
    346         Set<TrustAnchor> anchors = config.getTrustAnchors();
    347         boolean foundDebugCA = false;
    348         for (TrustAnchor anchor : anchors) {
    349             if (anchor.certificate.getSubjectDN().toString().equals(DEBUG_CA_SUBJ)) {
    350                 foundDebugCA = true;
    351                 assertTrue(anchor.overridesPins);
    352             }
    353         }
    354         assertTrue(foundDebugCA);
    355         SSLContext context = TestUtils.getSSLContext(source);
    356         TestUtils.assertConnectionSucceeds(context, "android.com", 443);
    357         TestUtils.assertConnectionSucceeds(context, "developer.android.com", 443);
    358     }
    359 
    360     public void testDebugInherit() throws Exception {
    361         ApplicationInfo info = TestUtils.makeApplicationInfo();
    362         info.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
    363         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.debug_domain, info);
    364         ApplicationConfig appConfig = new ApplicationConfig(source);
    365         NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
    366         Set<TrustAnchor> anchors = config.getTrustAnchors();
    367         boolean foundDebugCA = false;
    368         for (TrustAnchor anchor : anchors) {
    369             if (anchor.certificate.getSubjectDN().toString().equals(DEBUG_CA_SUBJ)) {
    370                 foundDebugCA = true;
    371                 assertTrue(anchor.overridesPins);
    372             }
    373         }
    374         assertTrue(foundDebugCA);
    375         assertTrue(anchors.size() > 1);
    376         SSLContext context = TestUtils.getSSLContext(source);
    377         TestUtils.assertConnectionSucceeds(context, "android.com", 443);
    378         TestUtils.assertConnectionSucceeds(context, "developer.android.com", 443);
    379     }
    380 
    381     private void testBadConfig(int configId) throws Exception {
    382         try {
    383             XmlConfigSource source = new XmlConfigSource(getContext(), configId,
    384                     TestUtils.makeApplicationInfo());
    385             ApplicationConfig appConfig = new ApplicationConfig(source);
    386             appConfig.getConfigForHostname("android.com");
    387             fail("Bad config " + getContext().getResources().getResourceName(configId)
    388                     + " did not fail to parse");
    389         } catch (RuntimeException e) {
    390             MoreAsserts.assertAssignableFrom(XmlConfigSource.ParserException.class,
    391                     e.getCause());
    392         }
    393     }
    394 
    395     public void testBadConfig0() throws Exception {
    396         testBadConfig(R.xml.bad_config0);
    397     }
    398 
    399     public void testBadConfig1() throws Exception {
    400         testBadConfig(R.xml.bad_config1);
    401     }
    402 
    403     public void testBadConfig2() throws Exception {
    404         testBadConfig(R.xml.bad_config2);
    405     }
    406 
    407     public void testBadConfig3() throws Exception {
    408         testBadConfig(R.xml.bad_config3);
    409     }
    410 
    411     public void testBadConfig4() throws Exception {
    412         testBadConfig(R.xml.bad_config4);
    413     }
    414 
    415     public void testBadConfig5() throws Exception {
    416         testBadConfig(R.xml.bad_config4);
    417     }
    418 
    419     public void testTrustManagerKeystore() throws Exception {
    420         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.bad_pin,
    421                 TestUtils.makeApplicationInfo());
    422         ApplicationConfig appConfig = new ApplicationConfig(source);
    423         Provider provider = new NetworkSecurityConfigProvider();
    424         TrustManagerFactory tmf =
    425                 TrustManagerFactory.getInstance("PKIX", provider);
    426         KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
    427         keystore.load(null);
    428         int i = 0;
    429         for (X509Certificate cert : SystemCertificateSource.getInstance().getCertificates()) {
    430             keystore.setEntry(String.valueOf(i),
    431                     new KeyStore.TrustedCertificateEntry(cert),
    432                     null);
    433             i++;
    434         }
    435         tmf.init(keystore);
    436         TrustManager[] tms = tmf.getTrustManagers();
    437         SSLContext context = SSLContext.getInstance("TLS");
    438         context.init(null, tms, null);
    439         TestUtils.assertConnectionSucceeds(context, "android.com" , 443);
    440     }
    441 
    442     public void testDebugDedup() throws Exception {
    443         ApplicationInfo info = TestUtils.makeApplicationInfo();
    444         info.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
    445         XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.override_dedup, info);
    446         ApplicationConfig appConfig = new ApplicationConfig(source);
    447         assertTrue(appConfig.hasPerDomainConfigs());
    448         // Check android.com.
    449         NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
    450         PinSet pinSet = config.getPins();
    451         assertFalse(pinSet.pins.isEmpty());
    452         // Check that all TrustAnchors come from the override pins debug source.
    453         for (TrustAnchor anchor : config.getTrustAnchors()) {
    454             assertTrue(anchor.overridesPins);
    455         }
    456         // Try connections.
    457         SSLContext context = TestUtils.getSSLContext(source);
    458         TestUtils.assertConnectionSucceeds(context, "android.com", 443);
    459         TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443);
    460     }
    461 
    462     public void testExtraDebugResource() throws Exception {
    463         ApplicationInfo info = TestUtils.makeApplicationInfo();
    464         info.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
    465         XmlConfigSource source =
    466                 new XmlConfigSource(getContext(), R.xml.extra_debug_resource, info);
    467         ApplicationConfig appConfig = new ApplicationConfig(source);
    468         assertFalse(appConfig.hasPerDomainConfigs());
    469         NetworkSecurityConfig config = appConfig.getConfigForHostname("");
    470         MoreAsserts.assertNotEmpty(config.getTrustAnchors());
    471 
    472         // Check that the _debug file is ignored if debug is false.
    473         source = new XmlConfigSource(getContext(), R.xml.extra_debug_resource,
    474                 TestUtils.makeApplicationInfo());
    475         appConfig = new ApplicationConfig(source);
    476         assertFalse(appConfig.hasPerDomainConfigs());
    477         config = appConfig.getConfigForHostname("");
    478         MoreAsserts.assertEmpty(config.getTrustAnchors());
    479     }
    480 
    481     public void testExtraDebugResourceIgnored() throws Exception {
    482         // Verify that parsing the extra debug config resource fails only when debugging is true.
    483         XmlConfigSource source =
    484                 new XmlConfigSource(getContext(), R.xml.bad_extra_debug_resource,
    485                         TestUtils.makeApplicationInfo());
    486         ApplicationConfig appConfig = new ApplicationConfig(source);
    487         // Force parsing the config file.
    488         appConfig.getConfigForHostname("");
    489 
    490         ApplicationInfo info = TestUtils.makeApplicationInfo();
    491         info.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
    492         source = new XmlConfigSource(getContext(), R.xml.bad_extra_debug_resource, info);
    493         appConfig = new ApplicationConfig(source);
    494         try {
    495             appConfig.getConfigForHostname("");
    496             fail("Bad extra debug resource did not fail to parse");
    497         } catch (RuntimeException expected) {
    498         }
    499     }
    500 
    501     public void testDomainWhitespaceTrimming() throws Exception {
    502         XmlConfigSource source =
    503                 new XmlConfigSource(getContext(), R.xml.domain_whitespace,
    504                         TestUtils.makeApplicationInfo());
    505         ApplicationConfig appConfig = new ApplicationConfig(source);
    506         NetworkSecurityConfig defaultConfig = appConfig.getConfigForHostname("");
    507         MoreAsserts.assertNotEqual(defaultConfig, appConfig.getConfigForHostname("developer.android.com"));
    508         MoreAsserts.assertNotEqual(defaultConfig, appConfig.getConfigForHostname("android.com"));
    509         SSLContext context = TestUtils.getSSLContext(source);
    510         TestUtils.assertConnectionSucceeds(context, "android.com", 443);
    511         TestUtils.assertConnectionSucceeds(context, "developer.android.com", 443);
    512     }
    513 }
    514