View Javadoc
1   /*
2    * MIT License
3    *
4    * Copyright (c) 2010-2024 The Waffle Project Contributors: https://github.com/Waffle/waffle/graphs/contributors
5    *
6    * Permission is hereby granted, free of charge, to any person obtaining a copy
7    * of this software and associated documentation files (the "Software"), to deal
8    * in the Software without restriction, including without limitation the rights
9    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10   * copies of the Software, and to permit persons to whom the Software is
11   * furnished to do so, subject to the following conditions:
12   *
13   * The above copyright notice and this permission notice shall be included in all
14   * copies or substantial portions of the Software.
15   *
16   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22   * SOFTWARE.
23   */
24  package waffle.jaas;
25  
26  import static org.assertj.core.api.Assertions.assertThat;
27  
28  import java.security.Principal;
29  import java.util.HashMap;
30  import java.util.Map;
31  
32  import javax.security.auth.Subject;
33  import javax.security.auth.login.LoginException;
34  
35  import org.junit.jupiter.api.Assertions;
36  import org.junit.jupiter.api.BeforeEach;
37  import org.junit.jupiter.api.Test;
38  
39  import waffle.mock.MockWindowsAuthProvider;
40  import waffle.windows.auth.impl.WindowsAccountImpl;
41  
42  /**
43   * The Class WindowsLoginModuleTest.
44   */
45  class WindowsLoginModuleTest {
46  
47      /** The login module. */
48      WindowsLoginModule loginModule;
49  
50      /** The provider. */
51      MockWindowsAuthProvider provider;
52  
53      /**
54       * Sets the up.
55       */
56      @BeforeEach
57      void setUp() {
58          this.provider = new MockWindowsAuthProvider();
59          this.loginModule = new WindowsLoginModule();
60          this.loginModule.setAuth(this.provider);
61      }
62  
63      /**
64       * Test initialize.
65       */
66      @Test
67      void testInitialize() {
68          final Subject subject = new Subject();
69          final UsernamePasswordCallbackHandler callbackHandler = new UsernamePasswordCallbackHandler("", "");
70          final Map<String, String> options = new HashMap<>();
71          options.put("debug", "true");
72          this.loginModule.initialize(subject, callbackHandler, null, options);
73          Assertions.assertTrue(this.loginModule.isDebug());
74      }
75  
76      /**
77       * Test get set auth.
78       */
79      @Test
80      void testGetSetAuth() {
81          Assertions.assertNotNull(this.loginModule.getAuth());
82          this.loginModule.setAuth(null);
83          Assertions.assertNull(this.loginModule.getAuth());
84      }
85  
86      /**
87       * Test login.
88       *
89       * @throws LoginException
90       *             the login exception
91       */
92      @Test
93      void testLogin() throws LoginException {
94          final Subject subject = new Subject();
95          final UsernamePasswordCallbackHandler callbackHandler = new UsernamePasswordCallbackHandler(
96                  WindowsAccountImpl.getCurrentUsername(), "password");
97          final Map<String, String> options = new HashMap<>();
98          options.put("debug", "true");
99          this.loginModule.initialize(subject, callbackHandler, null, options);
100         Assertions.assertTrue(this.loginModule.login());
101         Assertions.assertEquals(0, subject.getPrincipals().size());
102         Assertions.assertTrue(this.loginModule.commit());
103         Assertions.assertTrue(subject.getPrincipals().size() >= 3);
104         Assertions.assertTrue(subject.getPrincipals().contains(new RolePrincipal("Everyone")));
105         Assertions.assertTrue(subject.getPrincipals().contains(new RolePrincipal("Users")));
106         Assertions.assertTrue(
107                 subject.getPrincipals().contains(new UserPrincipal(WindowsAccountImpl.getCurrentUsername())));
108         Assertions.assertTrue(this.loginModule.logout());
109         Assertions.assertSame(Integer.valueOf(subject.getPrincipals().size()), Integer.valueOf(0));
110     }
111 
112     /**
113      * Test no callback handler.
114      *
115      * @throws LoginException
116      *             the login exception
117      */
118     @Test
119     void testNoCallbackHandler() throws LoginException {
120         final Subject subject = new Subject();
121         final Map<String, String> options = new HashMap<>();
122         this.loginModule.initialize(subject, null, null, options);
123         Assertions.assertThrows(LoginException.class, () -> {
124             this.loginModule.login();
125         });
126     }
127 
128     /**
129      * Test login no username.
130      *
131      * @throws LoginException
132      *             the login exception
133      */
134     @Test
135     void testLoginNoUsername() throws LoginException {
136         final Subject subject = new Subject();
137         final UsernamePasswordCallbackHandler callbackHandler = new UsernamePasswordCallbackHandler("", "");
138         final Map<String, String> options = new HashMap<>();
139         options.put("debug", "true");
140         this.loginModule.initialize(subject, callbackHandler, null, options);
141         final Throwable exception = Assertions.assertThrows(LoginException.class, () -> {
142             Assertions.assertFalse(this.loginModule.login());
143         });
144         Assertions.assertEquals("Mock error: ", exception.getMessage());
145     }
146 
147     /**
148      * Test role format none.
149      *
150      * @throws LoginException
151      *             the login exception
152      */
153     @Test
154     void testRoleFormatNone() throws LoginException {
155         final Subject subject = new Subject();
156         final UsernamePasswordCallbackHandler callbackHandler = new UsernamePasswordCallbackHandler(
157                 WindowsAccountImpl.getCurrentUsername(), "password");
158         final Map<String, String> options = new HashMap<>();
159         options.put("debug", "true");
160         options.put("roleFormat", "none");
161         this.loginModule.initialize(subject, callbackHandler, null, options);
162         Assertions.assertTrue(this.loginModule.login());
163         Assertions.assertTrue(this.loginModule.commit());
164         Assertions.assertEquals(1, subject.getPrincipals().size());
165     }
166 
167     /**
168      * Test role format both.
169      *
170      * @throws LoginException
171      *             the login exception
172      */
173     @Test
174     void testRoleFormatBoth() throws LoginException {
175         final Subject subject = new Subject();
176         final UsernamePasswordCallbackHandler callbackHandler = new UsernamePasswordCallbackHandler(
177                 WindowsAccountImpl.getCurrentUsername(), "password");
178         final Map<String, String> options = new HashMap<>();
179         options.put("debug", "true");
180         options.put("roleFormat", "both");
181         this.loginModule.initialize(subject, callbackHandler, null, options);
182         Assertions.assertTrue(this.loginModule.login());
183         Assertions.assertTrue(this.loginModule.commit());
184 
185         Assertions.assertTrue(subject.getPrincipals().size() >= 5);
186         Assertions.assertTrue(subject.getPrincipals().contains(new RolePrincipal("Everyone")));
187         Assertions.assertTrue(subject.getPrincipals().contains(new RolePrincipal("Users")));
188         int roleSize = 0;
189         int roleSidSize = 0;
190         for (final Principal principal : subject.getPrincipals()) {
191             if (principal instanceof RolePrincipal) {
192                 if (principal.getName().startsWith("S-")) {
193                     roleSidSize++;
194                 }
195                 roleSize++;
196             }
197         }
198         Assertions.assertEquals(4, roleSize);
199         Assertions.assertEquals(2, roleSidSize);
200     }
201 
202     /**
203      * Test principal format both.
204      *
205      * @throws LoginException
206      *             the login exception
207      */
208     @Test
209     void testPrincipalFormatBoth() throws LoginException {
210         final Subject subject = new Subject();
211         final UsernamePasswordCallbackHandler callbackHandler = new UsernamePasswordCallbackHandler(
212                 WindowsAccountImpl.getCurrentUsername(), "password");
213         final Map<String, String> options = new HashMap<>();
214         options.put("debug", "true");
215         options.put("principalFormat", "both");
216         options.put("roleFormat", "none");
217         this.loginModule.initialize(subject, callbackHandler, null, options);
218         Assertions.assertTrue(this.loginModule.login());
219         Assertions.assertTrue(this.loginModule.commit());
220         Assertions.assertEquals(2, subject.getPrincipals().size());
221     }
222 
223     /**
224      * Test role format sid.
225      *
226      * @throws LoginException
227      *             the login exception
228      */
229     @Test
230     void testRoleFormatSid() throws LoginException {
231         final Subject subject = new Subject();
232         final UsernamePasswordCallbackHandler callbackHandler = new UsernamePasswordCallbackHandler(
233                 WindowsAccountImpl.getCurrentUsername(), "password");
234         final Map<String, String> options = new HashMap<>();
235         options.put("debug", "true");
236         options.put("roleFormat", "sid");
237         this.loginModule.initialize(subject, callbackHandler, null, options);
238         Assertions.assertTrue(this.loginModule.login());
239         Assertions.assertTrue(this.loginModule.commit());
240 
241         Assertions.assertTrue(subject.getPrincipals().size() >= 3);
242         Assertions.assertTrue(
243                 subject.getPrincipals().contains(new UserPrincipal(WindowsAccountImpl.getCurrentUsername())));
244         int size = 0;
245         for (final Principal principal : subject.getPrincipals()) {
246             if (principal instanceof RolePrincipal) {
247                 if (principal.getName().startsWith("S-")) {
248                     size++;
249                 }
250             }
251         }
252         Assertions.assertEquals(2, size);
253     }
254 
255     /**
256      * Test role unique.
257      *
258      * @throws LoginException
259      *             the login exception
260      */
261     @Test
262     void testRoleUnique() throws LoginException {
263         final Subject subject = new Subject();
264         // the mock has an "Everyone" group
265         final UsernamePasswordCallbackHandler callbackHandler = new UsernamePasswordCallbackHandler(
266                 WindowsAccountImpl.getCurrentUsername(), "password");
267         this.provider.addGroup("Group 1");
268         this.provider.addGroup("Group 1");
269         final Map<String, String> options = new HashMap<>();
270         options.put("debug", "true");
271         this.loginModule.initialize(subject, callbackHandler, null, options);
272         Assertions.assertTrue(this.loginModule.login());
273         Assertions.assertTrue(this.loginModule.commit());
274 
275         Assertions.assertTrue(subject.getPrincipals().size() >= 4);
276         Assertions.assertTrue(subject.getPrincipals().contains(new RolePrincipal("Everyone")));
277         Assertions.assertTrue(subject.getPrincipals().contains(new RolePrincipal("Users")));
278         Assertions.assertTrue(subject.getPrincipals().contains(new RolePrincipal("Group 1")));
279     }
280 
281     /**
282      * Test guest login.
283      *
284      * @throws LoginException
285      *             the login exception
286      */
287     @Test
288     void testGuestLogin() throws LoginException {
289         final Subject subject = new Subject();
290         final UsernamePasswordCallbackHandler callbackHandler = new UsernamePasswordCallbackHandler("Guest",
291                 "password");
292         final Map<String, String> options = new HashMap<>();
293         options.put("debug", "true");
294         this.loginModule.initialize(subject, callbackHandler, null, options);
295         Assertions.assertTrue(this.loginModule.isAllowGuestLogin());
296         Assertions.assertTrue(this.loginModule.login());
297         Assertions.assertEquals(0, subject.getPrincipals().size());
298         Assertions.assertTrue(this.loginModule.commit());
299         Assertions.assertTrue(subject.getPrincipals().size() >= 3);
300         Assertions.assertTrue(subject.getPrincipals().contains(new RolePrincipal("Everyone")));
301         Assertions.assertTrue(subject.getPrincipals().contains(new RolePrincipal("Users")));
302         this.loginModule.setAllowGuestLogin(false);
303         final Throwable exception = Assertions.assertThrows(LoginException.class, () -> {
304             Assertions.assertTrue(this.loginModule.login());
305         });
306         Assertions.assertEquals("Guest login disabled", exception.getMessage());
307     }
308 
309     /**
310      * Test abort.
311      *
312      * @throws LoginException
313      *             the login exception
314      */
315     @Test
316     void testAbort() throws LoginException {
317         final Subject subject = new Subject();
318         final UsernamePasswordCallbackHandler callbackHandler = new UsernamePasswordCallbackHandler("Guest",
319                 "password");
320         final Map<String, String> options = new HashMap<>();
321         options.put("debug", "true");
322         this.loginModule.initialize(subject, callbackHandler, null, options);
323         Assertions.assertTrue(this.loginModule.login());
324         this.loginModule.abort();
325         assertThat(subject.getPrincipals().size()).isEqualTo(0);
326     }
327 
328 }