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