View Javadoc
1   /*
2    * SPDX-License-Identifier: MIT
3    * See LICENSE file for details.
4    *
5    * Copyright 2010-2026 The Waffle Project Contributors: https://github.com/Waffle/waffle/graphs/contributors
6    */
7   package waffle.jaas;
8   
9   import java.io.IOException;
10  import java.security.Principal;
11  import java.util.HashMap;
12  import java.util.LinkedHashSet;
13  import java.util.Map;
14  import java.util.Set;
15  
16  import javax.security.auth.Subject;
17  import javax.security.auth.callback.Callback;
18  import javax.security.auth.callback.CallbackHandler;
19  import javax.security.auth.callback.NameCallback;
20  import javax.security.auth.callback.UnsupportedCallbackException;
21  import javax.security.auth.login.LoginException;
22  
23  import mockit.Expectations;
24  import mockit.Mocked;
25  
26  import org.junit.jupiter.api.Assertions;
27  import org.junit.jupiter.api.BeforeEach;
28  import org.junit.jupiter.api.Test;
29  import org.powermock.reflect.Whitebox;
30  
31  import waffle.windows.auth.PrincipalFormat;
32  
33  /**
34   * The Class WindowsLoginModuleTest.
35   */
36  class WindowsLoginModuleTest {
37  
38      /** The login module. */
39      private WindowsLoginModule loginModule;
40  
41      /** The subject. */
42      private Subject subject;
43  
44      /** The callback handler. */
45      @Mocked
46      private CallbackHandler callbackHandler;
47  
48      /** The options. */
49      private Map<String, String> options;
50  
51      /**
52       * Check auth.
53       */
54      @Test
55      void checkAuth() {
56          Assertions.assertNotNull(this.loginModule.getAuth());
57          this.loginModule.setAuth(null);
58          Assertions.assertNull(this.loginModule.getAuth());
59      }
60  
61      /**
62       * Check guest login.
63       */
64      @Test
65      void checkGuestLogin() {
66          Assertions.assertTrue(this.loginModule.isAllowGuestLogin());
67          this.loginModule.setAllowGuestLogin(false);
68          Assertions.assertFalse(this.loginModule.isAllowGuestLogin());
69      }
70  
71      /**
72       * Commit_no principal.
73       *
74       * @throws LoginException
75       *             the login exception
76       */
77      @Test
78      void commit_noPrincipal() throws LoginException {
79          Assertions.assertFalse(this.loginModule.commit());
80      }
81  
82      /**
83       * Commit_subject read only.
84       *
85       * @throws LoginException
86       *             the login exception
87       */
88      @Test
89      void commit_subjectReadOnly() throws LoginException {
90          this.subject.setReadOnly();
91          Whitebox.setInternalState(this.loginModule, new LinkedHashSet<Principal>());
92          this.loginModule.initialize(this.subject, this.callbackHandler, null, this.options);
93          Assertions.assertThrows(LoginException.class, () -> {
94              this.loginModule.commit();
95          });
96      }
97  
98      /**
99       * Commit_success.
100      *
101      * @throws LoginException
102      *             the login exception
103      */
104     @Test
105     void commit_success() throws LoginException {
106         Whitebox.setInternalState(this.loginModule, new LinkedHashSet<Principal>());
107         this.loginModule.initialize(this.subject, this.callbackHandler, null, this.options);
108         Assertions.assertTrue(this.loginModule.commit());
109     }
110 
111     /**
112      * Commit_with debug.
113      *
114      * @throws LoginException
115      *             the login exception
116      */
117     @Test
118     void commit_withDebug() throws LoginException {
119         this.options.put("debug", "true");
120         this.loginModule.initialize(this.subject, this.callbackHandler, null, this.options);
121         final Set<Principal> principals = new LinkedHashSet<>();
122         principals.add(new UserPrincipal("FQN"));
123         Whitebox.setInternalState(this.loginModule, principals);
124         this.loginModule.initialize(this.subject, this.callbackHandler, null, this.options);
125         Assertions.assertTrue(this.loginModule.commit());
126     }
127 
128     /**
129      * Commit_with Roles.
130      *
131      * @throws LoginException
132      *             the login exception
133      */
134     @Test
135     void commit_withRoles() throws LoginException {
136         this.options.put("debug", "true");
137         final Set<Principal> principals = new LinkedHashSet<>();
138         principals.add(new UserPrincipal("FQN"));
139         principals.add(new RolePrincipal("WindowsGroup"));
140         Whitebox.setInternalState(this.loginModule, principals);
141         this.loginModule.initialize(this.subject, this.callbackHandler, null, this.options);
142         Assertions.assertTrue(this.loginModule.commit());
143     }
144 
145     /**
146      * Inits the.
147      */
148     @BeforeEach
149     void init() {
150         this.loginModule = new WindowsLoginModule();
151         this.subject = new Subject();
152         this.options = new HashMap<>();
153     }
154 
155     /**
156      * Initialize_with options.
157      */
158     @Test
159     void initialize_withOptions() {
160         this.options.put("debug", "true");
161         this.options.put("principalFormat", "sid");
162         this.options.put("roleFormat", "none");
163         this.options.put("junk", "junk");
164         this.loginModule.initialize(this.subject, this.callbackHandler, null, this.options);
165         Assertions.assertTrue(this.loginModule.isDebug());
166         Assertions.assertEquals(PrincipalFormat.SID, Whitebox.getInternalState(this.loginModule, "principalFormat"));
167         Assertions.assertEquals(PrincipalFormat.NONE, Whitebox.getInternalState(this.loginModule, "roleFormat"));
168     }
169 
170     /**
171      * Login_invalid guest login.
172      *
173      * @throws LoginException
174      *             the login exception
175      */
176     @Test
177     void login_invalidGuestLogin() throws LoginException {
178         this.callbackHandler = new UsernamePasswordCallbackHandler("Guest", "password");
179         this.options.put("debug", "true");
180         this.loginModule.initialize(this.subject, this.callbackHandler, null, this.options);
181         Assertions.assertTrue(this.loginModule.isAllowGuestLogin());
182         Assertions.assertThrows(LoginException.class, () -> {
183             this.loginModule.login();
184         });
185     }
186 
187     /**
188      * Login_null password.
189      *
190      * @throws LoginException
191      *             the login exception
192      */
193     @Test
194     void login_nullPassword() throws LoginException {
195         this.callbackHandler = new UsernamePasswordCallbackHandler("Guest", null);
196         this.options.put("debug", "true");
197         this.loginModule.initialize(this.subject, this.callbackHandler, null, this.options);
198         Assertions.assertTrue(this.loginModule.isAllowGuestLogin());
199         Assertions.assertThrows(LoginException.class, () -> {
200             this.loginModule.login();
201         });
202     }
203 
204     /**
205      * Login_throw io exception.
206      *
207      * @throws LoginException
208      *             the login exception
209      * @throws IOException
210      *             Signals that an I/O exception has occurred.
211      * @throws UnsupportedCallbackException
212      *             the unsupported callback exception
213      */
214     @Test
215     void login_throwIOException() throws LoginException, IOException, UnsupportedCallbackException {
216         this.options.put("debug", "true");
217         this.loginModule.initialize(this.subject, this.callbackHandler, null, this.options);
218         Assertions.assertTrue(this.loginModule.isAllowGuestLogin());
219         Assertions.assertNotNull(new Expectations() {
220             {
221                 WindowsLoginModuleTest.this.callbackHandler.handle(this.withInstanceOf(Callback[].class));
222                 this.result = new IOException();
223             }
224         });
225         Assertions.assertThrows(LoginException.class, () -> {
226             this.loginModule.login();
227         });
228     }
229 
230     /**
231      * Login_throw unsupported callback exception.
232      *
233      * @throws LoginException
234      *             the login exception
235      * @throws IOException
236      *             Signals that an I/O exception has occurred.
237      * @throws UnsupportedCallbackException
238      *             the unsupported callback exception
239      */
240     @Test
241     void login_throwUnsupportedCallbackException() throws LoginException, IOException, UnsupportedCallbackException {
242         this.options.put("debug", "true");
243         this.loginModule.initialize(this.subject, this.callbackHandler, null, this.options);
244         Assertions.assertTrue(this.loginModule.isAllowGuestLogin());
245         Assertions.assertNotNull(new Expectations() {
246             {
247                 WindowsLoginModuleTest.this.callbackHandler.handle(this.withInstanceOf(Callback[].class));
248                 this.result = new UnsupportedCallbackException(new NameCallback("Callback Exception"));
249             }
250         });
251         Assertions.assertThrows(LoginException.class, () -> {
252             this.loginModule.login();
253         });
254     }
255 
256     /**
257      * Logon_no callback handler.
258      *
259      * @throws LoginException
260      *             the login exception
261      */
262     @Test
263     void logon_noCallbackHandler() throws LoginException {
264         Assertions.assertThrows(LoginException.class, () -> {
265             this.loginModule.login();
266         });
267     }
268 
269     /**
270      * Logout_abort no user.
271      *
272      * @throws LoginException
273      *             the login exception
274      */
275     @Test
276     void logout_abortNoUser() throws LoginException {
277         this.loginModule.initialize(this.subject, this.callbackHandler, null, this.options);
278         Assertions.assertTrue(this.loginModule.abort());
279     }
280 
281     /**
282      * Logout_no user.
283      *
284      * @throws LoginException
285      *             the login exception
286      */
287     @Test
288     void logout_noUser() throws LoginException {
289         this.loginModule.initialize(this.subject, this.callbackHandler, null, this.options);
290         Assertions.assertTrue(this.loginModule.logout());
291     }
292 
293     /**
294      * Logout_subject read only.
295      *
296      * @throws LoginException
297      *             the login exception
298      */
299     @Test
300     void logout_subjectReadOnly() throws LoginException {
301         this.subject.setReadOnly();
302         this.loginModule.initialize(this.subject, this.callbackHandler, null, this.options);
303         Assertions.assertThrows(LoginException.class, () -> {
304             this.loginModule.logout();
305         });
306     }
307 
308     /**
309      * Logout_valid user.
310      *
311      * @throws LoginException
312      *             the login exception
313      */
314     @Test
315     void logout_validUser() throws LoginException {
316         Whitebox.setInternalState(this.loginModule, "username", "waffle-user");
317         this.loginModule.initialize(this.subject, this.callbackHandler, null, this.options);
318         Assertions.assertTrue(this.loginModule.logout());
319     }
320 
321 }