1 /*
   2  * Copyright (c) 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.
   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 8015081
  27  * @summary     javax.security.auth.Subject.toString() throws NPE
  28  */
  29 
  30 import java.io.File;
  31 import java.io.FileInputStream;
  32 import java.io.ObjectInputStream;
  33 import java.io.IOException;
  34 import java.lang.Exception;
  35 import java.security.Principal;
  36 import java.util.Arrays;
  37 import java.util.Collection;
  38 import java.util.Collections;
  39 import java.util.HashSet;
  40 import java.util.LinkedList;
  41 import java.util.List;
  42 import java.util.Set;
  43 import javax.management.remote.JMXPrincipal;
  44 import javax.security.auth.Subject;
  45 import javax.security.auth.x500.X500Principal;
  46 import javax.security.auth.kerberos.KerberosPrincipal;
  47 
  48 public class SubjectNullTests {
  49 
  50     // Value templates for the constructor
  51     private static Principal[] princVals = {
  52         new X500Principal("CN=Tom Sawyer, ST=Missouri, C=US"),
  53         new JMXPrincipal("Huckleberry Finn"),
  54         new KerberosPrincipal("mtwain/author@LITERATURE.US")
  55     };
  56     private static String[] pubVals = {"tsawyer", "hfinn", "mtwain"};
  57     private static String[] privVals = {"th3R!v3r", "oNth3R4ft", "5Cl3M3nz"};
  58 
  59     // Templates for collection-based modifiers for the Subject
  60     private static Principal[] tmplAddPrincs = {
  61         new X500Principal("CN=John Doe, O=Bogus Corp."),
  62         new KerberosPrincipal("jdoe/admin@BOGUSCORP.COM")
  63     };
  64     private static String[] tmplAddPubVals = {"jdoe", "djoe"};
  65     private static String[] tmplAddPrvVals = {"b4dpa55w0rd", "pass123"};
  66 
  67     /**
  68      * Construct a subject, and optionally place a null in any one
  69      * of the three Sets used to initialize a Subject's values
  70      */
  71     private static Subject makeSubj(boolean nullPrinc, boolean nullPub,
  72                              boolean nullPriv) {
  73         Set<Principal> setPrinc =
  74             new HashSet<Principal>(Arrays.asList(princVals));
  75         Set<String> setPubCreds = new HashSet<String>(Arrays.asList(pubVals));
  76         Set<String> setPrvCreds = new HashSet<String>(Arrays.asList(privVals));
  77 
  78         if (nullPrinc) {
  79             setPrinc.add(null);
  80         }
  81 
  82         if (nullPub) {
  83             setPubCreds.add(null);
  84         }
  85 
  86         if (nullPriv) {
  87             setPrvCreds.add(null);
  88         }
  89 
  90         return (new Subject(false, setPrinc, setPubCreds, setPrvCreds));
  91     }
  92 
  93     /**
  94      * Provide a simple interface for abstracting collection-on-collection
  95      * functions
  96      */
  97     public interface Function {
  98         boolean execCollection(Set<?> subjSet, Collection<?> actorData);
  99     }
 100 
 101     public static final Function methAdd = new Function() {
 102         public boolean execCollection(Set<?> subjSet, Collection<?> actorData) {
 103             return subjSet.addAll((Collection)actorData);
 104         }
 105     };
 106 
 107     public static final Function methContains = new Function() {
 108         public boolean execCollection(Set<?> subjSet, Collection<?> actorData) {
 109             return subjSet.containsAll(actorData);
 110         }
 111     };
 112 
 113     public static final Function methRemove = new Function() {
 114         public boolean execCollection(Set<?> subjSet, Collection<?> actorData) {
 115             return subjSet.removeAll(actorData);
 116         }
 117     };
 118 
 119     public static final Function methRetain = new Function() {
 120         public boolean execCollection(Set<?> subjSet, Collection<?> actorData) {
 121             return subjSet.retainAll(actorData);
 122         }
 123     };
 124 
 125     /**
 126      * Run a test using a specified Collection method upon a Subject's
 127      * SecureSet fields. This method expects NullPointerExceptions
 128      * to be thrown, and throws RuntimeException when the operation
 129      * succeeds
 130      */
 131     private static void nullTestCollection(Function meth, Set<?> subjSet,
 132            Collection<?> actorData) {
 133         try { 
 134             meth.execCollection(subjSet, actorData);
 135             throw new RuntimeException("Failed to throw NullPointerException");
 136         } catch (NullPointerException npe) {
 137             System.out.println("Caught expected NullPointerException [PASS]");
 138         }
 139     }
 140 
 141     /**
 142      * Run a test using a specified Collection method upon a Subject's
 143      * SecureSet fields. This method expects the function and arguments
 144      * passed in to complete without exception.  It returns false
 145      * if either an exception occurs or the result of the operation is
 146      * false.
 147      */
 148     private static boolean validTestCollection(Function meth, Set<?> subjSet,
 149            Collection<?> actorData) {
 150         boolean result = false;
 151 
 152         try { 
 153             result = meth.execCollection(subjSet, actorData);
 154         } catch (Exception exc) {
 155             System.out.println("Caught exception " + exc);
 156         }
 157 
 158         return result;
 159     }
 160 
 161     /**
 162      * Deserialize an object from a file.
 163      *
 164      * @param type The {@code Class} that the serialized file is supposed
 165      *             to contain.
 166      * @param fileName The name of the file to be deserialized.
 167      *
 168      * @return An object of the type specified in the {@code type} parameter
 169      */
 170     private static <T> T deserializeFile(Class type, String fileName)
 171             throws IOException, ClassNotFoundException {
 172         File fileObj = new File(System.getProperty("test.src", "."), fileName);
 173         FileInputStream fis = new FileInputStream(fileObj);
 174         ObjectInputStream ois = new ObjectInputStream(fis);
 175 
 176         T newObj = (T)ois.readObject();
 177         ois.close();
 178         fis.close();
 179 
 180         return newObj;
 181     }
 182 
 183     private static void testCTOR() {
 184         System.out.println("------ constructor ------");
 185 
 186         try {
 187             // Case 1: Create a subject with a null principal
 188             // Expected result: NullPointerException
 189             Subject mtSubj = makeSubj(true, false, false);
 190             throw new RuntimeException(
 191                     "constructor [principal w/ null]: Failed to throw NPE");
 192         } catch (NullPointerException npe) {
 193             System.out.println("constructor [principal w/ null]: " +
 194                     "NullPointerException [PASS]");
 195         }
 196 
 197         try {
 198             // Case 2: Create a subject with a null public credential element
 199             // Expected result: NullPointerException
 200             Subject mtSubj = makeSubj(false, true, false);
 201             throw new RuntimeException(
 202                     "constructor [pub cred w/ null]: Failed to throw NPE");
 203         } catch (NullPointerException npe) {
 204             System.out.println("constructor [pub cred w/ null]: " +
 205                     "NullPointerException [PASS]");
 206         }
 207 
 208         try {
 209             // Case 3: Create a subject with a null private credential element
 210             // Expected result: NullPointerException
 211             Subject mtSubj = makeSubj(false, false, true);
 212             throw new RuntimeException(
 213                     "constructor [priv cred w/ null]: Failed to throw NPE");
 214         } catch (NullPointerException npe) {
 215             System.out.println("constructor [priv cred w/ null]: " +
 216                     "NullPointerException [PASS]");
 217         }
 218 
 219         // Case 4: Create a new subject using the principals, public
 220         // and private credentials from another well-formed subject
 221         // Expected result: Successful construction
 222         Subject srcSubj = makeSubj(false, false, false);
 223         Subject mtSubj = new Subject(false, srcSubj.getPrincipals(),
 224                 srcSubj.getPublicCredentials(),
 225                 srcSubj.getPrivateCredentials());
 226         System.out.println("Construction from another well-formed Subject's " +
 227                 "principals/creds [PASS]");
 228     }
 229 
 230     private static void testDeserialize() throws Exception {
 231         System.out.println("------ deserialize -----");
 232 
 233         Subject subj = null;
 234         Set<Principal> prin = null;
 235 
 236         // Case 1: positive deserialization test of a Subject
 237         // Expected result: well-formed Subject
 238         subj = deserializeFile(Subject.class, "SubjNoNull.bin");
 239         System.out.println("Positive deserialization test (Subject) passed");
 240         
 241         // Case 2: positive deserialization test of a SecureSet
 242         // Expected result: well-formed Set
 243         prin = deserializeFile(Set.class, "PrinNoNull.bin");
 244         System.out.println("Positive deserialization test (SecureSet) passed");
 245  
 246         System.out.println(
 247                 "* Testing deserialization with null-poisoned objects");
 248         // Case 3: deserialization test of a null-poisoned Subject
 249         // Expected result: NullPointerException
 250         try {
 251             subj = deserializeFile(Subject.class, "SubjWithNull.bin");
 252             throw new RuntimeException("Failed to throw NullPointerException");
 253         } catch (NullPointerException npe) {
 254             System.out.println("Caught expected NullPointerException [PASS]");
 255         }
 256 
 257         // Case 4: deserialization test of a null-poisoned SecureSet
 258         // Expected result: NullPointerException
 259         try {
 260             prin = deserializeFile(Set.class, "PrinWithNull.bin");
 261             throw new RuntimeException("Failed to throw NullPointerException");
 262         } catch (NullPointerException npe) {
 263             System.out.println("Caught expected NullPointerException [PASS]");
 264         }
 265     }
 266 
 267     private static void testAdd() {
 268         System.out.println("------ add() ------");
 269         // Create a well formed subject
 270         Subject mtSubj = makeSubj(false, false, false);
 271 
 272         try {
 273             // Case 1: Attempt to add null values to principal
 274             // Expected result: NullPointerException
 275             mtSubj.getPrincipals().add(null);
 276             throw new RuntimeException(
 277                     "PRINCIPAL add(null): Failed to throw NPE");
 278         } catch (NullPointerException npe) {
 279             System.out.println(
 280                     "PRINCIPAL add(null): NullPointerException [PASS]");
 281         }
 282 
 283         try {
 284             // Case 2: Attempt to add null into the public creds
 285             // Expected result: NullPointerException
 286             mtSubj.getPublicCredentials().add(null);
 287             throw new RuntimeException(
 288                     "PUB CRED add(null): Failed to throw NPE");
 289         } catch (NullPointerException npe) {
 290             System.out.println(
 291                     "PUB CRED add(null): NullPointerException [PASS]");
 292         }
 293 
 294         try {
 295             // Case 3: Attempt to add null into the private creds
 296             // Expected result: NullPointerException
 297             mtSubj.getPrivateCredentials().add(null);
 298             throw new RuntimeException(
 299                     "PRIV CRED add(null): Failed to throw NPE");
 300         } catch (NullPointerException npe) {
 301             System.out.println(
 302                     "PRIV CRED add(null): NullPointerException [PASS]");
 303         }
 304     }
 305 
 306     private static void testRemove() {
 307         System.out.println("------ remove() ------");
 308         // Create a well formed subject
 309         Subject mtSubj = makeSubj(false, false, false);
 310 
 311         try {
 312             // Case 1: Attempt to remove null values from principal
 313             // Expected result: NullPointerException
 314             mtSubj.getPrincipals().remove(null);
 315             throw new RuntimeException(
 316                     "PRINCIPAL remove(null): Failed to throw NPE");
 317         } catch (NullPointerException npe) {
 318             System.out.println(
 319                     "PRINCIPAL remove(null): NullPointerException [PASS]");
 320         }
 321 
 322         try {
 323             // Case 2: Attempt to remove null from the public creds
 324             // Expected result: NullPointerException
 325             mtSubj.getPublicCredentials().remove(null);
 326             throw new RuntimeException(
 327                     "PUB CRED remove(null): Failed to throw NPE");
 328         } catch (NullPointerException npe) {
 329             System.out.println(
 330                     "PUB CRED remove(null): NullPointerException [PASS]");
 331         }
 332 
 333         try {
 334             // Case 3: Attempt to remove null from the private creds
 335             // Expected result: NullPointerException
 336             mtSubj.getPrivateCredentials().remove(null);
 337             throw new RuntimeException(
 338                     "PRIV CRED remove(null): Failed to throw NPE");
 339         } catch (NullPointerException npe) {
 340             System.out.println(
 341                     "PRIV CRED remove(null): NullPointerException [PASS]");
 342         }
 343     }
 344 
 345     private static void testContains() {
 346         System.out.println("------ contains() ------");
 347         // Create a well formed subject
 348         Subject mtSubj = makeSubj(false, false, false);
 349 
 350         try {
 351             // Case 1: Attempt to check for null values in principals
 352             // Expected result: NullPointerException
 353             mtSubj.getPrincipals().contains(null);
 354             throw new RuntimeException(
 355                     "PRINCIPAL contains(null): Failed to throw NPE");
 356         } catch (NullPointerException npe) {
 357             System.out.println(
 358                     "PRINCIPAL contains(null): NullPointerException [PASS]");
 359         }
 360 
 361         try {
 362             // Case 2: Attempt to check for null in public creds
 363             // Expected result: NullPointerException
 364             mtSubj.getPublicCredentials().contains(null);
 365             throw new RuntimeException(
 366                     "PUB CRED contains(null): Failed to throw NPE");
 367         } catch (NullPointerException npe) {
 368             System.out.println(
 369                     "PUB CRED contains(null): NullPointerException [PASS]");
 370         }
 371 
 372         try {
 373             // Case 3: Attempt to check for null in private creds
 374             // Expected result: NullPointerException
 375             mtSubj.getPrivateCredentials().contains(null);
 376             throw new RuntimeException(
 377                     "PRIV CRED contains(null): Failed to throw NPE");
 378         } catch (NullPointerException npe) {
 379             System.out.println(
 380                     "PRIV CRED contains(null): NullPointerException [PASS]");
 381         }
 382     }
 383 
 384     private static void testAddAll() {
 385         // Create a well formed subject and additional collections
 386         Subject mtSubj = makeSubj(false, false, false);
 387         Set<Principal> morePrincs = new HashSet<>(Arrays.asList(tmplAddPrincs));
 388         Set<Object> morePubVals = new HashSet<>(Arrays.asList(tmplAddPubVals));
 389         Set<Object> morePrvVals = new HashSet<>(Arrays.asList(tmplAddPrvVals));
 390 
 391         // Run one success test for each Subject family to verify the
 392         // overloaded method works as intended.
 393         Set<Principal> setPrin = mtSubj.getPrincipals();
 394         Set<Object> setPubCreds = mtSubj.getPublicCredentials();
 395         Set<Object> setPrvCreds = mtSubj.getPrivateCredentials();
 396         int prinOrigSize = setPrin.size();
 397         int pubOrigSize = setPubCreds.size();
 398         int prvOrigSize = setPrvCreds.size();
 399 
 400         System.out.println("------ addAll() -----");
 401 
 402         // Add the new members, then check the resulting size of the
 403         // Subject attributes to verify they've increased by the proper
 404         // amounts.
 405         if ((validTestCollection(methAdd, setPrin, morePrincs) != true) ||
 406             (setPrin.size() != prinOrigSize + morePrincs.size()))
 407         {
 408             throw new RuntimeException("Failed addAll() on principals");
 409         }
 410         if ((validTestCollection(methAdd, setPubCreds,
 411                 morePubVals) != true) ||
 412             (setPubCreds.size() != pubOrigSize + morePubVals.size()))
 413         {
 414             throw new RuntimeException("Failed addAll() on public creds");
 415         }
 416         if ((validTestCollection(methAdd, setPrvCreds,
 417                 morePrvVals) != true) ||
 418             (setPrvCreds.size() != prvOrigSize + morePrvVals.size()))
 419         {
 420             throw new RuntimeException("Failed addAll() on private creds");
 421         }
 422         System.out.println("Positive addAll() test passed");
 423 
 424         // Now add null elements into each container, then retest
 425         morePrincs.add(null);
 426         morePubVals.add(null);
 427         morePrvVals.add(null);
 428 
 429         System.out.println("* Testing addAll w/ null values on Principals");
 430         nullTestCollection(methAdd, mtSubj.getPrincipals(), null);
 431         nullTestCollection(methAdd, mtSubj.getPrincipals(), morePrincs);
 432 
 433         System.out.println("* Testing addAll w/ null values on Public Creds");
 434         nullTestCollection(methAdd, mtSubj.getPublicCredentials(), null);
 435         nullTestCollection(methAdd, mtSubj.getPublicCredentials(),
 436                 morePubVals);
 437  
 438         System.out.println("* Testing addAll w/ null values on Private Creds");
 439         nullTestCollection(methAdd, mtSubj.getPrivateCredentials(), null);
 440         nullTestCollection(methAdd, mtSubj.getPrivateCredentials(),
 441                 morePrvVals);
 442     }
 443 
 444     private static void testRemoveAll() {
 445         // Create a well formed subject and additional collections
 446         Subject mtSubj = makeSubj(false, false, false);
 447         Set<Principal> remPrincs = new HashSet<>();
 448         Set<Object> remPubVals = new HashSet<>();
 449         Set<Object> remPrvVals = new HashSet<>();
 450 
 451         remPrincs.add(new KerberosPrincipal("mtwain/author@LITERATURE.US"));
 452         remPubVals.add("mtwain");
 453         remPrvVals.add("5Cl3M3nz");
 454 
 455         // Run one success test for each Subject family to verify the
 456         // overloaded method works as intended.
 457         Set<Principal> setPrin = mtSubj.getPrincipals();
 458         Set<Object> setPubCreds = mtSubj.getPublicCredentials();
 459         Set<Object> setPrvCreds = mtSubj.getPrivateCredentials();
 460         int prinOrigSize = setPrin.size();
 461         int pubOrigSize = setPubCreds.size();
 462         int prvOrigSize = setPrvCreds.size();
 463 
 464         System.out.println("------ removeAll() -----");
 465 
 466         // Remove the specified members, then check the resulting size of the
 467         // Subject attributes to verify they've decreased by the proper
 468         // amounts.
 469         if ((validTestCollection(methRemove, setPrin, remPrincs) != true) ||
 470             (setPrin.size() != prinOrigSize - remPrincs.size()))
 471         {
 472             throw new RuntimeException("Failed removeAll() on principals");
 473         }
 474         if ((validTestCollection(methRemove, setPubCreds,
 475                 remPubVals) != true) ||
 476             (setPubCreds.size() != pubOrigSize - remPubVals.size()))
 477         {
 478             throw new RuntimeException("Failed removeAll() on public creds");
 479         }
 480         if ((validTestCollection(methRemove, setPrvCreds,
 481                 remPrvVals) != true) ||
 482             (setPrvCreds.size() != prvOrigSize - remPrvVals.size()))
 483         {
 484             throw new RuntimeException("Failed removeAll() on private creds");
 485         }
 486         System.out.println("Positive removeAll() test passed");
 487 
 488         // Now add null elements into each container, then retest
 489         remPrincs.add(null);
 490         remPubVals.add(null);
 491         remPrvVals.add(null);
 492 
 493         System.out.println("* Testing removeAll w/ null values on Principals");
 494         nullTestCollection(methRemove, mtSubj.getPrincipals(), null);
 495         nullTestCollection(methRemove, mtSubj.getPrincipals(), remPrincs);
 496 
 497         System.out.println(
 498                 "* Testing removeAll w/ null values on Public Creds");
 499         nullTestCollection(methRemove, mtSubj.getPublicCredentials(), null);
 500         nullTestCollection(methRemove, mtSubj.getPublicCredentials(),
 501                 remPubVals);
 502  
 503         System.out.println(
 504                 "* Testing removeAll w/ null values on Private Creds");
 505         nullTestCollection(methRemove, mtSubj.getPrivateCredentials(), null);
 506         nullTestCollection(methRemove, mtSubj.getPrivateCredentials(),
 507                 remPrvVals);
 508     }
 509 
 510     private static void testContainsAll() {
 511         // Create a well formed subject and additional collections
 512         Subject mtSubj = makeSubj(false, false, false);
 513         Set<Principal> testPrincs = new HashSet<>(Arrays.asList(princVals));
 514         Set<Object> testPubVals = new HashSet<>(Arrays.asList(pubVals));
 515         Set<Object> testPrvVals = new HashSet<>(Arrays.asList(privVals));
 516 
 517         System.out.println("------ containsAll() -----");
 518 
 519         // Run one success test for each Subject family to verify the
 520         // overloaded method works as intended.
 521         if ((validTestCollection(methContains, mtSubj.getPrincipals(),
 522                  testPrincs) == false) &&
 523             (validTestCollection(methContains, mtSubj.getPublicCredentials(),
 524                  testPubVals) == false) &&
 525             (validTestCollection(methContains,
 526                  mtSubj.getPrivateCredentials(), testPrvVals) == false)) {
 527             throw new RuntimeException("Valid containsAll() check failed");
 528         }
 529         System.out.println("Positive containsAll() test passed");
 530 
 531         // Now let's add a null into each collection and watch the fireworks.
 532         testPrincs.add(null);
 533         testPubVals.add(null);
 534         testPrvVals.add(null);
 535 
 536         System.out.println(
 537                 "* Testing containsAll w/ null values on Principals");
 538         nullTestCollection(methContains, mtSubj.getPrincipals(), null);
 539         nullTestCollection(methContains, mtSubj.getPrincipals(), testPrincs);
 540 
 541         System.out.println(
 542                 "* Testing containsAll w/ null values on Public Creds");
 543         nullTestCollection(methContains, mtSubj.getPublicCredentials(),
 544                 null);
 545         nullTestCollection(methContains, mtSubj.getPublicCredentials(),
 546                 testPubVals);
 547  
 548         System.out.println(
 549                 "* Testing containsAll w/ null values on Private Creds");
 550         nullTestCollection(methContains, mtSubj.getPrivateCredentials(),
 551                 null);
 552         nullTestCollection(methContains, mtSubj.getPrivateCredentials(),
 553                 testPrvVals);
 554     }
 555 
 556     private static void testRetainAll() {
 557         // Create a well formed subject and additional collections
 558         Subject mtSubj = makeSubj(false, false, false);
 559         Set<Principal> remPrincs = new HashSet<>(Arrays.asList(tmplAddPrincs));
 560         Set<Object> remPubVals = new HashSet<>(Arrays.asList(tmplAddPubVals));
 561         Set<Object> remPrvVals = new HashSet<>(Arrays.asList(tmplAddPrvVals));
 562 
 563         // Add in values that exist within the Subject
 564         remPrincs.add(princVals[2]);
 565         remPubVals.add(pubVals[2]);
 566         remPrvVals.add(privVals[2]);
 567 
 568         // Run one success test for each Subject family to verify the
 569         // overloaded method works as intended.
 570         Set<Principal> setPrin = mtSubj.getPrincipals();
 571         Set<Object> setPubCreds = mtSubj.getPublicCredentials();
 572         Set<Object> setPrvCreds = mtSubj.getPrivateCredentials();
 573         int prinOrigSize = setPrin.size();
 574         int pubOrigSize = setPubCreds.size();
 575         int prvOrigSize = setPrvCreds.size();
 576 
 577         System.out.println("------ retainAll() -----");
 578 
 579         // Retain the specified members (those that exist in the Subject)
 580         // and validate the results.
 581         if (validTestCollection(methRetain, setPrin, remPrincs) == false ||
 582             setPrin.size() != 1 || setPrin.contains(princVals[2]) == false)
 583         {
 584             throw new RuntimeException("Failed retainAll() on principals");
 585         }
 586  
 587         if (validTestCollection(methRetain, setPubCreds,
 588                 remPubVals) == false ||
 589             setPubCreds.size() != 1 ||
 590             setPubCreds.contains(pubVals[2]) == false)
 591         {
 592             throw new RuntimeException("Failed retainAll() on public creds");
 593         }
 594         if (validTestCollection(methRetain, setPrvCreds,
 595                 remPrvVals) == false ||
 596             setPrvCreds.size() != 1 ||
 597             setPrvCreds.contains(privVals[2]) == false)
 598         {
 599             throw new RuntimeException("Failed retainAll() on private creds");
 600         }
 601         System.out.println("Positive retainAll() test passed");
 602 
 603         // Now add null elements into each container, then retest
 604         remPrincs.add(null);
 605         remPubVals.add(null);
 606         remPrvVals.add(null);
 607 
 608         System.out.println("* Testing retainAll w/ null values on Principals");
 609         nullTestCollection(methRetain, mtSubj.getPrincipals(), null);
 610         nullTestCollection(methRetain, mtSubj.getPrincipals(), remPrincs);
 611 
 612         System.out.println(
 613                 "* Testing retainAll w/ null values on Public Creds");
 614         nullTestCollection(methRetain, mtSubj.getPublicCredentials(), null);
 615         nullTestCollection(methRetain, mtSubj.getPublicCredentials(),
 616                 remPubVals);
 617  
 618         System.out.println(
 619                 "* Testing retainAll w/ null values on Private Creds");
 620         nullTestCollection(methRetain, mtSubj.getPrivateCredentials(), null);
 621         nullTestCollection(methRetain, mtSubj.getPrivateCredentials(),
 622                 remPrvVals);
 623     }
 624 
 625     public static void main(String[] args) throws Exception {
 626 
 627         testCTOR();
 628 
 629         testDeserialize();
 630 
 631         testAdd();
 632 
 633         testRemove();
 634 
 635         testContains();
 636 
 637         testAddAll();
 638 
 639         testRemoveAll();
 640 
 641         testContainsAll();
 642 
 643         testRetainAll();
 644 
 645     }
 646 }