1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package waffle.apache;
25
26 import static org.assertj.core.api.Assertions.assertThat;
27
28 import com.sun.jna.platform.win32.Sspi;
29 import com.sun.jna.platform.win32.SspiUtil.ManagedSecBufferDesc;
30
31 import java.util.Base64;
32 import java.util.Collections;
33
34 import javax.servlet.ServletException;
35
36 import mockit.Expectations;
37 import mockit.Mocked;
38
39 import org.apache.catalina.Context;
40 import org.apache.catalina.Engine;
41 import org.apache.catalina.LifecycleException;
42 import org.apache.catalina.realm.GenericPrincipal;
43 import org.junit.jupiter.api.AfterEach;
44 import org.junit.jupiter.api.Assertions;
45 import org.junit.jupiter.api.BeforeEach;
46 import org.junit.jupiter.api.Test;
47
48 import waffle.apache.catalina.SimpleHttpRequest;
49 import waffle.apache.catalina.SimpleHttpResponse;
50 import waffle.mock.MockWindowsAuthProvider;
51 import waffle.windows.auth.IWindowsCredentialsHandle;
52 import waffle.windows.auth.IWindowsIdentity;
53 import waffle.windows.auth.PrincipalFormat;
54 import waffle.windows.auth.impl.WindowsAccountImpl;
55 import waffle.windows.auth.impl.WindowsCredentialsHandleImpl;
56 import waffle.windows.auth.impl.WindowsSecurityContextImpl;
57
58
59
60
61 class MixedAuthenticatorTest {
62
63
64 MixedAuthenticator authenticator;
65
66
67 @Mocked
68 Context context;
69
70
71 @Mocked
72 Engine engine;
73
74
75
76
77
78
79
80 @BeforeEach
81 void setUp() throws LifecycleException {
82 this.authenticator = new MixedAuthenticator();
83 this.authenticator.setContainer(this.context);
84 Assertions.assertNotNull(new Expectations() {
85 {
86 MixedAuthenticatorTest.this.context.getParent();
87 this.result = MixedAuthenticatorTest.this.engine;
88 MixedAuthenticatorTest.this.context.getParent();
89 this.result = null;
90 }
91 });
92 this.authenticator.start();
93 }
94
95
96
97
98
99
100
101 @AfterEach
102 void tearDown() throws LifecycleException {
103 this.authenticator.stop();
104 }
105
106
107
108
109 @Test
110 void testChallengeGET() {
111 final SimpleHttpRequest request = new SimpleHttpRequest();
112 request.setMethod("GET");
113 request.setQueryString("j_negotiate_check");
114 final SimpleHttpResponse response = new SimpleHttpResponse();
115 this.authenticator.authenticate(request, response);
116 final String[] wwwAuthenticates = response.getHeaderValues("WWW-Authenticate");
117 Assertions.assertNotNull(wwwAuthenticates);
118 Assertions.assertEquals(2, wwwAuthenticates.length);
119 Assertions.assertEquals("Negotiate", wwwAuthenticates[0]);
120 Assertions.assertEquals("NTLM", wwwAuthenticates[1]);
121 Assertions.assertEquals("close", response.getHeader("Connection"));
122 Assertions.assertEquals(2, response.getHeaderNames().size());
123 Assertions.assertEquals(401, response.getStatus());
124 }
125
126
127
128
129 @Test
130 void testChallengePOST() {
131 final String securityPackage = "Negotiate";
132 IWindowsCredentialsHandle clientCredentials = null;
133 WindowsSecurityContextImpl clientContext = null;
134 try {
135
136 clientCredentials = WindowsCredentialsHandleImpl.getCurrent(securityPackage);
137 clientCredentials.initialize();
138
139 clientContext = new WindowsSecurityContextImpl();
140 clientContext.setPrincipalName(WindowsAccountImpl.getCurrentUsername());
141 clientContext.setCredentialsHandle(clientCredentials);
142 clientContext.setSecurityPackage(securityPackage);
143 clientContext.initialize(null, null, WindowsAccountImpl.getCurrentUsername());
144 final SimpleHttpRequest request = new SimpleHttpRequest();
145 request.setQueryString("j_negotiate_check");
146 request.setMethod("POST");
147 request.setContentLength(0);
148 final String clientToken = Base64.getEncoder().encodeToString(clientContext.getToken());
149 request.addHeader("Authorization", securityPackage + " " + clientToken);
150 final SimpleHttpResponse response = new SimpleHttpResponse();
151 this.authenticator.authenticate(request, response);
152 Assertions.assertTrue(response.getHeader("WWW-Authenticate").startsWith(securityPackage + " "));
153 Assertions.assertEquals("keep-alive", response.getHeader("Connection"));
154 Assertions.assertEquals(2, response.getHeaderNames().size());
155 Assertions.assertEquals(401, response.getStatus());
156 } finally {
157 if (clientContext != null) {
158 clientContext.dispose();
159 }
160 if (clientCredentials != null) {
161 clientCredentials.dispose();
162 }
163 }
164 }
165
166
167
168
169 @Test
170 void testGet() {
171 final SimpleHttpRequest request = new SimpleHttpRequest();
172 final SimpleHttpResponse response = new SimpleHttpResponse();
173 Assertions.assertFalse(this.authenticator.authenticate(request, response));
174 }
175
176
177
178
179 @Test
180 void testGetInfo() {
181 assertThat(this.authenticator.getInfo()).isNotEmpty();
182 }
183
184
185
186
187 @Test
188 void testNegotiate() {
189 final String securityPackage = "Negotiate";
190 IWindowsCredentialsHandle clientCredentials = null;
191 WindowsSecurityContextImpl clientContext = null;
192 try {
193
194 clientCredentials = WindowsCredentialsHandleImpl.getCurrent(securityPackage);
195 clientCredentials.initialize();
196
197 clientContext = new WindowsSecurityContextImpl();
198 clientContext.setPrincipalName(WindowsAccountImpl.getCurrentUsername());
199 clientContext.setCredentialsHandle(clientCredentials);
200 clientContext.setSecurityPackage(securityPackage);
201 clientContext.initialize(null, null, WindowsAccountImpl.getCurrentUsername());
202
203 boolean authenticated = false;
204 final SimpleHttpRequest request = new SimpleHttpRequest();
205 request.setQueryString("j_negotiate_check");
206 String clientToken;
207 while (true) {
208 clientToken = Base64.getEncoder().encodeToString(clientContext.getToken());
209 request.addHeader("Authorization", securityPackage + " " + clientToken);
210
211 final SimpleHttpResponse response = new SimpleHttpResponse();
212 authenticated = this.authenticator.authenticate(request, response);
213
214 if (authenticated) {
215 assertThat(response.getHeaderNames().size()).isNotNegative();
216 break;
217 }
218
219 Assertions.assertTrue(response.getHeader("WWW-Authenticate").startsWith(securityPackage + " "));
220 Assertions.assertEquals("keep-alive", response.getHeader("Connection"));
221 Assertions.assertEquals(2, response.getHeaderNames().size());
222 Assertions.assertEquals(401, response.getStatus());
223 final String continueToken = response.getHeader("WWW-Authenticate")
224 .substring(securityPackage.length() + 1);
225 final byte[] continueTokenBytes = Base64.getDecoder().decode(continueToken);
226 assertThat(continueTokenBytes).isNotEmpty();
227 final ManagedSecBufferDesc continueTokenBuffer = new ManagedSecBufferDesc(Sspi.SECBUFFER_TOKEN,
228 continueTokenBytes);
229 clientContext.initialize(clientContext.getHandle(), continueTokenBuffer,
230 WindowsAccountImpl.getCurrentUsername());
231 }
232 Assertions.assertTrue(authenticated);
233 } finally {
234 if (clientContext != null) {
235 clientContext.dispose();
236 }
237 if (clientCredentials != null) {
238 clientCredentials.dispose();
239 }
240 }
241 }
242
243
244
245
246 @Test
247 void testPostSecurityCheck() {
248 final SimpleHttpRequest request = new SimpleHttpRequest();
249 request.setQueryString("j_security_check");
250 request.addParameter("j_username", "username");
251 request.addParameter("j_password", "password");
252 final SimpleHttpResponse response = new SimpleHttpResponse();
253 Assertions.assertFalse(this.authenticator.authenticate(request, response));
254 }
255
256
257
258
259
260
261
262
263
264
265 @Test
266 void testProgrammaticSecurityBoth(@Mocked final IWindowsIdentity identity) throws ServletException {
267 this.authenticator.setAuth(new MockWindowsAuthProvider());
268 final SimpleHttpRequest request = new SimpleHttpRequest();
269 request.getMappingData().context = (Context) this.authenticator.getContainer();
270
271 request.login(WindowsAccountImpl.getCurrentUsername(), "");
272
273 Assertions.assertNotNull(new Expectations() {
274 {
275 identity.getFqn();
276 this.result = "fqn";
277 identity.getSidString();
278 this.result = "S-1234";
279 }
280 });
281 request.setUserPrincipal(new GenericWindowsPrincipal(identity, PrincipalFormat.BOTH, PrincipalFormat.BOTH));
282
283 Assertions.assertTrue(request.getUserPrincipal() instanceof GenericWindowsPrincipal);
284 final GenericWindowsPrincipal windowsPrincipal = (GenericWindowsPrincipal) request.getUserPrincipal();
285 Assertions.assertTrue(windowsPrincipal.getSidString().startsWith("S-"));
286 }
287
288
289
290
291
292
293
294
295
296
297 @Test
298 void testProgrammaticSecuritySID(@Mocked final IWindowsIdentity identity) throws ServletException {
299 this.authenticator.setAuth(new MockWindowsAuthProvider());
300 final SimpleHttpRequest request = new SimpleHttpRequest();
301 request.getMappingData().context = (Context) this.authenticator.getContainer();
302
303 request.login(WindowsAccountImpl.getCurrentUsername(), "");
304
305 Assertions.assertNotNull(new Expectations() {
306 {
307 identity.getSidString();
308 this.result = "S-1234";
309 }
310 });
311 request.setUserPrincipal(new GenericWindowsPrincipal(identity, PrincipalFormat.SID, PrincipalFormat.SID));
312
313 Assertions.assertTrue(request.getUserPrincipal() instanceof GenericWindowsPrincipal);
314 final GenericWindowsPrincipal windowsPrincipal = (GenericWindowsPrincipal) request.getUserPrincipal();
315 Assertions.assertTrue(windowsPrincipal.getSidString().startsWith("S-"));
316 }
317
318
319
320
321
322
323
324
325
326
327 @Test
328 void testProgrammaticSecurityNone(@Mocked final IWindowsIdentity identity) throws ServletException {
329 this.authenticator.setAuth(new MockWindowsAuthProvider());
330 final SimpleHttpRequest request = new SimpleHttpRequest();
331 request.getMappingData().context = (Context) this.authenticator.getContainer();
332
333 request.login(WindowsAccountImpl.getCurrentUsername(), "");
334
335 request.setUserPrincipal(new GenericWindowsPrincipal(identity, PrincipalFormat.NONE, PrincipalFormat.NONE));
336
337 Assertions.assertTrue(request.getUserPrincipal() instanceof GenericWindowsPrincipal);
338 final GenericWindowsPrincipal windowsPrincipal = (GenericWindowsPrincipal) request.getUserPrincipal();
339 Assertions.assertNull(windowsPrincipal.getSidString());
340 }
341
342
343
344
345 @Test
346 void testSecurityCheckParameters() {
347 this.authenticator.setAuth(new MockWindowsAuthProvider());
348 final SimpleHttpRequest request = new SimpleHttpRequest();
349 request.addParameter("j_security_check", "");
350 request.addParameter("j_username", WindowsAccountImpl.getCurrentUsername());
351 request.addParameter("j_password", "");
352 final SimpleHttpResponse response = new SimpleHttpResponse();
353 Assertions.assertTrue(this.authenticator.authenticate(request, response));
354 }
355
356
357
358
359 @Test
360 void testSecurityCheckQueryString() {
361 this.authenticator.setAuth(new MockWindowsAuthProvider());
362 final SimpleHttpRequest request = new SimpleHttpRequest();
363 request.setQueryString("j_security_check");
364 request.addParameter("j_username", WindowsAccountImpl.getCurrentUsername());
365 request.addParameter("j_password", "");
366 final SimpleHttpResponse response = new SimpleHttpResponse();
367 Assertions.assertTrue(this.authenticator.authenticate(request, response));
368 }
369
370 @Test
371 void testCustomPrincipal() throws LifecycleException {
372 final GenericPrincipal genericPrincipal = new GenericPrincipal("my-principal", "my-password",
373 Collections.emptyList());
374 final MixedAuthenticator customAuthenticator = new MixedAuthenticator() {
375 @Override
376 protected GenericPrincipal createPrincipal(final IWindowsIdentity windowsIdentity) {
377 return genericPrincipal;
378 }
379 };
380 try {
381 customAuthenticator.setContainer(this.context);
382 customAuthenticator.setAlwaysUseSession(true);
383 customAuthenticator.start();
384
385 customAuthenticator.setAuth(new MockWindowsAuthProvider());
386 final SimpleHttpRequest request = new SimpleHttpRequest();
387 request.addParameter("j_security_check", "");
388 request.addParameter("j_username", WindowsAccountImpl.getCurrentUsername());
389 request.addParameter("j_password", "");
390 final SimpleHttpResponse response = new SimpleHttpResponse();
391 Assertions.assertTrue(customAuthenticator.authenticate(request, response));
392
393 Assertions.assertEquals(genericPrincipal, request.getUserPrincipal());
394 } finally {
395 customAuthenticator.stop();
396 }
397
398 }
399
400 }