Paul Martin
2015-10-25 0d7c650b3b59d8a7bbc47135975f040c832e04c0
commit | author | age
04a985 1 /*
JM 2  * Copyright 2013 gitblit.com.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.gitblit.tests;
17
18 import java.io.File;
19 import java.io.FilenameFilter;
20 import java.io.IOException;
21 import java.util.HashMap;
22
23 import org.apache.commons.io.FileUtils;
24 import org.junit.After;
25 import org.junit.Before;
26 import org.junit.Test;
27
28 import com.gitblit.IStoredSettings;
29 import com.gitblit.auth.HtpasswdAuthProvider;
b4a63a 30 import com.gitblit.manager.AuthenticationManager;
04a985 31 import com.gitblit.manager.RuntimeManager;
JM 32 import com.gitblit.manager.UserManager;
33 import com.gitblit.models.UserModel;
34 import com.gitblit.tests.mock.MemorySettings;
fc3a39 35 import com.gitblit.utils.XssFilter;
JM 36 import com.gitblit.utils.XssFilter.AllowXssFilter;
04a985 37
JM 38 /**
39  * Test the Htpasswd user service.
40  *
41  */
42 public class HtpasswdAuthenticationTest extends GitblitUnitTest {
43
44     private static final String RESOURCE_DIR = "src/test/resources/htpasswd/";
45     private static final String KEY_SUPPORT_PLAINTEXT_PWD = "realm.htpasswd.supportPlaintextPasswords";
46
47     private static final int NUM_USERS_HTPASSWD = 10;
48
49     private static final MemorySettings MS = new MemorySettings(new HashMap<String, Object>());
50
51     private HtpasswdAuthProvider htpasswd;
52
b4a63a 53     private AuthenticationManager auth;
04a985 54
JM 55     private MemorySettings getSettings(String userfile, String groupfile, Boolean overrideLA)
56     {
57         MS.put("realm.userService", RESOURCE_DIR + "users.conf");
58         MS.put("realm.htpasswd.userfile", (userfile == null) ? (RESOURCE_DIR + "htpasswd") : userfile);
59         MS.put("realm.htpasswd.groupfile", (groupfile == null) ? (RESOURCE_DIR + "htgroup") : groupfile);
60         MS.put("realm.htpasswd.overrideLocalAuthentication", (overrideLA == null) ? "false" : overrideLA.toString());
61         // Default to keep test the same on all platforms.
62         MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "false");
63
64         return MS;
65     }
66
67     private MemorySettings getSettings()
68     {
69         return getSettings(null, null, null);
70     }
71
72     private void setupUS()
73     {
74         htpasswd = newHtpasswdAuthentication(getSettings());
b4a63a 75         auth = newAuthenticationManager(getSettings());
04a985 76     }
JM 77
78     private HtpasswdAuthProvider newHtpasswdAuthentication(IStoredSettings settings) {
fc3a39 79         XssFilter xssFilter = new AllowXssFilter();
JM 80         RuntimeManager runtime = new RuntimeManager(settings, xssFilter, GitBlitSuite.BASEFOLDER).start();
ca4d98 81         UserManager users = new UserManager(runtime, null).start();
04a985 82         HtpasswdAuthProvider htpasswd = new HtpasswdAuthProvider();
JM 83         htpasswd.setup(runtime, users);
84         return htpasswd;
b4a63a 85     }
ca4d98 86
b4a63a 87     private AuthenticationManager newAuthenticationManager(IStoredSettings settings) {
fc3a39 88         XssFilter xssFilter = new AllowXssFilter();
JM 89         RuntimeManager runtime = new RuntimeManager(settings, xssFilter, GitBlitSuite.BASEFOLDER).start();
ca4d98 90         UserManager users = new UserManager(runtime, null).start();
b4a63a 91         HtpasswdAuthProvider htpasswd = new HtpasswdAuthProvider();
JM 92         htpasswd.setup(runtime, users);
93         AuthenticationManager auth = new AuthenticationManager(runtime, users);
94         auth.addAuthenticationProvider(htpasswd);
95         return auth;
04a985 96     }
JM 97
98
99     private void copyInFiles() throws IOException
100     {
101         File dir = new File(RESOURCE_DIR);
102         FilenameFilter filter = new FilenameFilter() {
103             @Override
104             public boolean accept(File dir, String file) {
105                 return file.endsWith(".in");
106                 }
107             };
108         for (File inf : dir.listFiles(filter)) {
109             File dest = new File(inf.getParent(), inf.getName().substring(0, inf.getName().length() - 3));
110             FileUtils.copyFile(inf, dest);
111         }
112     }
113
114
115     private void deleteGeneratedFiles()
116     {
117         File dir = new File(RESOURCE_DIR);
118         FilenameFilter filter = new FilenameFilter() {
119             @Override
120             public boolean accept(File dir, String file) {
121                 return !(file.endsWith(".in"));
122                 }
123             };
124         for (File file : dir.listFiles(filter)) {
125             file.delete();
126         }
127     }
128
129
130     @Before
131     public void setup() throws IOException
132     {
133         copyInFiles();
134         setupUS();
135     }
136
137
138     @After
139     public void tearDown()
140     {
141         deleteGeneratedFiles();
142     }
143
144
145
146     @Test
147     public void testSetup() throws IOException
148     {
149         assertEquals(NUM_USERS_HTPASSWD, htpasswd.getNumberHtpasswdUsers());
150     }
151
152
153     @Test
154     public void testAuthenticate()
155     {
156         MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true");
157         UserModel user = htpasswd.authenticate("user1", "pass1".toCharArray());
158         assertNotNull(user);
159         assertEquals("user1", user.username);
160
161         user = htpasswd.authenticate("user2", "pass2".toCharArray());
162         assertNotNull(user);
163         assertEquals("user2", user.username);
164
165         // Test different encryptions
166         user = htpasswd.authenticate("plain", "passWord".toCharArray());
167         assertNotNull(user);
168         assertEquals("plain", user.username);
169
170         MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "false");
171         user = htpasswd.authenticate("crypt", "password".toCharArray());
172         assertNotNull(user);
173         assertEquals("crypt", user.username);
174
175         user = htpasswd.authenticate("md5", "password".toCharArray());
176         assertNotNull(user);
177         assertEquals("md5", user.username);
178
179         user = htpasswd.authenticate("sha", "password".toCharArray());
180         assertNotNull(user);
181         assertEquals("sha", user.username);
182
183
184         // Test leading and trailing whitespace
185         user = htpasswd.authenticate("trailing", "whitespace".toCharArray());
186         assertNotNull(user);
187         assertEquals("trailing", user.username);
188
189         user = htpasswd.authenticate("tabbed", "frontAndBack".toCharArray());
190         assertNotNull(user);
191         assertEquals("tabbed", user.username);
192
193         user = htpasswd.authenticate("leading", "whitespace".toCharArray());
194         assertNotNull(user);
195         assertEquals("leading", user.username);
196     }
197
ca4d98 198
b4a63a 199     @Test
JM 200     public void testAuthenticationManager()
201     {
202         MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true");
0d7c65 203         UserModel user = auth.authenticate("user1", "pass1".toCharArray(), null);
b4a63a 204         assertNotNull(user);
JM 205         assertEquals("user1", user.username);
206
0d7c65 207         user = auth.authenticate("user2", "pass2".toCharArray(), null);
b4a63a 208         assertNotNull(user);
JM 209         assertEquals("user2", user.username);
210
211         // Test different encryptions
0d7c65 212         user = auth.authenticate("plain", "passWord".toCharArray(), null);
b4a63a 213         assertNotNull(user);
JM 214         assertEquals("plain", user.username);
215
216         MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "false");
0d7c65 217         user = auth.authenticate("crypt", "password".toCharArray(), null);
b4a63a 218         assertNotNull(user);
JM 219         assertEquals("crypt", user.username);
220
0d7c65 221         user = auth.authenticate("md5", "password".toCharArray(), null);
b4a63a 222         assertNotNull(user);
JM 223         assertEquals("md5", user.username);
224
0d7c65 225         user = auth.authenticate("sha", "password".toCharArray(), null);
b4a63a 226         assertNotNull(user);
JM 227         assertEquals("sha", user.username);
228
229
230         // Test leading and trailing whitespace
0d7c65 231         user = auth.authenticate("trailing", "whitespace".toCharArray(), null);
b4a63a 232         assertNotNull(user);
JM 233         assertEquals("trailing", user.username);
234
0d7c65 235         user = auth.authenticate("tabbed", "frontAndBack".toCharArray(), null);
b4a63a 236         assertNotNull(user);
JM 237         assertEquals("tabbed", user.username);
238
0d7c65 239         user = auth.authenticate("leading", "whitespace".toCharArray(), null);
b4a63a 240         assertNotNull(user);
JM 241         assertEquals("leading", user.username);
242     }
243
04a985 244
JM 245     @Test
246     public void testAttributes()
247     {
248         MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true");
249         UserModel user = htpasswd.authenticate("user1", "pass1".toCharArray());
250         assertNotNull(user);
251         assertEquals("El Capitan", user.displayName);
252         assertEquals("cheffe@example.com", user.emailAddress);
253         assertTrue(user.canAdmin);
254
255         user = htpasswd.authenticate("user2", "pass2".toCharArray());
256         assertNotNull(user);
257         assertEquals("User Two", user.displayName);
258         assertTrue(user.canCreate);
259         assertTrue(user.canFork);
260     }
261
262
263     @Test
264     public void testAuthenticateDenied()
265     {
266         UserModel user = null;
267         MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true");
268         user = htpasswd.authenticate("user1", "".toCharArray());
269         assertNull("User 'user1' falsely authenticated.", user);
270
271         user = htpasswd.authenticate("user1", "pass2".toCharArray());
272         assertNull("User 'user1' falsely authenticated.", user);
273
274         user = htpasswd.authenticate("user2", "lalala".toCharArray());
275         assertNull("User 'user2' falsely authenticated.", user);
276
277
278         user = htpasswd.authenticate("user3", "disabled".toCharArray());
279         assertNull("User 'user3' falsely authenticated.", user);
280
281         user = htpasswd.authenticate("user4", "disabled".toCharArray());
282         assertNull("User 'user4' falsely authenticated.", user);
283
284
285         user = htpasswd.authenticate("plain", "text".toCharArray());
286         assertNull("User 'plain' falsely authenticated.", user);
287
288         user = htpasswd.authenticate("plain", "password".toCharArray());
289         assertNull("User 'plain' falsely authenticated.", user);
290
291
292         MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "false");
293
294         user = htpasswd.authenticate("crypt", "".toCharArray());
295         assertNull("User 'cyrpt' falsely authenticated.", user);
296
297         user = htpasswd.authenticate("crypt", "passwd".toCharArray());
298         assertNull("User 'crypt' falsely authenticated.", user);
299
300         user = htpasswd.authenticate("md5", "".toCharArray());
301         assertNull("User 'md5' falsely authenticated.", user);
302
303         user = htpasswd.authenticate("md5", "pwd".toCharArray());
304         assertNull("User 'md5' falsely authenticated.", user);
305
306         user = htpasswd.authenticate("sha", "".toCharArray());
307         assertNull("User 'sha' falsely authenticated.", user);
308
309         user = htpasswd.authenticate("sha", "letmein".toCharArray());
310         assertNull("User 'sha' falsely authenticated.", user);
311
312
313         user = htpasswd.authenticate("  tabbed", "frontAndBack".toCharArray());
314         assertNull("User 'tabbed' falsely authenticated.", user);
315
316         user = htpasswd.authenticate("    leading", "whitespace".toCharArray());
317         assertNull("User 'leading' falsely authenticated.", user);
318     }
319
320
321     @Test
b4a63a 322     public void testAuthenticationMangerDenied()
JM 323     {
324         UserModel user = null;
325         MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true");
0d7c65 326         user = auth.authenticate("user1", "".toCharArray(), null);
b4a63a 327         assertNull("User 'user1' falsely authenticated.", user);
JM 328
0d7c65 329         user = auth.authenticate("user1", "pass2".toCharArray(), null);
b4a63a 330         assertNull("User 'user1' falsely authenticated.", user);
JM 331
0d7c65 332         user = auth.authenticate("user2", "lalala".toCharArray(), null);
b4a63a 333         assertNull("User 'user2' falsely authenticated.", user);
JM 334
335
0d7c65 336         user = auth.authenticate("user3", "disabled".toCharArray(), null);
b4a63a 337         assertNull("User 'user3' falsely authenticated.", user);
JM 338
0d7c65 339         user = auth.authenticate("user4", "disabled".toCharArray(), null);
b4a63a 340         assertNull("User 'user4' falsely authenticated.", user);
JM 341
342
0d7c65 343         user = auth.authenticate("plain", "text".toCharArray(), null);
b4a63a 344         assertNull("User 'plain' falsely authenticated.", user);
JM 345
0d7c65 346         user = auth.authenticate("plain", "password".toCharArray(), null);
b4a63a 347         assertNull("User 'plain' falsely authenticated.", user);
JM 348
349
350         MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "false");
351
0d7c65 352         user = auth.authenticate("crypt", "".toCharArray(), null);
b4a63a 353         assertNull("User 'cyrpt' falsely authenticated.", user);
JM 354
0d7c65 355         user = auth.authenticate("crypt", "passwd".toCharArray(), null);
b4a63a 356         assertNull("User 'crypt' falsely authenticated.", user);
JM 357
0d7c65 358         user = auth.authenticate("md5", "".toCharArray(), null);
b4a63a 359         assertNull("User 'md5' falsely authenticated.", user);
JM 360
0d7c65 361         user = auth.authenticate("md5", "pwd".toCharArray(), null);
b4a63a 362         assertNull("User 'md5' falsely authenticated.", user);
JM 363
0d7c65 364         user = auth.authenticate("sha", "".toCharArray(), null);
b4a63a 365         assertNull("User 'sha' falsely authenticated.", user);
JM 366
0d7c65 367         user = auth.authenticate("sha", "letmein".toCharArray(), null);
b4a63a 368         assertNull("User 'sha' falsely authenticated.", user);
JM 369
370
0d7c65 371         user = auth.authenticate("  tabbed", "frontAndBack".toCharArray(), null);
b4a63a 372         assertNull("User 'tabbed' falsely authenticated.", user);
JM 373
0d7c65 374         user = auth.authenticate("    leading", "whitespace".toCharArray(), null);
b4a63a 375         assertNull("User 'leading' falsely authenticated.", user);
JM 376     }
377
378     @Test
04a985 379     public void testCleartextIntrusion()
JM 380     {
381         MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true");
382         assertNull(htpasswd.authenticate("md5", "$apr1$qAGGNfli$sAn14mn.WKId/3EQS7KSX0".toCharArray()));
383         assertNull(htpasswd.authenticate("sha", "{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=".toCharArray()));
384
385         assertNull(htpasswd.authenticate("user1", "#externalAccount".toCharArray()));
386
387         MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "false");
388         assertNull(htpasswd.authenticate("md5", "$apr1$qAGGNfli$sAn14mn.WKId/3EQS7KSX0".toCharArray()));
389         assertNull(htpasswd.authenticate("sha", "{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=".toCharArray()));
390
391         assertNull(htpasswd.authenticate("user1", "#externalAccount".toCharArray()));
392     }
393
394
395     @Test
396     public void testCryptVsPlaintext()
397     {
398         MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "false");
399         assertNull(htpasswd.authenticate("crypt", "6TmlbxqZ2kBIA".toCharArray()));
400         assertNotNull(htpasswd.authenticate("crypt", "password".toCharArray()));
401
402         MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true");
403         assertNotNull(htpasswd.authenticate("crypt", "6TmlbxqZ2kBIA".toCharArray()));
404         assertNull(htpasswd.authenticate("crypt", "password".toCharArray()));
405     }
406
407     @Test
408     public void testChangeHtpasswdFile()
409     {
410         UserModel user;
411
412         // User default set up.
413         user = htpasswd.authenticate("md5", "password".toCharArray());
414         assertNotNull(user);
415         assertEquals("md5", user.username);
416
417         user = htpasswd.authenticate("sha", "password".toCharArray());
418         assertNotNull(user);
419         assertEquals("sha", user.username);
420
421         user = htpasswd.authenticate("blueone", "GoBlue!".toCharArray());
422         assertNull(user);
423
424         user = htpasswd.authenticate("bluetwo", "YayBlue!".toCharArray());
425         assertNull(user);
426
427
428         // Switch to different htpasswd file.
429         getSettings(RESOURCE_DIR + "htpasswd-user", null, null);
430
431         user = htpasswd.authenticate("md5", "password".toCharArray());
432         assertNull(user);
433
434         user = htpasswd.authenticate("sha", "password".toCharArray());
435         assertNull(user);
436
437         user = htpasswd.authenticate("blueone", "GoBlue!".toCharArray());
438         assertNotNull(user);
439         assertEquals("blueone", user.username);
440
441         user = htpasswd.authenticate("bluetwo", "YayBlue!".toCharArray());
442         assertNotNull(user);
443         assertEquals("bluetwo", user.username);
444     }
445
446
447     @Test
448     public void testChangeHtpasswdFileNotExisting()
449     {
450         UserModel user;
451
452         // User default set up.
453         user = htpasswd.authenticate("md5", "password".toCharArray());
454         assertNotNull(user);
455         assertEquals("md5", user.username);
456
457         user = htpasswd.authenticate("sha", "password".toCharArray());
458         assertNotNull(user);
459         assertEquals("sha", user.username);
460
461         user = htpasswd.authenticate("blueone", "GoBlue!".toCharArray());
462         assertNull(user);
463
464         user = htpasswd.authenticate("bluetwo", "YayBlue!".toCharArray());
465         assertNull(user);
466
467
468         // Switch to different htpasswd file that doesn't exist.
469         // Currently we stop working with old users upon this change.
470         getSettings(RESOURCE_DIR + "no-such-file", null, null);
471
472         user = htpasswd.authenticate("md5", "password".toCharArray());
473         assertNull(user);
474
475         user = htpasswd.authenticate("sha", "password".toCharArray());
476         assertNull(user);
477
478         user = htpasswd.authenticate("blueone", "GoBlue!".toCharArray());
479         assertNull(user);
480
481         user = htpasswd.authenticate("bluetwo", "YayBlue!".toCharArray());
482         assertNull(user);
483     }
484
485 }