--- old/src/share/classes/javax/security/auth/Subject.java 2014-06-04 14:13:11.651311957 -0700 +++ new/src/share/classes/javax/security/auth/Subject.java 2014-06-04 14:13:11.149248146 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -142,7 +142,9 @@ *

The newly constructed Sets check whether this {@code Subject} * has been set read-only before permitting subsequent modifications. * The newly created Sets also prevent illegal modifications - * by ensuring that callers have sufficient permissions. + * by ensuring that callers have sufficient permissions. These Sets + * also prohibit null elements, and attempts to add or query a null + * element will result in a {@code NullPointerException}. * *

To modify the Principals Set, the caller must have * {@code AuthPermission("modifyPrincipals")}. @@ -170,7 +172,9 @@ * These newly created Sets check whether this {@code Subject} * has been set read-only before permitting subsequent modifications. * The newly created Sets also prevent illegal modifications - * by ensuring that callers have sufficient permissions. + * by ensuring that callers have sufficient permissions. These Sets + * also prohibit null elements, and attempts to add or query a null + * element will result in a {@code NullPointerException}. * *

To modify the Principals Set, the caller must have * {@code AuthPermission("modifyPrincipals")}. @@ -194,17 +198,19 @@ * * @exception NullPointerException if the specified * {@code principals}, {@code pubCredentials}, - * or {@code privCredentials} are {@code null}. + * or {@code privCredentials} are {@code null}, + * or a null value exists within any of these three + * Sets. */ public Subject(boolean readOnly, Set principals, Set pubCredentials, Set privCredentials) { - - if (principals == null || - pubCredentials == null || - privCredentials == null) + if (collectionNullClean(principals) == false || + collectionNullClean(pubCredentials) == false || + collectionNullClean(privCredentials) == false) { throw new NullPointerException (ResourcesMgr.getString("invalid.null.input.s.")); + } this.principals = Collections.synchronizedSet(new SecureSet (this, PRINCIPAL_SET, principals)); @@ -970,10 +976,6 @@ Set inputPrincs = (Set)gf.get("principals", null); // Rewrap the principals into a SecureSet - if (inputPrincs == null) { - throw new NullPointerException - (ResourcesMgr.getString("invalid.null.input.s.")); - } try { principals = Collections.synchronizedSet(new SecureSet (this, PRINCIPAL_SET, inputPrincs)); @@ -993,13 +995,36 @@ } /** + * Tests for null-clean collections (both non-null reference and + * no null elements) + * + * @param coll A {@code Collection} to be tested for null references + * + * @return true if {@code coll} is non-null and contains no null + * elements, false otherwise. + */ + private static boolean collectionNullClean(Collection coll) { + boolean isClean = false; + + try { + isClean = (coll != null) && !coll.contains(null); + } catch (NullPointerException npe) { + // A null-hostile collection may choose to return null if + // contains(null) is called on it rather than returning false. + // If so then we know no nulls are present. + isClean = true; + } + + return isClean; + } + + /** * Prevent modifications unless caller has permission. * * @serial include */ private static class SecureSet - extends AbstractSet - implements java.io.Serializable { + implements Set, java.io.Serializable { private static final long serialVersionUID = 7911754171111800359L; @@ -1098,6 +1123,11 @@ public boolean add(E o) { + if (o == null) { + throw new NullPointerException + (ResourcesMgr.getString("invalid.null.input.s.")); + } + if (subject.isReadOnly()) { throw new IllegalStateException (ResourcesMgr.getString("Subject.is.read.only")); @@ -1139,6 +1169,11 @@ public boolean remove(Object o) { + if (o == null) { + throw new NullPointerException + (ResourcesMgr.getString("invalid.null.input.s.")); + } + final Iterator e = iterator(); while (e.hasNext()) { E next; @@ -1153,12 +1188,7 @@ }); } - if (next == null) { - if (o == null) { - e.remove(); - return true; - } - } else if (next.equals(o)) { + if (next.equals(o)) { e.remove(); return true; } @@ -1167,6 +1197,12 @@ } public boolean contains(Object o) { + + if (o == null) { + throw new NullPointerException + (ResourcesMgr.getString("invalid.null.input.s.")); + } + final Iterator e = iterator(); while (e.hasNext()) { E next; @@ -1194,19 +1230,34 @@ }); } - if (next == null) { - if (o == null) { - return true; - } - } else if (next.equals(o)) { + if (next.equals(o)) { return true; } } return false; } + public boolean addAll(Collection c) { + boolean result = false; + + if (collectionNullClean(c) == false) { + throw new NullPointerException + (ResourcesMgr.getString("invalid.null.input.s.")); + } + + for (E item : c) { + result |= this.add(item); + } + + return result; + } + public boolean removeAll(Collection c) { - Objects.requireNonNull(c); + if (collectionNullClean(c) == false) { + throw new NullPointerException + (ResourcesMgr.getString("invalid.null.input.s.")); + } + boolean modified = false; final Iterator e = iterator(); while (e.hasNext()) { @@ -1224,14 +1275,7 @@ Iterator ce = c.iterator(); while (ce.hasNext()) { - Object o = ce.next(); - if (next == null) { - if (o == null) { - e.remove(); - modified = true; - break; - } - } else if (next.equals(o)) { + if (next.equals(ce.next())) { e.remove(); modified = true; break; @@ -1241,13 +1285,30 @@ return modified; } + public boolean containsAll(Collection c) { + if (collectionNullClean(c) == false) { + throw new NullPointerException + (ResourcesMgr.getString("invalid.null.input.s.")); + } + + for (Object item : c) { + if (this.contains(item) == false) { + return false; + } + } + + return true; + } + public boolean retainAll(Collection c) { - Objects.requireNonNull(c); + if (collectionNullClean(c) == false) { + throw new NullPointerException + (ResourcesMgr.getString("invalid.null.input.s.")); + } + boolean modified = false; - boolean retain = false; final Iterator e = iterator(); while (e.hasNext()) { - retain = false; E next; if (which != Subject.PRIV_CREDENTIAL_SET) { next = e.next(); @@ -1260,26 +1321,12 @@ }); } - Iterator ce = c.iterator(); - while (ce.hasNext()) { - Object o = ce.next(); - if (next == null) { - if (o == null) { - retain = true; - break; - } - } else if (next.equals(o)) { - retain = true; - break; - } - } - - if (!retain) { + if (c.contains(next) == false) { e.remove(); - retain = false; modified = true; } } + return modified; } @@ -1301,6 +1348,56 @@ } } + public boolean isEmpty() { + return elements.isEmpty(); + } + + public Object[] toArray() { + final Iterator e = iterator(); + while (e.hasNext()) { + // The next() method performs a security manager check + // on each element in the SecureSet. If we make it all + // the way through we should be able to simply return + // element's toArray results. Otherwise we'll let + // the SecurityException pass up the call stack. + e.next(); + } + + return elements.toArray(); + } + + public T[] toArray(T[] a) { + final Iterator e = iterator(); + while (e.hasNext()) { + // The next() method performs a security manager check + // on each element in the SecureSet. If we make it all + // the way through we should be able to simply return + // element's toArray results. Otherwise we'll let + // the SecurityException pass up the call stack. + e.next(); + } + + return elements.toArray(a); + } + + public boolean equals(Object o) { + if (o == this) + return true; + + if (!(o instanceof Set)) + return false; + Collection c = (Collection) o; + if (c.size() != size()) + return false; + try { + return containsAll(c); + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } + /** * Writes this object out to a stream (i.e., serializes it). * @@ -1338,12 +1435,19 @@ which = fields.get("which", 0); LinkedList tmp = (LinkedList) fields.get("elements", null); + + if (Subject.collectionNullClean(tmp) == false) { + throw new NullPointerException + (ResourcesMgr.getString("invalid.null.input.s.")); + } + if (tmp.getClass() != LinkedList.class) { elements = new LinkedList(tmp); } else { elements = tmp; } } + } /** Binary files /dev/null and new/test/javax/security/auth/Subject/PrinNoNull.bin differ Binary files /dev/null and new/test/javax/security/auth/Subject/PrinWithNull.bin differ Binary files /dev/null and new/test/javax/security/auth/Subject/SubjNoNull.bin differ Binary files /dev/null and new/test/javax/security/auth/Subject/SubjWithNull.bin differ --- /dev/null 2014-05-30 09:27:22.741293751 -0700 +++ new/test/javax/security/auth/Subject/SubjectNullTests.java 2014-06-04 14:13:14.399661269 -0700 @@ -0,0 +1,760 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8015081 + * @summary javax.security.auth.Subject.toString() throws NPE + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.ObjectInputStream; +import java.io.IOException; +import java.lang.Exception; +import java.security.Principal; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.TreeSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import javax.management.remote.JMXPrincipal; +import javax.security.auth.Subject; +import javax.security.auth.x500.X500Principal; +import javax.security.auth.kerberos.KerberosPrincipal; + +public class SubjectNullTests { + + // Value templates for the constructor + private static Principal[] princVals = { + new X500Principal("CN=Tom Sawyer, ST=Missouri, C=US"), + new JMXPrincipal("Huckleberry Finn"), + new KerberosPrincipal("mtwain/author@LITERATURE.US") + }; + private static String[] pubVals = {"tsawyer", "hfinn", "mtwain"}; + private static String[] privVals = {"th3R!v3r", "oNth3R4ft", "5Cl3M3nz"}; + + // Templates for collection-based modifiers for the Subject + private static Principal[] tmplAddPrincs = { + new X500Principal("CN=John Doe, O=Bogus Corp."), + new KerberosPrincipal("jdoe/admin@BOGUSCORP.COM") + }; + private static String[] tmplAddPubVals = {"jdoe", "djoe"}; + private static String[] tmplAddPrvVals = {"b4dpa55w0rd", "pass123"}; + + /** + * Construct a subject, and optionally place a null in any one + * of the three Sets used to initialize a Subject's values + */ + private static Subject makeSubj(boolean nullPrinc, boolean nullPub, + boolean nullPriv) { + Set setPrinc = + new HashSet(Arrays.asList(princVals)); + Set setPubCreds = new HashSet(Arrays.asList(pubVals)); + Set setPrvCreds = new HashSet(Arrays.asList(privVals)); + + if (nullPrinc) { + setPrinc.add(null); + } + + if (nullPub) { + setPubCreds.add(null); + } + + if (nullPriv) { + setPrvCreds.add(null); + } + + return (new Subject(false, setPrinc, setPubCreds, setPrvCreds)); + } + + /** + * Provide a simple interface for abstracting collection-on-collection + * functions + */ + public interface Function { + boolean execCollection(Set subjSet, Collection actorData); + } + + public static final Function methAdd = new Function() { + public boolean execCollection(Set subjSet, Collection actorData) { + return subjSet.addAll((Collection)actorData); + } + }; + + public static final Function methContains = new Function() { + public boolean execCollection(Set subjSet, Collection actorData) { + return subjSet.containsAll(actorData); + } + }; + + public static final Function methRemove = new Function() { + public boolean execCollection(Set subjSet, Collection actorData) { + return subjSet.removeAll(actorData); + } + }; + + public static final Function methRetain = new Function() { + public boolean execCollection(Set subjSet, Collection actorData) { + return subjSet.retainAll(actorData); + } + }; + + /** + * Run a test using a specified Collection method upon a Subject's + * SecureSet fields. This method expects NullPointerExceptions + * to be thrown, and throws RuntimeException when the operation + * succeeds + */ + private static void nullTestCollection(Function meth, Set subjSet, + Collection actorData) { + try { + meth.execCollection(subjSet, actorData); + throw new RuntimeException("Failed to throw NullPointerException"); + } catch (NullPointerException npe) { + System.out.println("Caught expected NullPointerException [PASS]"); + } + } + + /** + * Run a test using a specified Collection method upon a Subject's + * SecureSet fields. This method expects the function and arguments + * passed in to complete without exception. It returns false + * if either an exception occurs or the result of the operation is + * false. + */ + private static boolean validTestCollection(Function meth, Set subjSet, + Collection actorData) { + boolean result = false; + + try { + result = meth.execCollection(subjSet, actorData); + } catch (Exception exc) { + System.out.println("Caught exception " + exc); + } + + return result; + } + + /** + * Deserialize an object from a file. + * + * @param type The {@code Class} that the serialized file is supposed + * to contain. + * @param fileName The name of the file to be deserialized. + * + * @return An object of the type specified in the {@code type} parameter + */ + private static T deserializeFile(Class type, String fileName) + throws IOException, ClassNotFoundException { + File fileObj = new File(System.getProperty("test.src", "."), fileName); + FileInputStream fis = new FileInputStream(fileObj); + ObjectInputStream ois = new ObjectInputStream(fis); + + T newObj = (T)ois.readObject(); + ois.close(); + fis.close(); + + return newObj; + } + + private static void testCTOR() { + System.out.println("------ constructor ------"); + + try { + // Case 1: Create a subject with a null principal + // Expected result: NullPointerException + Subject mtSubj = makeSubj(true, false, false); + throw new RuntimeException( + "constructor [principal w/ null]: Failed to throw NPE"); + } catch (NullPointerException npe) { + System.out.println("constructor [principal w/ null]: " + + "NullPointerException [PASS]"); + } + + try { + // Case 2: Create a subject with a null public credential element + // Expected result: NullPointerException + Subject mtSubj = makeSubj(false, true, false); + throw new RuntimeException( + "constructor [pub cred w/ null]: Failed to throw NPE"); + } catch (NullPointerException npe) { + System.out.println("constructor [pub cred w/ null]: " + + "NullPointerException [PASS]"); + } + + try { + // Case 3: Create a subject with a null private credential element + // Expected result: NullPointerException + Subject mtSubj = makeSubj(false, false, true); + throw new RuntimeException( + "constructor [priv cred w/ null]: Failed to throw NPE"); + } catch (NullPointerException npe) { + System.out.println("constructor [priv cred w/ null]: " + + "NullPointerException [PASS]"); + } + + // Case 4: Create a new subject using the principals, public + // and private credentials from another well-formed subject + // Expected result: Successful construction + Subject srcSubj = makeSubj(false, false, false); + Subject mtSubj = new Subject(false, srcSubj.getPrincipals(), + srcSubj.getPublicCredentials(), + srcSubj.getPrivateCredentials()); + System.out.println("Construction from another well-formed Subject's " + + "principals/creds [PASS]"); + + + + // XXX random tests here + System.out.println("------ Random Tests Here -----"); + System.out.println("isEmpty test: " + + srcSubj.getPrincipals().isEmpty() + ", " + + srcSubj.getPublicCredentials().isEmpty() + ", " + + srcSubj.getPrivateCredentials().isEmpty()); + Set pl = srcSubj.getPrincipals(); + Object[] oar = pl.toArray(); + System.out.println("toArray display: " + oar.length + " elements"); + System.out.print("Subj.princ: "); + for (Object y : pl) { + System.out.print(y + " | "); + } + System.out.println(); + System.out.print("Subj.princ.toArray: "); + for (Object y : oar) { + System.out.print(y + " | "); + } + System.out.println(); + + List emptyList = new LinkedList<>(); + Set emptySet = new HashSet<>(); + Set someSet = new HashSet(Arrays.asList(princVals)); + System.out.println("What happens if you containsAll(emptyColl)? " + + someSet.containsAll(emptyList)); + System.out.println("What about empty-on-empty? " + + emptySet.containsAll(emptyList)); + + + } + + private static void testDeserialize() throws Exception { + System.out.println("------ deserialize -----"); + + Subject subj = null; + Set prin = null; + + // Case 1: positive deserialization test of a Subject + // Expected result: well-formed Subject + subj = deserializeFile(Subject.class, "SubjNoNull.bin"); + System.out.println("Positive deserialization test (Subject) passed"); + + // Case 2: positive deserialization test of a SecureSet + // Expected result: well-formed Set + prin = deserializeFile(Set.class, "PrinNoNull.bin"); + System.out.println("Positive deserialization test (SecureSet) passed"); + + System.out.println( + "* Testing deserialization with null-poisoned objects"); + // Case 3: deserialization test of a null-poisoned Subject + // Expected result: NullPointerException + try { + subj = deserializeFile(Subject.class, "SubjWithNull.bin"); + throw new RuntimeException("Failed to throw NullPointerException"); + } catch (NullPointerException npe) { + System.out.println("Caught expected NullPointerException [PASS]"); + } + + // Case 4: deserialization test of a null-poisoned SecureSet + // Expected result: NullPointerException + try { + prin = deserializeFile(Set.class, "PrinWithNull.bin"); + throw new RuntimeException("Failed to throw NullPointerException"); + } catch (NullPointerException npe) { + System.out.println("Caught expected NullPointerException [PASS]"); + } + } + + private static void testAdd() { + System.out.println("------ add() ------"); + // Create a well formed subject + Subject mtSubj = makeSubj(false, false, false); + + try { + // Case 1: Attempt to add null values to principal + // Expected result: NullPointerException + mtSubj.getPrincipals().add(null); + throw new RuntimeException( + "PRINCIPAL add(null): Failed to throw NPE"); + } catch (NullPointerException npe) { + System.out.println( + "PRINCIPAL add(null): NullPointerException [PASS]"); + } + + try { + // Case 2: Attempt to add null into the public creds + // Expected result: NullPointerException + mtSubj.getPublicCredentials().add(null); + throw new RuntimeException( + "PUB CRED add(null): Failed to throw NPE"); + } catch (NullPointerException npe) { + System.out.println( + "PUB CRED add(null): NullPointerException [PASS]"); + } + + try { + // Case 3: Attempt to add null into the private creds + // Expected result: NullPointerException + mtSubj.getPrivateCredentials().add(null); + throw new RuntimeException( + "PRIV CRED add(null): Failed to throw NPE"); + } catch (NullPointerException npe) { + System.out.println( + "PRIV CRED add(null): NullPointerException [PASS]"); + } + } + + private static void testRemove() { + System.out.println("------ remove() ------"); + // Create a well formed subject + Subject mtSubj = makeSubj(false, false, false); + + try { + // Case 1: Attempt to remove null values from principal + // Expected result: NullPointerException + mtSubj.getPrincipals().remove(null); + throw new RuntimeException( + "PRINCIPAL remove(null): Failed to throw NPE"); + } catch (NullPointerException npe) { + System.out.println( + "PRINCIPAL remove(null): NullPointerException [PASS]"); + } + + try { + // Case 2: Attempt to remove null from the public creds + // Expected result: NullPointerException + mtSubj.getPublicCredentials().remove(null); + throw new RuntimeException( + "PUB CRED remove(null): Failed to throw NPE"); + } catch (NullPointerException npe) { + System.out.println( + "PUB CRED remove(null): NullPointerException [PASS]"); + } + + try { + // Case 3: Attempt to remove null from the private creds + // Expected result: NullPointerException + mtSubj.getPrivateCredentials().remove(null); + throw new RuntimeException( + "PRIV CRED remove(null): Failed to throw NPE"); + } catch (NullPointerException npe) { + System.out.println( + "PRIV CRED remove(null): NullPointerException [PASS]"); + } + } + + private static void testContains() { + System.out.println("------ contains() ------"); + // Create a well formed subject + Subject mtSubj = makeSubj(false, false, false); + + try { + // Case 1: Attempt to check for null values in principals + // Expected result: NullPointerException + mtSubj.getPrincipals().contains(null); + throw new RuntimeException( + "PRINCIPAL contains(null): Failed to throw NPE"); + } catch (NullPointerException npe) { + System.out.println( + "PRINCIPAL contains(null): NullPointerException [PASS]"); + } + + try { + // Case 2: Attempt to check for null in public creds + // Expected result: NullPointerException + mtSubj.getPublicCredentials().contains(null); + throw new RuntimeException( + "PUB CRED contains(null): Failed to throw NPE"); + } catch (NullPointerException npe) { + System.out.println( + "PUB CRED contains(null): NullPointerException [PASS]"); + } + + try { + // Case 3: Attempt to check for null in private creds + // Expected result: NullPointerException + mtSubj.getPrivateCredentials().contains(null); + throw new RuntimeException( + "PRIV CRED contains(null): Failed to throw NPE"); + } catch (NullPointerException npe) { + System.out.println( + "PRIV CRED contains(null): NullPointerException [PASS]"); + } + } + + private static void testAddAll() { + // Create a well formed subject and additional collections + Subject mtSubj = makeSubj(false, false, false); + Set morePrincs = new HashSet<>(Arrays.asList(tmplAddPrincs)); + Set morePubVals = new HashSet<>(Arrays.asList(tmplAddPubVals)); + Set morePrvVals = new HashSet<>(Arrays.asList(tmplAddPrvVals)); + + // Run one success test for each Subject family to verify the + // overloaded method works as intended. + Set setPrin = mtSubj.getPrincipals(); + Set setPubCreds = mtSubj.getPublicCredentials(); + Set setPrvCreds = mtSubj.getPrivateCredentials(); + int prinOrigSize = setPrin.size(); + int pubOrigSize = setPubCreds.size(); + int prvOrigSize = setPrvCreds.size(); + + System.out.println("------ addAll() -----"); + + // Add the new members, then check the resulting size of the + // Subject attributes to verify they've increased by the proper + // amounts. + if ((validTestCollection(methAdd, setPrin, morePrincs) != true) || + (setPrin.size() != prinOrigSize + morePrincs.size())) + { + throw new RuntimeException("Failed addAll() on principals"); + } + if ((validTestCollection(methAdd, setPubCreds, + morePubVals) != true) || + (setPubCreds.size() != pubOrigSize + morePubVals.size())) + { + throw new RuntimeException("Failed addAll() on public creds"); + } + if ((validTestCollection(methAdd, setPrvCreds, + morePrvVals) != true) || + (setPrvCreds.size() != prvOrigSize + morePrvVals.size())) + { + throw new RuntimeException("Failed addAll() on private creds"); + } + System.out.println("Positive addAll() test passed"); + + // Now add null elements into each container, then retest + morePrincs.add(null); + morePubVals.add(null); + morePrvVals.add(null); + + System.out.println("* Testing addAll w/ null values on Principals"); + nullTestCollection(methAdd, mtSubj.getPrincipals(), null); + nullTestCollection(methAdd, mtSubj.getPrincipals(), morePrincs); + + System.out.println("* Testing addAll w/ null values on Public Creds"); + nullTestCollection(methAdd, mtSubj.getPublicCredentials(), null); + nullTestCollection(methAdd, mtSubj.getPublicCredentials(), + morePubVals); + + System.out.println("* Testing addAll w/ null values on Private Creds"); + nullTestCollection(methAdd, mtSubj.getPrivateCredentials(), null); + nullTestCollection(methAdd, mtSubj.getPrivateCredentials(), + morePrvVals); + } + + private static void testRemoveAll() { + // Create a well formed subject and additional collections + Subject mtSubj = makeSubj(false, false, false); + Set remPrincs = new HashSet<>(); + Set remPubVals = new HashSet<>(); + Set remPrvVals = new HashSet<>(); + + remPrincs.add(new KerberosPrincipal("mtwain/author@LITERATURE.US")); + remPubVals.add("mtwain"); + remPrvVals.add("5Cl3M3nz"); + + // Run one success test for each Subject family to verify the + // overloaded method works as intended. + Set setPrin = mtSubj.getPrincipals(); + Set setPubCreds = mtSubj.getPublicCredentials(); + Set setPrvCreds = mtSubj.getPrivateCredentials(); + int prinOrigSize = setPrin.size(); + int pubOrigSize = setPubCreds.size(); + int prvOrigSize = setPrvCreds.size(); + + System.out.println("------ removeAll() -----"); + + // Remove the specified members, then check the resulting size of the + // Subject attributes to verify they've decreased by the proper + // amounts. + if ((validTestCollection(methRemove, setPrin, remPrincs) != true) || + (setPrin.size() != prinOrigSize - remPrincs.size())) + { + throw new RuntimeException("Failed removeAll() on principals"); + } + if ((validTestCollection(methRemove, setPubCreds, + remPubVals) != true) || + (setPubCreds.size() != pubOrigSize - remPubVals.size())) + { + throw new RuntimeException("Failed removeAll() on public creds"); + } + if ((validTestCollection(methRemove, setPrvCreds, + remPrvVals) != true) || + (setPrvCreds.size() != prvOrigSize - remPrvVals.size())) + { + throw new RuntimeException("Failed removeAll() on private creds"); + } + System.out.println("Positive removeAll() test passed"); + + // Now add null elements into each container, then retest + remPrincs.add(null); + remPubVals.add(null); + remPrvVals.add(null); + + System.out.println("* Testing removeAll w/ null values on Principals"); + nullTestCollection(methRemove, mtSubj.getPrincipals(), null); + nullTestCollection(methRemove, mtSubj.getPrincipals(), remPrincs); + + System.out.println( + "* Testing removeAll w/ null values on Public Creds"); + nullTestCollection(methRemove, mtSubj.getPublicCredentials(), null); + nullTestCollection(methRemove, mtSubj.getPublicCredentials(), + remPubVals); + + System.out.println( + "* Testing removeAll w/ null values on Private Creds"); + nullTestCollection(methRemove, mtSubj.getPrivateCredentials(), null); + nullTestCollection(methRemove, mtSubj.getPrivateCredentials(), + remPrvVals); + } + + private static void testContainsAll() { + // Create a well formed subject and additional collections + Subject mtSubj = makeSubj(false, false, false); + Set testPrincs = new HashSet<>(Arrays.asList(princVals)); + Set testPubVals = new HashSet<>(Arrays.asList(pubVals)); + Set testPrvVals = new HashSet<>(Arrays.asList(privVals)); + + System.out.println("------ containsAll() -----"); + + // Run one success test for each Subject family to verify the + // overloaded method works as intended. + if ((validTestCollection(methContains, mtSubj.getPrincipals(), + testPrincs) == false) && + (validTestCollection(methContains, mtSubj.getPublicCredentials(), + testPubVals) == false) && + (validTestCollection(methContains, + mtSubj.getPrivateCredentials(), testPrvVals) == false)) { + throw new RuntimeException("Valid containsAll() check failed"); + } + System.out.println("Positive containsAll() test passed"); + + // Now let's add a null into each collection and watch the fireworks. + testPrincs.add(null); + testPubVals.add(null); + testPrvVals.add(null); + + System.out.println( + "* Testing containsAll w/ null values on Principals"); + nullTestCollection(methContains, mtSubj.getPrincipals(), null); + nullTestCollection(methContains, mtSubj.getPrincipals(), testPrincs); + + System.out.println( + "* Testing containsAll w/ null values on Public Creds"); + nullTestCollection(methContains, mtSubj.getPublicCredentials(), + null); + nullTestCollection(methContains, mtSubj.getPublicCredentials(), + testPubVals); + + System.out.println( + "* Testing containsAll w/ null values on Private Creds"); + nullTestCollection(methContains, mtSubj.getPrivateCredentials(), + null); + nullTestCollection(methContains, mtSubj.getPrivateCredentials(), + testPrvVals); + } + + private static void testRetainAll() { + // Create a well formed subject and additional collections + Subject mtSubj = makeSubj(false, false, false); + Set remPrincs = new HashSet<>(Arrays.asList(tmplAddPrincs)); + Set remPubVals = new HashSet<>(Arrays.asList(tmplAddPubVals)); + Set remPrvVals = new HashSet<>(Arrays.asList(tmplAddPrvVals)); + + // Add in values that exist within the Subject + remPrincs.add(princVals[2]); + remPubVals.add(pubVals[2]); + remPrvVals.add(privVals[2]); + + // Run one success test for each Subject family to verify the + // overloaded method works as intended. + Set setPrin = mtSubj.getPrincipals(); + Set setPubCreds = mtSubj.getPublicCredentials(); + Set setPrvCreds = mtSubj.getPrivateCredentials(); + int prinOrigSize = setPrin.size(); + int pubOrigSize = setPubCreds.size(); + int prvOrigSize = setPrvCreds.size(); + + System.out.println("------ retainAll() -----"); + + // Retain the specified members (those that exist in the Subject) + // and validate the results. + if (validTestCollection(methRetain, setPrin, remPrincs) == false || + setPrin.size() != 1 || setPrin.contains(princVals[2]) == false) + { + throw new RuntimeException("Failed retainAll() on principals"); + } + + if (validTestCollection(methRetain, setPubCreds, + remPubVals) == false || + setPubCreds.size() != 1 || + setPubCreds.contains(pubVals[2]) == false) + { + throw new RuntimeException("Failed retainAll() on public creds"); + } + if (validTestCollection(methRetain, setPrvCreds, + remPrvVals) == false || + setPrvCreds.size() != 1 || + setPrvCreds.contains(privVals[2]) == false) + { + throw new RuntimeException("Failed retainAll() on private creds"); + } + System.out.println("Positive retainAll() test passed"); + + // Now add null elements into each container, then retest + remPrincs.add(null); + remPubVals.add(null); + remPrvVals.add(null); + + System.out.println("* Testing retainAll w/ null values on Principals"); + nullTestCollection(methRetain, mtSubj.getPrincipals(), null); + nullTestCollection(methRetain, mtSubj.getPrincipals(), remPrincs); + + System.out.println( + "* Testing retainAll w/ null values on Public Creds"); + nullTestCollection(methRetain, mtSubj.getPublicCredentials(), null); + nullTestCollection(methRetain, mtSubj.getPublicCredentials(), + remPubVals); + + System.out.println( + "* Testing retainAll w/ null values on Private Creds"); + nullTestCollection(methRetain, mtSubj.getPrivateCredentials(), null); + nullTestCollection(methRetain, mtSubj.getPrivateCredentials(), + remPrvVals); + } + + private static void testIsEmpty() { + Subject populatedSubj = makeSubj(false, false, false); + Subject emptySubj = new Subject(); + + System.out.println("------ isEmpty() -----"); + + if (populatedSubj.getPrincipals().isEmpty()) { + throw new RuntimeException( + "Populated Subject Principals incorrectly returned empty"); + } + if (emptySubj.getPrincipals().isEmpty() == false) { + throw new RuntimeException( + "Empty Subject Principals incorrectly returned non-empty"); + } + System.out.println("isEmpty() test passed"); + } + + private static void testSecureSetEquals() { + System.out.println("------ SecureSet.equals() -----"); + + Subject subj = makeSubj(false, false, false); + + // Case 1: null comparison [expect false] + if (subj.getPublicCredentials().equals(null) != false) { + throw new RuntimeException( + "equals(null) incorrectly returned true"); + } + + // Case 2: Self-comparison [expect true] + Set princs = subj.getPrincipals(); + princs.equals(subj.getPrincipals()); + + // Case 3: Comparison with non-Set type [expect false] + List listPrinc = + new LinkedList(Arrays.asList(princVals)); + if (subj.getPublicCredentials().equals(listPrinc) != false) { + throw new RuntimeException( + "equals([Non-Set]) incorrectly returned true"); + } + + // Case 4: SecureSets of differing sizes [expect false] + Subject subj1princ = new Subject(); + Subject subj2princ = new Subject(); + subj1princ.getPrincipals().add( + new X500Principal("CN=Tom Sawyer, ST=Missouri, C=US")); + subj1princ.getPrincipals().add( + new X500Principal("CN=John Doe, O=Bogus Corp.")); + subj2princ.getPrincipals().add( + new X500Principal("CN=Tom Sawyer, ST=Missouri, C=US")); + if (subj1princ.getPrincipals().equals( + subj2princ.getPrincipals()) != false) { + throw new RuntimeException( + "equals([differing sizes]) incorrectly returned true"); + } + + // Case 5: Content equality test [expect true] + Set equalSet = + new HashSet(Arrays.asList(princVals)); + if (subj.getPrincipals().equals(equalSet) != true) { + throw new RuntimeException( + "equals([equivalent set]) incorrectly returned false"); + } + + // Case 5: Content inequality test [expect false] + + // Note: to not fall into the size inequality check the two + // sets need to have the same number of elements. + Set inequalSet = + new HashSet(Arrays.asList(tmplAddPrincs)); + inequalSet.add(new JMXPrincipal("Samuel Clemens")); + + if (subj.getPrincipals().equals(inequalSet) != false) { + throw new RuntimeException( + "equals([equivalent set]) incorrectly returned false"); + } + System.out.println("SecureSet.equals() test passed"); + } + + public static void main(String[] args) throws Exception { + + testCTOR(); + + testDeserialize(); + + testAdd(); + + testRemove(); + + testContains(); + + testAddAll(); + + testRemoveAll(); + + testContainsAll(); + + testRetainAll(); + + testIsEmpty(); + + testSecureSetEquals(); + } +}