12f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin/* 22f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * Copyright (C) 2015 The Android Open Source Project 32f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * 42f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * Licensed under the Apache License, Version 2.0 (the "License"); 52f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * you may not use this file except in compliance with the License. 62f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * You may obtain a copy of the License at 72f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * 82f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * http://www.apache.org/licenses/LICENSE-2.0 92f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * 102f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * Unless required by applicable law or agreed to in writing, software 112f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * distributed under the License is distributed on an "AS IS" BASIS, 122f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * See the License for the specific language governing permissions and 142f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * limitations under the License. 152f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin */ 162f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 172f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinpackage libcore.net; 182f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 192f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport junit.framework.TestCase; 202f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport libcore.io.IoUtils; 212f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.io.Closeable; 222f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.io.IOException; 232f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.net.JarURLConnection; 242f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.net.ServerSocket; 252f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.net.Socket; 262f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.net.URL; 272f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.util.Arrays; 28b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubakerimport java.util.HashMap; 29b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubakerimport java.util.Map; 302f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.util.concurrent.Callable; 31c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fullerimport java.util.concurrent.ExecutorService; 32c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fullerimport java.util.concurrent.Executors; 332f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.util.concurrent.Future; 342f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.util.concurrent.TimeUnit; 352f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.util.concurrent.TimeoutException; 362f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.util.logging.ErrorManager; 372f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.util.logging.Level; 382f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.util.logging.LogRecord; 392f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.util.logging.SocketHandler; 402f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 412f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinpublic class NetworkSecurityPolicyTest extends TestCase { 422f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 437a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker private NetworkSecurityPolicy mOriginalPolicy; 442f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 452f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin @Override 462f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin protected void setUp() throws Exception { 472f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin super.setUp(); 487a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker mOriginalPolicy = NetworkSecurityPolicy.getInstance(); 492f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 502f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 512f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin @Override 522f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin protected void tearDown() throws Exception { 532f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try { 547a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(mOriginalPolicy); 552f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } finally { 562f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin super.tearDown(); 572f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 582f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 592f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 602f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public void testCleartextTrafficPolicySetterAndGetter() { 617a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(false)); 627a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker assertEquals(false, NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted()); 632f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 647a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(true)); 657a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker assertEquals(true, NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted()); 662f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 677a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(false)); 687a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker assertEquals(false, NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted()); 692f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 707a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(true)); 717a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker assertEquals(true, NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted()); 722f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 732f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 74b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker public void testHostnameAwareCleartextTrafficPolicySetterAndGetter() { 75b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(false)); 76b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker assertEquals(false, 77b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted("localhost")); 78b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker 79b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(true)); 80b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker assertEquals(true, 81b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted("localhost")); 82b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker 83b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker TestNetworkSecurityPolicy policy = new TestNetworkSecurityPolicy(false); 84b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker policy.addHostMapping("localhost", true); 85b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker policy.addHostMapping("example.com", false); 86b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker NetworkSecurityPolicy.setInstance(policy); 87b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker assertEquals(false, NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted()); 88b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker assertEquals(true, 89b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted("localhost")); 90b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker assertEquals(false, 91b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted("example.com")); 92b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker 93b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker } 94b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker 955a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin public void testCleartextTrafficPolicyWithHttpURLConnection() throws Exception { 965a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin // Assert that client transmits some data when cleartext traffic is permitted. 977a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(true)); 985a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin try (CapturingServerSocket server = new CapturingServerSocket()) { 995a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin URL url = new URL("http://localhost:" + server.getPort() + "/test.txt"); 1005a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin try { 1015a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin url.openConnection().getContent(); 1025a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin fail(); 1035a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } catch (IOException expected) { 1045a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1055a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin server.assertDataTransmittedByClient(); 1065a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1075a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin 1085a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin // Assert that client does not transmit any data when cleartext traffic is not permitted and 1095a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin // that URLConnection.openConnection or getContent fail with an IOException. 1107a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(false)); 1115a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin try (CapturingServerSocket server = new CapturingServerSocket()) { 1125a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin URL url = new URL("http://localhost:" + server.getPort() + "/test.txt"); 1135a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin try { 1145a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin url.openConnection().getContent(); 1155a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin fail(); 1165a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } catch (IOException expected) { 1175a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1185a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin server.assertNoDataTransmittedByClient(); 1195a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1205a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1215a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin 1222f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public void testCleartextTrafficPolicyWithFtpURLConnection() throws Exception { 1232f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // Assert that client transmits some data when cleartext traffic is permitted. 1247a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(true)); 1252f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin byte[] serverReplyOnConnect = "220\r\n".getBytes("US-ASCII"); 1262f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try (CapturingServerSocket server = new CapturingServerSocket(serverReplyOnConnect)) { 1272f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin URL url = new URL("ftp://localhost:" + server.getPort() + "/test.txt"); 1282f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try { 1292f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin url.openConnection().getContent(); 1302f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin fail(); 1312f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } catch (IOException expected) { 1322f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 1332f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin server.assertDataTransmittedByClient(); 1342f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 1352f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 1362f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // Assert that client does not transmit any data when cleartext traffic is not permitted and 1372f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // that URLConnection.openConnection or getContent fail with an IOException. 1387a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(false)); 1392f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try (CapturingServerSocket server = new CapturingServerSocket(serverReplyOnConnect)) { 1402f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin URL url = new URL("ftp://localhost:" + server.getPort() + "/test.txt"); 1412f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try { 1422f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin url.openConnection().getContent(); 1432f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin fail(); 1442f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } catch (IOException expected) { 1452f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 1462f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin server.assertNoDataTransmittedByClient(); 1472f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 1482f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 1492f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 1505a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin public void testCleartextTrafficPolicyWithJarHttpURLConnection() throws Exception { 1515a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin // Assert that client transmits some data when cleartext traffic is permitted. 1527a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(true)); 1535a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin try (CapturingServerSocket server = new CapturingServerSocket()) { 1545a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin URL url = new URL("jar:http://localhost:" + server.getPort() + "/test.jar!/"); 1555a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin try { 1565a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin ((JarURLConnection) url.openConnection()).getManifest(); 1575a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin fail(); 1585a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } catch (IOException expected) { 1595a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1605a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin server.assertDataTransmittedByClient(); 1615a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1625a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin 1635a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin // Assert that client does not transmit any data when cleartext traffic is not permitted and 1645a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin // that JarURLConnection.openConnection or getManifest fail with an IOException. 1657a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(false)); 1665a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin try (CapturingServerSocket server = new CapturingServerSocket()) { 1675a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin URL url = new URL("jar:http://localhost:" + server.getPort() + "/test.jar!/"); 1685a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin try { 1695a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin ((JarURLConnection) url.openConnection()).getManifest(); 1705a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin fail(); 1715a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } catch (IOException expected) { 1725a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1735a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin server.assertNoDataTransmittedByClient(); 1745a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1755a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1765a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin 1772f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public void testCleartextTrafficPolicyWithJarFtpURLConnection() throws Exception { 1782f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // Assert that client transmits some data when cleartext traffic is permitted. 1797a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(true)); 1802f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin byte[] serverReplyOnConnect = "220\r\n".getBytes("US-ASCII"); 1812f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try (CapturingServerSocket server = new CapturingServerSocket(serverReplyOnConnect)) { 1822f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin URL url = new URL("jar:ftp://localhost:" + server.getPort() + "/test.jar!/"); 1832f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try { 1842f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin ((JarURLConnection) url.openConnection()).getManifest(); 1852f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin fail(); 1862f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } catch (IOException expected) { 1872f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 1882f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin server.assertDataTransmittedByClient(); 1892f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 1902f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 1912f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // Assert that client does not transmit any data when cleartext traffic is not permitted and 1922f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // that JarURLConnection.openConnection or getManifest fail with an IOException. 1937a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(false)); 1942f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try (CapturingServerSocket server = new CapturingServerSocket(serverReplyOnConnect)) { 1952f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin URL url = new URL("jar:ftp://localhost:" + server.getPort() + "/test.jar!/"); 1962f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try { 1972f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin ((JarURLConnection) url.openConnection()).getManifest(); 1982f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin fail(); 1992f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } catch (IOException expected) { 2002f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2012f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin server.assertNoDataTransmittedByClient(); 2022f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2032f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2042f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2052f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public void testCleartextTrafficPolicyWithLoggingSocketHandler() throws Exception { 2062f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // Assert that client transmits some data when cleartext traffic is permitted. 2077a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(true)); 2082f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try (CapturingServerSocket server = new CapturingServerSocket()) { 2092f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin SocketHandler logger = new SocketHandler("localhost", server.getPort()); 2102f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin MockErrorManager mockErrorManager = new MockErrorManager(); 2112f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin logger.setErrorManager(mockErrorManager); 2122f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin logger.setLevel(Level.ALL); 2132f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin LogRecord record = new LogRecord(Level.INFO, "A log record"); 2142f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin assertTrue(logger.isLoggable(record)); 2152f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin logger.publish(record); 2162f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin assertNull(mockErrorManager.getMostRecentException()); 2172f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin server.assertDataTransmittedByClient(); 218c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller logger.close(); 2192f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2202f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2212f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // Assert that client does not transmit any data when cleartext traffic is not permitted. 2227a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(false)); 2232f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try (CapturingServerSocket server = new CapturingServerSocket()) { 2242f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try { 2252f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin new SocketHandler("localhost", server.getPort()); 2262f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin fail(); 2272f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } catch (IOException expected) { 2282f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2292f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin server.assertNoDataTransmittedByClient(); 2302f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2312f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2322f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2332f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin /** 2342f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * Server socket which listens on a local port and captures the first chunk of data transmitted 2352f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * by the client. 2362f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin */ 2372f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin private static class CapturingServerSocket implements Closeable { 2382f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin private final ServerSocket mSocket; 2392f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin private final int mPort; 240c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller private final ExecutorService executor; 241c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller private final Future<byte[]> mFirstChunkReceivedFuture; 2422f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2432f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin /** 2442f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * Constructs a new socket listening on a local port. 2452f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin */ 2462f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public CapturingServerSocket() throws IOException { 2472f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin this(null); 2482f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2492f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2502f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin /** 2512f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * Constructs a new socket listening on a local port, which sends the provided reply as 2522f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * soon as a client connects to it. 2532f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin */ 2542f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public CapturingServerSocket(final byte[] replyOnConnect) throws IOException { 2552f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin mSocket = new ServerSocket(0); 2562f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin mPort = mSocket.getLocalPort(); 257c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller Callable<byte[]> callable = () -> { 258c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller try (Socket client = mSocket.accept()) { 259c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller // Reply (if requested) 260c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller if (replyOnConnect != null) { 261c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller client.getOutputStream().write(replyOnConnect); 262c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller client.getOutputStream().flush(); 2632f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 264c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller 265c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller // Read request 266c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller byte[] buf = new byte[64 * 1024]; 267c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller int chunkSize = client.getInputStream().read(buf); 268c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller if (chunkSize == -1) { 269c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller // Connection closed without any data received 270c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller return new byte[0]; 271c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller } 272c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller // Received some data 273c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller return Arrays.copyOf(buf, chunkSize); 274c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller } finally { 275c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller IoUtils.closeQuietly(mSocket); 2762f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 277c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller }; 278c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller executor = Executors.newSingleThreadExecutor(); 279c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller mFirstChunkReceivedFuture = executor.submit(callable); 2802f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2812f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2822f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public int getPort() { 2832f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin return mPort; 2842f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2852f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2862f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public Future<byte[]> getFirstReceivedChunkFuture() { 2872f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin return mFirstChunkReceivedFuture; 2882f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2892f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2902f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin @Override 2912f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public void close() { 2922f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin IoUtils.closeQuietly(mSocket); 293c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller executor.shutdown(); 2942f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2952f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2962f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin private void assertDataTransmittedByClient() 2972f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin throws Exception { 298c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller byte[] firstChunkFromClient = getFirstReceivedChunkFuture().get(4, TimeUnit.SECONDS); 2992f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin if ((firstChunkFromClient == null) || (firstChunkFromClient.length == 0)) { 3002f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin fail("Client did not transmit any data to server"); 3012f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3022f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3032f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 3042f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin private void assertNoDataTransmittedByClient() 3052f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin throws Exception { 3062f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin byte[] firstChunkFromClient; 3072f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try { 308c0c30eb6f377b1eefd57d1bfd908546ca92b527cNeil Fuller firstChunkFromClient = getFirstReceivedChunkFuture().get(4, TimeUnit.SECONDS); 3092f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } catch (TimeoutException expected) { 3102f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin return; 3112f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3122f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin if ((firstChunkFromClient != null) && (firstChunkFromClient.length > 0)) { 3132f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin fail("Client transmitted " + firstChunkFromClient.length+ " bytes: " 3142f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin + new String(firstChunkFromClient, "US-ASCII")); 3152f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3162f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3172f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3182f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 3192f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin private static class MockErrorManager extends ErrorManager { 3202f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin private Exception mMostRecentException; 3212f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 3222f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public Exception getMostRecentException() { 3232f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin synchronized (this) { 3242f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin return mMostRecentException; 3252f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3262f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3272f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 3282f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin @Override 3292f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public void error(String message, Exception exception, int errorCode) { 3302f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin synchronized (this) { 3312f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin mMostRecentException = exception; 3322f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3332f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3342f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3357a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker 3367a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker private static class TestNetworkSecurityPolicy extends NetworkSecurityPolicy { 3377a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker private final boolean mCleartextTrafficPermitted; 338b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker private final Map<String, Boolean> mHostMap = new HashMap<String, Boolean>(); 3397a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker 3407a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker public TestNetworkSecurityPolicy(boolean cleartextTrafficPermitted) { 3417a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker mCleartextTrafficPermitted = cleartextTrafficPermitted; 3427a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker } 3437a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker 344b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker public void addHostMapping(String hostname, boolean isCleartextTrafficPermitted) { 345b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker mHostMap.put(hostname, isCleartextTrafficPermitted); 346b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker } 347b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker 3487a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker @Override 3497a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker public boolean isCleartextTrafficPermitted() { 3507a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker return mCleartextTrafficPermitted; 3517a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker } 352b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker 353b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker @Override 354b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker public boolean isCleartextTrafficPermitted(String hostname) { 355b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker if (mHostMap.containsKey(hostname)) { 356b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker return mHostMap.get(hostname); 357b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker } 358b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker 359b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker return isCleartextTrafficPermitted(); 360b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker } 36188e73140702b45b792f91edddfe41ca3e9310c04Chad Brubaker 36288e73140702b45b792f91edddfe41ca3e9310c04Chad Brubaker @Override 36388e73140702b45b792f91edddfe41ca3e9310c04Chad Brubaker public boolean isCertificateTransparencyVerificationRequired(String hostname) { 36488e73140702b45b792f91edddfe41ca3e9310c04Chad Brubaker return false; 36588e73140702b45b792f91edddfe41ca3e9310c04Chad Brubaker } 3667a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker } 3672f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin} 368