1 /*
   2  * Copyright (c) 2011, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package test.javafx.concurrent;
  27 
  28 import java.security.Permission;
  29 import org.junit.Ignore;
  30 import org.junit.runner.RunWith;
  31 import org.junit.runners.BlockJUnit4ClassRunner;
  32 import org.junit.runners.model.FrameworkMethod;
  33 import org.junit.runners.model.InitializationError;
  34 import org.junit.runners.model.Statement;
  35 import sun.awt.AWTSecurityManager;
  36 
  37 /**
  38  * A test for the Service lifecycle methods with a security manager installed.
  39  * The security manager installed lets privileged code run (most of the time)
  40  * and otherwise lets the tests do what they need to but restricts the
  41  * runtime from doing more or less anything else other than load library.
  42  * It is ad-hoc, a more rigorous analysis on what the permissions should be
  43  * would be great, and then we could add the ability to do security manager
  44  * related tests on lots of different unit tests.
  45  */
  46 @RunWith(ServiceWithSecurityManagerTest.ServiceTestRunner.class)
  47 @Ignore("This class doesn't appear to run correctly, often s.evaluate isn't called. Likely bogus test at present.")
  48 public class ServiceWithSecurityManagerTest extends ServiceLifecycleTest {
  49     
  50     public static final class ServiceTestRunner extends BlockJUnit4ClassRunner {
  51         private ThreadGroup mainThreadGroup;
  52         
  53         public ServiceTestRunner(Class<?> klass) throws InitializationError {
  54             super(klass);
  55         }
  56 
  57         @Override protected Statement methodBlock(FrameworkMethod method) {
  58             final Statement s = super.methodBlock(method);
  59             return new Statement() {
  60                 Throwable throwable;
  61                 @Override public void evaluate() throws Throwable {
  62                     SecurityManager original = System.getSecurityManager();
  63                     try {
  64                         mainThreadGroup = new ThreadGroup(Thread.currentThread().getThreadGroup(), "FX Test Thread Group");
  65                         Thread thread = new Thread(mainThreadGroup, () -> {
  66                             try {
  67                                 s.evaluate();
  68                             } catch (Throwable t) {
  69                                 throwable = t;
  70                             }
  71                         });
  72                         
  73                         System.setSecurityManager(new StrictSecurityManager());
  74                         thread.start();
  75                         thread.join();
  76                     } finally {
  77                         System.setSecurityManager(original);
  78                         mainThreadGroup = null;
  79                         if (throwable != null) {
  80                             throw throwable;
  81                         }
  82                     }
  83                 }
  84             };
  85         }
  86         
  87         /**
  88          */
  89         private final class StrictSecurityManager extends AWTSecurityManager {
  90             // If you create a Thread that is a child of mainThreadGroup, that is OK.
  91             // If you create a ThreadGroup that is a child of mainThreadGroup, then that is bad.
  92             private ThreadGroup securityThreadGroup = new ThreadGroup("Security Thread Group");
  93 
  94             @Override public void checkPermission(Permission permission) {
  95                 if (isPrivileged()) return; // OK
  96                 if (permission instanceof RuntimePermission) {
  97                     if ("setSecurityManager".equals(permission.getName())) {
  98                         return; // OK
  99                     }
 100                     if ("accessClassInPackage.sun.util.logging".equals(permission.getName())) {
 101                         return; // OK
 102                     }
 103                 }
 104                 super.checkPermission(permission);
 105             }
 106 
 107             @Override public void checkAccess(ThreadGroup g) {
 108                 if (g == securityThreadGroup) return;
 109                 if (!isPrivileged()) throw new SecurityException("ThreadGroup doesn't have permissions");
 110                 super.checkAccess(g);
 111             }
 112 
 113             @Override public ThreadGroup getThreadGroup() {
 114                 return securityThreadGroup;
 115             }
 116 
 117             private boolean isPrivileged() {
 118                 StackTraceElement[] stack = Thread.currentThread().getStackTrace();
 119                 for (StackTraceElement e : stack) {
 120                     if (e.getClassName().equals("java.security.AccessController")
 121                             && e.getMethodName().equals("doPrivileged")) {
 122                         return true;
 123                     }
 124                 }
 125                 return false;
 126             }
 127         }
 128     }
 129 }