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  * @compile Subject.java
  28  * @compile SubjectNullTests.java
  29  * @build SubjectNullTests
  30  * @run main SubjectNullTests
  31  * @summary javax.security.auth.Subject.toString() throws NPE
  32  */
  33 
  34 import java.io.File;
  35 import java.io.ByteArrayInputStream;
  36 import java.io.FileInputStream;
  37 import java.io.ObjectInputStream;
  38 import java.io.IOException;
  39 import java.security.Principal;
  40 import java.util.Arrays;
  41 import java.util.Collection;
  42 import java.util.HashSet;
  43 import java.util.LinkedList;
  44 import java.util.List;
  45 import java.util.Set;
  46 import javax.management.remote.JMXPrincipal;
  47 import javax.security.auth.Subject;
  48 import javax.security.auth.x500.X500Principal;
  49 import javax.security.auth.kerberos.KerberosPrincipal;
  50 
  51 public class SubjectNullTests {
  52 
  53     // Value templates for the constructor
  54     private static Principal[] princVals = {
  55         new X500Principal("CN=Tom Sawyer, ST=Missouri, C=US"),
  56         new JMXPrincipal("Huckleberry Finn"),
  57         new KerberosPrincipal("mtwain/author@LITERATURE.US")
  58     };
  59     private static String[] pubVals = {"tsawyer", "hfinn", "mtwain"};
  60     private static String[] privVals = {"th3R!v3r", "oNth3R4ft", "5Cl3M3nz"};
  61 
  62     // Templates for collection-based modifiers for the Subject
  63     private static Principal[] tmplAddPrincs = {
  64         new X500Principal("CN=John Doe, O=Bogus Corp."),
  65         new KerberosPrincipal("jdoe/admin@BOGUSCORP.COM")
  66     };
  67     private static String[] tmplAddPubVals = {"jdoe", "djoe"};
  68     private static String[] tmplAddPrvVals = {"b4dpa55w0rd", "pass123"};
  69 
  70     /**
  71      * Byte arrays used for deserialization:
  72      * These byte arrays contain serialized Subjects and SecureSets,
  73      * either with or without nulls.  These use
  74      * jjjjj.security.auth.Subject, which is a modified Subject
  75      * implementation that allows the addition of null elements
  76      */
  77     private static final byte[] SUBJ_NO_NULL =
  78         jjjjj.security.auth.Subject.enc(makeSubjWithNull(false));
  79     private static final byte[] SUBJ_WITH_NULL =
  80         jjjjj.security.auth.Subject.enc(makeSubjWithNull(true));
  81     private static final byte[] PRIN_NO_NULL =
  82         jjjjj.security.auth.Subject.enc(makeSecSetWithNull(false));
  83     private static final byte[] PRIN_WITH_NULL =
  84         jjjjj.security.auth.Subject.enc(makeSecSetWithNull(true));
  85 
  86     /**
  87      * Method to allow creation of a subject that can optionally
  88      * insert a null reference into the principals Set.
  89      */
  90     private static jjjjj.security.auth.Subject makeSubjWithNull(
  91             boolean nullPrinc) {
  92         Set<Principal> setPrinc = new HashSet<>(Arrays.asList(princVals));
  93         if (nullPrinc) {
  94             setPrinc.add(null);
  95         }
  96 
  97         return (new jjjjj.security.auth.Subject(setPrinc));
  98     }
  99 
 100     /**
 101      * Method to allow creation of a SecureSet that can optionally
 102      * insert a null reference.
 103      */
 104     private static Set<Principal> makeSecSetWithNull(boolean nullPrinc) {
 105         Set<Principal> setPrinc = new HashSet<>(Arrays.asList(princVals));
 106         if (nullPrinc) {
 107             setPrinc.add(null);
 108         }
 109 
 110         jjjjj.security.auth.Subject subj =
 111             new jjjjj.security.auth.Subject(setPrinc);
 112 
 113         return subj.getPrincipals();
 114     }
 115 
 116     /**
 117      * Construct a subject, and optionally place a null in any one
 118      * of the three Sets used to initialize a Subject's values
 119      */
 120     private static Subject makeSubj(boolean nullPrinc, boolean nullPub,
 121                              boolean nullPriv) {
 122         Set<Principal> setPrinc = new HashSet<>(Arrays.asList(princVals));
 123         Set<String> setPubCreds = new HashSet<>(Arrays.asList(pubVals));
 124         Set<String> setPrvCreds = new HashSet<>(Arrays.asList(privVals));
 125 
 126         if (nullPrinc) {
 127             setPrinc.add(null);
 128         }
 129 
 130         if (nullPub) {
 131             setPubCreds.add(null);
 132         }
 133 
 134         if (nullPriv) {
 135             setPrvCreds.add(null);
 136         }
 137 
 138         return (new Subject(false, setPrinc, setPubCreds, setPrvCreds));
 139     }
 140 
 141     /**
 142      * Provide a simple interface for abstracting collection-on-collection
 143      * functions
 144      */
 145     public interface Function {
 146         boolean execCollection(Set<?> subjSet, Collection<?> actorData);
 147     }
 148 
 149     public static final Function methAdd = new Function() {
 150         @SuppressWarnings("unchecked")
 151         @Override
 152         public boolean execCollection(Set<?> subjSet, Collection<?> actorData) {
 153             return subjSet.addAll((Collection)actorData);
 154         }
 155     };
 156 
 157     public static final Function methContains = new Function() {
 158         @Override
 159         public boolean execCollection(Set<?> subjSet, Collection<?> actorData) {
 160             return subjSet.containsAll(actorData);
 161         }
 162     };
 163 
 164     public static final Function methRemove = new Function() {
 165         @Override
 166         public boolean execCollection(Set<?> subjSet, Collection<?> actorData) {
 167             return subjSet.removeAll(actorData);
 168         }
 169     };
 170 
 171     public static final Function methRetain = new Function() {
 172         @Override
 173         public boolean execCollection(Set<?> subjSet, Collection<?> actorData) {
 174             return subjSet.retainAll(actorData);
 175         }
 176     };
 177 
 178     /**
 179      * Run a test using a specified Collection method upon a Subject's
 180      * SecureSet fields. This method expects NullPointerExceptions
 181      * to be thrown, and throws RuntimeException when the operation
 182      * succeeds
 183      */
 184     private static void nullTestCollection(Function meth, Set<?> subjSet,
 185            Collection<?> actorData) {
 186         try {
 187             meth.execCollection(subjSet, actorData);
 188             throw new RuntimeException("Failed to throw NullPointerException");
 189         } catch (NullPointerException npe) {
 190             System.out.println("Caught expected NullPointerException [PASS]");
 191         }
 192     }
 193 
 194     /**
 195      * Run a test using a specified Collection method upon a Subject's
 196      * SecureSet fields. This method expects the function and arguments
 197      * passed in to complete without exception.  It returns false
 198      * if either an exception occurs or the result of the operation is
 199      * false.
 200      */
 201     private static boolean validTestCollection(Function meth, Set<?> subjSet,
 202            Collection<?> actorData) {
 203         boolean result = false;
 204 
 205         try {
 206             result = meth.execCollection(subjSet, actorData);
 207         } catch (Exception exc) {
 208             System.out.println("Caught exception " + exc);
 209         }
 210 
 211         return result;
 212     }
 213 
 214     /**
 215      * Deserialize an object from a byte array.
 216      *
 217      * @param type The {@code Class} that the serialized file is supposed
 218      *             to contain.
 219      * @param serBuffer The byte array containing the serialized object data
 220      *
 221      * @return An object of the type specified in the {@code type} parameter
 222      */
 223     private static <T> T deserializeBuffer(Class<T> type, byte[] serBuffer)
 224             throws IOException, ClassNotFoundException {
 225 
 226         ByteArrayInputStream bis = new ByteArrayInputStream(serBuffer);
 227         ObjectInputStream ois = new ObjectInputStream(bis);
 228 
 229         T newObj = type.cast(ois.readObject());
 230         ois.close();
 231         bis.close();
 232 
 233         return newObj;
 234     }
 235 
 236     private static void testCTOR() {
 237         System.out.println("------ constructor ------");
 238 
 239         try {
 240             // Case 1: Create a subject with a null principal
 241             // Expected result: NullPointerException
 242             Subject mtSubj = makeSubj(true, false, false);
 243             throw new RuntimeException(
 244                     "constructor [principal w/ null]: Failed to throw NPE");
 245         } catch (NullPointerException npe) {
 246             System.out.println("constructor [principal w/ null]: " +
 247                     "NullPointerException [PASS]");
 248         }
 249 
 250         try {
 251             // Case 2: Create a subject with a null public credential element
 252             // Expected result: NullPointerException
 253             Subject mtSubj = makeSubj(false, true, false);
 254             throw new RuntimeException(
 255                     "constructor [pub cred w/ null]: Failed to throw NPE");
 256         } catch (NullPointerException npe) {
 257             System.out.println("constructor [pub cred w/ null]: " +
 258                     "NullPointerException [PASS]");
 259         }
 260 
 261         try {
 262             // Case 3: Create a subject with a null private credential element
 263             // Expected result: NullPointerException
 264             Subject mtSubj = makeSubj(false, false, true);
 265             throw new RuntimeException(
 266                     "constructor [priv cred w/ null]: Failed to throw NPE");
 267         } catch (NullPointerException npe) {
 268             System.out.println("constructor [priv cred w/ null]: " +
 269                     "NullPointerException [PASS]");
 270         }
 271 
 272         // Case 4: Create a new subject using the principals, public
 273         // and private credentials from another well-formed subject
 274         // Expected result: Successful construction
 275         Subject srcSubj = makeSubj(false, false, false);
 276         Subject mtSubj = new Subject(false, srcSubj.getPrincipals(),
 277                 srcSubj.getPublicCredentials(),
 278                 srcSubj.getPrivateCredentials());
 279         System.out.println("Construction from another well-formed Subject's " +
 280                 "principals/creds [PASS]");
 281     }
 282 
 283     @SuppressWarnings("unchecked")
 284     private static void testDeserialize() throws Exception {
 285         System.out.println("------ deserialize -----");
 286 
 287         Subject subj = null;
 288         Set<Principal> prin = null;
 289 
 290         // Case 1: positive deserialization test of a Subject
 291         // Expected result: well-formed Subject
 292         subj = deserializeBuffer(Subject.class, SUBJ_NO_NULL);
 293         System.out.println("Positive deserialization test (Subject) passed");
 294 
 295         // Case 2: positive deserialization test of a SecureSet
 296         // Expected result: well-formed Set
 297         prin = deserializeBuffer(Set.class, PRIN_NO_NULL);
 298         System.out.println("Positive deserialization test (SecureSet) passed");
 299 
 300         System.out.println(
 301                 "* Testing deserialization with null-poisoned objects");
 302         // Case 3: deserialization test of a null-poisoned Subject
 303         // Expected result: NullPointerException
 304         try {
 305             subj = deserializeBuffer(Subject.class, SUBJ_WITH_NULL);
 306             throw new RuntimeException("Failed to throw NullPointerException");
 307         } catch (NullPointerException npe) {
 308             System.out.println("Caught expected NullPointerException [PASS]");
 309         }
 310 
 311         // Case 4: deserialization test of a null-poisoned SecureSet
 312         // Expected result: NullPointerException
 313         try {
 314             prin = deserializeBuffer(Set.class, PRIN_WITH_NULL);
 315             throw new RuntimeException("Failed to throw NullPointerException");
 316         } catch (NullPointerException npe) {
 317             System.out.println("Caught expected NullPointerException [PASS]");
 318         }
 319     }
 320 
 321     private static void testAdd() {
 322         System.out.println("------ add() ------");
 323         // Create a well formed subject
 324         Subject mtSubj = makeSubj(false, false, false);
 325 
 326         try {
 327             // Case 1: Attempt to add null values to principal
 328             // Expected result: NullPointerException
 329             mtSubj.getPrincipals().add(null);
 330             throw new RuntimeException(
 331                     "PRINCIPAL add(null): Failed to throw NPE");
 332         } catch (NullPointerException npe) {
 333             System.out.println(
 334                     "PRINCIPAL add(null): NullPointerException [PASS]");
 335         }
 336 
 337         try {
 338             // Case 2: Attempt to add null into the public creds
 339             // Expected result: NullPointerException
 340             mtSubj.getPublicCredentials().add(null);
 341             throw new RuntimeException(
 342                     "PUB CRED add(null): Failed to throw NPE");
 343         } catch (NullPointerException npe) {
 344             System.out.println(
 345                     "PUB CRED add(null): NullPointerException [PASS]");
 346         }
 347 
 348         try {
 349             // Case 3: Attempt to add null into the private creds
 350             // Expected result: NullPointerException
 351             mtSubj.getPrivateCredentials().add(null);
 352             throw new RuntimeException(
 353                     "PRIV CRED add(null): Failed to throw NPE");
 354         } catch (NullPointerException npe) {
 355             System.out.println(
 356                     "PRIV CRED add(null): NullPointerException [PASS]");
 357         }
 358     }
 359 
 360     private static void testRemove() {
 361         System.out.println("------ remove() ------");
 362         // Create a well formed subject
 363         Subject mtSubj = makeSubj(false, false, false);
 364 
 365         try {
 366             // Case 1: Attempt to remove null values from principal
 367             // Expected result: NullPointerException
 368             mtSubj.getPrincipals().remove(null);
 369             throw new RuntimeException(
 370                     "PRINCIPAL remove(null): Failed to throw NPE");
 371         } catch (NullPointerException npe) {
 372             System.out.println(
 373                     "PRINCIPAL remove(null): NullPointerException [PASS]");
 374         }
 375 
 376         try {
 377             // Case 2: Attempt to remove null from the public creds
 378             // Expected result: NullPointerException
 379             mtSubj.getPublicCredentials().remove(null);
 380             throw new RuntimeException(
 381                     "PUB CRED remove(null): Failed to throw NPE");
 382         } catch (NullPointerException npe) {
 383             System.out.println(
 384                     "PUB CRED remove(null): NullPointerException [PASS]");
 385         }
 386 
 387         try {
 388             // Case 3: Attempt to remove null from the private creds
 389             // Expected result: NullPointerException
 390             mtSubj.getPrivateCredentials().remove(null);
 391             throw new RuntimeException(
 392                     "PRIV CRED remove(null): Failed to throw NPE");
 393         } catch (NullPointerException npe) {
 394             System.out.println(
 395                     "PRIV CRED remove(null): NullPointerException [PASS]");
 396         }
 397     }
 398 
 399     private static void testContains() {
 400         System.out.println("------ contains() ------");
 401         // Create a well formed subject
 402         Subject mtSubj = makeSubj(false, false, false);
 403 
 404         try {
 405             // Case 1: Attempt to check for null values in principals
 406             // Expected result: NullPointerException
 407             mtSubj.getPrincipals().contains(null);
 408             throw new RuntimeException(
 409                     "PRINCIPAL contains(null): Failed to throw NPE");
 410         } catch (NullPointerException npe) {
 411             System.out.println(
 412                     "PRINCIPAL contains(null): NullPointerException [PASS]");
 413         }
 414 
 415         try {
 416             // Case 2: Attempt to check for null in public creds
 417             // Expected result: NullPointerException
 418             mtSubj.getPublicCredentials().contains(null);
 419             throw new RuntimeException(
 420                     "PUB CRED contains(null): Failed to throw NPE");
 421         } catch (NullPointerException npe) {
 422             System.out.println(
 423                     "PUB CRED contains(null): NullPointerException [PASS]");
 424         }
 425 
 426         try {
 427             // Case 3: Attempt to check for null in private creds
 428             // Expected result: NullPointerException
 429             mtSubj.getPrivateCredentials().contains(null);
 430             throw new RuntimeException(
 431                     "PRIV CRED contains(null): Failed to throw NPE");
 432         } catch (NullPointerException npe) {
 433             System.out.println(
 434                     "PRIV CRED contains(null): NullPointerException [PASS]");
 435         }
 436     }
 437 
 438     private static void testAddAll() {
 439         // Create a well formed subject and additional collections
 440         Subject mtSubj = makeSubj(false, false, false);
 441         Set<Principal> morePrincs = new HashSet<>(Arrays.asList(tmplAddPrincs));
 442         Set<Object> morePubVals = new HashSet<>(Arrays.asList(tmplAddPubVals));
 443         Set<Object> morePrvVals = new HashSet<>(Arrays.asList(tmplAddPrvVals));
 444 
 445         // Run one success test for each Subject family to verify the
 446         // overloaded method works as intended.
 447         Set<Principal> setPrin = mtSubj.getPrincipals();
 448         Set<Object> setPubCreds = mtSubj.getPublicCredentials();
 449         Set<Object> setPrvCreds = mtSubj.getPrivateCredentials();
 450         int prinOrigSize = setPrin.size();
 451         int pubOrigSize = setPubCreds.size();
 452         int prvOrigSize = setPrvCreds.size();
 453 
 454         System.out.println("------ addAll() -----");
 455 
 456         // Add the new members, then check the resulting size of the
 457         // Subject attributes to verify they've increased by the proper
 458         // amounts.
 459         if ((validTestCollection(methAdd, setPrin, morePrincs) != true) ||
 460             (setPrin.size() != prinOrigSize + morePrincs.size()))
 461         {
 462             throw new RuntimeException("Failed addAll() on principals");
 463         }
 464         if ((validTestCollection(methAdd, setPubCreds,
 465                 morePubVals) != true) ||
 466             (setPubCreds.size() != pubOrigSize + morePubVals.size()))
 467         {
 468             throw new RuntimeException("Failed addAll() on public creds");
 469         }
 470         if ((validTestCollection(methAdd, setPrvCreds,
 471                 morePrvVals) != true) ||
 472             (setPrvCreds.size() != prvOrigSize + morePrvVals.size()))
 473         {
 474             throw new RuntimeException("Failed addAll() on private creds");
 475         }
 476         System.out.println("Positive addAll() test passed");
 477 
 478         // Now add null elements into each container, then retest
 479         morePrincs.add(null);
 480         morePubVals.add(null);
 481         morePrvVals.add(null);
 482 
 483         System.out.println("* Testing addAll w/ null values on Principals");
 484         nullTestCollection(methAdd, mtSubj.getPrincipals(), null);
 485         nullTestCollection(methAdd, mtSubj.getPrincipals(), morePrincs);
 486 
 487         System.out.println("* Testing addAll w/ null values on Public Creds");
 488         nullTestCollection(methAdd, mtSubj.getPublicCredentials(), null);
 489         nullTestCollection(methAdd, mtSubj.getPublicCredentials(),
 490                 morePubVals);
 491 
 492         System.out.println("* Testing addAll w/ null values on Private Creds");
 493         nullTestCollection(methAdd, mtSubj.getPrivateCredentials(), null);
 494         nullTestCollection(methAdd, mtSubj.getPrivateCredentials(),
 495                 morePrvVals);
 496     }
 497 
 498     private static void testRemoveAll() {
 499         // Create a well formed subject and additional collections
 500         Subject mtSubj = makeSubj(false, false, false);
 501         Set<Principal> remPrincs = new HashSet<>();
 502         Set<Object> remPubVals = new HashSet<>();
 503         Set<Object> remPrvVals = new HashSet<>();
 504 
 505         remPrincs.add(new KerberosPrincipal("mtwain/author@LITERATURE.US"));
 506         remPubVals.add("mtwain");
 507         remPrvVals.add("5Cl3M3nz");
 508 
 509         // Run one success test for each Subject family to verify the
 510         // overloaded method works as intended.
 511         Set<Principal> setPrin = mtSubj.getPrincipals();
 512         Set<Object> setPubCreds = mtSubj.getPublicCredentials();
 513         Set<Object> setPrvCreds = mtSubj.getPrivateCredentials();
 514         int prinOrigSize = setPrin.size();
 515         int pubOrigSize = setPubCreds.size();
 516         int prvOrigSize = setPrvCreds.size();
 517 
 518         System.out.println("------ removeAll() -----");
 519 
 520         // Remove the specified members, then check the resulting size of the
 521         // Subject attributes to verify they've decreased by the proper
 522         // amounts.
 523         if ((validTestCollection(methRemove, setPrin, remPrincs) != true) ||
 524             (setPrin.size() != prinOrigSize - remPrincs.size()))
 525         {
 526             throw new RuntimeException("Failed removeAll() on principals");
 527         }
 528         if ((validTestCollection(methRemove, setPubCreds,
 529                 remPubVals) != true) ||
 530             (setPubCreds.size() != pubOrigSize - remPubVals.size()))
 531         {
 532             throw new RuntimeException("Failed removeAll() on public creds");
 533         }
 534         if ((validTestCollection(methRemove, setPrvCreds,
 535                 remPrvVals) != true) ||
 536             (setPrvCreds.size() != prvOrigSize - remPrvVals.size()))
 537         {
 538             throw new RuntimeException("Failed removeAll() on private creds");
 539         }
 540         System.out.println("Positive removeAll() test passed");
 541 
 542         // Now add null elements into each container, then retest
 543         remPrincs.add(null);
 544         remPubVals.add(null);
 545         remPrvVals.add(null);
 546 
 547         System.out.println("* Testing removeAll w/ null values on Principals");
 548         nullTestCollection(methRemove, mtSubj.getPrincipals(), null);
 549         nullTestCollection(methRemove, mtSubj.getPrincipals(), remPrincs);
 550 
 551         System.out.println(
 552                 "* Testing removeAll w/ null values on Public Creds");
 553         nullTestCollection(methRemove, mtSubj.getPublicCredentials(), null);
 554         nullTestCollection(methRemove, mtSubj.getPublicCredentials(),
 555                 remPubVals);
 556 
 557         System.out.println(
 558                 "* Testing removeAll w/ null values on Private Creds");
 559         nullTestCollection(methRemove, mtSubj.getPrivateCredentials(), null);
 560         nullTestCollection(methRemove, mtSubj.getPrivateCredentials(),
 561                 remPrvVals);
 562     }
 563 
 564     private static void testContainsAll() {
 565         // Create a well formed subject and additional collections
 566         Subject mtSubj = makeSubj(false, false, false);
 567         Set<Principal> testPrincs = new HashSet<>(Arrays.asList(princVals));
 568         Set<Object> testPubVals = new HashSet<>(Arrays.asList(pubVals));
 569         Set<Object> testPrvVals = new HashSet<>(Arrays.asList(privVals));
 570 
 571         System.out.println("------ containsAll() -----");
 572 
 573         // Run one success test for each Subject family to verify the
 574         // overloaded method works as intended.
 575         if ((validTestCollection(methContains, mtSubj.getPrincipals(),
 576                  testPrincs) == false) &&
 577             (validTestCollection(methContains, mtSubj.getPublicCredentials(),
 578                  testPubVals) == false) &&
 579             (validTestCollection(methContains,
 580                  mtSubj.getPrivateCredentials(), testPrvVals) == false)) {
 581             throw new RuntimeException("Valid containsAll() check failed");
 582         }
 583         System.out.println("Positive containsAll() test passed");
 584 
 585         // Now let's add a null into each collection and watch the fireworks.
 586         testPrincs.add(null);
 587         testPubVals.add(null);
 588         testPrvVals.add(null);
 589 
 590         System.out.println(
 591                 "* Testing containsAll w/ null values on Principals");
 592         nullTestCollection(methContains, mtSubj.getPrincipals(), null);
 593         nullTestCollection(methContains, mtSubj.getPrincipals(), testPrincs);
 594 
 595         System.out.println(
 596                 "* Testing containsAll w/ null values on Public Creds");
 597         nullTestCollection(methContains, mtSubj.getPublicCredentials(),
 598                 null);
 599         nullTestCollection(methContains, mtSubj.getPublicCredentials(),
 600                 testPubVals);
 601 
 602         System.out.println(
 603                 "* Testing containsAll w/ null values on Private Creds");
 604         nullTestCollection(methContains, mtSubj.getPrivateCredentials(),
 605                 null);
 606         nullTestCollection(methContains, mtSubj.getPrivateCredentials(),
 607                 testPrvVals);
 608     }
 609 
 610     private static void testRetainAll() {
 611         // Create a well formed subject and additional collections
 612         Subject mtSubj = makeSubj(false, false, false);
 613         Set<Principal> remPrincs = new HashSet<>(Arrays.asList(tmplAddPrincs));
 614         Set<Object> remPubVals = new HashSet<>(Arrays.asList(tmplAddPubVals));
 615         Set<Object> remPrvVals = new HashSet<>(Arrays.asList(tmplAddPrvVals));
 616 
 617         // Add in values that exist within the Subject
 618         remPrincs.add(princVals[2]);
 619         remPubVals.add(pubVals[2]);
 620         remPrvVals.add(privVals[2]);
 621 
 622         // Run one success test for each Subject family to verify the
 623         // overloaded method works as intended.
 624         Set<Principal> setPrin = mtSubj.getPrincipals();
 625         Set<Object> setPubCreds = mtSubj.getPublicCredentials();
 626         Set<Object> setPrvCreds = mtSubj.getPrivateCredentials();
 627         int prinOrigSize = setPrin.size();
 628         int pubOrigSize = setPubCreds.size();
 629         int prvOrigSize = setPrvCreds.size();
 630 
 631         System.out.println("------ retainAll() -----");
 632 
 633         // Retain the specified members (those that exist in the Subject)
 634         // and validate the results.
 635         if (validTestCollection(methRetain, setPrin, remPrincs) == false ||
 636             setPrin.size() != 1 || setPrin.contains(princVals[2]) == false)
 637         {
 638             throw new RuntimeException("Failed retainAll() on principals");
 639         }
 640 
 641         if (validTestCollection(methRetain, setPubCreds,
 642                 remPubVals) == false ||
 643             setPubCreds.size() != 1 ||
 644             setPubCreds.contains(pubVals[2]) == false)
 645         {
 646             throw new RuntimeException("Failed retainAll() on public creds");
 647         }
 648         if (validTestCollection(methRetain, setPrvCreds,
 649                 remPrvVals) == false ||
 650             setPrvCreds.size() != 1 ||
 651             setPrvCreds.contains(privVals[2]) == false)
 652         {
 653             throw new RuntimeException("Failed retainAll() on private creds");
 654         }
 655         System.out.println("Positive retainAll() test passed");
 656 
 657         // Now add null elements into each container, then retest
 658         remPrincs.add(null);
 659         remPubVals.add(null);
 660         remPrvVals.add(null);
 661 
 662         System.out.println("* Testing retainAll w/ null values on Principals");
 663         nullTestCollection(methRetain, mtSubj.getPrincipals(), null);
 664         nullTestCollection(methRetain, mtSubj.getPrincipals(), remPrincs);
 665 
 666         System.out.println(
 667                 "* Testing retainAll w/ null values on Public Creds");
 668         nullTestCollection(methRetain, mtSubj.getPublicCredentials(), null);
 669         nullTestCollection(methRetain, mtSubj.getPublicCredentials(),
 670                 remPubVals);
 671 
 672         System.out.println(
 673                 "* Testing retainAll w/ null values on Private Creds");
 674         nullTestCollection(methRetain, mtSubj.getPrivateCredentials(), null);
 675         nullTestCollection(methRetain, mtSubj.getPrivateCredentials(),
 676                 remPrvVals);
 677     }
 678 
 679     private static void testIsEmpty() {
 680         Subject populatedSubj = makeSubj(false, false, false);
 681         Subject emptySubj = new Subject();
 682 
 683         System.out.println("------ isEmpty() -----");
 684 
 685         if (populatedSubj.getPrincipals().isEmpty()) {
 686             throw new RuntimeException(
 687                     "Populated Subject Principals incorrectly returned empty");
 688         }
 689         if (emptySubj.getPrincipals().isEmpty() == false) {
 690             throw new RuntimeException(
 691                     "Empty Subject Principals incorrectly returned non-empty");
 692         }
 693         System.out.println("isEmpty() test passed");
 694     }
 695 
 696     private static void testSecureSetEquals() {
 697         System.out.println("------ SecureSet.equals() -----");
 698 
 699         Subject subj = makeSubj(false, false, false);
 700         Subject subjComp = makeSubj(false, false, false);
 701 
 702         // Case 1: null comparison [expect false]
 703         if (subj.getPublicCredentials().equals(null) != false) {
 704             throw new RuntimeException(
 705                     "equals(null) incorrectly returned true");
 706         }
 707 
 708         // Case 2: Self-comparison [expect true]
 709         Set<Principal> princs = subj.getPrincipals();
 710         princs.equals(subj.getPrincipals());
 711 
 712         // Case 3: Comparison with non-Set type [expect false]
 713         List<Principal> listPrinc = new LinkedList<>(Arrays.asList(princVals));
 714         if (subj.getPublicCredentials().equals(listPrinc) != false) {
 715             throw new RuntimeException(
 716                     "equals([Non-Set]) incorrectly returned true");
 717         }
 718 
 719         // Case 4: SecureSets of differing sizes [expect false]
 720         Subject subj1princ = new Subject();
 721         Subject subj2princ = new Subject();
 722         subj1princ.getPrincipals().add(
 723                 new X500Principal("CN=Tom Sawyer, ST=Missouri, C=US"));
 724         subj1princ.getPrincipals().add(
 725                 new X500Principal("CN=John Doe, O=Bogus Corp."));
 726         subj2princ.getPrincipals().add(
 727                 new X500Principal("CN=Tom Sawyer, ST=Missouri, C=US"));
 728         if (subj1princ.getPrincipals().equals(
 729                     subj2princ.getPrincipals()) != false) {
 730             throw new RuntimeException(
 731                     "equals([differing sizes]) incorrectly returned true");
 732         }
 733 
 734         // Case 5: Content equality test [expect true]
 735         Set<Principal> equalSet = new HashSet<>(Arrays.asList(princVals));
 736         if (subj.getPrincipals().equals(equalSet) != true) {
 737             throw new RuntimeException(
 738                     "equals([equivalent set]) incorrectly returned false");
 739         }
 740 
 741         // Case 5: Content inequality test [expect false]
 742         // Note: to not fall into the size inequality check the two
 743         // sets need to have the same number of elements.
 744         Set<Principal> inequalSet =
 745             new HashSet<Principal>(Arrays.asList(tmplAddPrincs));
 746         inequalSet.add(new JMXPrincipal("Samuel Clemens"));
 747 
 748         if (subj.getPrincipals().equals(inequalSet) != false) {
 749             throw new RuntimeException(
 750                     "equals([equivalent set]) incorrectly returned false");
 751         }
 752         System.out.println("SecureSet.equals() tests passed");
 753     }
 754 
 755     private static void testSecureSetHashCode() {
 756         System.out.println("------ SecureSet.hashCode() -----");
 757 
 758         Subject subj = makeSubj(false, false, false);
 759 
 760         // Make sure two other Set types that we know are equal per
 761         // SecureSet.equals() and verify their hashCodes are also the same
 762         Set<Principal> equalHashSet = new HashSet<>(Arrays.asList(princVals));
 763 
 764         if (subj.getPrincipals().hashCode() != equalHashSet.hashCode()) {
 765             throw new RuntimeException(
 766                     "SecureSet and HashSet hashCodes() differ");
 767         }
 768         System.out.println("SecureSet.hashCode() tests passed");
 769     }
 770 
 771     private static void testToArray() {
 772         System.out.println("------ toArray() -----");
 773 
 774         Subject subj = makeSubj(false, false, false);
 775 
 776         // Case 1: no-parameter toArray with equality comparison
 777         // Expected result: true
 778         List<Object> alSubj = Arrays.asList(subj.getPrincipals().toArray());
 779         List<Principal> alPrincs = Arrays.asList(princVals);
 780 
 781         if (alSubj.size() != alPrincs.size() ||
 782                 alSubj.containsAll(alPrincs) != true) {
 783             throw new RuntimeException(
 784                     "Unexpected inequality on returned toArray()");
 785         }
 786 
 787         // Case 2: generic-type toArray where passed array is of sufficient
 788         //         size.
 789         // Expected result: returned Array is reference-equal to input param
 790         // and content equal to data used to construct the originating Subject.
 791         Principal[] pBlock = new Principal[3];
 792         Principal[] pBlockRef = subj.getPrincipals().toArray(pBlock);
 793         alSubj = Arrays.asList((Object[])pBlockRef);
 794 
 795         if (pBlockRef != pBlock) {
 796             throw new RuntimeException(
 797                     "Unexpected reference-inequality on returned toArray(T[])");
 798         } else if (alSubj.size() != alPrincs.size() ||
 799                 alSubj.containsAll(alPrincs) != true) {
 800             throw new RuntimeException(
 801                     "Unexpected content-inequality on returned toArray(T[])");
 802         }
 803 
 804         // Case 3: generic-type toArray where passed array is of
 805         //         insufficient size.
 806         // Expected result: returned Array is not reference-equal to
 807         // input param but is content equal to data used to construct the
 808         // originating Subject.
 809         pBlock = new Principal[1];
 810         pBlockRef = subj.getPrincipals().toArray(pBlock);
 811         alSubj = Arrays.asList((Object[])pBlockRef);
 812 
 813         if (pBlockRef == pBlock) {
 814             throw new RuntimeException(
 815                     "Unexpected reference-equality on returned toArray(T[])");
 816         } else if (alSubj.size() != alPrincs.size() ||
 817                 alSubj.containsAll(alPrincs) != true) {
 818             throw new RuntimeException(
 819                     "Unexpected content-inequality on returned toArray(T[])");
 820         }
 821         System.out.println("toArray() tests passed");
 822     }
 823 
 824     public static void main(String[] args) throws Exception {
 825 
 826         testCTOR();
 827 
 828         testDeserialize();
 829 
 830         testAdd();
 831 
 832         testRemove();
 833 
 834         testContains();
 835 
 836         testAddAll();
 837 
 838         testRemoveAll();
 839 
 840         testContainsAll();
 841 
 842         testRetainAll();
 843 
 844         testIsEmpty();
 845 
 846         testSecureSetEquals();
 847 
 848         testSecureSetHashCode();
 849 
 850         testToArray();
 851     }
 852 }