1 /*
   2  * Copyright (c) 2004, 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 5025141
  27  * @summary Tests that MBeanServerFileAccessController supports
  28  *          principals other than JMXPrincipal.
  29  * @author Luis-Miguel Alventosa
  30  * @run clean NonJMXPrincipalsTest SimpleStandard SimpleStandardMBean
  31  * @run build NonJMXPrincipalsTest SimpleStandard SimpleStandardMBean
  32  * @run main NonJMXPrincipalsTest
  33  */
  34 
  35 import java.io.File;
  36 import java.io.Serializable;
  37 import java.security.Principal;
  38 import java.util.HashMap;
  39 import javax.management.Attribute;
  40 import javax.management.MBeanServer;
  41 import javax.management.MBeanServerConnection;
  42 import javax.management.MBeanServerFactory;
  43 import javax.management.MBeanServerInvocationHandler;
  44 import javax.management.Notification;
  45 import javax.management.NotificationListener;
  46 import javax.management.ObjectName;
  47 import javax.management.remote.JMXAuthenticator;
  48 import javax.management.remote.JMXConnector;
  49 import javax.management.remote.JMXConnectorFactory;
  50 import javax.management.remote.JMXConnectorServer;
  51 import javax.management.remote.JMXConnectorServerFactory;
  52 import javax.management.remote.JMXPrincipal;
  53 import javax.management.remote.JMXServiceURL;
  54 import javax.security.auth.Subject;
  55 
  56 public class NonJMXPrincipalsTest {
  57 
  58     private static class OtherPrincipal implements Principal, Serializable {
  59 
  60         private String name;
  61 
  62         public OtherPrincipal(String name) {
  63             if (name == null)
  64                 throw new NullPointerException("illegal null input");
  65             this.name = name;
  66         }
  67 
  68         public String getName() {
  69             return name;
  70         }
  71 
  72         public String toString() {
  73             return("OtherPrincipal:  " + name);
  74         }
  75 
  76         public boolean equals(Object o) {
  77             if (o == null)
  78                 return false;
  79             if (this == o)
  80                 return true;
  81             if (!(o instanceof OtherPrincipal))
  82                 return false;
  83             OtherPrincipal that = (OtherPrincipal)o;
  84             return (this.getName().equals(that.getName()));
  85         }
  86 
  87         public int hashCode() {
  88             return name.hashCode();
  89         }
  90     }
  91 
  92     private static class OtherPrincipalAuthenticator
  93         implements JMXAuthenticator {
  94         public Subject authenticate(Object credentials) {
  95             final String[] aCredentials = (String[]) credentials;
  96             final String username = (String) aCredentials[0];
  97             final Subject subject = new Subject();
  98             subject.getPrincipals().add(new JMXPrincipal("dummy"));
  99             subject.getPrincipals().add(new OtherPrincipal(username));
 100             return subject;
 101         }
 102     }
 103 
 104     private static class NoPrincipalAuthenticator
 105         implements JMXAuthenticator {
 106         public Subject authenticate(Object credentials) {
 107             return new Subject();
 108         }
 109     }
 110 
 111     public static void runTest(JMXAuthenticator authenticator)
 112         throws Exception {
 113         //------------------------------------------------------------------
 114         // SERVER
 115         //------------------------------------------------------------------
 116 
 117         // Instantiate the MBean server
 118         //
 119         System.out.println("Create the MBean server");
 120         MBeanServer mbs = MBeanServerFactory.createMBeanServer();
 121 
 122         // Create SimpleStandard MBean
 123         //
 124         ObjectName mbeanName = new ObjectName("MBeans:type=SimpleStandard");
 125         System.out.println("Create SimpleStandard MBean...");
 126         mbs.createMBean("SimpleStandard", mbeanName, null, null);
 127 
 128         // Server's environment map
 129         //
 130         System.out.println(">>> Initialize the server's environment map");
 131         HashMap sEnv = new HashMap();
 132 
 133         // Provide a JMX Authenticator
 134         //
 135         sEnv.put("jmx.remote.authenticator", authenticator);
 136 
 137         // Provide the access level file used by the connector server to
 138         // perform user authorization. The access level file is a properties
 139         // based text file specifying username/access level pairs where
 140         // access level is either "readonly" or "readwrite" access to the
 141         // MBeanServer operations. This properties based access control
 142         // checker has been implemented using the MBeanServerForwarder
 143         // interface which wraps the real MBean server inside an access
 144         // controller MBean server which performs the access control checks
 145         // before forwarding the requests to the real MBean server.
 146         //
 147         // This property is implementation-dependent and might not be
 148         // supported by all implementations of the JMX Remote API.
 149         //
 150         sEnv.put("jmx.remote.x.access.file",
 151                  System.getProperty("test.src") +
 152                  File.separator +
 153                  "access.properties");
 154 
 155         // Create an RMI connector server
 156         //
 157         System.out.println("Create an RMI connector server");
 158         JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");
 159         JMXConnectorServer cs =
 160             JMXConnectorServerFactory.newJMXConnectorServer(url, sEnv, mbs);
 161 
 162         // Start the RMI connector server
 163         //
 164         System.out.println("Start the RMI connector server");
 165         cs.start();
 166         System.out.println("RMI connector server successfully started");
 167         System.out.println("Waiting for incoming connections...");
 168 
 169         //------------------------------------------------------------------
 170         // CLIENT (admin)
 171         //------------------------------------------------------------------
 172 
 173         // Admin client environment map
 174         //
 175         String[] adminCreds = new String[] { "admin" , "adminPassword" };
 176         System.out.println(">>> Initialize the client environment map for" +
 177                            " user [" + adminCreds[0] + "] with " +
 178                            "password [" + adminCreds[1] + "]");
 179         HashMap adminEnv = new HashMap();
 180         adminEnv.put("jmx.remote.credentials", adminCreds);
 181 
 182         // Create an RMI connector client and
 183         // connect it to the RMI connector server
 184         //
 185         System.out.println("Create an RMI connector client and " +
 186                            "connect it to the RMI connector server");
 187         JMXConnector adminConnector =
 188             JMXConnectorFactory.connect(cs.getAddress(), adminEnv);
 189 
 190         // Get an MBeanServerConnection
 191         //
 192         System.out.println("Get an MBeanServerConnection");
 193         MBeanServerConnection adminConnection =
 194             adminConnector.getMBeanServerConnection();
 195 
 196         // Get the proxy for the Simple MBean
 197         //
 198         SimpleStandardMBean adminProxy = (SimpleStandardMBean)
 199             MBeanServerInvocationHandler.newProxyInstance(
 200                                                  adminConnection,
 201                                                  mbeanName,
 202                                                  SimpleStandardMBean.class,
 203                                                  false);
 204 
 205         // Get State attribute
 206         //
 207         System.out.println("State = " + adminProxy.getState());
 208 
 209         // Set State attribute
 210         //
 211         adminProxy.setState("changed state");
 212 
 213         // Get State attribute
 214         //
 215         System.out.println("State = " + adminProxy.getState());
 216 
 217         // Invoke "reset" in SimpleStandard MBean
 218         //
 219         System.out.println("Invoke reset() in SimpleStandard MBean...");
 220         adminProxy.reset();
 221 
 222         // Close MBeanServer connection
 223         //
 224         System.out.println("Close the admin connection to the server");
 225         adminConnector.close();
 226 
 227         //------------------------------------------------------------------
 228         // CLIENT (user)
 229         //------------------------------------------------------------------
 230 
 231         // User client environment map
 232         //
 233         String[] userCreds = new String[] { "user" , "userPassword" };
 234         System.out.println(">>> Initialize the client environment map for" +
 235                            " user [" + userCreds[0] + "] with " +
 236                            "password [" + userCreds[1] + "]");
 237         HashMap userEnv = new HashMap();
 238         userEnv.put("jmx.remote.credentials", userCreds);
 239 
 240         // Create an RMI connector client and
 241         // connect it to the RMI connector server
 242         //
 243         System.out.println("Create an RMI connector client and " +
 244                            "connect it to the RMI connector server");
 245         JMXConnector userConnector =
 246             JMXConnectorFactory.connect(cs.getAddress(), userEnv);
 247 
 248         // Get an MBeanServerConnection
 249         //
 250         System.out.println("Get an MBeanServerConnection");
 251         MBeanServerConnection userConnection =
 252             userConnector.getMBeanServerConnection();
 253 
 254         // Get the proxy for the Simple MBean
 255         //
 256         SimpleStandardMBean userProxy = (SimpleStandardMBean)
 257             MBeanServerInvocationHandler.newProxyInstance(
 258                                                  userConnection,
 259                                                  mbeanName,
 260                                                  SimpleStandardMBean.class,
 261                                                  false);
 262 
 263         // Get State attribute
 264         //
 265         System.out.println("State = " + userProxy.getState());
 266 
 267         // Set State attribute
 268         //
 269         try {
 270             userProxy.setState("changed state");
 271         } catch (SecurityException e) {
 272             System.out.println("Got expected security exception: " + e);
 273         } catch (Exception e) {
 274             System.out.println("Got unexpected exception: " + e);
 275             e.printStackTrace(System.out);
 276         }
 277 
 278         // Get State attribute
 279         //
 280         System.out.println("State = " + userProxy.getState());
 281 
 282         // Invoke "reset" in SimpleStandard MBean
 283         //
 284         try {
 285             System.out.println("Invoke reset() in SimpleStandard MBean...");
 286             userProxy.reset();
 287         } catch (SecurityException e) {
 288             System.out.println("Got expected security exception: " + e);
 289         } catch (Exception e) {
 290             System.out.println("Got unexpected exception: " + e);
 291             e.printStackTrace(System.out);
 292         }
 293 
 294         // Close MBeanServer connection
 295         //
 296         System.out.println("Close the user connection to the server");
 297         userConnector.close();
 298 
 299         //------------------------------------------------------------------
 300         // SERVER
 301         //------------------------------------------------------------------
 302 
 303         // Stop the connector server
 304         //
 305         System.out.println(">>> Stop the connector server");
 306         cs.stop();
 307     }
 308 
 309     public static void main(String[] args) {
 310         int errorCount = 0;
 311         // Runt tests
 312         //
 313         System.out.println("\n>>> Run NoPrincipalAuthenticator test...");
 314         try {
 315             NonJMXPrincipalsTest.runTest(new NoPrincipalAuthenticator());
 316             System.out.println("Did not get expected SecurityException");
 317             errorCount++;
 318         } catch (Exception e) {
 319             if (e instanceof SecurityException) {
 320                 System.out.println("Got expected exception: " + e);
 321             } else {
 322                 System.out.println("Got unexpected exception: " + e);
 323                 errorCount++;
 324             }
 325             e.printStackTrace(System.out);
 326         }
 327         System.out.println("\n>>> Run OtherPrincipalAuthenticator test...");
 328         try {
 329             NonJMXPrincipalsTest.runTest(new OtherPrincipalAuthenticator());
 330         } catch (Exception e) {
 331             errorCount++;
 332             System.out.println("Got unexpected exception: " + e);
 333             e.printStackTrace(System.out);
 334         }
 335 
 336         if (errorCount > 0) {
 337             System.out.println("\nTEST FAILED! Error count = " + errorCount);
 338             System.exit(1);
 339         }
 340 
 341         System.out.println("\nTEST PASSED!");
 342         System.out.println("\nBye! Bye!");
 343     }
 344 }