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/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
setupSecurityManager()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
connectSocketTest()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
connectDatagramSocketTest()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
acceptServerSocketTest()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
sendDatagramPacketTest()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
joinGroupMulticastTest()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
listenDatagramSocketTest()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
listenMulticastSocketTest()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
listenServerSocketTest()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 
getAccessControlContext(Permission... ps)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.
main(String[] args)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 }
340