View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
5    */
6   package mockit;
7   
8   import static org.junit.jupiter.api.Assertions.assertEquals;
9   import static org.junit.jupiter.api.Assertions.assertFalse;
10  import static org.junit.jupiter.api.Assertions.assertNotNull;
11  import static org.junit.jupiter.api.Assertions.assertNull;
12  import static org.junit.jupiter.api.Assertions.assertThrows;
13  import static org.junit.jupiter.api.Assertions.assertTrue;
14  
15  import java.util.Collections;
16  import java.util.Map;
17  
18  import javax.security.auth.Subject;
19  import javax.security.auth.callback.CallbackHandler;
20  import javax.security.auth.login.AppConfigurationEntry;
21  import javax.security.auth.login.Configuration;
22  import javax.security.auth.login.LoginContext;
23  import javax.security.auth.login.LoginException;
24  import javax.security.auth.spi.LoginModule;
25  
26  import org.junit.jupiter.api.Test;
27  
28  /**
29   * The Class FakeLoginContextTest.
30   */
31  final class FakeLoginContextTest {
32  
33      /**
34       * Fake JRE method and constructor using fake class.
35       *
36       * @throws Exception
37       *             the exception
38       */
39      @Test
40      void fakeJREMethodAndConstructorUsingFakeClass() throws Exception {
41          new FakeLoginContext();
42  
43          new LoginContext("test", (CallbackHandler) null).login();
44      }
45  
46      /**
47       * The Class FakeLoginContext.
48       */
49      public static class FakeLoginContext extends MockUp<LoginContext> {
50  
51          /**
52           * $init.
53           *
54           * @param name
55           *            the name
56           * @param callbackHandler
57           *            the callback handler
58           */
59          @Mock
60          public void $init(String name, CallbackHandler callbackHandler) {
61              assertEquals("test", name);
62              assertNull(callbackHandler);
63          }
64  
65          /**
66           * Login.
67           */
68          @Mock
69          public void login() {
70          }
71  
72          /**
73           * Gets the subject.
74           *
75           * @return the subject
76           */
77          @Mock
78          public Subject getSubject() {
79              return null;
80          }
81      }
82  
83      /**
84       * Fake JRE method and constructor with fake class.
85       *
86       * @throws Exception
87       *             the exception
88       */
89      @Test
90      void fakeJREMethodAndConstructorWithFakeClass() throws Exception {
91          new MockUp<LoginContext>() {
92              @Mock
93              void $init(String name) {
94                  assertEquals("test", name);
95              }
96  
97              @Mock
98              void login() throws LoginException {
99                  throw new LoginException();
100             }
101         };
102 
103         assertThrows(LoginException.class, () -> {
104             new LoginContext("test").login();
105         });
106     }
107 
108     /**
109      * Fake JRE class with stubs.
110      *
111      * @throws Exception
112      *             the exception
113      */
114     @Test
115     void fakeJREClassWithStubs() throws Exception {
116         new FakeLoginContextWithStubs();
117 
118         LoginContext context = new LoginContext("");
119         context.login();
120         context.logout();
121     }
122 
123     /**
124      * The Class FakeLoginContextWithStubs.
125      */
126     static final class FakeLoginContextWithStubs extends MockUp<LoginContext> {
127 
128         /**
129          * $init.
130          *
131          * @param s
132          *            the s
133          */
134         @Mock
135         void $init(String s) {
136         }
137 
138         /**
139          * Logout.
140          */
141         @Mock
142         void logout() {
143         }
144 
145         /**
146          * Login.
147          */
148         @Mock
149         void login() {
150         }
151     }
152 
153     /**
154      * Access faked instance.
155      *
156      * @throws Exception
157      *             the exception
158      */
159     @Test
160     void accessFakedInstance() throws Exception {
161         new MockUp<LoginContext>() {
162             Subject testSubject;
163 
164             @Mock
165             void $init(Invocation inv, String name, Subject subject) {
166                 assertNotNull(name);
167                 assertNotNull(subject);
168                 LoginContext it = inv.getInvokedInstance();
169                 assertNotNull(it);
170                 assertEquals(1, inv.getInvocationCount());
171             }
172 
173             @Mock
174             void login(Invocation inv) {
175                 LoginContext it = inv.getInvokedInstance();
176                 assertNull(it.getSubject()); // returns null until the subject is authenticated
177                 testSubject = new Subject();
178             }
179 
180             @Mock
181             void logout() {
182                 testSubject = null;
183             }
184 
185             @Mock
186             Subject getSubject() {
187                 return testSubject;
188             }
189         };
190 
191         LoginContext fakedInstance = new LoginContext("test", new Subject());
192         assertNull(fakedInstance.getSubject());
193         fakedInstance.login();
194         assertNotNull(fakedInstance.getSubject());
195         fakedInstance.logout();
196         assertNull(fakedInstance.getSubject());
197     }
198 
199     /**
200      * Proceed into real implementations of faked methods.
201      *
202      * @throws Exception
203      *             the exception
204      */
205     @Test
206     void proceedIntoRealImplementationsOfFakedMethods() throws Exception {
207         // Create objects to be exercised by the code under test:
208         Configuration configuration = new Configuration() {
209             @Override
210             public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
211                 Map<String, ?> options = Collections.emptyMap();
212 
213                 return new AppConfigurationEntry[] { new AppConfigurationEntry(TestLoginModule.class.getName(),
214                         AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT, options) };
215             }
216         };
217 
218         LoginContext loginContext = new LoginContext("test", null, null, configuration);
219 
220         // Apply fakes:
221         ProceedingFakeLoginContext fakeInstance = new ProceedingFakeLoginContext();
222 
223         // Exercise the code under test:
224         assertNull(loginContext.getSubject());
225         loginContext.login();
226         assertNotNull(loginContext.getSubject());
227         assertTrue(fakeInstance.loggedIn);
228 
229         fakeInstance.ignoreLogout = true;
230         loginContext.logout();
231         assertTrue(fakeInstance.loggedIn);
232 
233         fakeInstance.ignoreLogout = false;
234         loginContext.logout();
235         assertFalse(fakeInstance.loggedIn);
236     }
237 
238     /**
239      * The Class ProceedingFakeLoginContext.
240      */
241     static final class ProceedingFakeLoginContext extends MockUp<LoginContext> {
242 
243         /** The ignore logout. */
244         boolean ignoreLogout;
245 
246         /** The logged in. */
247         boolean loggedIn;
248 
249         /**
250          * Login.
251          *
252          * @param inv
253          *            the inv
254          */
255         @Mock
256         void login(Invocation inv) {
257             LoginContext it = inv.getInvokedInstance();
258 
259             try {
260                 inv.proceed();
261                 loggedIn = true;
262             } finally {
263                 it.getSubject();
264             }
265         }
266 
267         /**
268          * Logout.
269          *
270          * @param inv
271          *            the inv
272          */
273         @Mock
274         void logout(Invocation inv) {
275             if (!ignoreLogout) {
276                 inv.proceed();
277                 loggedIn = false;
278             }
279         }
280     }
281 
282     /**
283      * The Class TestLoginModule.
284      */
285     public static class TestLoginModule implements LoginModule {
286         @Override
287         public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
288                 Map<String, ?> options) {
289         }
290 
291         @Override
292         public boolean login() {
293             return true;
294         }
295 
296         @Override
297         public boolean commit() {
298             return true;
299         }
300 
301         @Override
302         public boolean abort() {
303             return false;
304         }
305 
306         @Override
307         public boolean logout() {
308             return true;
309         }
310     }
311 }