1 /*
   2  * Copyright (c) 2013, 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 import java.net.URLPermission;
  25 /*
  26  * @test
  27  * @bug 8010464
  28  * @modules jdk.httpserver
  29  * @library /lib/testlibrary/
  30  * @build jdk.testlibrary.SimpleSSLContext
  31  * @run main/othervm URLTest
  32  * @summary check URLPermission with Http(s)URLConnection
  33  */
  34 
  35 import java.net.*;
  36 import java.io.*;
  37 import java.security.*;
  38 import java.util.concurrent.*;
  39 import com.sun.net.httpserver.*;
  40 import javax.net.ssl.*;
  41 import jdk.testlibrary.SimpleSSLContext;
  42 
  43 public class URLTest {
  44 
  45     static boolean failed;
  46 
  47     public static void main (String[] args) throws Exception {
  48         createServers();
  49 
  50         try {
  51             // Verify without a Security Manager
  52             test1();
  53             test2();
  54             test3();
  55 
  56             // Set the security manager. Each test will set its own policy.
  57             Policy.setPolicy(new CustomPolicy());
  58             System.setSecurityManager(new SecurityManager());
  59             System.out.println("\n Security Manager has been set.");
  60 
  61             test1();
  62             test2();
  63             test3();
  64 
  65             if (failed)
  66                 throw new RuntimeException("Test failed");
  67         } finally {
  68             shutdown();
  69         }
  70     }
  71 
  72     static void test1() throws IOException {
  73         System.out.println("\n--- Test 1 ---");
  74 
  75         boolean expectException = false;
  76         SecurityManager sm = System.getSecurityManager();
  77         if (sm != null) {
  78             expectException = true;
  79             Policy.setPolicy(new CustomPolicy(
  80                 new URLPermission("http://127.0.0.1:"+httpPort+"/foo.html", "GET:X-Foo,Z-Bar"),
  81                 new URLPermission("https://127.0.0.1:"+httpsPort+"/foo.html", "POST:X-Fob,T-Bar")));
  82         }
  83 
  84         String url1 = "http://127.0.0.1:"+httpPort+"/foo.html";
  85         String url2 = "https://127.0.0.1:"+httpsPort+"/foo.html";
  86         String url3 = "http://127.0.0.1:"+httpPort+"/bar.html";
  87         String url4 = "https://127.0.0.1:"+httpsPort+"/bar.html";
  88 
  89         // simple positive test. Should succeed
  90         test(url1, "GET", "X-Foo");
  91         test(url1, "GET", "Z-Bar", "X-Foo");
  92         test(url1, "GET", "X-Foo", "Z-Bar");
  93         test(url1, "GET", "Z-Bar");
  94         test(url2, "POST", "X-Fob");
  95 
  96         // reverse the methods, should fail
  97         test(url1, "POST", "X-Foo", expectException);
  98         test(url2, "GET", "X-Fob", expectException);
  99 
 100         // different URLs, should fail
 101         test(url3, "GET", "X-Foo", expectException);
 102         test(url4, "POST", "X-Fob", expectException);
 103     }
 104 
 105     static void test2() throws IOException {
 106         System.out.println("\n--- Test 2 ---");
 107 
 108         SecurityManager sm = System.getSecurityManager();
 109         if (sm != null) {
 110             Policy.setPolicy(new CustomPolicy(
 111                 new URLPermission("http://127.0.0.1:"+httpPort+"/*", "GET:X-Foo"),
 112                 new URLPermission("https://127.0.0.1:"+httpsPort+"/*", "POST:X-Fob")));
 113         }
 114 
 115         String url1 = "http://127.0.0.1:"+httpPort+"/foo.html";
 116         String url2 = "https://127.0.0.1:"+httpsPort+"/foo.html";
 117         String url3 = "http://127.0.0.1:"+httpPort+"/bar.html";
 118         String url4 = "https://127.0.0.1:"+httpsPort+"/bar.html";
 119 
 120         // simple positive test. Should succeed
 121         test(url1, "GET", "X-Foo");
 122         test(url2, "POST", "X-Fob");
 123         test(url3, "GET", "X-Foo");
 124         test(url4, "POST", "X-Fob");
 125     }
 126 
 127     static void test3() throws IOException {
 128         System.out.println("\n--- Test 3 ---");
 129 
 130         boolean expectException = false;
 131         SecurityManager sm = System.getSecurityManager();
 132         if (sm != null) {
 133             expectException = true;
 134             Policy.setPolicy(new CustomPolicy(
 135                 new URLPermission("http://127.0.0.1:"+httpPort+"/a/b/-", "DELETE,GET:X-Foo,Y-Foo"),
 136                 new URLPermission("https://127.0.0.1:"+httpsPort+"/a/c/-", "POST:*")));
 137         }
 138 
 139         String url1 = "http://127.0.0.1:"+httpPort+"/foo.html";
 140         String url2 = "https://127.0.0.1:"+httpsPort+"/a/c/d/e/foo.html";
 141         String url3 = "http://127.0.0.1:"+httpPort+"/a/b/c";
 142         String url4 = "https://127.0.0.1:"+httpsPort+"/a/b/c";
 143 
 144         test(url1, "GET", "X-Foo", expectException);
 145         test(url2, "POST", "X-Zxc");
 146         test(url3, "DELETE", "Y-Foo");
 147         test(url4, "POST", "Y-Foo", expectException);
 148     }
 149 
 150     // Convenience methods to simplify previous explicit test scenarios.
 151     static void test(String u, String method, String header) throws IOException {
 152         test(u, method, header, null, false);
 153     }
 154 
 155     static void test(String u, String method, String header, boolean expectException)
 156         throws IOException
 157     {
 158         test(u, method, header, null, expectException);
 159     }
 160 
 161     static void test(String u, String method, String header1, String header2)
 162         throws IOException
 163     {
 164         test(u, method, header1, header2, false);
 165     }
 166 
 167     static void test(String u,
 168                      String method,
 169                      String header1,
 170                      String header2,
 171                      boolean expectException)
 172         throws IOException
 173     {
 174         URL url = new URL(u);
 175         System.out.println("url=" + u + " method=" + method +
 176                            " header1=" + header1 + " header2=" + header2 +
 177                            " expectException=" + expectException);
 178         HttpURLConnection urlc = (HttpURLConnection)url.openConnection();
 179         if (urlc instanceof HttpsURLConnection) {
 180             HttpsURLConnection ssl = (HttpsURLConnection)urlc;
 181             ssl.setHostnameVerifier((host, sess) -> true);
 182             ssl.setSSLSocketFactory(ctx.getSocketFactory());
 183         }
 184         urlc.setRequestMethod(method);
 185         if (header1 != null)
 186             urlc.addRequestProperty(header1, "foo");
 187         if (header2 != null)
 188             urlc.addRequestProperty(header2, "bar");
 189 
 190         try {
 191             int code = urlc.getResponseCode();
 192             if (expectException) {
 193                 failed = true;
 194                 System.out.println("FAIL");
 195                 return;
 196             }
 197             if (code != 200)
 198                 throw new RuntimeException("Unexpected response " + code);
 199 
 200             InputStream is = urlc.getInputStream();
 201             is.readAllBytes();
 202             is.close();
 203         } catch (RuntimeException e) {
 204             if (!expectException || !(e.getCause() instanceof SecurityException)) {
 205                 System.out.println ("FAIL. Unexpected: " + e.getMessage());
 206                 e.printStackTrace();
 207                 failed = true;
 208                 return;
 209             } else {
 210                 System.out.println("Got expected exception: " + e.getMessage());
 211             }
 212         }
 213         System.out.println ("PASS");
 214     }
 215 
 216     static HttpServer httpServer;
 217     static HttpsServer httpsServer;
 218     static HttpContext c, cs;
 219     static ExecutorService e, es;
 220     static SSLContext ctx;
 221     static int httpPort;
 222     static int httpsPort;
 223 
 224     static void createServers() throws Exception {
 225         InetSocketAddress any = new InetSocketAddress(0);
 226         httpServer = HttpServer.create(any, 0);
 227         httpsServer = HttpsServer.create(any, 0);
 228 
 229         OkHandler h = new OkHandler();
 230 
 231         c = httpServer.createContext("/", h);
 232         cs = httpsServer.createContext("/", h);
 233         e = Executors.newCachedThreadPool();
 234         es = Executors.newCachedThreadPool();
 235         httpServer.setExecutor(e);
 236         httpsServer.setExecutor(es);
 237 
 238         ctx = new SimpleSSLContext().get();
 239         httpsServer.setHttpsConfigurator(new HttpsConfigurator (ctx));
 240 
 241         httpServer.start();
 242         httpsServer.start();
 243 
 244         httpPort = httpServer.getAddress().getPort();
 245         httpsPort = httpsServer.getAddress().getPort();
 246     }
 247 
 248     static void shutdown() {
 249         httpServer.stop(1);
 250         httpsServer.stop(1);
 251         e.shutdown();
 252         es.shutdown();
 253     }
 254 
 255     static class OkHandler implements HttpHandler {
 256         public void handle(HttpExchange x) throws IOException {
 257             x.sendResponseHeaders(200, -1);
 258             x.close();
 259         }
 260     }
 261 
 262     static class CustomPolicy extends Policy {
 263         final PermissionCollection perms = new Permissions();
 264         CustomPolicy(Permission... permissions) {
 265             java.util.Arrays.stream(permissions).forEach(perms::add);
 266 
 267             // needed for the HTTP(S) server
 268             perms.add(new SocketPermission("localhost:1024-", "listen,resolve,accept"));
 269             // needed by the test to reset the policy, per testX method
 270             perms.add(new SecurityPermission("setPolicy"));
 271             // needed to shutdown the ThreadPoolExecutor ( used by the servers )
 272             perms.add(new RuntimePermission("modifyThread"));
 273             // needed by the client code forHttpsURLConnection.setSSLSocketFactory
 274             perms.add(new RuntimePermission("setFactory"));
 275         }
 276 
 277         public PermissionCollection getPermissions(ProtectionDomain domain) {
 278             return perms;
 279         }
 280 
 281         public PermissionCollection getPermissions(CodeSource codesource) {
 282             return perms;
 283         }
 284 
 285         public boolean implies(ProtectionDomain domain, Permission perm) {
 286             return perms.implies(perm);
 287         }
 288     }
 289 }