1
2
3
4
5
6
7
8
9
10
11
12
13
14 package waffle.apache;
15
16 import javax.servlet.ServletException;
17
18 import org.apache.catalina.Context;
19 import org.apache.catalina.LifecycleException;
20 import org.apache.catalina.Valve;
21 import org.apache.catalina.deploy.LoginConfig;
22 import org.assertj.core.api.Assertions;
23 import org.junit.After;
24 import org.junit.Assert;
25 import org.junit.Before;
26 import org.junit.Test;
27 import org.mockito.Mockito;
28
29 import waffle.apache.catalina.SimpleContext;
30 import waffle.apache.catalina.SimpleEngine;
31 import waffle.apache.catalina.SimpleHttpRequest;
32 import waffle.apache.catalina.SimpleHttpResponse;
33 import waffle.apache.catalina.SimplePipeline;
34 import waffle.apache.catalina.SimpleRealm;
35 import waffle.apache.catalina.SimpleServletContext;
36 import waffle.mock.MockWindowsAuthProvider;
37 import waffle.windows.auth.IWindowsCredentialsHandle;
38 import waffle.windows.auth.impl.WindowsAccountImpl;
39 import waffle.windows.auth.impl.WindowsCredentialsHandleImpl;
40 import waffle.windows.auth.impl.WindowsSecurityContextImpl;
41
42 import com.google.common.io.BaseEncoding;
43 import com.sun.jna.platform.win32.Sspi;
44 import com.sun.jna.platform.win32.Sspi.SecBufferDesc;
45
46
47
48
49
50
51 public class MixedAuthenticatorTests {
52
53 private MixedAuthenticator authenticator;
54
55 @Before
56 public void setUp() throws LifecycleException {
57 this.authenticator = new MixedAuthenticator();
58 final SimpleContext ctx = Mockito.mock(SimpleContext.class, Mockito.CALLS_REAL_METHODS);
59 ctx.setServletContext(Mockito.mock(SimpleServletContext.class, Mockito.CALLS_REAL_METHODS));
60 ctx.setPath("/");
61 ctx.setName("SimpleContext");
62 ctx.setRealm(Mockito.mock(SimpleRealm.class, Mockito.CALLS_REAL_METHODS));
63 final SimpleEngine engine = Mockito.mock(SimpleEngine.class, Mockito.CALLS_REAL_METHODS);
64 ctx.setParent(engine);
65 final SimplePipeline pipeline = Mockito.mock(SimplePipeline.class, Mockito.CALLS_REAL_METHODS);
66 pipeline.setValves(new Valve[0]);
67 engine.setPipeline(pipeline);
68 ctx.setPipeline(pipeline);
69 ctx.setAuthenticator(this.authenticator);
70 this.authenticator.setContainer(ctx);
71 this.authenticator.start();
72 }
73
74 @After
75 public void tearDown() throws LifecycleException {
76 this.authenticator.stop();
77 }
78
79 @Test
80 public void testChallengeGET() {
81 final SimpleHttpRequest request = new SimpleHttpRequest();
82 request.setMethod("GET");
83 request.setQueryString("j_negotiate_check");
84 final SimpleHttpResponse response = new SimpleHttpResponse();
85 this.authenticator.authenticate(request, response, null);
86 final String[] wwwAuthenticates = response.getHeaderValues("WWW-Authenticate");
87 Assert.assertNotNull(wwwAuthenticates);
88 Assert.assertEquals(2, wwwAuthenticates.length);
89 Assert.assertEquals("Negotiate", wwwAuthenticates[0]);
90 Assert.assertEquals("NTLM", wwwAuthenticates[1]);
91 Assert.assertEquals("close", response.getHeader("Connection"));
92 Assert.assertEquals(2, response.getHeaderNames().size());
93 Assert.assertEquals(401, response.getStatus());
94 }
95
96 @Test
97 public void testChallengePOST() {
98 final String securityPackage = "Negotiate";
99 IWindowsCredentialsHandle clientCredentials = null;
100 WindowsSecurityContextImpl clientContext = null;
101 try {
102
103 clientCredentials = WindowsCredentialsHandleImpl.getCurrent(securityPackage);
104 clientCredentials.initialize();
105
106 clientContext = new WindowsSecurityContextImpl();
107 clientContext.setPrincipalName(WindowsAccountImpl.getCurrentUsername());
108 clientContext.setCredentialsHandle(clientCredentials.getHandle());
109 clientContext.setSecurityPackage(securityPackage);
110 clientContext.initialize(null, null, WindowsAccountImpl.getCurrentUsername());
111 final SimpleHttpRequest request = new SimpleHttpRequest();
112 request.setQueryString("j_negotiate_check");
113 request.setMethod("POST");
114 request.setContentLength(0);
115 final String clientToken = BaseEncoding.base64().encode(clientContext.getToken());
116 request.addHeader("Authorization", securityPackage + " " + clientToken);
117 final SimpleHttpResponse response = new SimpleHttpResponse();
118 this.authenticator.authenticate(request, response, null);
119 Assert.assertTrue(response.getHeader("WWW-Authenticate").startsWith(securityPackage + " "));
120 Assert.assertEquals("keep-alive", response.getHeader("Connection"));
121 Assert.assertEquals(2, response.getHeaderNames().size());
122 Assert.assertEquals(401, response.getStatus());
123 } finally {
124 if (clientContext != null) {
125 clientContext.dispose();
126 }
127 if (clientCredentials != null) {
128 clientCredentials.dispose();
129 }
130 }
131 }
132
133 @Test
134 public void testGet() {
135 final LoginConfig loginConfig = new LoginConfig();
136 loginConfig.setErrorPage("error.html");
137 loginConfig.setLoginPage("login.html");
138 final SimpleHttpRequest request = new SimpleHttpRequest();
139 final SimpleHttpResponse response = new SimpleHttpResponse();
140 Assert.assertFalse(this.authenticator.authenticate(request, response, loginConfig));
141 Assert.assertEquals(304, response.getStatus());
142 Assert.assertEquals("login.html", response.getHeader("Location"));
143 Assert.assertEquals(1, response.getHeaderNames().size());
144 }
145
146 @Test
147 public void testGetInfo() {
148 Assertions.assertThat(this.authenticator.getInfo().length()).isGreaterThan(0);
149 }
150
151 @Test
152 public void testNegotiate() {
153 final String securityPackage = "Negotiate";
154 IWindowsCredentialsHandle clientCredentials = null;
155 WindowsSecurityContextImpl clientContext = null;
156 try {
157
158 clientCredentials = WindowsCredentialsHandleImpl.getCurrent(securityPackage);
159 clientCredentials.initialize();
160
161 clientContext = new WindowsSecurityContextImpl();
162 clientContext.setPrincipalName(WindowsAccountImpl.getCurrentUsername());
163 clientContext.setCredentialsHandle(clientCredentials.getHandle());
164 clientContext.setSecurityPackage(securityPackage);
165 clientContext.initialize(null, null, WindowsAccountImpl.getCurrentUsername());
166
167 boolean authenticated = false;
168 final SimpleHttpRequest request = new SimpleHttpRequest();
169 request.setQueryString("j_negotiate_check");
170 String clientToken;
171 while (true) {
172 clientToken = BaseEncoding.base64().encode(clientContext.getToken());
173 request.addHeader("Authorization", securityPackage + " " + clientToken);
174
175 final SimpleHttpResponse response = new SimpleHttpResponse();
176 authenticated = this.authenticator.authenticate(request, response, null);
177
178 if (authenticated) {
179 Assertions.assertThat(response.getHeaderNames().size()).isGreaterThanOrEqualTo(0);
180 break;
181 }
182
183 Assert.assertTrue(response.getHeader("WWW-Authenticate").startsWith(securityPackage + " "));
184 Assert.assertEquals("keep-alive", response.getHeader("Connection"));
185 Assert.assertEquals(2, response.getHeaderNames().size());
186 Assert.assertEquals(401, response.getStatus());
187 final String continueToken = response.getHeader("WWW-Authenticate").substring(
188 securityPackage.length() + 1);
189 final byte[] continueTokenBytes = BaseEncoding.base64().decode(continueToken);
190 Assertions.assertThat(continueTokenBytes.length).isGreaterThan(0);
191 final SecBufferDesc continueTokenBuffer = new SecBufferDesc(Sspi.SECBUFFER_TOKEN, continueTokenBytes);
192 clientContext.initialize(clientContext.getHandle(), continueTokenBuffer,
193 WindowsAccountImpl.getCurrentUsername());
194 }
195 Assert.assertTrue(authenticated);
196 } finally {
197 if (clientContext != null) {
198 clientContext.dispose();
199 }
200 if (clientCredentials != null) {
201 clientCredentials.dispose();
202 }
203 }
204 }
205
206 @Test
207 public void testPostSecurityCheck() {
208 final LoginConfig loginConfig = new LoginConfig();
209 loginConfig.setErrorPage("error.html");
210 loginConfig.setLoginPage("login.html");
211 final SimpleHttpRequest request = new SimpleHttpRequest();
212 request.setQueryString("j_security_check");
213 request.addParameter("j_username", "username");
214 request.addParameter("j_password", "password");
215 final SimpleHttpResponse response = new SimpleHttpResponse();
216 Assert.assertFalse(this.authenticator.authenticate(request, response, loginConfig));
217 Assert.assertEquals(304, response.getStatus());
218 Assert.assertEquals("error.html", response.getHeader("Location"));
219 Assert.assertEquals(1, response.getHeaderNames().size());
220 }
221
222 @Test
223 public void testProgrammaticSecurity() throws ServletException {
224 this.authenticator.setAuth(new MockWindowsAuthProvider());
225 final SimpleHttpRequest request = new SimpleHttpRequest();
226 request.setContext((Context) this.authenticator.getContainer());
227
228 request.login(WindowsAccountImpl.getCurrentUsername(), "");
229
230
231
232 Assert.assertTrue(request.getUserPrincipal() instanceof GenericWindowsPrincipal);
233 final GenericWindowsPrincipal windowsPrincipal = (GenericWindowsPrincipal) request.getUserPrincipal();
234 Assert.assertTrue(windowsPrincipal.getSidString().startsWith("S-"));
235 }
236
237 @Test
238 public void testSecurityCheckParameters() {
239 this.authenticator.setAuth(new MockWindowsAuthProvider());
240 final LoginConfig loginConfig = new LoginConfig();
241 loginConfig.setErrorPage("error.html");
242 loginConfig.setLoginPage("login.html");
243 final SimpleHttpRequest request = new SimpleHttpRequest();
244 request.addParameter("j_security_check", "");
245 request.addParameter("j_username", WindowsAccountImpl.getCurrentUsername());
246 request.addParameter("j_password", "");
247 final SimpleHttpResponse response = new SimpleHttpResponse();
248 Assert.assertTrue(this.authenticator.authenticate(request, response, loginConfig));
249 }
250
251 @Test
252 public void testSecurityCheckQueryString() {
253 this.authenticator.setAuth(new MockWindowsAuthProvider());
254 final LoginConfig loginConfig = new LoginConfig();
255 loginConfig.setErrorPage("error.html");
256 loginConfig.setLoginPage("login.html");
257 final SimpleHttpRequest request = new SimpleHttpRequest();
258 request.setQueryString("j_security_check");
259 request.addParameter("j_username", WindowsAccountImpl.getCurrentUsername());
260 request.addParameter("j_password", "");
261 final SimpleHttpResponse response = new SimpleHttpResponse();
262 Assert.assertTrue(this.authenticator.authenticate(request, response, loginConfig));
263 }
264 }