1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.net.InetAddress; 25 import java.net.InetSocketAddress; 26 import java.net.ServerSocket; 27 import java.net.SocketAddress; 28 import java.net.SocketPermission; 29 import java.nio.channels.ServerSocketChannel; 30 import java.security.AccessControlContext; 31 import java.security.AllPermission; 32 import java.security.Permission; 33 import java.security.Permissions; 34 import java.security.Policy; 35 import java.security.PrivilegedAction; 36 import java.security.PrivilegedExceptionAction; 37 import java.security.ProtectionDomain; 38 import org.testng.annotations.BeforeTest; 39 import org.testng.annotations.Test; 40 import static java.lang.System.out; 41 import static java.security.AccessController.*; 42 import static org.testng.Assert.*; 43 44 /* 45 * @test 46 * @bug 8224730 47 * @summary Check local address access with a security manager 48 * @run testng/othervm TestLocalAddress 49 */ 50 51 public class TestLocalAddress { 52 53 InetAddress localHost; 54 ExposedSecurityManager exposedSecurityManager; 55 56 @BeforeTest 57 public void setup() throws Exception { 58 localHost = InetAddress.getLocalHost(); 59 out.println("localHost: " + localHost); 60 61 Policy.setPolicy(new AllPermissionsPolicy()); 62 exposedSecurityManager = new ExposedSecurityManager(); 63 System.setSecurityManager(exposedSecurityManager); 64 out.println("Security manager set"); 65 } 66 67 @Test 68 public void serverSocketNoSecurityManager() throws Exception { 69 out.println("\n\n--- serverSocketNoSecurityManager ---"); 70 try (ServerSocket ss = new ServerSocket()) { 71 testWithNoSecurityManager(ss); 72 } 73 } 74 75 @Test 76 public void socketAdapterNoSecurityManager() throws Exception { 77 out.println("\n\n--- socketAdapterNoSecurityManager ---"); 78 try (ServerSocket ss = ServerSocketChannel.open().socket()) { 79 testWithNoSecurityManager(ss); 80 } 81 } 82 83 void testWithNoSecurityManager(ServerSocket ss) throws Exception { 84 final SecurityManager sm = System.getSecurityManager(); 85 System.setSecurityManager(null); 86 try { 87 ss.bind(new InetSocketAddress(localHost, 0)); 88 89 var localSocketAddr = ((InetSocketAddress)ss.getLocalSocketAddress()); 90 var localInetAddress = ss.getInetAddress(); 91 assertEquals(localInetAddress, localSocketAddr.getAddress()); 92 if (!(localHost.equals(InetAddress.getLoopbackAddress()))) 93 assertNotEquals(localInetAddress, InetAddress.getLoopbackAddress()); 94 95 // toString 96 String s = ss.toString(); 97 out.println("toString returned:" + s); 98 assertTrue(s.contains(localInetAddress.toString()), 99 "Expected [" + localInetAddress + "] in " + s); 100 101 } finally { 102 System.setSecurityManager(sm); 103 } 104 } 105 106 @Test 107 public void serverSocketNoPermissions() throws Exception { 108 out.println("\n\n--- serverSocketNoPermissions ---"); 109 try (ServerSocket ss = new ServerSocket()) { 110 testWithNoPermissions(ss); 111 } 112 } 113 114 @Test 115 public void socketAdapterNoPermissions() throws Exception { 116 out.println("\n\n--- socketAdapterNoPermissions ---"); 117 try (ServerSocket ss = ServerSocketChannel.open().socket()) { 118 testWithNoPermissions(ss); 119 } 120 } 121 122 void testWithNoPermissions(ServerSocket ss) throws Exception { 123 ss.bind(new InetSocketAddress(localHost, 0)); 124 125 PrivilegedExceptionAction<SocketAddress> pa = ss::getLocalSocketAddress; 126 var localSocketAddr = (InetSocketAddress) doPrivileged(pa, noPermissions()); 127 assertSecurityManagerCalled(); 128 PrivilegedExceptionAction<InetAddress> pa1 = ss::getInetAddress; 129 var localInetAddress = doPrivileged(pa1, noPermissions()); 130 assertSecurityManagerCalled(); 131 132 assertEquals(localInetAddress, localSocketAddr.getAddress()); 133 assertEquals(localInetAddress, InetAddress.getLoopbackAddress()); 134 135 // toString 136 PrivilegedExceptionAction<String> pa2 = ss::toString; 137 String s = doPrivileged(pa2, noPermissions()); 138 assertSecurityManagerCalled(); 139 out.println("toString returned:" + s); 140 assertTrue(s.contains(localInetAddress.toString()), 141 "Expected [" + localInetAddress + "] in " + s); 142 } 143 144 145 @Test 146 public void serverSocketFineGrainPermissions() throws Exception { 147 out.println("\n\n--- serverSocketFineGrainPermissions ---"); 148 try (ServerSocket ss = new ServerSocket()) { 149 testWithFineGrainPermissions(ss); 150 } 151 } 152 153 @Test 154 public void socketAdapterFineGrainPermissions() throws Exception { 155 out.println("\n\n--- socketAdapterFineGrainPermissions ---"); 156 try (ServerSocket ss = ServerSocketChannel.open().socket()) { 157 testWithFineGrainPermissions(ss); 158 } 159 } 160 161 void testWithFineGrainPermissions(ServerSocket ss) throws Exception { 162 AccessControlContext connectPermission = withPermissions( 163 new SocketPermission(localHost.getHostName(), "connect") 164 ); 165 ss.bind(new InetSocketAddress(localHost, 0)); 166 167 PrivilegedExceptionAction<SocketAddress> pa = ss::getLocalSocketAddress; 168 var localSocketAddr = (InetSocketAddress) doPrivileged(pa, connectPermission); 169 assertSecurityManagerCalled(); 170 PrivilegedExceptionAction<InetAddress> pa1 = ss::getInetAddress; 171 var localInetAddress = doPrivileged(pa1, connectPermission); 172 assertSecurityManagerCalled(); 173 174 assertEquals(localInetAddress, localSocketAddr.getAddress()); 175 assertEquals(localInetAddress, localHost); 176 177 // toString 178 PrivilegedExceptionAction<String> pa2 = ss::toString; 179 String s = doPrivileged(pa2, connectPermission); 180 assertSecurityManagerCalled(); 181 out.println("toString returned:" + s); 182 assertTrue(s.contains(localInetAddress.toString()), 183 "Expected [" + localInetAddress + "] in " + s); 184 } 185 186 187 @Test 188 public void serverSocketUnbound() throws Exception { 189 out.println("\n\n--- serverSocketUnbound ---"); 190 try (ServerSocket ss = new ServerSocket()) { 191 testUnbound(ss); 192 } 193 } 194 195 @Test 196 public void socketAdapterUnbound() throws Exception { 197 out.println("\n\n--- socketAdapterUnbound ---"); 198 try (ServerSocket ss = ServerSocketChannel.open().socket()) { 199 testUnbound(ss); 200 } 201 } 202 203 void testUnbound(ServerSocket ss) { 204 assert !ss.isBound(); 205 exposedSecurityManager.reset(); 206 assertEquals(ss.getLocalSocketAddress(), null); 207 assertEquals(exposedSecurityManager.port, -999); 208 assertEquals(ss.getInetAddress(), null); 209 assertEquals(exposedSecurityManager.port, -999); 210 String s = ss.toString(); 211 assertEquals(exposedSecurityManager.port, -999); 212 out.println("toString returned:" + s); 213 assertTrue(s.contains("unbound"), "Expected [unbound] in " + s); 214 } 215 216 // A security manager that allows inspection of checkConnect's host/port. 217 static class ExposedSecurityManager extends SecurityManager { 218 volatile String host; 219 volatile int port; 220 ExposedSecurityManager() { 221 reset(); 222 } 223 @Override 224 public void checkConnect(String host, int port) { 225 this.host = host; 226 this.port = port; 227 super.checkConnect(host, port); 228 } 229 void reset() { 230 host = "reset"; 231 port = -999; 232 } 233 } 234 235 void assertSecurityManagerCalled() { 236 assertEquals(exposedSecurityManager.port, -1); 237 assertEquals(exposedSecurityManager.host, localHost.getHostAddress()); 238 exposedSecurityManager.reset(); 239 } 240 241 @Test 242 // Ensures that the test machinery is operating as expected. 243 public void sanity() { 244 PrivilegedAction<?> connectAction = () -> { 245 System.getSecurityManager().checkConnect("example.com", 80); 246 return null; 247 }; 248 249 try { 250 doPrivileged(connectAction, allPermissions()); 251 } catch (SecurityException unexpected) { 252 throw unexpected; 253 } 254 try { 255 doPrivileged(connectAction, noPermissions()); 256 fail("Expected exception not thrown"); 257 } catch (SecurityException expected) { } 258 try { 259 doPrivileged(connectAction, 260 withPermissions(new SocketPermission("example.com:80", "connect"))); 261 } catch (SecurityException unexpected) { 262 throw unexpected; 263 } 264 } 265 266 static AccessControlContext withPermissions(Permission... perms) { 267 Permissions p = new Permissions(); 268 for (Permission perm : perms) { 269 p.add(perm); 270 } 271 ProtectionDomain pd = new ProtectionDomain(null, p); 272 return new AccessControlContext(new ProtectionDomain[]{ pd }); 273 } 274 275 static AccessControlContext allPermissions() { 276 return withPermissions(new AllPermission()); 277 } 278 279 static AccessControlContext noPermissions() { 280 return withPermissions(/*empty*/); 281 } 282 283 // A Policy that implies all permissions. 284 static class AllPermissionsPolicy extends Policy { 285 public boolean implies(ProtectionDomain domain, Permission permission) { 286 return true; 287 } 288 } 289 }