Source code: com/xpn/xwiki/test/LDAPTest.java
1 /**
2 * ===================================================================
3 *
4 * Copyright (c) 2005 Ludovic Dubost, All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details, published at
15 * http://www.gnu.org/copyleft/lesser.html or in lesser.txt in the
16 * root folder of this distribution.
17 */
18 package com.xpn.xwiki.test;
19
20 import com.xpn.xwiki.XWikiException;
21 import com.xpn.xwiki.web.XWikiServletURLFactory;
22 import com.xpn.xwiki.objects.classes.BaseClass;
23 import com.xpn.xwiki.objects.BaseObject;
24 import com.xpn.xwiki.doc.XWikiDocument;
25 import com.xpn.xwiki.user.api.XWikiAuthService;
26 import com.novell.ldap.*;
27
28 import java.security.Principal;
29 import java.io.UnsupportedEncodingException;
30 import java.util.ArrayList;
31 import java.net.URL;
32
33 /**
34 * Test for LDAP authentication
35 * ***********************************************************************
36 * This test need a TEST local LDAP server
37 * ***********************************************************************
38 * BEWARE : THIS TEST DELETE ALL LDAP SERVER CONTENTS !
39 * NEVER USE IT WITH PRODUCTION SERVER !
40 * ***********************************************************************
41 * If you use OpenLDAP server, the sldap.conf must containts the statements :
42 *
43 * include /etc/schema/cosine.schema
44 * include /etc/schema/inetorgperson.schema
45 * access to *
46 * by self read
47 * by anonymous auth
48 * by * none
49 * suffix "dc=xwiki,dc=com"
50 * rootdn "cn=Manager,dc=xwiki,dc=com"
51 * rootpw secret
52 * Other default values should work
53 *
54 * Test works with out of the box ldap database.
55 */
56 public class LDAPTest extends HibernateTestCase {
57
58 public static boolean inTest = false;
59
60 public void setUp() throws Exception {
61 super.setUp();
62 getXWikiContext().setURLFactory(new XWikiServletURLFactory(new URL("http://www.xwiki.org/"), "xwiki/" , "bin/"));
63
64 Utils.setStringValue("XWiki.XWikiPreferences", "XWiki.XWikiPreferences", "ldap_server", "127.0.0.1", getXWikiContext());
65 Utils.setStringValue("XWiki.XWikiPreferences", "XWiki.XWikiPreferences", "ldap_port", "389", getXWikiContext());
66 Utils.setStringValue("XWiki.XWikiPreferences", "XWiki.XWikiPreferences", "ldap_base_DN", "dc=xwiki,dc=com", getXWikiContext());
67 Utils.setStringValue("XWiki.XWikiPreferences", "XWiki.XWikiPreferences", "ldap_bind_DN", "cn=Manager,dc=xwiki,dc=com", getXWikiContext());
68 Utils.setStringValue("XWiki.XWikiPreferences", "XWiki.XWikiPreferences", "ldap_bind_pass", "secret", getXWikiContext());
69 Utils.setStringValue("XWiki.XWikiPreferences", "XWiki.XWikiPreferences", "ldap_UID_attr", "uid", getXWikiContext());
70
71 }
72
73 public void prepareLDAP(boolean addUser, String userPassword)
74 {
75 int ldapPort = getXWikiContext().getWiki().getXWikiPreferenceAsInt("ldap_port", LDAPConnection.DEFAULT_PORT, getXWikiContext());
76 int ldapVersion = LDAPConnection.LDAP_V3;
77 String ldapHost = getXWikiContext().getWiki().getXWikiPreference("ldap_server", getXWikiContext());
78 String loginDN = getXWikiContext().getWiki().getXWikiPreference("ldap_bind_DN", getXWikiContext());
79 String password = getXWikiContext().getWiki().getXWikiPreference("ldap_bind_pass",getXWikiContext());
80
81 String containerName = getXWikiContext().getWiki().getXWikiPreference("ldap_base_DN", getXWikiContext());
82
83 try
84 {
85 LDAPConnection lc = new LDAPConnection();
86
87 lc.connect( ldapHost, ldapPort );
88 lc.bind( ldapVersion, loginDN, password.getBytes("UTF8") );
89
90 boolean hasRoot = false;
91 boolean attributeOnly = true;
92 String attrs[] = {LDAPConnection.NO_ATTRS};
93 LDAPSearchResults searchResults =
94 lc.search( containerName,
95 LDAPConnection.SCOPE_SUB,
96 "(objectclass=*)",
97 attrs,
98 attributeOnly);
99 if (searchResults.hasMore())
100 {
101 ArrayList l = new ArrayList();
102 // print out all the objects
103 while ( searchResults.hasMore()) {
104 LDAPEntry nextEntry = null;
105 try {
106 nextEntry = searchResults.next();
107 }
108 catch(LDAPException e) {
109 System.out.println("Error: " + e.toString());
110 continue;
111 }
112 hasRoot = true;
113 l.add(nextEntry.getDN());
114 }
115
116 // Don't delete root
117 for(int i=l.size(); --i>0;)
118 {
119 String dn = (String)l.get(i);
120 lc.delete(dn);
121 }
122 }
123
124 LDAPAttribute attribute = null;
125 LDAPEntry newEntry = null;
126 LDAPAttributeSet attributeSet = new LDAPAttributeSet();
127 String dn;
128 if (!hasRoot)
129 {
130 // Root creation
131 attributeSet.add( new LDAPAttribute(
132 "dc", new String("xwiki")));
133 attributeSet.add( new LDAPAttribute(
134 "o", new String("XWiki")));
135 attributeSet.add( new LDAPAttribute("objectClass",
136 new String[]{"dcObject", "organization", "top"}));
137 dn = containerName;
138 newEntry = new LDAPEntry( dn, attributeSet );
139
140 lc.add( newEntry );
141 }
142
143 // Add manager branch
144 attributeSet = new LDAPAttributeSet();
145 attributeSet.add( new LDAPAttribute(
146 "cn", new String("Manager")));
147 attributeSet.add( new LDAPAttribute("objectClass",
148 new String[]{"organizationalRole", "top"}));
149 dn = "cn=Manager," + containerName;
150 newEntry = new LDAPEntry( dn, attributeSet );
151 lc.add( newEntry );
152
153 if (addUser)
154 {
155 attributeSet = new LDAPAttributeSet();
156 attributeSet.add( new LDAPAttribute(
157 "cn", new String("akartmann")));
158 attributeSet.add( new LDAPAttribute(
159 "uid", new String("akartmann")));
160 attributeSet.add( new LDAPAttribute(
161 "sn", new String("KARTMANN")));
162 attributeSet.add( new LDAPAttribute(
163 "givenName", new String("Alexis")));
164 attributeSet.add( new LDAPAttribute(
165 "displayName", new String("Alexis KARTMANN")));
166 attributeSet.add( new LDAPAttribute(
167 "mail", new String("alexis@xwiki.com")));
168 attributeSet.add( new LDAPAttribute(
169 "userPassword", userPassword));
170 attributeSet.add( new LDAPAttribute("objectClass",
171 new String[]{"inetOrgPerson", "top", "uidObject"}));
172 dn = "cn=akartmann,cn=Manager," + containerName;
173 newEntry = new LDAPEntry( dn, attributeSet );
174 lc.add( newEntry );
175 }
176
177
178 lc.disconnect();
179 }
180 catch( LDAPException e ) {
181 System.out.println( "Error: " + e.toString());
182 }
183 catch( UnsupportedEncodingException e ) {
184 System.out.println( "Error: " + e.toString() );
185 }
186 }
187
188 public void prepareData(boolean withLDAPDN, boolean withpassword) throws XWikiException {
189 XWikiDocument doc = new XWikiDocument("XWiki","akartmann");
190 try {
191 getXWiki().getDocument(doc, null, getXWikiContext());
192 getXWiki().deleteDocument(doc, getXWikiContext());
193 } catch (XWikiException e) {
194 }
195
196 BaseClass bclass = getXWiki().getUserClass(getXWikiContext());
197 BaseObject bobj = new BaseObject();
198 bobj.setName("XWiki.akartmann");
199 bobj.setClassName(bclass.getName());
200 bobj.setStringValue("fullname", "Alexis KARTMANN");
201 bobj.setStringValue("email", "alexis@xwiki.com");
202 if (withLDAPDN)
203 bobj.setStringValue("ldap_dn", "cn=akartmann,cn=Manager,dc=xwiki,dc=com");
204 if (withpassword)
205 bobj.setStringValue("password", "toto");
206 doc.setObject(bclass.getName(), 0, bobj);
207 doc.setContent("---+ Alexis KARTMANN HomePage");
208 getXWiki().saveDocument(doc, getXWikiContext());
209
210 doc = new XWikiDocument("XWiki","AdminGroup");
211 bclass = getXWiki().getGroupClass(getXWikiContext());
212 bobj = new BaseObject();
213 bobj.setName("XWiki.AdminGroup");
214 bobj.setClassName(bclass.getName());
215 bobj.setStringValue("member", "XWiki.akartmann");
216 doc.setObject(bclass.getName(), 0, bobj);
217 doc.setContent("---+ AdminGroup");
218 getXWiki().saveDocument(doc, getXWikiContext());
219
220 doc = new XWikiDocument("Test","TestDoc");
221 doc.setContent("---+ TestDoc");
222 getXWiki().saveDocument(doc, getXWikiContext());
223
224 }
225
226 public void testCheckLogonWithBind() throws ClassNotFoundException, IllegalAccessException, InstantiationException, XWikiException {
227
228 prepareLDAP(true, "alexis");
229 prepareData(false, false);
230
231 XWikiAuthService service = (XWikiAuthService) Class.forName("com.xpn.xwiki.user.impl.LDAP.LDAPAuthServiceImpl").newInstance();
232 Principal principal = service.authenticate("akartmann", "alexis", getXWikiContext());
233 assertNotNull("Authenticate failed", principal);
234 assertEquals("Name is not equal", "XWiki.akartmann", principal.getName());
235 }
236
237 public void testCheckLogonWithoutBind() throws ClassNotFoundException, IllegalAccessException, InstantiationException, XWikiException {
238
239 prepareLDAP(true, "alexis");
240 prepareData(true, false);
241
242 Utils.setStringValue("XWiki.XWikiPreferences", "XWiki.XWikiPreferences", "ldap_bind_DN", "", getXWikiContext());
243 Utils.setStringValue("XWiki.XWikiPreferences", "XWiki.XWikiPreferences", "ldap_bind_pass", "", getXWikiContext());
244
245 XWikiAuthService service = (XWikiAuthService) Class.forName("com.xpn.xwiki.user.impl.LDAP.LDAPAuthServiceImpl").newInstance();
246 Principal principal = service.authenticate("akartmann", "alexis", getXWikiContext());
247 assertNotNull("Authenticate failed", principal);
248 assertEquals("Name is not equal", "XWiki.akartmann", principal.getName());
249 }
250
251 public void testCheckLogonWithUserBind() throws ClassNotFoundException, IllegalAccessException, InstantiationException, XWikiException {
252
253 prepareLDAP(true, "alexis");
254 prepareData(false, false);
255
256 Utils.setStringValue("XWiki.XWikiPreferences", "XWiki.XWikiPreferences", "ldap_bind_DN", "cn={0},cn=Manager,dc=xwiki,dc=com", getXWikiContext());
257 Utils.setStringValue("XWiki.XWikiPreferences", "XWiki.XWikiPreferences", "ldap_bind_pass", "{1}", getXWikiContext());
258
259 XWikiAuthService service = (XWikiAuthService) Class.forName("com.xpn.xwiki.user.impl.LDAP.LDAPAuthServiceImpl").newInstance();
260 Principal principal = service.authenticate("akartmann", "alexis", getXWikiContext());
261 assertNotNull("Authenticate failed", principal);
262 assertEquals("Name is not equal", "XWiki.akartmann", principal.getName());
263 }
264
265 public void testCheckLogonWithBadBind() throws ClassNotFoundException, IllegalAccessException, InstantiationException, XWikiException {
266
267 prepareLDAP(true, "alexis");
268 prepareData(true, false);
269
270 Utils.setStringValue("XWiki.XWikiPreferences", "XWiki.XWikiPreferences", "ldap_bind_DN", "cn=nothere", getXWikiContext());
271 Utils.setStringValue("XWiki.XWikiPreferences", "XWiki.XWikiPreferences", "ldap_bind_pass", "bad", getXWikiContext());
272
273 XWikiAuthService service = (XWikiAuthService) Class.forName("com.xpn.xwiki.user.impl.LDAP.LDAPAuthServiceImpl").newInstance();
274 Principal principal = service.authenticate("akartmann", "alexis", getXWikiContext());
275 assertNotNull("Authenticate failed", principal);
276 assertEquals("Name is not equal", "XWiki.akartmann", principal.getName());
277 }
278
279 public void testCheckLogonFromWiki() throws ClassNotFoundException, IllegalAccessException, InstantiationException, XWikiException {
280
281 prepareLDAP(false, null);
282 prepareData(false, true);
283
284 XWikiAuthService service = (XWikiAuthService) Class.forName("com.xpn.xwiki.user.impl.LDAP.LDAPAuthServiceImpl").newInstance();
285 Principal principal = service.authenticate("akartmann", "toto", getXWikiContext());
286 assertNotNull("Authenticate failed", principal);
287 assertEquals("Name is not equal", "XWiki.akartmann", principal.getName());
288 }
289
290 public void testCheckLogonFromWikiBadLDAP() throws ClassNotFoundException, IllegalAccessException, InstantiationException, XWikiException {
291
292 prepareLDAP(false, null);
293 prepareData(true, true);
294
295 XWikiAuthService service = (XWikiAuthService) Class.forName("com.xpn.xwiki.user.impl.LDAP.LDAPAuthServiceImpl").newInstance();
296 Principal principal = service.authenticate("akartmann", "toto", getXWikiContext());
297 assertNull("Authenticate failed", principal);
298 }
299
300 public void testCheckLogonKOFromWikiPassword() throws ClassNotFoundException, IllegalAccessException, InstantiationException, XWikiException {
301
302 prepareLDAP(true, "alexis");
303 prepareData(true, true);
304
305 XWikiAuthService service = (XWikiAuthService) Class.forName("com.xpn.xwiki.user.impl.LDAP.LDAPAuthServiceImpl").newInstance();
306 Principal principal = service.authenticate("akartmann", "toto", getXWikiContext());
307 assertNull("Authenticate failed", principal);
308 }
309
310 public void testCheckLogonLevel() throws ClassNotFoundException, IllegalAccessException, InstantiationException, XWikiException {
311
312 prepareLDAP(true, "alexis");
313 prepareData(false, false);
314
315 // Full check : bind, search, password
316 Utils.setStringValue("XWiki.XWikiPreferences", "XWiki.XWikiPreferences", "ldap_check_level", "2", getXWikiContext());
317
318 XWikiAuthService service = (XWikiAuthService) Class.forName("com.xpn.xwiki.user.impl.LDAP.LDAPAuthServiceImpl").newInstance();
319 Principal principal = service.authenticate("akartmann", "alexis", getXWikiContext());
320 assertNotNull("Authenticate failed", principal);
321 assertEquals("Name is not equal", "XWiki.akartmann", principal.getName());
322
323 // Integrated check : bind, search
324 Utils.setStringValue("XWiki.XWikiPreferences", "XWiki.XWikiPreferences", "ldap_check_level", "1", getXWikiContext());
325 prepareLDAP(true, "notme");
326
327 service = (XWikiAuthService) Class.forName("com.xpn.xwiki.user.impl.LDAP.LDAPAuthServiceImpl").newInstance();
328 principal = service.authenticate("akartmann", "alexis", getXWikiContext());
329 assertNotNull("Authenticate failed", principal);
330 assertEquals("Name is not equal", "XWiki.akartmann", principal.getName());
331
332 // Trivial check : bind
333 Utils.setStringValue("XWiki.XWikiPreferences", "XWiki.XWikiPreferences", "ldap_check_level", "0", getXWikiContext());
334 prepareLDAP(false, null);
335
336 service = (XWikiAuthService) Class.forName("com.xpn.xwiki.user.impl.LDAP.LDAPAuthServiceImpl").newInstance();
337 principal = service.authenticate("akartmann", "alexis", getXWikiContext());
338 assertNotNull("Authenticate failed", principal);
339 assertEquals("Name is not equal", "XWiki.akartmann", principal.getName());
340
341 }
342
343 public void testTransfertUserFromLDAP() throws ClassNotFoundException, XWikiException, IllegalAccessException, InstantiationException {
344 XWikiDocument doc = new XWikiDocument("XWiki","akartmann");
345 try {
346 getXWiki().getDocument(doc, null, getXWikiContext());
347 getXWiki().deleteDocument(doc, getXWikiContext());
348 } catch (XWikiException e) {
349 }
350 prepareLDAP(true, "alexis");
351 assertEquals("getUserName failed", "akartmann", getXWiki().getUserName("XWiki.akartmann", getXWikiContext()));
352 assertEquals("getUserName failed", "akartmann", getXWiki().getLocalUserName("XWiki.akartmann", getXWikiContext()));
353 assertEquals("getUserName failed", "akartmann", getXWiki().getLocalUserName("xwiki:XWiki.akartmann", getXWikiContext()));
354
355 Utils.setStringValue("XWiki.XWikiPreferences", "XWiki.XWikiPreferences", "ldap_fields_mapping",
356 "name=cn,last_name=sn,first_name=givenName,fullname=displayName,mail=mail,ldap_dn=dn", getXWikiContext());
357
358 XWikiAuthService service = (XWikiAuthService) Class.forName("com.xpn.xwiki.user.impl.LDAP.LDAPAuthServiceImpl").newInstance();
359 Principal principal = service.authenticate("akartmann", "alexis", getXWikiContext());
360 assertNotNull("Authenticate failed", principal);
361 assertEquals("Name is not equal", "XWiki.akartmann", principal.getName());
362 String result = getXWiki().getUserName("XWiki.akartmann", getXWikiContext());
363 assertEquals("getUserName failed", "<span class=\"wikilink\"><a href=\"/xwiki/bin/view/XWiki/akartmann\">Alexis KARTMANN</a></span>", result );
364 result = getXWiki().getUserName("xwikitest:XWiki.akartmann", getXWikiContext());
365 assertEquals("getUserName failed", "<span class=\"wikilink\"><a href=\"/xwiki/bin/view/XWiki/akartmann\">Alexis KARTMANN</a></span>", result);
366 result = getXWiki().getLocalUserName("XWiki.akartmann", getXWikiContext());
367 assertEquals("getLocalUserName failed", "<span class=\"wikilink\"><a href=\"/xwiki/bin/view/XWiki/akartmann\">Alexis KARTMANN</a></span>", result);
368 result = getXWiki().getLocalUserName("xwikitest:XWiki.akartmann", getXWikiContext());
369 assertEquals("getLocalUserName failed", "<span class=\"wikilink\"><a href=\"/xwiki/bin/view/XWiki/akartmann\">Alexis KARTMANN</a></span>", result);
370 result = getXWiki().getLocalUserName("XWiki.akartmann", "$last_name", getXWikiContext());
371 assertEquals("getLocalUserName failed", "<span class=\"wikilink\"><a href=\"/xwiki/bin/view/XWiki/akartmann\">KARTMANN</a></span>", result);
372 result = getXWiki().getLocalUserName("XWiki.akartmann", "$last_name", false, getXWikiContext());
373 assertEquals("getLocalUserName failed", "KARTMANN", result);
374 result = getXWiki().getLocalUserName("XWiki.akartmann", "$first_name", getXWikiContext());
375 assertEquals("getLocalUserName failed", "<span class=\"wikilink\"><a href=\"/xwiki/bin/view/XWiki/akartmann\">Alexis</a></span>", result);
376 result = getXWiki().getLocalUserName("XWiki.akartmann", "$first_name", false, getXWikiContext());
377 assertEquals("getLocalUserName failed", "Alexis", result);
378 }
379 }