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