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