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; 312f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.util.concurrent.Future; 322f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.util.concurrent.FutureTask; 332f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.util.concurrent.TimeUnit; 342f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.util.concurrent.TimeoutException; 352f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.util.logging.ErrorManager; 362f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.util.logging.Level; 372f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.util.logging.LogRecord; 382f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinimport java.util.logging.SocketHandler; 392f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 402f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubinpublic class NetworkSecurityPolicyTest extends TestCase { 412f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 427a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker private NetworkSecurityPolicy mOriginalPolicy; 432f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 442f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin @Override 452f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin protected void setUp() throws Exception { 462f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin super.setUp(); 477a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker mOriginalPolicy = NetworkSecurityPolicy.getInstance(); 482f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 492f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 502f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin @Override 512f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin protected void tearDown() throws Exception { 522f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try { 537a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(mOriginalPolicy); 542f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } finally { 552f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin super.tearDown(); 562f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 572f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 582f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 592f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public void testCleartextTrafficPolicySetterAndGetter() { 607a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(false)); 617a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker assertEquals(false, NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted()); 622f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 637a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(true)); 647a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker assertEquals(true, NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted()); 652f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 667a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(false)); 677a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker assertEquals(false, NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted()); 682f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 697a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(true)); 707a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker assertEquals(true, NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted()); 712f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 722f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 73b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker public void testHostnameAwareCleartextTrafficPolicySetterAndGetter() { 74b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(false)); 75b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker assertEquals(false, 76b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted("localhost")); 77b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker 78b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(true)); 79b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker assertEquals(true, 80b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted("localhost")); 81b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker 82b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker TestNetworkSecurityPolicy policy = new TestNetworkSecurityPolicy(false); 83b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker policy.addHostMapping("localhost", true); 84b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker policy.addHostMapping("example.com", false); 85b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker NetworkSecurityPolicy.setInstance(policy); 86b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker assertEquals(false, NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted()); 87b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker assertEquals(true, 88b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted("localhost")); 89b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker assertEquals(false, 90b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted("example.com")); 91b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker 92b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker } 93b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker 945a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin public void testCleartextTrafficPolicyWithHttpURLConnection() throws Exception { 955a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin // Assert that client transmits some data when cleartext traffic is permitted. 967a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(true)); 975a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin try (CapturingServerSocket server = new CapturingServerSocket()) { 985a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin URL url = new URL("http://localhost:" + server.getPort() + "/test.txt"); 995a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin try { 1005a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin url.openConnection().getContent(); 1015a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin fail(); 1025a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } catch (IOException expected) { 1035a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1045a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin server.assertDataTransmittedByClient(); 1055a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1065a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin 1075a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin // Assert that client does not transmit any data when cleartext traffic is not permitted and 1085a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin // that URLConnection.openConnection or getContent fail with an IOException. 1097a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(false)); 1105a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin try (CapturingServerSocket server = new CapturingServerSocket()) { 1115a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin URL url = new URL("http://localhost:" + server.getPort() + "/test.txt"); 1125a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin try { 1135a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin url.openConnection().getContent(); 1145a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin fail(); 1155a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } catch (IOException expected) { 1165a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1175a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin server.assertNoDataTransmittedByClient(); 1185a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1195a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1205a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin 1212f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public void testCleartextTrafficPolicyWithFtpURLConnection() throws Exception { 1222f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // Assert that client transmits some data when cleartext traffic is permitted. 1237a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(true)); 1242f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin byte[] serverReplyOnConnect = "220\r\n".getBytes("US-ASCII"); 1252f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try (CapturingServerSocket server = new CapturingServerSocket(serverReplyOnConnect)) { 1262f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin URL url = new URL("ftp://localhost:" + server.getPort() + "/test.txt"); 1272f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try { 1282f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin url.openConnection().getContent(); 1292f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin fail(); 1302f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } catch (IOException expected) { 1312f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 1322f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin server.assertDataTransmittedByClient(); 1332f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 1342f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 1352f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // Assert that client does not transmit any data when cleartext traffic is not permitted and 1362f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // that URLConnection.openConnection or getContent fail with an IOException. 1377a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(false)); 1382f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try (CapturingServerSocket server = new CapturingServerSocket(serverReplyOnConnect)) { 1392f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin URL url = new URL("ftp://localhost:" + server.getPort() + "/test.txt"); 1402f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try { 1412f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin url.openConnection().getContent(); 1422f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin fail(); 1432f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } catch (IOException expected) { 1442f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 1452f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin server.assertNoDataTransmittedByClient(); 1462f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 1472f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 1482f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 1495a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin public void testCleartextTrafficPolicyWithJarHttpURLConnection() throws Exception { 1505a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin // Assert that client transmits some data when cleartext traffic is permitted. 1517a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(true)); 1525a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin try (CapturingServerSocket server = new CapturingServerSocket()) { 1535a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin URL url = new URL("jar:http://localhost:" + server.getPort() + "/test.jar!/"); 1545a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin try { 1555a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin ((JarURLConnection) url.openConnection()).getManifest(); 1565a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin fail(); 1575a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } catch (IOException expected) { 1585a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1595a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin server.assertDataTransmittedByClient(); 1605a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1615a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin 1625a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin // Assert that client does not transmit any data when cleartext traffic is not permitted and 1635a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin // that JarURLConnection.openConnection or getManifest fail with an IOException. 1647a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(false)); 1655a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin try (CapturingServerSocket server = new CapturingServerSocket()) { 1665a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin URL url = new URL("jar:http://localhost:" + server.getPort() + "/test.jar!/"); 1675a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin try { 1685a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin ((JarURLConnection) url.openConnection()).getManifest(); 1695a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin fail(); 1705a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } catch (IOException expected) { 1715a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1725a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin server.assertNoDataTransmittedByClient(); 1735a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1745a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin } 1755a0a80d050d1bc7da77af16b7b2ad8a94d8e9bf6Alex Klyubin 1762f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public void testCleartextTrafficPolicyWithJarFtpURLConnection() throws Exception { 1772f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // Assert that client transmits some data when cleartext traffic is permitted. 1787a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(true)); 1792f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin byte[] serverReplyOnConnect = "220\r\n".getBytes("US-ASCII"); 1802f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try (CapturingServerSocket server = new CapturingServerSocket(serverReplyOnConnect)) { 1812f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin URL url = new URL("jar:ftp://localhost:" + server.getPort() + "/test.jar!/"); 1822f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try { 1832f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin ((JarURLConnection) url.openConnection()).getManifest(); 1842f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin fail(); 1852f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } catch (IOException expected) { 1862f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 1872f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin server.assertDataTransmittedByClient(); 1882f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 1892f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 1902f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // Assert that client does not transmit any data when cleartext traffic is not permitted and 1912f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // that JarURLConnection.openConnection or getManifest fail with an IOException. 1927a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(false)); 1932f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try (CapturingServerSocket server = new CapturingServerSocket(serverReplyOnConnect)) { 1942f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin URL url = new URL("jar:ftp://localhost:" + server.getPort() + "/test.jar!/"); 1952f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try { 1962f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin ((JarURLConnection) url.openConnection()).getManifest(); 1972f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin fail(); 1982f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } catch (IOException expected) { 1992f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2002f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin server.assertNoDataTransmittedByClient(); 2012f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2022f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2032f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2042f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public void testCleartextTrafficPolicyWithLoggingSocketHandler() throws Exception { 2052f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // Assert that client transmits some data when cleartext traffic is permitted. 2067a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(true)); 2072f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try (CapturingServerSocket server = new CapturingServerSocket()) { 2082f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin SocketHandler logger = new SocketHandler("localhost", server.getPort()); 2092f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin MockErrorManager mockErrorManager = new MockErrorManager(); 2102f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin logger.setErrorManager(mockErrorManager); 2112f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin logger.setLevel(Level.ALL); 2122f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin LogRecord record = new LogRecord(Level.INFO, "A log record"); 2132f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin assertTrue(logger.isLoggable(record)); 2142f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin logger.publish(record); 2152f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin assertNull(mockErrorManager.getMostRecentException()); 2162f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin server.assertDataTransmittedByClient(); 2172f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2182f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2192f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // Assert that client does not transmit any data when cleartext traffic is not permitted. 2207a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker NetworkSecurityPolicy.setInstance(new TestNetworkSecurityPolicy(false)); 2212f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try (CapturingServerSocket server = new CapturingServerSocket()) { 2222f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try { 2232f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin new SocketHandler("localhost", server.getPort()); 2242f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin fail(); 2252f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } catch (IOException expected) { 2262f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2272f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin server.assertNoDataTransmittedByClient(); 2282f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2292f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2302f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2312f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin /** 2322f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * Server socket which listens on a local port and captures the first chunk of data transmitted 2332f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * by the client. 2342f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin */ 2352f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin private static class CapturingServerSocket implements Closeable { 2362f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin private final ServerSocket mSocket; 2372f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin private final int mPort; 2382f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin private final Thread mListeningThread; 2392f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin private final FutureTask<byte[]> mFirstChunkReceivedFuture; 2402f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2412f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin /** 2422f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * Constructs a new socket listening on a local port. 2432f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin */ 2442f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public CapturingServerSocket() throws IOException { 2452f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin this(null); 2462f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2472f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2482f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin /** 2492f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * Constructs a new socket listening on a local port, which sends the provided reply as 2502f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin * soon as a client connects to it. 2512f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin */ 2522f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public CapturingServerSocket(final byte[] replyOnConnect) throws IOException { 2532f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin mSocket = new ServerSocket(0); 2542f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin mPort = mSocket.getLocalPort(); 2552f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin mFirstChunkReceivedFuture = new FutureTask<byte[]>(new Callable<byte[]>() { 2562f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin @Override 2572f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public byte[] call() throws Exception { 2582f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try (Socket client = mSocket.accept()) { 2592f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // Reply (if requested) 2602f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin if (replyOnConnect != null) { 2612f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin client.getOutputStream().write(replyOnConnect); 2622f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin client.getOutputStream().flush(); 2632f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2642f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2652f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // Read request 2662f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin byte[] buf = new byte[64 * 1024]; 2672f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin int chunkSize = client.getInputStream().read(buf); 2682f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin if (chunkSize == -1) { 2692f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // Connection closed without any data received 2702f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin return new byte[0]; 2712f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2722f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin // Received some data 2732f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin return Arrays.copyOf(buf, chunkSize); 2742f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } finally { 2752f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin IoUtils.closeQuietly(mSocket); 2762f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2772f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2782f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin }); 2792f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin mListeningThread = new Thread(mFirstChunkReceivedFuture); 2802f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin mListeningThread.start(); 2812f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2822f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2832f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public int getPort() { 2842f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin return mPort; 2852f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2862f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2872f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public Future<byte[]> getFirstReceivedChunkFuture() { 2882f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin return mFirstChunkReceivedFuture; 2892f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2902f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2912f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin @Override 2922f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public void close() { 2932f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin IoUtils.closeQuietly(mSocket); 2942f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin mListeningThread.interrupt(); 2952f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 2962f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 2972f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin private void assertDataTransmittedByClient() 2982f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin throws Exception { 2992f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin byte[] firstChunkFromClient = getFirstReceivedChunkFuture().get(2, TimeUnit.SECONDS); 3002f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin if ((firstChunkFromClient == null) || (firstChunkFromClient.length == 0)) { 3012f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin fail("Client did not transmit any data to server"); 3022f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3032f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3042f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 3052f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin private void assertNoDataTransmittedByClient() 3062f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin throws Exception { 3072f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin byte[] firstChunkFromClient; 3082f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin try { 3092f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin firstChunkFromClient = getFirstReceivedChunkFuture().get(2, TimeUnit.SECONDS); 3102f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } catch (TimeoutException expected) { 3112f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin return; 3122f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3132f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin if ((firstChunkFromClient != null) && (firstChunkFromClient.length > 0)) { 3142f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin fail("Client transmitted " + firstChunkFromClient.length+ " bytes: " 3152f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin + new String(firstChunkFromClient, "US-ASCII")); 3162f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3172f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3182f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3192f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 3202f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin private static class MockErrorManager extends ErrorManager { 3212f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin private Exception mMostRecentException; 3222f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 3232f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public Exception getMostRecentException() { 3242f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin synchronized (this) { 3252f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin return mMostRecentException; 3262f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3272f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3282f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin 3292f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin @Override 3302f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin public void error(String message, Exception exception, int errorCode) { 3312f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin synchronized (this) { 3322f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin mMostRecentException = exception; 3332f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3342f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3352f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin } 3367a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker 3377a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker private static class TestNetworkSecurityPolicy extends NetworkSecurityPolicy { 3387a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker private final boolean mCleartextTrafficPermitted; 339b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker private final Map<String, Boolean> mHostMap = new HashMap<String, Boolean>(); 3407a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker 3417a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker public TestNetworkSecurityPolicy(boolean cleartextTrafficPermitted) { 3427a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker mCleartextTrafficPermitted = cleartextTrafficPermitted; 3437a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker } 3447a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker 345b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker public void addHostMapping(String hostname, boolean isCleartextTrafficPermitted) { 346b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker mHostMap.put(hostname, isCleartextTrafficPermitted); 347b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker } 348b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker 3497a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker @Override 3507a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker public boolean isCleartextTrafficPermitted() { 3517a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker return mCleartextTrafficPermitted; 3527a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker } 353b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker 354b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker @Override 355b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker public boolean isCleartextTrafficPermitted(String hostname) { 356b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker if (mHostMap.containsKey(hostname)) { 357b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker return mHostMap.get(hostname); 358b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker } 359b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker 360b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker return isCleartextTrafficPermitted(); 361b80fefa18b3a185422222cfad3c7210c4903c37fChad Brubaker } 3627a6f1687cfa0929e68ac7813b7432259b8088b4dChad Brubaker } 3632f4d25190a7d2cc8328a202417ca9077a02e6d9aAlex Klyubin} 364