1 /*
   2  * Copyright (c) 2003, 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 8058865
  27  * @summary Checks various authentication behavior from remote jmx client
  28  * @author Olivier Lagneau
  29  *
  30  * @library /lib/testlibrary
  31  * @modules java.management.rmi
  32  *
  33  * @compile Simple.java
  34  * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dusername=username1 -Dpassword=password1 AuthorizationTest -server -mapType x.access.file;x.password.file -populate -client -mapType credentials
  35  * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dusername=username2 -Dpassword=password2 AuthorizationTest -server -mapType x.access.file;x.password.file -populate -client -mapType credentials -expectedCreateException -expectedSetException -expectedInvokeException
  36  * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dusername=username6 -Dpassword=password6 AuthorizationTest -server -mapType x.access.file;x.password.file -populate -client -mapType credentials -expectedCreateException -expectedGetException -expectedSetException -expectedInvokeException
  37  * @run main/othervm/timeout=300/policy=java.policy.authorization -DDEBUG_STANDARD -Dusername=username1 -Dpassword=password1 AuthorizationTest -server -mapType x.password.file -populate -client -mapType credentials
  38  * @run main/othervm/timeout=300/policy=java.policy.authorization -DDEBUG_STANDARD -Dusername=username3 -Dpassword=password3 AuthorizationTest -server -mapType x.password.file -populate -client -mapType credentials -expectedGetException
  39  * @run main/othervm/timeout=300/policy=java.policy.authorization -DDEBUG_STANDARD -Dusername=username5 -Dpassword=password5 AuthorizationTest -server -mapType x.password.file -populate -client -mapType credentials -expectedCreateException -expectedGetException -expectedSetException -expectedInvokeException
  40  * @run main/othervm/timeout=300/policy=java.policy.authorization -DDEBUG_STANDARD -Dusername=username6 -Dpassword=password6 AuthorizationTest -server -mapType x.password.file -populate -client -mapType credentials -expectedCreateException -expectedGetException -expectedSetException -expectedInvokeException
  41  * @run main/othervm/timeout=300/policy=java.policy.authorization -DDEBUG_STANDARD -Dusername=username1 -Dpassword=password1 AuthorizationTest -server -mapType x.access.file;x.password.file -populate -client -mapType credentials
  42  * @run main/othervm/timeout=300/policy=java.policy.authorization -DDEBUG_STANDARD -Dusername=username2 -Dpassword=password2 AuthorizationTest -server -mapType x.access.file;x.password.file -populate -client -mapType credentials -expectedCreateException -expectedSetException -expectedInvokeException
  43  * @run main/othervm/timeout=300/policy=java.policy.authorization -DDEBUG_STANDARD -Dusername=username3 -Dpassword=password3 AuthorizationTest -server -mapType x.access.file;x.password.file -populate -client -mapType credentials -expectedCreateException -expectedGetException -expectedSetException -expectedInvokeException
  44  * @run main/othervm/timeout=300/policy=java.policy.authorization -DDEBUG_STANDARD -Dusername=username4 -Dpassword=password4 AuthorizationTest -server -mapType x.access.file;x.password.file -populate -client -mapType credentials -expectedGetException -expectedSetException
  45  * @run main/othervm/timeout=300/policy=java.policy.authorization -DDEBUG_STANDARD -Dusername=username5 -Dpassword=password5 AuthorizationTest -server -mapType x.access.file;x.password.file -populate -client -mapType credentials -expectedCreateException -expectedGetException -expectedSetException -expectedInvokeException
  46  */
  47 
  48 import java.io.File;
  49 import java.util.Map ;
  50 import java.util.HashMap ;
  51 import java.util.List;
  52 import java.util.ArrayList;
  53 import java.util.Arrays;
  54 
  55 import java.lang.management.ManagementFactory;
  56 
  57 import javax.management.MBeanServer;
  58 import javax.management.MBeanServerFactory ;
  59 import javax.management.MBeanServerConnection;
  60 import javax.management.remote.JMXConnector;
  61 import javax.management.remote.JMXConnectorFactory;
  62 import javax.management.remote.JMXConnectorServer;
  63 import javax.management.remote.JMXConnectorServerFactory;
  64 import javax.management.remote.JMXServiceURL;
  65 
  66 import javax.management.Attribute ;
  67 import javax.management.ObjectName ;
  68 
  69 import jdk.testlibrary.ProcessTools;
  70 import jdk.testlibrary.JDKToolFinder;
  71 
  72 public class AuthorizationTest {
  73 
  74     static final String SERVER_CLASS_NAME = "AuthorizationTest";
  75     static final String CLIENT_CLASS_NAME = "AuthorizationTest$ClientSide";
  76     static final String CLIENT_CLASS_MAIN = CLIENT_CLASS_NAME;
  77 
  78     static final String USERNAME_PROPERTY = "username";
  79     static final String PASSWORD_PROPERTY = "password";
  80 
  81     private JMXConnectorServer cs;
  82 
  83     /*
  84      * First Debug properties and arguments are collect in expected
  85      * map  (argName, value) format, then calls original test's run method.
  86      */
  87     public static void main(String args[]) throws Exception {
  88 
  89         System.out.println("=================================================");
  90 
  91         // Parses parameters
  92         Utils.parseDebugProperties();
  93 
  94         // Supported parameters list format is :
  95         // "MainClass [-server <param-spec> ...] [-client <param-spec> ...]
  96         // with <param-spec> either "-parami valuei" or "-parami"
  97         HashMap<String, Object> serverMap = new HashMap<>() ;
  98         int clientArgsIndex =
  99             Utils.parseServerParameters(args, SERVER_CLASS_NAME, serverMap);
 100 
 101         // Extract and records client params
 102         String[] clientParams = null;
 103         if (clientArgsIndex < args.length) {
 104             int clientParamsSize = args.length - clientArgsIndex;
 105             clientParams = new String[clientParamsSize];
 106             System.arraycopy(args, clientArgsIndex, clientParams, 0, clientParamsSize);
 107         } else {
 108             clientParams = new String[0];
 109         }
 110 
 111         // Run test
 112         AuthorizationTest test = new AuthorizationTest();
 113         test.run(serverMap, clientParams);
 114 
 115     }
 116 
 117     /*
 118      * Create the MBeansServer side of the test and returns its address
 119      */
 120     private JMXServiceURL createServerSide(Map<String, Object> serverMap)
 121     throws Exception {
 122         final int NINETY_SECONDS = 90;
 123 
 124         System.out.println("AuthorizationTest::createServerSide: Start") ;
 125 
 126         MBeanServer mbs = MBeanServerFactory.newMBeanServer();
 127         JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
 128 
 129         // Creates connection environment from server side params
 130         HashMap<String, Object> env = new HashMap<>();
 131         String value = null;
 132 
 133         if ((value = (String)serverMap.get("-mapType")) != null) {
 134             if (value.contains("x.access.file")) {
 135                 String accessFileStr = System.getProperty("test.src") +
 136                     File.separator + "access.properties";
 137                 env.put("jmx.remote.x.access.file", accessFileStr);
 138                 System.out.println("Added " + accessFileStr + " file as jmx.remote.x.access.file");
 139             }
 140             if (value.contains("x.password.file")) {
 141                 String passwordFileStr = System.getProperty("test.src") +
 142                     File.separator + "password.properties";
 143                 env.put("jmx.remote.x.password.file", passwordFileStr);
 144                 System.out.println("Added " + passwordFileStr + " file as jmx.remote.x.password.file");
 145             }
 146         }
 147 
 148         if (serverMap.containsKey("-populate")) {
 149             String populateClassName = "Simple";
 150             ObjectName on =
 151                 new ObjectName("defaultDomain:class=Simple");
 152 
 153             Utils.debug(Utils.DEBUG_STANDARD, "create and register Simple MBean") ;
 154             mbs.createMBean(populateClassName, on);
 155         }
 156 
 157         cs = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
 158         cs.start();
 159 
 160         Utils.waitReady(cs, NINETY_SECONDS);
 161 
 162         JMXServiceURL addr = cs.getAddress();
 163 
 164         System.out.println("AuthorizationTest::createServerSide: Done.") ;
 165 
 166         return addr;
 167     }
 168 
 169     /*
 170      * Creating command-line for running subprocess JVM:
 171      *
 172      * JVM command line is like:
 173      * {test_jdk}/bin/java {defaultopts} -cp {test.class.path} {testopts} main
 174      *
 175      * {defaultopts} are the default java options set by the framework.
 176      *
 177      */
 178     private List<String> buildCommandLine(String args[]) {
 179         List<String> opts = new ArrayList<>();
 180         opts.add(JDKToolFinder.getJDKTool("java"));
 181         opts.addAll(Arrays.asList(jdk.testlibrary.Utils.getTestJavaOpts()));
 182 
 183         String usernameValue = System.getProperty(USERNAME_PROPERTY);
 184         if (usernameValue != null) {
 185             opts.add("-D" + USERNAME_PROPERTY + "=" + usernameValue);
 186         }
 187         String passwordValue = System.getProperty(PASSWORD_PROPERTY);
 188         if (passwordValue != null) {
 189             opts.add("-D" + PASSWORD_PROPERTY + "=" + passwordValue);
 190         }
 191 
 192         opts.add("-cp");
 193         opts.add(System.getProperty("test.class.path", "test.class.path"));
 194         opts.add(CLIENT_CLASS_MAIN);
 195         opts.addAll(Arrays.asList(args));
 196         return opts;
 197     }
 198 
 199     /**
 200      * Runs AuthorizationTest$ClientSide with the passed options and redirects
 201      * subprocess standard I/O to the current (parent) process. This provides a
 202      * trace of what happens in the subprocess while it is runnning (and before
 203      * it terminates).
 204      *
 205      * @param serviceUrlStr string representing the JMX service Url to connect to.
 206      */
 207     private int runClientSide(String args[], String serviceUrlStr) throws Exception {
 208 
 209         // Building command-line
 210         List<String> opts = buildCommandLine(args);
 211         opts.add("-serviceUrl");
 212         opts.add(serviceUrlStr);
 213 
 214         // Launch separate JVM subprocess
 215         int exitCode = 0;
 216         String[] optsArray = opts.toArray(new String[0]);
 217         ProcessBuilder pb = new ProcessBuilder(optsArray);
 218         Process p = ProcessTools.startProcess("AuthorizationTest$ClientSide", pb);
 219 
 220         // Handling end of subprocess
 221         try {
 222             exitCode = p.waitFor();
 223             if (exitCode != 0) {
 224                 System.out.println(
 225                     "Subprocess unexpected exit value of [" + exitCode +
 226                     "]. Expected 0.\n");
 227             }
 228         } catch (InterruptedException e) {
 229             System.out.println("Parent process interrupted with exception : \n " + e + " :" );
 230 
 231             // Parent thread unknown state, killing subprocess.
 232             p.destroyForcibly();
 233 
 234             throw new RuntimeException(
 235                 "Parent process interrupted with exception : \n " + e + " :" );
 236 
 237         } finally {
 238             if (p.isAlive()) {
 239                 p.destroyForcibly();
 240             }
 241             return exitCode;
 242         }
 243 
 244      }
 245 
 246     public void run(Map<String, Object> serverArgs, String clientArgs[]) {
 247 
 248         System.out.println("AuthorizationTest::run: Start") ;
 249         int errorCount = 0;
 250 
 251         try {
 252             // Initialise the server side
 253             JMXServiceURL urlToUse = createServerSide(serverArgs);
 254 
 255             // Run client side
 256             errorCount = runClientSide(clientArgs, urlToUse.toString());
 257 
 258             if ( errorCount == 0 ) {
 259                 System.out.println("AuthorizationTest::run: Done without any error") ;
 260             } else {
 261                 System.out.println("AuthorizationTest::run: Done with "
 262                         + errorCount
 263                         + " error(s)") ;
 264                 throw new RuntimeException("errorCount = " + errorCount);
 265             }
 266 
 267             cs.stop();
 268 
 269         } catch(Exception e) {
 270             throw new RuntimeException(e);
 271         }
 272 
 273     }
 274 
 275     private static class ClientSide {
 276 
 277         private JMXConnector cc = null;
 278         private MBeanServerConnection mbsc = null;
 279 
 280         public static void main(String args[]) throws Exception {
 281 
 282             // Parses parameters
 283             Utils.parseDebugProperties();
 284 
 285             // Supported parameters list format is : "MainClass [-client <param-spec> ...]
 286             // with <param-spec> either "-parami valuei" or "-parami"
 287             HashMap<String, Object> clientMap = new HashMap<>() ;
 288             Utils.parseClientParameters(args, CLIENT_CLASS_NAME, clientMap);
 289 
 290             // Run test
 291             ClientSide test = new ClientSide();
 292             test.run(clientMap);
 293 
 294         }
 295 
 296         public void run(Map<String, Object> args) {
 297 
 298             int errorCount = 0 ;
 299 
 300             try {
 301                 boolean expectedCreateException =
 302                         (args.containsKey("-expectedCreateException")) ? true : false ;
 303                 boolean expectedGetException =
 304                         (args.containsKey("-expectedGetException")) ? true : false ;
 305                 boolean expectedSetException =
 306                         (args.containsKey("-expectedSetException")) ? true : false ;
 307                 boolean expectedInvokeException =
 308                         (args.containsKey("-expectedInvokeException")) ? true : false ;
 309                 // JSR262 (see bug 6440374)
 310                 // There is no special JSR262 protocol operation for connect.
 311                 // The first request sent initiate the connection.
 312                 // In the JSR262 current implementation, getDefaultDomain is sent to
 313                 // the server in order to get the server part of the connection ID.
 314                 // => the connection may fail if no access permission on get requests.
 315                 boolean expectedConnectException =
 316                         (args.containsKey("-expectedConnectException")) ? true : false ;
 317                 // Before connection,
 318                 // remove the element of the Map with null values (not supported by RMI)
 319                 // See bug 4982668
 320                 args.remove("-expectedCreateException");
 321                 args.remove("-expectedGetException");
 322                 args.remove("-expectedSetException");
 323                 args.remove("-expectedInvokeException");
 324                 args.remove("-expectedConnectException");
 325 
 326 
 327                 // Here do connect to the JMX Server
 328                 String username = System.getProperty("username");
 329                 Utils.debug(Utils.DEBUG_STANDARD,
 330                     "ClientSide::run: CONNECT on behalf of \"" + username + "\"");
 331                 doConnect(args, expectedConnectException);
 332 
 333                 // If the connection did not fail, perform some requests.
 334                 // At this stage the mbeanserver connection is up and running
 335                 if (mbsc != null) {
 336                     ObjectName on = new ObjectName("defaultDomain:class=Simple");
 337 
 338                     // Create request
 339                     Utils.debug(Utils.DEBUG_STANDARD,
 340                         "ClientSide::run: CREATE on behalf of \"" +
 341                         username + "\"");
 342                     errorCount += doCreateRequest(mbsc,
 343                         new ObjectName("defaultDomain:class=Simple,user=" + username),
 344                         expectedCreateException);
 345 
 346                     // Get request
 347                     Utils.debug(Utils.DEBUG_STANDARD,
 348                         "ClientSide::run: GET on behalf of \"" +
 349                         username + "\"");
 350                     errorCount += doGetRequest(mbsc, on, expectedGetException);
 351 
 352                     // Set request
 353                     Utils.debug(Utils.DEBUG_STANDARD,
 354                         "ClientSide::run: SET on behalf of \"" +
 355                         username + "\"");
 356                     errorCount += doSetRequest(mbsc, on, expectedSetException);
 357 
 358                     // Invoke request
 359                     Utils.debug(Utils.DEBUG_STANDARD,
 360                         "ClientSide::run: INVOKE on behalf of \"" +
 361                         username + "\"");
 362                     errorCount += doInvokeRequest(mbsc, on, expectedInvokeException);
 363                 }
 364 
 365             } catch(Exception e) {
 366                 Utils.printThrowable(e, true) ;
 367                 errorCount++;
 368             } finally {
 369                 // Terminate the JMX Client
 370                 try {
 371                     cc.close();
 372                 } catch (Exception e) {
 373                     Utils.printThrowable(e, true) ;
 374                     errorCount++;
 375                 }
 376             }
 377 
 378             System.out.println("ClientSide::run: Done") ;
 379 
 380             // Handle result
 381             if (errorCount == 0) {
 382                 System.out.println("ClientSide::run: (OK) authorization test succeeded.");
 383             } else {
 384                 String message = "AuthorizationTest$ClientSide::run: (ERROR) " +
 385                         " authorization test failed with " +
 386                         errorCount + " error(s)";
 387                 System.out.println(message);
 388                 throw new RuntimeException(message);
 389             }
 390         }
 391 
 392         protected void doConnect(Map<String, Object> args,
 393                                  boolean expectedException) {
 394 
 395             String msgTag = "ClientSide::doConnect";
 396             boolean throwRuntimeException = false;
 397             String message = "";
 398 
 399             try {
 400                 Utils.debug(Utils.DEBUG_STANDARD,
 401                     "ClientSide::doConnect: Connect the client");
 402 
 403                 // Collect connection environment
 404                 HashMap<String, Object> env = new HashMap<>();
 405 
 406                 Object value = args.get("-mapType");
 407                 if (value != null) {
 408                     String username = System.getProperty("username");
 409                     String password = System.getProperty("password");
 410                     Utils.debug(Utils.DEBUG_STANDARD,
 411                         msgTag + "add \"jmx.remote.credentials\" = \"" +
 412                         username + "\", \"" + password + "\"");
 413                     env.put("jmx.remote.credentials",
 414                         new String[] { username , password });
 415                 }
 416 
 417                 // Get a connection to remote mbean server
 418                 JMXServiceURL addr = new JMXServiceURL((String)args.get("-serviceUrl"));
 419                 cc = JMXConnectorFactory.connect(addr,env);
 420                 mbsc = cc.getMBeanServerConnection();
 421 
 422                 if (expectedException) {
 423                     message = "ClientSide::doConnect: (ERROR) " +
 424                         "Connect did not fail with expected SecurityException";
 425                     System.out.println(message);
 426                     throwRuntimeException = true;
 427                 } else {
 428                     System.out.println("ClientSide::doConnect: (OK) Connect succeed");
 429                 }
 430             } catch(Exception e) {
 431                 Utils.printThrowable(e, true);
 432                 if (expectedException) {
 433                     if (e instanceof java.lang.SecurityException) {
 434                         System.out.println("ClientSide::doConnect: (OK) " +
 435                             "Connect failed with expected SecurityException");
 436                     } else {
 437                         message = "ClientSide::doConnect: (ERROR) " +
 438                             "Create failed with " + e.getClass() +
 439                             " instead of expected SecurityException";
 440                         System.out.println(message);
 441                         throwRuntimeException = true;
 442                     }
 443                 } else {
 444                     message = "ClientSide::doConnect: (ERROR) " +
 445                         "Connect failed";
 446                     System.out.println(message);
 447                     throwRuntimeException = true;
 448                 }
 449             }
 450 
 451             // If the connection failed, or if the connection succeeded but should not,
 452             // no need to go further => throw RuntimeException and exit the test
 453             if (throwRuntimeException) {
 454                 throw new RuntimeException(message);
 455             }
 456         }
 457 
 458         protected int doCreateRequest(MBeanServerConnection mbsc,
 459                                       ObjectName on,
 460                                       boolean expectedException) {
 461             int errorCount = 0;
 462 
 463             try {
 464                 Utils.debug(Utils.DEBUG_STANDARD,
 465                     "ClientSide::doCreateRequest: Create and register the MBean") ;
 466 
 467                 mbsc.createMBean("Simple", on) ;
 468 
 469                 if (expectedException) {
 470                     System.out.println("ClientSide::doCreateRequest: " +
 471                         "(ERROR) Create did not fail with expected SecurityException");
 472                     errorCount++;
 473                 } else {
 474                     System.out.println("ClientSide::doCreateRequest: (OK) Create succeed") ;
 475                 }
 476             } catch(Exception e) {
 477                 Utils.printThrowable(e, true) ;
 478                 if (expectedException) {
 479                     if (e instanceof java.lang.SecurityException) {
 480                         System.out.println("ClientSide::doCreateRequest: " +
 481                             "(OK) Create failed with expected SecurityException") ;
 482                     } else {
 483                         System.out.println("ClientSide::doCreateRequest: " +
 484                             "(ERROR) Create failed with " +
 485                             e.getClass() + " instead of expected SecurityException");
 486                         errorCount++;
 487                     }
 488                 } else {
 489                     System.out.println("ClientSide::doCreateRequest: " +
 490                         "(ERROR) Create failed");
 491                     errorCount++;
 492                 }
 493             }
 494             return errorCount;
 495         }
 496 
 497         protected int doGetRequest(MBeanServerConnection mbsc,
 498                                    ObjectName on,
 499                                    boolean expectedException) {
 500             int errorCount = 0;
 501 
 502             try {
 503                 Utils.debug(Utils.DEBUG_STANDARD,
 504                     "ClientSide::doGetRequest: Get attributes of the MBean") ;
 505 
 506                 mbsc.getAttribute(on, "Attribute");
 507 
 508                 if (expectedException) {
 509                     System.out.println("ClientSide::doGetRequest: " +
 510                         "(ERROR) Get did not fail with expected SecurityException");
 511                     errorCount++;
 512                 } else {
 513                     System.out.println("ClientSide::doGetRequest: (OK) Get succeed") ;
 514                 }
 515             } catch(Exception e) {
 516                 Utils.printThrowable(e, true) ;
 517                 if (expectedException) {
 518                     if (e instanceof java.lang.SecurityException) {
 519                         System.out.println("ClientSide::doGetRequest: " +
 520                             "(OK) Get failed with expected SecurityException") ;
 521                     } else {
 522                         System.out.println("ClientSide::doGetRequest: " +
 523                             "(ERROR) Get failed with " +
 524                             e.getClass() + " instead of expected SecurityException");
 525                         errorCount++;
 526                     }
 527                 } else {
 528                     System.out.println("ClientSide::doGetRequest: (ERROR) Get failed");
 529                     errorCount++;
 530                 }
 531             }
 532 
 533             return errorCount;
 534         }
 535 
 536         protected int doSetRequest(MBeanServerConnection mbsc,
 537                                    ObjectName on,
 538                                    boolean expectedException) {
 539             int errorCount = 0;
 540 
 541             try {
 542                 Utils.debug(Utils.DEBUG_STANDARD,
 543                     "ClientSide::doSetRequest: Set attributes of the MBean") ;
 544 
 545                 Attribute attribute = new Attribute("Attribute", "My value") ;
 546                 mbsc.setAttribute(on, attribute) ;
 547 
 548                 if (expectedException) {
 549                     System.out.println("ClientSide::doSetRequest: " +
 550                         "(ERROR) Set did not fail with expected SecurityException");
 551                     errorCount++;
 552                 } else {
 553                     System.out.println("ClientSide::doSetRequest: (OK) Set succeed") ;
 554                 }
 555             } catch(Exception e) {
 556                 Utils.printThrowable(e, true) ;
 557                 if (expectedException) {
 558                     if (e instanceof java.lang.SecurityException) {
 559                         System.out.println("ClientSide::doSetRequest: " +
 560                             "(OK) Set failed with expected SecurityException") ;
 561                     } else {
 562                         System.out.println("ClientSide::doSetRequest: " +
 563                             "(ERROR) Set failed with " +
 564                             e.getClass() + " instead of expected SecurityException");
 565                         errorCount++;
 566                     }
 567                 } else {
 568                     System.out.println("ClientSide::doSetRequest: (ERROR) Set failed");
 569                     errorCount++;
 570                 }
 571             }
 572             return errorCount;
 573         }
 574 
 575         protected int doInvokeRequest(MBeanServerConnection mbsc,
 576                                       ObjectName on,
 577                                       boolean expectedException) {
 578             int errorCount = 0;
 579 
 580             try {
 581                 Utils.debug(Utils.DEBUG_STANDARD,
 582                     "ClientSide::doInvokeRequest: Invoke operations on the MBean") ;
 583 
 584                 mbsc.invoke(on, "operation", null, null) ;
 585 
 586                 if (expectedException) {
 587                     System.out.println("ClientSide::doInvokeRequest: " +
 588                         "(ERROR) Invoke did not fail with expected SecurityException");
 589                     errorCount++;
 590                 } else {
 591                     System.out.println("ClientSide::doInvokeRequest: (OK) Invoke succeed") ;
 592                 }
 593             } catch(Exception e) {
 594                 Utils.printThrowable(e, true) ;
 595                 if (expectedException) {
 596                     if (e instanceof java.lang.SecurityException) {
 597                         System.out.println("ClientSide::doInvokeRequest: " +
 598                             "(OK) Invoke failed with expected SecurityException") ;
 599                     } else {
 600                         System.out.println("ClientSide::doInvokeRequest: " +
 601                             " (ERROR) Invoke failed with " +
 602                             e.getClass() + " instead of expected SecurityException");
 603                         errorCount++;
 604                     }
 605                 } else {
 606                     System.out.println("ClientSide::doInvokeRequest: " +
 607                         "(ERROR) Invoke failed");
 608                     errorCount++;
 609                 }
 610             }
 611             return errorCount;
 612         }
 613 
 614     }
 615 }