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