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.tomcat.util.descriptor.web.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 LoginConfig loginConfig = new LoginConfig();
59 loginConfig.setErrorPage("error.html");
60 loginConfig.setLoginPage("login.html");
61 final SimpleContext ctx = Mockito.mock(SimpleContext.class, Mockito.CALLS_REAL_METHODS);
62 Mockito.when(ctx.getLoginConfig()).thenReturn(loginConfig);
63 ctx.setServletContext(Mockito.mock(SimpleServletContext.class, Mockito.CALLS_REAL_METHODS));
64 ctx.setPath("/");
65 ctx.setName("SimpleContext");
66 ctx.setRealm(Mockito.mock(SimpleRealm.class, Mockito.CALLS_REAL_METHODS));
67 final SimpleEngine engine = Mockito.mock(SimpleEngine.class, Mockito.CALLS_REAL_METHODS);
68 ctx.setParent(engine);
69 final SimplePipeline pipeline = Mockito.mock(SimplePipeline.class, Mockito.CALLS_REAL_METHODS);
70 pipeline.setValves(new Valve[0]);
71 engine.setPipeline(pipeline);
72 ctx.setPipeline(pipeline);
73 ctx.setAuthenticator(this.authenticator);
74 this.authenticator.setContainer(ctx);
75 this.authenticator.start();
76 }
77
78 @After
79 public void tearDown() throws LifecycleException {
80 this.authenticator.stop();
81 }
82
83 @Test
84 public void testChallengeGET() {
85 final SimpleHttpRequest request = new SimpleHttpRequest();
86 request.setMethod("GET");
87 request.setQueryString("j_negotiate_check");
88 final SimpleHttpResponse response = new SimpleHttpResponse();
89 this.authenticator.authenticate(request, response);
90 final String[] wwwAuthenticates = response.getHeaderValues("WWW-Authenticate");
91 Assert.assertNotNull(wwwAuthenticates);
92 Assert.assertEquals(2, wwwAuthenticates.length);
93 Assert.assertEquals("Negotiate", wwwAuthenticates[0]);
94 Assert.assertEquals("NTLM", wwwAuthenticates[1]);
95 Assert.assertEquals("close", response.getHeader("Connection"));
96 Assert.assertEquals(2, response.getHeaderNames().size());
97 Assert.assertEquals(401, response.getStatus());
98 }
99
100 @Test
101 public void testChallengePOST() {
102 final String securityPackage = "Negotiate";
103 IWindowsCredentialsHandle clientCredentials = null;
104 WindowsSecurityContextImpl clientContext = null;
105 try {
106
107 clientCredentials = WindowsCredentialsHandleImpl.getCurrent(securityPackage);
108 clientCredentials.initialize();
109
110 clientContext = new WindowsSecurityContextImpl();
111 clientContext.setPrincipalName(WindowsAccountImpl.getCurrentUsername());
112 clientContext.setCredentialsHandle(clientCredentials.getHandle());
113 clientContext.setSecurityPackage(securityPackage);
114 clientContext.initialize(null, null, WindowsAccountImpl.getCurrentUsername());
115 final SimpleHttpRequest request = new SimpleHttpRequest();
116 request.setQueryString("j_negotiate_check");
117 request.setMethod("POST");
118 request.setContentLength(0);
119 final String clientToken = BaseEncoding.base64().encode(clientContext.getToken());
120 request.addHeader("Authorization", securityPackage + " " + clientToken);
121 final SimpleHttpResponse response = new SimpleHttpResponse();
122 this.authenticator.authenticate(request, response);
123 Assert.assertTrue(response.getHeader("WWW-Authenticate").startsWith(securityPackage + " "));
124 Assert.assertEquals("keep-alive", response.getHeader("Connection"));
125 Assert.assertEquals(2, response.getHeaderNames().size());
126 Assert.assertEquals(401, response.getStatus());
127 } finally {
128 if (clientContext != null) {
129 clientContext.dispose();
130 }
131 if (clientCredentials != null) {
132 clientCredentials.dispose();
133 }
134 }
135 }
136
137 @Test
138 public void testGet() {
139
140 final SimpleHttpRequest request = new SimpleHttpRequest();
141 final SimpleHttpResponse response = new SimpleHttpResponse();
142 Assert.assertFalse(this.authenticator.authenticate(request, response));
143 Assert.assertEquals(304, response.getStatus());
144 Assert.assertEquals("login.html", response.getHeader("Location"));
145 Assert.assertEquals(1, response.getHeaderNames().size());
146 }
147
148 @Test
149 public void testGetInfo() {
150 Assertions.assertThat(this.authenticator.getInfo().length()).isGreaterThan(0);
151 }
152
153 @Test
154 public void testNegotiate() {
155 final String securityPackage = "Negotiate";
156 IWindowsCredentialsHandle clientCredentials = null;
157 WindowsSecurityContextImpl clientContext = null;
158 try {
159
160 clientCredentials = WindowsCredentialsHandleImpl.getCurrent(securityPackage);
161 clientCredentials.initialize();
162
163 clientContext = new WindowsSecurityContextImpl();
164 clientContext.setPrincipalName(WindowsAccountImpl.getCurrentUsername());
165 clientContext.setCredentialsHandle(clientCredentials.getHandle());
166 clientContext.setSecurityPackage(securityPackage);
167 clientContext.initialize(null, null, WindowsAccountImpl.getCurrentUsername());
168
169 boolean authenticated = false;
170 final SimpleHttpRequest request = new SimpleHttpRequest();
171 request.setQueryString("j_negotiate_check");
172 String clientToken;
173 while (true) {
174 clientToken = BaseEncoding.base64().encode(clientContext.getToken());
175 request.addHeader("Authorization", securityPackage + " " + clientToken);
176
177 final SimpleHttpResponse response = new SimpleHttpResponse();
178 authenticated = this.authenticator.authenticate(request, response);
179
180 if (authenticated) {
181 Assertions.assertThat(response.getHeaderNames().size()).isGreaterThanOrEqualTo(0);
182 break;
183 }
184
185 Assert.assertTrue(response.getHeader("WWW-Authenticate").startsWith(securityPackage + " "));
186 Assert.assertEquals("keep-alive", response.getHeader("Connection"));
187 Assert.assertEquals(2, response.getHeaderNames().size());
188 Assert.assertEquals(401, response.getStatus());
189 final String continueToken = response.getHeader("WWW-Authenticate").substring(
190 securityPackage.length() + 1);
191 final byte[] continueTokenBytes = BaseEncoding.base64().decode(continueToken);
192 Assertions.assertThat(continueTokenBytes.length).isGreaterThan(0);
193 final SecBufferDesc continueTokenBuffer = new SecBufferDesc(Sspi.SECBUFFER_TOKEN, continueTokenBytes);
194 clientContext.initialize(clientContext.getHandle(), continueTokenBuffer,
195 WindowsAccountImpl.getCurrentUsername());
196 }
197 Assert.assertTrue(authenticated);
198 } finally {
199 if (clientContext != null) {
200 clientContext.dispose();
201 }
202 if (clientCredentials != null) {
203 clientCredentials.dispose();
204 }
205 }
206 }
207
208 @Test
209 public void testPostSecurityCheck() {
210 final SimpleHttpRequest request = new SimpleHttpRequest();
211 request.setQueryString("j_security_check");
212 request.addParameter("j_username", "username");
213 request.addParameter("j_password", "password");
214 final SimpleHttpResponse response = new SimpleHttpResponse();
215 Assert.assertFalse(this.authenticator.authenticate(request, response));
216 Assert.assertEquals(304, response.getStatus());
217 Assert.assertEquals("error.html", response.getHeader("Location"));
218 Assert.assertEquals(1, response.getHeaderNames().size());
219 }
220
221 @Test
222 public void testProgrammaticSecurity() throws ServletException {
223 this.authenticator.setAuth(new MockWindowsAuthProvider());
224 final SimpleHttpRequest request = new SimpleHttpRequest();
225 request.getMappingData().context = (Context) this.authenticator.getContainer();
226
227 request.login(WindowsAccountImpl.getCurrentUsername(), "");
228
229
230
231 Assert.assertTrue(request.getUserPrincipal() instanceof GenericWindowsPrincipal);
232 final GenericWindowsPrincipal windowsPrincipal = (GenericWindowsPrincipal) request.getUserPrincipal();
233 Assert.assertTrue(windowsPrincipal.getSidString().startsWith("S-"));
234 }
235
236 @Test
237 public void testSecurityCheckParameters() {
238 this.authenticator.setAuth(new MockWindowsAuthProvider());
239 final SimpleHttpRequest request = new SimpleHttpRequest();
240 request.addParameter("j_security_check", "");
241 request.addParameter("j_username", WindowsAccountImpl.getCurrentUsername());
242 request.addParameter("j_password", "");
243 final SimpleHttpResponse response = new SimpleHttpResponse();
244 Assert.assertTrue(this.authenticator.authenticate(request, response));
245 }
246
247 @Test
248 public void testSecurityCheckQueryString() {
249 this.authenticator.setAuth(new MockWindowsAuthProvider());
250 final SimpleHttpRequest request = new SimpleHttpRequest();
251 request.setQueryString("j_security_check");
252 request.addParameter("j_username", WindowsAccountImpl.getCurrentUsername());
253 request.addParameter("j_password", "");
254 final SimpleHttpResponse response = new SimpleHttpResponse();
255 Assert.assertTrue(this.authenticator.authenticate(request, response));
256 }
257 }