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 /* 25 * @test 26 * @bug 7150256 27 * @summary Permissions Tests for the DiagnosticCommandMBean 28 * @author Frederic Parain 29 * 30 * @modules java.logging 31 * java.management 32 * 33 * @run main/othervm DcmdMBeanPermissionsTest 34 */ 35 36 import java.lang.management.ManagementFactory; 37 import java.lang.reflect.Constructor; 38 import java.lang.reflect.InvocationTargetException; 39 import java.lang.reflect.ReflectPermission; 40 import java.security.Permission; 41 import java.util.HashSet; 42 import java.util.Iterator; 43 import javax.management.Descriptor; 44 import javax.management.InstanceNotFoundException; 45 import javax.management.IntrospectionException; 46 import javax.management.MBeanException; 47 import javax.management.MBeanInfo; 48 import javax.management.MBeanOperationInfo; 49 import javax.management.MBeanPermission; 50 import javax.management.MBeanServer; 51 import javax.management.MalformedObjectNameException; 52 import javax.management.ObjectName; 53 import javax.management.ReflectionException; 54 import javax.management.RuntimeMBeanException; 55 56 /** 57 * 58 * @author fparain 59 */ 60 public class DcmdMBeanPermissionsTest { 61 62 private static String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME = 63 "com.sun.management:type=DiagnosticCommand"; 64 65 static public class CustomSecurityManager extends SecurityManager { 66 67 private HashSet<Permission> grantedPermissions; 68 69 public CustomSecurityManager() { 70 grantedPermissions = new HashSet<Permission>(); 71 } 72 73 public final void grantPermission(final Permission perm) { 74 grantedPermissions.add(perm); 75 } 76 77 public final void denyPermission(final Permission perm) { 78 Iterator<Permission> it = grantedPermissions.iterator(); 79 while (it.hasNext()) { 80 Permission p = it.next(); 81 if (p.equals(perm)) { 82 it.remove(); 83 } 84 } 85 } 86 87 public final void checkPermission(final Permission perm) { 88 for (Permission p : grantedPermissions) { 89 if (p.implies(perm)) { 90 return; 91 } 92 } 93 throw new SecurityException(perm.toString()); 94 } 95 }; 96 97 static Permission createPermission(String classname, String name, 98 String action) { 99 Permission permission = null; 100 try { 101 Class c = Class.forName(classname); 102 if (action == null) { 103 try { 104 Constructor constructor = c.getConstructor(String.class); 105 permission = (Permission) constructor.newInstance(name); 106 107 } catch (InstantiationException | IllegalAccessException 108 | IllegalArgumentException | InvocationTargetException 109 | NoSuchMethodException | SecurityException ex) { 110 ex.printStackTrace(); 111 throw new RuntimeException("TEST FAILED"); 112 } 113 } 114 if (permission == null) { 115 try { 116 Constructor constructor = c.getConstructor(String.class, 117 String.class); 118 permission = (Permission) constructor.newInstance( 119 name, 120 action); 121 } catch (InstantiationException | IllegalAccessException 122 | IllegalArgumentException | InvocationTargetException 123 | NoSuchMethodException | SecurityException ex) { 124 ex.printStackTrace(); 125 throw new RuntimeException("TEST FAILED"); 126 } 127 } 128 } catch (ClassNotFoundException ex) { 129 ex.printStackTrace(); 130 throw new RuntimeException("TEST FAILED"); 131 } 132 if (permission == null) { 133 throw new RuntimeException("TEST FAILED"); 134 } 135 return permission; 136 } 137 138 // return true if invokation triggered a SecurityException 139 static boolean invokeOperation(MBeanServer mbs, ObjectName on, 140 MBeanOperationInfo opInfo) { 141 try { 142 if (opInfo.getSignature().length == 0) { 143 mbs.invoke(on, opInfo.getName(), 144 new Object[0], new String[0]); 145 } else { 146 mbs.invoke(on, opInfo.getName(), 147 new Object[1], new String[]{ String[].class.getName()}); 148 } 149 } catch (SecurityException ex) { 150 ex.printStackTrace(); 151 return true; 152 } catch (RuntimeMBeanException ex) { 153 if (ex.getCause() instanceof SecurityException) { 154 //ex.printStackTrace(); 155 return true; 156 } 157 } catch (MBeanException | InstanceNotFoundException 158 | ReflectionException ex) { 159 throw new RuntimeException("TEST FAILED"); 160 } 161 return false; 162 } 163 164 static void testOperation(MBeanServer mbs, CustomSecurityManager sm, 165 ObjectName on, MBeanOperationInfo opInfo) { 166 System.out.println("Testing " + opInfo.getName()); 167 Descriptor desc = opInfo.getDescriptor(); 168 if (desc.getFieldValue("dcmd.permissionClass") == null) { 169 // No special permission required, execution should not trigger 170 // any security exception 171 if (invokeOperation(mbs, on, opInfo)) { 172 throw new RuntimeException("TEST FAILED"); 173 } 174 } else { 175 // Building the required permission 176 Permission reqPerm = createPermission( 177 (String)desc.getFieldValue("dcmd.permissionClass"), 178 (String)desc.getFieldValue("dcmd.permissionName"), 179 (String)desc.getFieldValue("dcmd.permissionAction")); 180 // Paranoid mode: check that the SecurityManager has not already 181 // been granted the permission 182 sm.denyPermission(reqPerm); 183 // A special permission is required for this operation, 184 // invoking it without the permission granted must trigger 185 // a security exception 186 if(!invokeOperation(mbs, on, opInfo)) { 187 throw new RuntimeException("TEST FAILED"); 188 } 189 // grant the permission and re-try invoking the operation 190 sm.grantPermission(reqPerm); 191 if(invokeOperation(mbs, on, opInfo)) { 192 throw new RuntimeException("TEST FAILED"); 193 } 194 // Clean up 195 sm.denyPermission(reqPerm); 196 } 197 } 198 199 public static void main(final String[] args) { 200 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 201 ObjectName on = null; 202 try { 203 on = new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME); 204 } catch (MalformedObjectNameException ex) { 205 ex.printStackTrace(); 206 throw new RuntimeException("TEST FAILED"); 207 } 208 MBeanInfo info = null; 209 try { 210 info = mbs.getMBeanInfo(on); 211 } catch (InstanceNotFoundException | IntrospectionException 212 | ReflectionException ex) { 213 ex.printStackTrace(); 214 throw new RuntimeException("TEST FAILED"); 215 } 216 CustomSecurityManager sm = new CustomSecurityManager(); 217 System.setSecurityManager(sm); 218 // Set of permission required to run the test cleanly 219 // Some permissions are required by the MBeanServer and other 220 // platform services (RuntimePermission("createClassLoader"), 221 // ReflectPermission("suppressAccessChecks"), 222 // java.util.logging.LoggingPermission("control"), 223 // RuntimePermission("exitVM.97")). 224 // Other permissions are required by commands being invoked 225 // in the test (for instance, RuntimePermission("modifyThreadGroup") 226 // and RuntimePermission("modifyThread") are checked when 227 // runFinalization() is invoked by the gcRunFinalization command. 228 sm.grantPermission(new RuntimePermission("createClassLoader")); 229 sm.grantPermission(new ReflectPermission("suppressAccessChecks")); 230 sm.grantPermission(new java.util.logging.LoggingPermission("control", "")); 231 sm.grantPermission(new java.lang.RuntimePermission("exitVM.*")); 232 sm.grantPermission(new java.lang.RuntimePermission("modifyThreadGroup")); 233 sm.grantPermission(new java.lang.RuntimePermission("modifyThread")); 234 sm.grantPermission(new java.security.SecurityPermission("getProperty.jdk.jar.disabledAlgorithms")); 235 for(MBeanOperationInfo opInfo : info.getOperations()) { 236 Permission opPermission = new MBeanPermission(info.getClassName(), 237 opInfo.getName(), 238 on, 239 "invoke"); 240 sm.grantPermission(opPermission); 241 testOperation(mbs, sm, on, opInfo); 242 sm.denyPermission(opPermission); 243 } 244 System.out.println("TEST PASSED"); 245 } 246 }