1 /*
   2  * Copyright (c) 2014, 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 /*
  25  * @test
  26  * @bug 8047031
  27  * @summary SocketPermission tests for legacy socket types
  28  * @run testng SocketPermissionTest
  29  * @key intermittent
  30  */
  31 import java.io.IOException;
  32 import java.net.DatagramPacket;
  33 import java.net.DatagramSocket;
  34 import java.net.InetAddress;
  35 import java.net.MulticastSocket;
  36 import java.net.ServerSocket;
  37 import java.net.Socket;
  38 import java.net.SocketPermission;
  39 import java.security.AccessControlContext;
  40 import java.security.AccessController;
  41 import java.security.CodeSource;
  42 import java.security.Permission;
  43 import java.security.PermissionCollection;
  44 import java.security.Permissions;
  45 import java.security.Policy;
  46 import java.security.PrivilegedExceptionAction;
  47 import java.security.ProtectionDomain;
  48 
  49 import org.testng.annotations.BeforeMethod;
  50 import org.testng.annotations.Test;
  51 import static org.testng.Assert.*;
  52 
  53 import static java.nio.charset.StandardCharsets.UTF_8;
  54 
  55 public class SocketPermissionTest {
  56 
  57     @BeforeMethod
  58     public void setupSecurityManager() throws Exception {
  59         // All permissions, a specific ACC will be used to when testing
  60         // with a reduced permission set.
  61         Policy.setPolicy(new Policy() {
  62              final PermissionCollection perms = new Permissions();
  63              { perms.add(new java.security.AllPermission()); }
  64              public PermissionCollection getPermissions(ProtectionDomain domain) {
  65                  return perms;
  66              }
  67              public PermissionCollection getPermissions(CodeSource codesource) {
  68                  return perms;
  69              }
  70              public boolean implies(ProtectionDomain domain, Permission perm) {
  71                  return perms.implies(perm);
  72              }
  73         } );
  74         System.setSecurityManager(new SecurityManager());
  75     }
  76 
  77     static final AccessControlContext RESTRICTED_ACC = getAccessControlContext();
  78 
  79     @Test
  80     public void connectSocketTest() throws Exception {
  81         try (ServerSocket ss = new ServerSocket(0)) {
  82             int port = ss.getLocalPort();
  83 
  84             String addr = "localhost:" + port;
  85             AccessControlContext acc = getAccessControlContext(
  86                     new SocketPermission(addr, "listen,connect,resolve"));
  87 
  88             // Positive
  89             AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
  90                 try (Socket client = new Socket(InetAddress.getLocalHost(), port)) {
  91                 }
  92                 return null;
  93             }, acc);
  94 
  95             //Negative
  96             try {
  97                 AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
  98                     Socket client = new Socket(InetAddress.getLocalHost(), port);
  99                     fail("Expected SecurityException");
 100                     return null;
 101                 }, RESTRICTED_ACC);
 102             } catch (SecurityException expected) { }
 103         }
 104     }
 105 
 106     @Test
 107     public void connectDatagramSocketTest() throws Exception {
 108         byte[] msg = "Hello".getBytes(UTF_8);
 109         InetAddress lh = InetAddress.getLocalHost();
 110 
 111         try (DatagramSocket ds = new DatagramSocket(0)) {
 112             int port = ds.getLocalPort();
 113 
 114             String addr = lh.getHostAddress() + ":" + port;
 115             AccessControlContext acc = getAccessControlContext(
 116                     new SocketPermission(addr, "connect,resolve"));
 117 
 118             // Positive
 119             AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
 120                 DatagramPacket dp = new DatagramPacket(msg, msg.length, lh, port);
 121                 ds.send(dp);
 122                 return null;
 123             }, acc);
 124 
 125             // Negative
 126             try {
 127                 AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
 128                     DatagramPacket dp = new DatagramPacket(msg, msg.length, lh, port);
 129                     ds.send(dp);
 130                     fail("Expected SecurityException");
 131                     return null;
 132                 }, RESTRICTED_ACC);
 133             } catch (SecurityException expected) { }
 134         }
 135     }
 136 
 137     @Test
 138     public void acceptServerSocketTest() throws Exception {
 139         try (ServerSocket ss = new ServerSocket(0)) {
 140             int port = ss.getLocalPort();
 141 
 142             String addr = "localhost:" + port;
 143             AccessControlContext acc = getAccessControlContext(
 144                     new SocketPermission(addr, "listen,connect,resolve"),
 145                     new SocketPermission("localhost:1024-", "accept"));
 146 
 147             // Positive
 148             AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
 149                 InetAddress me = InetAddress.getLocalHost();
 150                 try (Socket client = new Socket(me, port)) {
 151                     ss.accept();
 152                 }
 153                 return null;
 154             }, acc);
 155 
 156             // Negative
 157             try {
 158                 AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
 159                     InetAddress me = InetAddress.getLocalHost();
 160                     try (Socket client = new Socket(me, port)) {
 161                         ss.accept();
 162                     }
 163                     fail("Expected SecurityException");
 164                     return null;
 165                 }, RESTRICTED_ACC);
 166             } catch (SecurityException expected) { }
 167         }
 168     }
 169 
 170     @Test
 171     public void sendDatagramPacketTest() throws Exception {
 172         byte[] msg = "Hello".getBytes(UTF_8);
 173         InetAddress group = InetAddress.getByName("229.227.226.221");
 174 
 175         try (DatagramSocket ds = new DatagramSocket(0)) {
 176             int port = ds.getLocalPort();
 177 
 178             String addr = "localhost:" + port;
 179             //test for SocketPermission "229.227.226.221", "connect,accept"
 180             AccessControlContext acc = getAccessControlContext(
 181                     new SocketPermission(addr, "listen,resolve"),
 182                     new SocketPermission("229.227.226.221", "connect,accept"));
 183 
 184             // Positive
 185             AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
 186                 DatagramPacket hi = new DatagramPacket(msg, msg.length, group, port);
 187                 ds.send(hi);
 188                 return null;
 189             }, acc);
 190 
 191             // Negative
 192             try {
 193                 AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
 194                     DatagramPacket hi = new DatagramPacket(msg, msg.length, group, port);
 195                     ds.send(hi);
 196                     fail("Expected SecurityException");
 197                     return null;
 198                 }, RESTRICTED_ACC);
 199             } catch (SecurityException expected) { }
 200         }
 201     }
 202 
 203     @Test
 204     public void joinGroupMulticastTest() throws Exception {
 205         InetAddress group = InetAddress.getByName("229.227.226.221");
 206         try (MulticastSocket s = new MulticastSocket(0)) {
 207             int port = s.getLocalPort();
 208 
 209             String addr = "localhost:" + port;
 210             AccessControlContext acc = getAccessControlContext(
 211                     new SocketPermission(addr, "listen,resolve"),
 212                     new SocketPermission("229.227.226.221", "connect,accept"));
 213 
 214             // Positive
 215             AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
 216                 s.joinGroup(group);
 217                 s.leaveGroup(group);
 218                 return null;
 219             }, acc);
 220 
 221             // Negative
 222             try {
 223                 AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
 224                     s.joinGroup(group);
 225                     s.leaveGroup(group);
 226                     fail("Expected SecurityException");
 227                     return null;
 228                 }, RESTRICTED_ACC);
 229             } catch (SecurityException expected) { }
 230         }
 231 
 232     }
 233 
 234     @Test
 235     public void listenDatagramSocketTest() throws Exception {
 236         // the hardcoded port number doesn't really matter since we expect the
 237         // security permission to be checked before the underlying operation.
 238         int port = 8899;
 239         String addr = "localhost:" + port;
 240         AccessControlContext acc = getAccessControlContext(
 241                 new SocketPermission(addr, "listen"));
 242 
 243         // Positive
 244         AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
 245             try (DatagramSocket ds = new DatagramSocket(port)) { }
 246             catch (IOException intermittentlyExpected) { /* ignore */ }
 247             return null;
 248         }, acc);
 249 
 250         // Negative
 251         try {
 252             AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
 253                 try (DatagramSocket ds = new DatagramSocket(port)) { }
 254                 catch (IOException intermittentlyExpected) { /* ignore */ }
 255                 fail("Expected SecurityException");
 256                 return null;
 257             }, RESTRICTED_ACC);
 258         } catch (SecurityException expected) { }
 259     }
 260 
 261     @Test
 262     public void listenMulticastSocketTest() throws Exception {
 263         // the hardcoded port number doesn't really matter since we expect the
 264         // security permission to be checked before the underlying operation.
 265         int port = 8899;
 266         String addr = "localhost:" + port;
 267         AccessControlContext acc = getAccessControlContext(
 268                 new SocketPermission(addr, "listen"));
 269 
 270         // Positive
 271         AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
 272             try (MulticastSocket ms = new MulticastSocket(port)) { }
 273             catch (IOException intermittentlyExpected) { /* ignore */ }
 274             return null;
 275         }, acc);
 276 
 277         // Negative
 278         try {
 279             AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
 280                 try (MulticastSocket ms = new MulticastSocket(port)) { }
 281                 catch (IOException intermittentlyExpected) { /* ignore */ }
 282                 fail("Expected SecurityException");
 283                 return null;
 284             }, RESTRICTED_ACC);
 285         } catch (SecurityException expected) { }
 286     }
 287 
 288     @Test
 289     public void listenServerSocketTest() throws Exception {
 290         // the hardcoded port number doesn't really matter since we expect the
 291         // security permission to be checked before the underlying operation.
 292         int port = 8899;
 293         String addr = "localhost:" + port;
 294         AccessControlContext acc = getAccessControlContext(
 295                 new SocketPermission(addr, "listen"));
 296 
 297         // Positive
 298         AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
 299             try (ServerSocket ss = new ServerSocket(port)) { }
 300             catch (IOException intermittentlyExpected) { /* ignore */ }
 301             return null;
 302         }, acc);
 303 
 304         // Negative
 305         try {
 306             AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
 307                 try (ServerSocket ss = new ServerSocket(port)) { }
 308                 catch (IOException intermittentlyExpected) { /* ignore */ }
 309                 fail("Expected SecurityException");
 310                 return null;
 311             }, RESTRICTED_ACC);
 312         } catch (SecurityException expected) { }
 313 
 314     }
 315 
 316     private static AccessControlContext getAccessControlContext(Permission... ps) {
 317         Permissions perms = new Permissions();
 318         for (Permission p : ps) {
 319             perms.add(p);
 320         }
 321         /*
 322          *Create an AccessControlContext that consist a single protection domain
 323          * with only the permissions calculated above
 324          */
 325         ProtectionDomain pd = new ProtectionDomain(null, perms);
 326         return new AccessControlContext(new ProtectionDomain[]{pd});
 327     }
 328 
 329     // Standalone entry point for running with, possibly older, JDKs.
 330     public static void main(String[] args) throws Throwable {
 331         SocketPermissionTest test = new SocketPermissionTest();
 332         test.setupSecurityManager();
 333         for (java.lang.reflect.Method m : SocketPermissionTest.class.getDeclaredMethods()) {
 334             if (m.getAnnotation(Test.class) != null) {
 335                 System.out.println("Invoking " + m.getName());
 336                 m.invoke(test);
 337             }
 338         }
 339     }
 340 }