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