1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18/**
19* @author Stepan M. Mishura
20*/
21
22package org.apache.harmony.auth.tests.javax.security.auth.login;
23
24import java.io.File;
25import java.security.Security;
26import java.util.ArrayList;
27import java.util.HashMap;
28import java.util.Hashtable;
29import java.util.Map;
30import java.util.Properties;
31
32import javax.security.auth.Subject;
33import javax.security.auth.callback.Callback;
34import javax.security.auth.callback.CallbackHandler;
35import javax.security.auth.login.AppConfigurationEntry;
36import javax.security.auth.login.Configuration;
37import javax.security.auth.login.LoginContext;
38import javax.security.auth.login.LoginException;
39import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
40import javax.security.auth.spi.LoginModule;
41
42import junit.framework.TestCase;
43
44import org.apache.harmony.auth.tests.support.TestUtils;
45
46import tests.support.Support_Exec;
47
48/**
49 * Tests LoginContext class
50 */
51public class LoginContextTest extends TestCase {
52
53    // system property to specify another login configuration file
54    private static final String AUTH_LOGIN_CONFIG = "java.security.auth.login.config";
55
56    private static final String moduleName = "moduleName";
57
58    private final Subject subject = new Subject();
59
60    private final MyCallbackHandler handler = new MyCallbackHandler();
61
62    @Override
63    protected void setUp() throws Exception {
64        super.setUp();
65
66        Configuration.setConfiguration(new MyConfig());
67    }
68
69    /**
70     * Constructor: LoginContext(java.lang.String)
71     *
72     * Parameters: valid app. name
73     *
74     * Expected: no exceptions
75     */
76    public final void testLC_String() throws Exception {
77
78        // configuration contains requested login module
79        LoginContext context = new LoginContext(moduleName);
80
81        assertTrue("Requested module", MyConfig.getLastAppName() == moduleName);
82
83        //FIXME lazy subject initialization? should it be initialized in ctor?
84        assertNull("Instantiated subject", context.getSubject());
85    }
86
87    /**
88     * Constructor: LoginContext(java.lang.String)
89     *
90     * Parameters: invalid (null app. name)
91     *
92     * Expected: LoginException
93     */
94    public final void testLC_String_NullApp() {
95
96        try {
97            new LoginContext(null);
98            fail("No expected LoginException");
99        } catch (LoginException e) {
100        }
101    }
102
103    /**
104     * Constructor: LoginContext(java.lang.String)
105     *
106     * Precondition: app. name absent in the current configuration
107     *
108     * Expected: LoginException
109     */
110    public final void testLC_String_NoApp() {
111
112        // configuration doesn't contain requested application name
113        MyConfig.resetConfiguration();
114
115        try {
116            new LoginContext(moduleName);
117            fail("No expected LoginException");
118        } catch (LoginException e) {
119            assertEquals("Default module", "other", MyConfig.getLastAppName());
120        }
121    }
122
123    /**
124     * Constructor: LoginContext(java.lang.String)
125     *
126     * Precondition: configuration contains requested login module and
127     *             default callback handler is specified via security
128     *             property but its class is not accessible
129     *
130     * Expected: LoginException
131     */
132    public final void testLC_String_InaccessibleCallbackHandler() {
133
134        try {
135            Security.setProperty("auth.login.defaultCallbackHandler",
136                    "absentCallBackhandlerClassName");
137
138            new LoginContext(moduleName);
139            fail("No expected LoginException");
140        } catch (LoginException e) {
141            assertTrue("Default module",
142                    MyConfig.getLastAppName() == moduleName);
143        } finally {
144            //FIXME how to reset security property correctly?
145            Security.setProperty("auth.login.defaultCallbackHandler", "");
146        }
147    }
148
149    /**
150     * Constructor: LoginContext(java.lang.String)
151     *
152     * Precondition: configuration contains requested login module and
153     *             default callback handler is specified via security
154     *             property but its class doesn't implement
155     *             CallbackHandler interface
156     *
157     * Expected: LoginException
158     */
159    public final void testLC_String_InvalidCallbackHandler() throws Exception {
160
161        try {
162            Security.setProperty("auth.login.defaultCallbackHandler",
163                    LoginContextTest.class.getName());
164
165            new LoginContext(moduleName);
166            fail("No expected ClassCastException");
167        } catch (ClassCastException e) {
168        } finally {
169            //FIXME how to reset security property correctly?
170            Security.setProperty("auth.login.defaultCallbackHandler", "");
171        }
172    }
173
174    /**
175     * Constructor: LoginContext(java.lang.String)
176     *
177     * Expected: creation of default callback handler
178     */
179    public final void testLC_String_InitCallbackHandler() throws Exception {
180
181        // checks initialization of specified callback handler
182        MyCallbackHandler.initialized = false;
183        try {
184            Security
185                    .setProperty("auth.login.defaultCallbackHandler",
186                            MyCallbackHandler.class.getName());
187
188            new LoginContext(moduleName);
189
190            assertTrue("Initialization", MyCallbackHandler.initialized);
191        } finally {
192            //FIXME how to reset security property correctly?
193            Security.setProperty("auth.login.defaultCallbackHandler", "");
194        }
195    }
196
197    /**
198     * Constructor: LoginContext(java.lang.String)
199     *
200     * Precondition: parameters for login module initialization
201     *               are created in the constructor above
202     *
203     * Expected: not null subject, null callback handler or
204     *           wrapped default callback handler, not null shared
205     *           state and not null options.
206     */
207    public final void testLC_String_LoginModuleInitialize() throws Exception {
208
209        Hashtable<String, Object> options = new Hashtable<String, Object>();
210
211        // add required module to the current configuration
212        MyConfig.addRequired("MyLoginModule", options);
213
214        // reset initialized login modules list
215        MyLoginModule.reset();
216
217        LoginContext context = new LoginContext(moduleName);
218
219        context.login();
220
221        // only one module must be created
222        assertEquals("Number of modules", 1, MyLoginModule.list.size());
223
224        MyLoginModule module = MyLoginModule.list.get(0);
225
226        // login context instantiates subject object itself.
227        assertNotNull("Subject", module.subject);
228        assertTrue("getSubject", module.subject == context.getSubject());
229
230        // login context doesn't have callback handler
231        assertNull("Handler", module.handler);
232
233        // login context provides login module with shared state object
234        assertNotNull("Shared state", module.sharedState);
235
236        // login context provides login module with module's options
237        assertTrue("Option references", module.options != options);
238        assertEquals("Option objects", module.options, options);
239
240        // checks initialization of specified callback handler
241        MyLoginModule.reset();
242        try {
243            Security
244                    .setProperty("auth.login.defaultCallbackHandler",
245                            MyCallbackHandler.class.getName());
246
247            context = new LoginContext(moduleName);
248
249            context.login();
250
251            // TODO how to test default callback handler wrapping for LoginContext(java.lang.String)?
252
253            // FIXME wrap a handler
254            //assertFalse("Handler", MyLoginModule.handler.getClass().equals(
255            //        MyCallbackHandler.class));
256        } finally {
257            // FIXME how to reset security property correctly?
258            Security.setProperty("auth.login.defaultCallbackHandler", "");
259        }
260    }
261
262    /**
263     * Constructor: LoginContext(String, CallbackHandler)
264     *
265     * Parameters: are valid
266     *
267     * Expected: no exceptions
268     */
269    public final void testLC_StringCallbackHandler() throws Exception {
270
271        LoginContext context = new LoginContext(moduleName, handler);
272
273        assertTrue("Requested module", MyConfig.getLastAppName() == moduleName);
274
275        //FIXME lazy subject initialization? should it be initialized in ctor?
276        assertNull("Instantiated subject", context.getSubject());
277    }
278
279    /**
280     * Constructor: LoginContext(String, CallbackHandler)
281     *
282     * Parameters: invalid (null app. name)
283     *
284     * Expected: LoginException
285     */
286    public final void testLC_StringCallbackHandler_NullApp() {
287
288        try {
289            new LoginContext(null, handler);
290            fail("No expected LoginException");
291        } catch (LoginException e) {
292        }
293    }
294
295    /**
296     * Constructor: LoginContext(String, CallbackHandler)
297     *
298     * Parameters: invalid (null callback handler)
299     *
300     * Expected: LoginException
301     */
302    public final void testLC_StringCallbackHandler_NullCallbackHandler() {
303
304        try {
305            new LoginContext(moduleName, (CallbackHandler) null);
306            fail("No expected LoginException");
307        } catch (LoginException e) {
308        }
309    }
310
311    /**
312     * Constructor: LoginContext(String, CallbackHandler)
313     *
314     * Precondition: app. name absent in the current configuration
315     *
316     * Expected: LoginException
317     */
318    public final void testLC_StringCallbackHandler_NoApp() {
319
320        // configuration doesn't contain requested application name
321        MyConfig.resetConfiguration();
322
323        try {
324            new LoginContext(moduleName, handler);
325            fail("No expected LoginException");
326        } catch (LoginException e) {
327            assertEquals("Default module", "other", MyConfig.getLastAppName());
328        }
329    }
330
331    /**
332     * Constructor: LoginContext(String, CallbackHandler)
333     *
334     * Precondition: configuration contains requested login module and
335     *             default callback handler is specified via security property
336     *
337     * Expected: no default callback handler initialization
338     */
339    public final void testLC_StringCallbackHandler_NoInit() throws Exception {
340
341        // checks initialization of specified callback handler
342        MyCallbackHandler.initialized = false;
343        try {
344            Security
345                    .setProperty("auth.login.defaultCallbackHandler",
346                            MyCallbackHandler.class.getName());
347
348            new LoginContext(moduleName, handler);
349
350            assertFalse("Initialization", MyCallbackHandler.initialized);
351        } finally {
352            //FIXME how to reset security property correctly?
353            Security.setProperty("auth.login.defaultCallbackHandler", "");
354        }
355    }
356
357    /**
358     * Constructor: LoginContext(String, CallbackHandler)
359     *
360     * Precondition: parameters for login module initialization
361     *               are created in the constructor above
362     *
363     * Expected: not null subject, wrapped provided callback handler,
364     *           not null shared state and not null options.
365     */
366    public final void testLC_StringCallbackHandler_LoginModuleInitialize()
367            throws Exception {
368
369        Hashtable<String, Object> options = new Hashtable<String, Object>();
370
371        // add required module to the current configuration
372        MyConfig.addRequired("MyLoginModule", options);
373
374        // reset initialized login modules list
375        MyLoginModule.reset();
376
377        LoginContext context = new LoginContext(moduleName, handler);
378
379        context.login();
380
381        // only one module must be created
382        assertEquals("Number of modules", 1, MyLoginModule.list.size());
383
384        MyLoginModule module = MyLoginModule.list.get(0);
385
386        // login context instantiates subject object itself.
387        assertNotNull("Subject", module.subject);
388        assertTrue("getSubject", module.subject == context.getSubject());
389
390        //  TODO how to test callback handler wrapping for LoginContext(String, CallbackHandler)?
391
392        // FIXME wrap a handler
393        //assertFalse("Handler", MyLoginModule.handler.getClass().equals(
394        //        handler.getClass()));
395
396        // login context provides login module with shared state object
397        assertNotNull("Shared state", module.sharedState);
398
399        // login context provides login module with module's options
400        assertTrue("Option references", module.options != options);
401        assertEquals("Option objects", module.options, options);
402    }
403
404    /**
405     * Constructor: LoginContext(String, Subject)
406     *
407     * Parameters: are valid
408     *
409     * Expected: no exceptions
410     */
411    public final void testLC_StringSubject() throws Exception {
412
413        LoginContext context = new LoginContext(moduleName, subject);
414
415        assertTrue("Requested module", MyConfig.getLastAppName() == moduleName);
416        assertTrue("Instantiated subject", context.getSubject() == subject);
417    }
418
419    /**
420     * Constructor: LoginContext(String, Subject)
421     *
422     * Parameters: invalid (null app. name)
423     *
424     * Expected: LoginException
425     */
426    public final void testLC_StringSubject_NullApp() {
427
428        try {
429            new LoginContext(null, subject);
430            fail("No expected LoginException");
431        } catch (LoginException e) {
432        }
433    }
434
435    /**
436     * Constructor: LoginContext(String, Subject)
437     *
438     * Parameters: invalid (null subject)
439     *
440     * Expected: LoginException
441     */
442    public final void testLC_StringSubject_NullSubject() {
443
444        try {
445            new LoginContext(moduleName, (Subject) null);
446            fail("No expected LoginException");
447        } catch (LoginException e) {
448        }
449    }
450
451    /**
452     * Constructor: LoginContext(String, Subject)
453     *
454     * Precondition: app. name absent in the current configuration
455     *
456     * Expected: LoginException
457     */
458    public final void testLC_StringSubject_NoApp() throws Exception {
459
460        MyConfig.resetConfiguration();
461        try {
462            new LoginContext(moduleName, subject);
463            fail("No expected LoginException");
464        } catch (LoginException e) {
465            assertEquals("Default module", "other", MyConfig.getLastAppName());
466        }
467    }
468
469    /**
470     * Constructor: LoginContext(String, Subject)
471     *
472     * Precondition: configuration contains requested login module and
473     *             default callback handler is specified via security
474     *             property but its class is not accessible
475     *
476     * Expected: LoginException
477     */
478    public final void testLC_StringSubject_InaccessibleCallbackHandler() {
479
480        try {
481            Security.setProperty("auth.login.defaultCallbackHandler",
482                    "absentCallBackhandlerClassName");
483
484            new LoginContext(moduleName, subject);
485            fail("No expected LoginException");
486        } catch (LoginException e) {
487            assertTrue("Default module",
488                    MyConfig.getLastAppName() == moduleName);
489        } finally {
490            // FIXME how to reset security property correctly?
491            Security.setProperty("auth.login.defaultCallbackHandler", "");
492        }
493    }
494
495    /**
496     * Constructor: LoginContext(String, Subject)
497     *
498     * Expected: creation of default callback handler
499     */
500    public final void testLC_StringSubject_InitCallbackHandler()
501            throws Exception {
502
503        // checks initialization of specified callback handler
504        MyCallbackHandler.initialized = false;
505        try {
506            Security
507                    .setProperty("auth.login.defaultCallbackHandler",
508                            MyCallbackHandler.class.getName());
509
510            new LoginContext(moduleName, subject);
511
512            assertTrue("Initialization", MyCallbackHandler.initialized);
513        } finally {
514            // FIXME how to reset security property correctly?
515            Security.setProperty("auth.login.defaultCallbackHandler", "");
516        }
517    }
518
519    /**
520     * Constructor: LoginContext(String, Subject)
521     *
522     * Precondition: parameters for login module initialization
523     *               are created in the constructor above
524     *
525     * Expected: provided subject, null callback handler or
526     *           wrapped default callback handler, not null shared
527     *           state and not null options.
528     */
529    public final void testLC_StringSubject_LoginModuleInitialize()
530            throws Exception {
531
532        Hashtable<String, Object> options = new Hashtable<String, Object>();
533
534        // add required module to the current configuration
535        MyConfig.addRequired("MyLoginModule", options);
536
537        // reset initialized login modules list
538        MyLoginModule.reset();
539
540        LoginContext context = new LoginContext(moduleName, subject);
541
542        context.login();
543
544        // only one module must be created
545        assertEquals("Number of modules", 1, MyLoginModule.list.size());
546
547        MyLoginModule module = MyLoginModule.list.get(0);
548
549        // login context has provided subject
550        assertTrue("Subject", module.subject == subject);
551        assertTrue("getSubject", module.subject == context.getSubject());
552
553        // login context doesn't have callback handler
554        assertNull("Handler", module.handler);
555
556        // login context provides login module with shared state object
557        assertNotNull("Shared state", module.sharedState);
558
559        // login context provides login module with module's options
560        assertTrue("Option references", module.options != options);
561        assertEquals("Option objects", module.options, options);
562
563        // checks initialization of specified callback handler
564        MyLoginModule.reset();
565        try {
566            Security
567                    .setProperty("auth.login.defaultCallbackHandler",
568                            MyCallbackHandler.class.getName());
569
570            context = new LoginContext(moduleName, subject);
571
572            context.login();
573
574            // TODO how to test callback handler wrapping for LoginContext(String, Subject)?
575
576            // FIXME wrap a handler
577            //assertFalse("Handler", MyLoginModule.handler.getClass().equals(
578            //        MyCallbackHandler.class));
579        } finally {
580            Security.setProperty("auth.login.defaultCallbackHandler", "");
581        }
582    }
583
584    /**
585     * Constructor: LoginContext(String, Subject, CallbackHandler)
586     *
587     * Parameters: are valid
588     *
589     * Expected: no exceptions
590     */
591    public final void testLC_StringSubjectCallbackHandler() throws Exception {
592
593        LoginContext context = new LoginContext(moduleName, subject, handler);
594
595        assertTrue("Requested module", MyConfig.getLastAppName() == moduleName);
596        assertTrue("Instantiated subject", context.getSubject() == subject);
597    }
598
599    /**
600     * Constructor: LoginContext(String, Subject, CallbackHandler)
601     *
602     * Parameters: invalid (null app. name)
603     *
604     * Expected: LoginException
605     */
606
607    public final void testLC_StringSubjectCallbackHandler_NullApp() {
608        try {
609            new LoginContext(null, subject, handler);
610            fail("No expected LoginException");
611        } catch (LoginException e) {
612        }
613    }
614
615    /**
616     * Constructor: LoginContext(String, Subject, CallbackHandler)
617     *
618     * Parameters: invalid (null subject)
619     *
620     * Expected: LoginException
621     */
622    public final void testLC_StringSubjectCallbackHandler_NullSubject() {
623        try {
624            new LoginContext(moduleName, null, handler);
625            fail("No expected LoginException");
626        } catch (LoginException e) {
627        }
628    }
629
630    /**
631     * Constructor: LoginContext(String, Subject, CallbackHandler)
632     *
633     * Parameters: invalid (null callback handler)
634     *
635     * Expected: LoginException
636     */
637    public final void testLC_StringSubjectCallbackHandler_NullCallbackHandler() {
638        try {
639            new LoginContext(moduleName, subject, null);
640            fail("No expected LoginException");
641        } catch (LoginException e) {
642        }
643    }
644
645    /**
646     * Constructor: LoginContext(String, Subject, CallbackHandler)
647     *
648     * Precondition: app. name absent in the current configuration
649     *
650     * Expected: LoginException
651     */
652    public final void testLC_StringSubjectCallbackHandler_NoApp() {
653
654        // configuration doesn't contain requested login module
655        MyConfig.resetConfiguration();
656
657        try {
658            new LoginContext(moduleName, subject, handler);
659            fail("No expected LoginException");
660        } catch (LoginException e) {
661            assertEquals("Default module", "other", MyConfig.getLastAppName());
662        }
663    }
664
665    /**
666     * Constructor: LoginContext(String, Subject, CallbackHandler)
667     *
668     * Precondition: parameters for login module initialization
669     *               are created in the constructor above
670     *
671     * Expected: provided subject, wrapped default callback handler,
672     *           not null shared state and not null options.
673     */
674
675    public final void testLC_StringSubjectCallbackHandler_LoginModuleInitialize()
676            throws Exception {
677
678        Hashtable<String, Object> options = new Hashtable<String, Object>();
679
680        // add required module to the current configuration
681        MyConfig.addRequired("MyLoginModule", options);
682
683        // reset initialized login modules list
684        MyLoginModule.reset();
685
686        LoginContext context = new LoginContext(moduleName, subject, handler);
687
688        context.login();
689
690        // only one module must be created
691        assertEquals("Number of modules", 1, MyLoginModule.list.size());
692
693        MyLoginModule module = MyLoginModule.list.get(0);
694
695        // login context has provided subject
696        assertTrue("Subject", module.subject == subject);
697        assertTrue("getSubject", module.subject == context.getSubject());
698
699        //  TODO how to test callback handler wrapping for LoginContext(String, Subject, CallbackHandler)?
700
701        // FIXME wrap a handler
702        //assertFalse("Handler", MyLoginModule.handler.getClass().equals(
703        //        handler.getClass()));
704
705        // login context provides login module with shared state object
706        assertNotNull("Shared state", module.sharedState);
707
708        // login context provides login module with module's options
709        assertTrue("Option references", module.options != options);
710        assertEquals("Option objects", module.options, options);
711    }
712
713    /**
714     * Method: LoginContext.login()
715     *
716     * Precondition: returned list of login modules is empty
717     *
718     * Expected: LoginException
719     */
720    public final void testLogin_EmptyModulesList() throws Exception {
721
722        LoginContext context = new LoginContext(moduleName);
723
724        try {
725            context.login();
726            fail("No expected LoginException");
727        } catch (LoginException e) {
728        }
729    }
730
731    /*
732     * Method: LoginContext.login()
733     *
734    public final void testLogin_() throws Exception {
735
736        Hashtable options = new Hashtable();
737
738        // add required module to the current configuration
739        MyConfig.addRequired("MyLoginModule", options);
740
741        LoginContext context = new LoginContext(moduleName);
742
743        context.login();
744        context.login();
745    }
746    */
747
748    public final void testLogout() {
749        //TODO Implement logout().
750    }
751
752    public final void testGetSubject() {
753        //TODO Implement getSubject().
754        // test failed login
755    }
756
757    /**
758     * @tests javax.security.auth.login.LoginContext
759     */
760    public void test_LoginContext_defaultConfigProvider() throws Exception {
761
762        // test: LoginContext constructor fails because there are no config
763        // files to be read (the test is modification of test case
764        // in ConfigurationTest)
765
766        // no login.config.url.N security properties should be set
767        String javaSecurityFile = TestUtils
768                .createJavaPropertiesFile(new Properties());
769
770        // tmp user home to avoid presence of ${user.home}/.java.login.config
771        String tmpUserHome = System.getProperty("java.io.tmpdir")
772                + File.separatorChar + "tmpUserHomeForLoginContextTest";
773        File dir = new File(tmpUserHome);
774        if (!dir.exists()) {
775            dir.mkdirs();
776            dir.deleteOnExit();
777        }
778        String javaLoginConfig = tmpUserHome + File.separatorChar
779                + ".java.login.config";
780        assertFalse("There should be no login config file: " + javaLoginConfig,
781                new File(javaLoginConfig).exists());
782
783        String[] arg = new String[] { "-Duser.home=" + tmpUserHome,
784                "-Djava.security.properties=" + javaSecurityFile,
785                NoConfigFileToBeRead.class.getName() };
786
787        Support_Exec.execJava(arg, null, true);
788    }
789
790    public static class NoConfigFileToBeRead {
791
792        // the test is based on assumption that security properties
793        // login.config.url.N are unset and there is no file
794        // ${user.home}/.java.login.config
795        public static void main(String[] args) throws LoginException {
796
797            //reset path to alternative configuration file
798            TestUtils.setSystemProperty(AUTH_LOGIN_CONFIG, null);
799
800            Configuration.setConfiguration(null); // reset default config
801            try {
802                // Regression for HARMONY-771
803                new LoginContext("0");
804                fail("No expected SecurityException");
805            } catch (SecurityException e) {
806            }
807        }
808    }
809    /**
810     * @tests javax.security.auth.login.LoginContext.login()
811     */
812    public void test_login_resourcesLeakage() throws Exception {
813
814        // This is a compatibility test.
815        // The test verifies that LoginContext allows to invoke login() method
816        // multiple times without invoking logout() before. In testing scenario
817        // each login() invocation adds new credentials to the passed subject.
818        Configuration.setConfiguration(new Configuration() {
819
820            @Override
821            public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
822                return new AppConfigurationEntry[] { new AppConfigurationEntry(
823                        MyModule.class.getName(),
824                        LoginModuleControlFlag.REQUIRED,
825                        new HashMap<String, Object>()) };
826            }
827
828            @Override
829            public void refresh() {
830            }
831        });
832
833        LoginContext context = new LoginContext("moduleName", new Subject());
834
835        context.login();
836        context.login();
837
838        Subject subject = context.getSubject();
839
840        assertEquals(2, subject.getPrivateCredentials().size());
841        assertEquals(2, subject.getPublicCredentials().size());
842    }
843
844    public static class MyModule implements LoginModule {
845
846        Subject sub;
847
848        public boolean abort() throws LoginException {
849            return false;
850        }
851
852        public boolean commit() throws LoginException {
853            sub.getPrivateCredentials().add(new Object());
854            return true;
855        }
856
857        public void initialize(Subject arg0, CallbackHandler arg1,
858                Map<String, ?> arg2, Map<String, ?> arg3) {
859            sub = arg0;
860        }
861
862        public boolean login() throws LoginException {
863            sub.getPublicCredentials().add(new Object());
864            return true;
865        }
866
867        public boolean logout() throws LoginException {
868            return false;
869        }
870    }
871
872    private static class MyConfig extends Configuration {
873
874        private String appName;
875
876        private ArrayList<AppConfigurationEntry> entries;
877
878        public MyConfig() {
879            entries = new ArrayList<AppConfigurationEntry>();
880        }
881
882        @Override
883        public AppConfigurationEntry[] getAppConfigurationEntry(String applicationName) {
884            appName = applicationName;
885            if (entries != null) {
886                if (entries.size() == 0) {
887                    return new AppConfigurationEntry[0];
888                }
889                AppConfigurationEntry[] appEntries = new AppConfigurationEntry[entries.size()];
890                entries.toArray(appEntries);
891                return appEntries;
892            }
893            return null;
894        }
895
896        @Override
897        public void refresh() {
898        }
899
900        /**
901         * Returns the last application name requested by LoginContext constructor
902         *
903         * @return the last application name
904         */
905        public static String getLastAppName() {
906            return ((MyConfig) Configuration.getConfiguration()).appName;
907        }
908
909        /**
910         * Reset configuration.
911         *
912         * After invocation the configuration doesn't have login modules
913         * and the method Configuration.getAppConfigurationEntry(String)
914         * always returns null;
915         */
916        public static void resetConfiguration() {
917            ((MyConfig) Configuration.getConfiguration()).entries = null;
918        }
919
920        /**
921         * Appends required login module to the current configuration
922         */
923        public static void addRequired(String name, Map<String, ?> options) {
924            ArrayList<AppConfigurationEntry> list = ((MyConfig) Configuration.getConfiguration()).entries;
925
926            AppConfigurationEntry entry = new AppConfigurationEntry(
927                    LoginContextTest.class.getName() + '$' + name,
928                    javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
929                    options);
930
931            list.add(entry);
932        }
933    }
934
935    public static class MyCallbackHandler implements CallbackHandler {
936
937        public static boolean initialized;
938
939        public MyCallbackHandler() {
940            initialized = true;
941        }
942
943        public void handle(Callback[] callbacks) {
944        }
945    }
946
947    public static class MyLoginModule implements LoginModule {
948
949        public static ArrayList<MyLoginModule> list = new ArrayList<MyLoginModule>();
950
951        public static void reset() {
952            list = new ArrayList<MyLoginModule>();
953        }
954
955        public boolean aborted;
956
957        public boolean commited;
958
959        public boolean initialized;
960
961        public boolean logined;
962
963        public boolean logouted;
964
965        public Subject subject;
966
967        public CallbackHandler handler;
968
969        public Map<String, ?> sharedState;
970
971        public Map<String, ?> options;
972
973        public MyLoginModule() {
974            list.add(this);
975        }
976
977        public boolean abort() throws LoginException {
978
979            if (!initialized || !logined) {
980                throw new AssertionError(
981                        "MUST initialize and try to login first before abort");
982            }
983            aborted = true;
984            return true;
985        }
986
987        public boolean commit() throws LoginException {
988
989            if (!initialized || !logined) {
990                throw new AssertionError(
991                        "MUST initialize and try to login first before abort");
992            }
993            commited = true;
994            return true;
995        }
996
997        public void initialize(Subject subject, CallbackHandler handler,
998                Map<String, ?> sharedState, Map<String, ?> options) {
999
1000            if (logined || commited || aborted) {
1001                throw new AssertionError("MUST be initialized first");
1002            }
1003
1004            this.subject = subject;
1005            this.handler = handler;
1006            this.sharedState = sharedState;
1007            this.options = options;
1008
1009            initialized = true;
1010        }
1011
1012        public boolean login() throws LoginException {
1013
1014            if (!initialized) {
1015                throw new AssertionError("MUST be initialized first");
1016            }
1017            if (commited || aborted) {
1018                throw new AssertionError(
1019                        "MUST try to login first before commit/abort");
1020            }
1021            logined = true;
1022            return true;
1023        }
1024
1025        public boolean logout() throws LoginException {
1026            logouted = true;
1027            return true;
1028        }
1029    }
1030
1031    public static class TestLoginModule implements LoginModule {
1032
1033        public boolean abort() throws LoginException {
1034            return false;
1035        }
1036
1037        public boolean commit() throws LoginException {
1038            return false;
1039        }
1040
1041        public void initialize(Subject arg0, CallbackHandler arg1, Map<String, ?> arg2,
1042                Map<String, ?> arg3) {
1043        }
1044
1045        public boolean login() throws LoginException {
1046            return false;
1047        }
1048
1049        public boolean logout() throws LoginException {
1050            return false;
1051        }
1052    }
1053}
1054