Wiki source code of Authentication
Version 31.1 by Thomas Mortagne on 2010/01/20
Show last authors
author | version | line-number | content |
---|---|---|---|
1 | 1 User Authentication | ||
2 | |||
3 | XWiki supports several different authentication mechanisms for authenticating users: | ||
4 | #toc("" "" "") | ||
5 | |||
6 | The form authentication is the default mechanism. | ||
7 | |||
8 | #info("Note that currently XWiki allows only one method of authentication to be enabled at a time. This will probably be improved in the future.") | ||
9 | |||
10 | 1.1 Form Authentication | ||
11 | |||
12 | TODO | ||
13 | |||
14 | 1.1 LDAP Authentication | ||
15 | |||
16 | #warning("New LDAP implementation since XWiki Platform 1.3M2, see [previous LDAP authentication service documentation>AuthenticationLdapOld]") | ||
17 | |||
18 | 1.1.1 Generic LDAP configuration | ||
19 | |||
20 | In order to enable the LDAP support you have to change the authentication method in ~~WEB-INF/xwiki.cfg~~ as follows: | ||
21 | {code} | ||
22 | ## Turn LDAP authentication on - otherwise only XWiki authentication | ||
23 | ## 0 : disable | ||
24 | ## 1 : enable | ||
25 | xwiki.authentication.ldap=1 | ||
26 | |||
27 | ## set LDAP as authentication service | ||
28 | xwiki.authentication.authclass=com.xpn.xwiki.user.impl.LDAP.XWikiLDAPAuthServiceImpl | ||
29 | |||
30 | {code} | ||
31 | |||
32 | You can setup the LDAP configuration in the ~~xwiki.cfg~~ file by filling the following properties: | ||
33 | |||
34 | {code:none} | ||
35 | ## LDAP Server (Active Directory, eDirectory, OpenLDAP, etc.) | ||
36 | xwiki.authentication.ldap.server=156.58.101.204 | ||
37 | xwiki.authentication.ldap.port=389 | ||
38 | |||
39 | ## LDAP login, empty = anonymous access, otherwise specify full dn | ||
40 | ## {0} is replaced with the username, {1} with the password | ||
41 | xwiki.authentication.ldap.bind_DN=cn={0},department=USER,department=INFORMATIK,department=1230,o=MP | ||
42 | xwiki.authentication.ldap.bind_pass={1} | ||
43 | |||
44 | ## Force to check password after LDAP connection | ||
45 | ## 0: disable | ||
46 | ## 1: enable | ||
47 | xwiki.authentication.ldap.validate_password=0 | ||
48 | |||
49 | ## only members of the following group will be verified in the LDAP | ||
50 | ## otherwise only users that are found after searching starting from the base_DN | ||
51 | xwiki.authentication.ldap.user_group=cn=developers,ou=groups,o=MegaNova,c=US | ||
52 | |||
53 | ## only users not member of the following group can autheticate | ||
54 | xwiki.authentication.ldap.exclude_group=cn=admin,ou=groups,o=MegaNova,c=US | ||
55 | |||
56 | ## base DN for searches | ||
57 | xwiki.authentication.ldap.base_DN= | ||
58 | department=USER,department=INFORMATIK,department=1230,o=MP | ||
59 | |||
60 | ## specifies the LDAP attribute containing the identifier to be used as the XWiki name (default=cn) | ||
61 | xwiki.authentication.ldap.UID_attr=cn | ||
62 | |||
63 | ## retrieve the following fields from LDAP and store them in the XWiki user object (xwiki-attribute=ldap-attribute) | ||
64 | xwiki.authentication.ldap.fields_mapping=last_name=sn,first_name=givenName,fullname=fullName,email=mail | ||
65 | |||
66 | # on every login update the mapped attributes from LDAP to XWiki otherwise this happens only once when the XWiki account is created. | ||
67 | xwiki.authentication.ldap.update_user=1 | ||
68 | |||
69 | ## maps XWiki groups to LDAP groups, separator is "|" | ||
70 | xwiki.authentication.ldap.group_mapping=XWiki.XWikiAdminGroup=cn=AdminRole,ou=groups,o=MegaNova,c=US|\ | ||
71 | XWiki.Organisation=cn=testers,ou=groups,o=MegaNova,c=US | ||
72 | |||
73 | ## time in seconds after which the list of members in a group is refreshed from LDAP (default=3600*6) | ||
74 | xwiki.authentication.ldap.groupcache_expiration=21800 | ||
75 | |||
76 | ## - create : synchronize group membership only when the user is first created | ||
77 | ## - always: synchronize on every login | ||
78 | xwiki.authentication.ldap.mode_group_sync=always | ||
79 | |||
80 | ## if ldap authentication fails for any reason, try XWiki DB authentication with the same credentials | ||
81 | xwiki.authentication.ldap.trylocal=1 | ||
82 | |||
83 | ## SSL connection to LDAP server | ||
84 | ## 0 : normal | ||
85 | ## 1 : SSL | ||
86 | xwiki.authentication.ldap.ssl=1 | ||
87 | |||
88 | ## The keystore file to use in SSL connection | ||
89 | xwiki.authentication.ldap.ssl.keystore= | ||
90 | {code} | ||
91 | |||
92 | #info("You can also setup the LDAP configuration in XWiki.XWikiPreferences page by going to the object editor. Simply replace \"xwiki.authentication.ldap.\" by \"ldap_\". For example <tt>xwiki.authentication.ldap.base_DN</tt> become <tt>ldap_base_DN</tt>") | ||
93 | |||
94 | The bind_DN and bind_pass fields contain the username and password for binding to the LDAP server in order to search, which will not necessarily be the same credentials as the user logging in. | ||
95 | |||
96 | The exact details of this configuration will vary based on your server configuration. It may not be necessary to prefix the username (represented by {0}) with the subdomain. | ||
97 | |||
98 | For testing purposes, you may wish to omit the "ldap.fields_mapping" field, to test the authentication first, and then add it later to get the mappings right. | ||
99 | |||
100 | Here are some LDAP client for checking your configuration: | ||
101 | * This java client, [LDAP Browser/Editor > http://www-unix.mcs.anl.gov/~gawor/ldap/] is a handy tool for checking your configuration. | ||
102 | * [Apache Directory Studio>http://directory.apache.org/studio/] | ||
103 | |||
104 | 1.1.1 Detailed use cases | ||
105 | |||
106 | See [LDAP configuration uses cases>LDAPAuthenticationUseCases] for some detailed use cases. | ||
107 | |||
108 | 1.1.1 Enable LDAP debug log | ||
109 | |||
110 | See [AdminGuide.Logging]. The specific targets for LDAP authentication are: | ||
111 | {code} | ||
112 | log4j.logger.com.xpn.xwiki.plugin.ldap=debug | ||
113 | log4j.logger.com.xpn.xwiki.user.impl.LDAP=debug | ||
114 | {code} | ||
115 | |||
116 | |||
117 | 1.1 eXo Authentication | ||
118 | |||
119 | The eXo authentication is used automatically by adding/editing the ~~xwiki.exo=1~~ property in ~~WEB-INF/xwiki.cfg~~. | ||
120 | |||
121 | 1.1 Custom Authentication | ||
122 | |||
123 | This allows plugging to any existing authentication mechanism such as SiteMinder, etc. To configure a custom authentication do the following: | ||
124 | # Implement the [XWikiAuthService>http://svn.xwiki.org/svnroot/xwiki/platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/user/api/XWikiAuthService.java] interface. | ||
125 | # Edit the ~~WEB-INF/xwiki.cfg~~ file and add a ~~xwiki.authentication.authclass~~ property pointing to your class. For example: | ||
126 | |||
127 | {code} | ||
128 | xwiki.authentication.authclass = com.acme.MyCustomAuthenticationService | ||
129 | {code} | ||
130 | |||
131 | Here's a [tutorial on implementing a custom authentication class for authenticating against Oracle's SSO>http://bodez.wordpress.com/2008/10/15/xwiki-user-authentication-with-oracle-sso/]. | ||
132 | |||
133 | Note, that you also can implement own right management service by implementing [XWikiRightService>http://svn.xwiki.org/svnroot/xwiki/platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/user/api/XWikiRightService.java] interface: | ||
134 | {code} | ||
135 | xwiki.authentication.rightsclass = com.acme.MyCustomRightsService | ||
136 | {code} | ||
137 | |||
138 | and Group Service by implementing [XWikiGroupService>http://svn.xwiki.org/svnroot/xwiki/platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/user/api/XWikiGroupService.java]: | ||
139 | |||
140 | {code} | ||
141 | xwiki.authentication.groupclass = com.acme.MyCustomGroupService | ||
142 | {code} | ||
143 | |||
144 | 1.1.1 Custom Authentication using a Groovy script in a wiki page | ||
145 | |||
146 | Start by specifying you want to use the Groovy Authenticator: | ||
147 | |||
148 | {code} | ||
149 | xwiki.authentication.authclass = com.xpn.xwiki.user.impl.xwiki.GroovyAuthServiceImpl | ||
150 | {code} | ||
151 | |||
152 | Then add another configuration parameter to specify in which wiki page the authenticator is: | ||
153 | |||
154 | {code} | ||
155 | xwiki.authentication.groovy.pagename = MySpace.MyPage | ||
156 | {code} | ||
157 | |||
158 | Then in a wiki page put some Groovy code that returns a XWikiAuthService object. | ||
159 | |||
160 | 1.1 Authentication parameters | ||
161 | |||
162 | You can set each of these parameters by setting: | ||
163 | |||
164 | {code} | ||
165 | xwiki.authentication.~~param_name~~=~~param_value~~ | ||
166 | {code} | ||
167 | |||
168 | {table} | ||
169 | Name | Optional | Allowed values | Default value | Description | ||
170 | encryptionKey | No(1) | ? | n/a | Set the Encryption Key used to create a secret key, the secret key is passed to the Cipher object to be used during encryption and decryption of cookie values. | ||
171 | validationKey | No(2) | ? | n/a | Set the Validation Key used to generate hash value; the hash value is stored with the cookie and used to verify that the cookie has not been tampered with. | ||
172 | cookiedomains | Yes | String | Server host name | Which host(s) should your cookies be sent to; use only if you want to share cookies across domains, otherwise should be commented out | ||
173 | cookielife | Yes | Number | 14 | Number of days cookies take to expire | ||
174 | cookiepath | Yes | String | / | The webapp path that XWiki cookies should be sent to; if you have anything else running on your web server, this should be set to ~~/xwiki~~ | ||
175 | default_page | Yes | String | /bin/view/ Main/WebHome | Page to redirect to if xredirect parameter is not set | ||
176 | encryptionalgorithm | Yes | ? | ? | Set the Encryption Algorithm used to encrypt and decrypt cookies | ||
177 | encryptionmode | Yes | ? | ? | Set the Encryption Mode used to encrypt and decrypt cookies | ||
178 | encryptionpadding | Yes | ? | ? | Set the Encryption Padding used to encrypt and decrypt cookies | ||
179 | errorpage | Yes | String | /bin/loginerror/ XWiki/XWikiLogin | Page to redirect to if there is an error logging in | ||
180 | loginpage | Yes | String | /bin/login/ XWiki/XWikiLogin | Page to redirect to when not logged in | ||
181 | loginsubmitpage | Yes | String | /loginsubmit/ XWiki/XWikiLogin | ? | ||
182 | logoutpage | Yes | String | /bin/logout/ XWiki/XWikiLogout | Page to redirect to after logged out | ||
183 | realmname | Yes | String | XWiki | Sets the realm name | ||
184 | protection | Yes | all, validation, encryption, none | all | Protection level for the "remember me" cookie functionality | ||
185 | unauthorized_code | Yes | ? | ? | ? | ||
186 | useip | Yes | true / false | true | Specify to use the IP address when encrypting the cookie data; if IP address changes will need to re-login. | ||
187 | {table} | ||
188 | # Only required if protection = encryption or all (default) | ||
189 | # Only required if protection = validation or all (default) | ||
190 | |||
191 | 1.1 Kerberos SSO Authentication | ||
192 | |||
193 | #warning("This implementation of SSO is currently under review see: http://jira.xwiki.org/jira/browse/XWIKI-2496 . The class which is described in this segment of documentation, AppServerTrustedKerberosAuthServiceImpl, is not part of the default XWiki distribution!") | ||
194 | |||
195 | The following is an example of mod_auth_kerb for Apache being used to easily implement Xwiki authentication of users via by HTTP Negotiate on a linux server. This example assumes you already have a working Apache2 HTTPD and Apache Tomcat setup with mod_jk. | ||
196 | |||
197 | First of all you need to create a principal and keytab for the webserver: | ||
198 | {code} | ||
199 | # kadmin | ||
200 | kadmin> addprinc -randkey HTTP/wiki.example.com | ||
201 | kadmin> ktadd -k /etc/apache2/ssl/wiki.keytab HTTP/wiki.example.com | ||
202 | kadmin> quit | ||
203 | {code} | ||
204 | |||
205 | Make sure the keytab has the right permissions and ownership: | ||
206 | {code} | ||
207 | chown www-data:www-data /etc/apache2/ssl/wiki.keytab | ||
208 | chmod 400 /etc/apache2/ssl/wiki.keytab | ||
209 | {code} | ||
210 | |||
211 | Install mod_auth_kerb in your linux installation. On Debian or Ubuntu this would be achieved by running: | ||
212 | {code} | ||
213 | aptitude install libapache2-mod-auth-kerb | ||
214 | {code} | ||
215 | Of course the installation procedure varies per Linux distribution. | ||
216 | |||
217 | If your xwiki installation is mounted in Apache HTTPD under /xwiki, add the following to the virtual host configuration: | ||
218 | {code} | ||
219 | <Location /xwiki/> | ||
220 | AuthType Kerberos | ||
221 | AuthName "Kerberos Login" | ||
222 | KrbAuthRealms EXAMPLE.COM | ||
223 | Krb5Keytab "/etc/apache2/ssl/wiki.keytab" | ||
224 | KrbMethodK5Passwd off | ||
225 | KrbMethodNegotiate on | ||
226 | KrbSaveCredentials on | ||
227 | require valid-user | ||
228 | </Location> | ||
229 | {code} | ||
230 | |||
231 | Make sure Apache Tomcat uses the authentication performed by Apache HTTPD with the "tomcatAuthentication" property in the connector description (which is in the server.xml file of Apache Tomcat): | ||
232 | {code} | ||
233 | <Connector port="8009" address="127.0.0.1" enableLookups="false" tomcatAuthentication="false" redirectPort="8443" protocol="AJP/1.3" /> | ||
234 | {code} | ||
235 | |||
236 | Place the authkerb.jar jar in the WEB-INF/lib directory of Xwiki in Apache Tomcat. | ||
237 | |||
238 | Have Xwiki use the authentication module by changing the "xwiki.authentication.authclass" property in WEB-INF/lib/xwiki.cfg file. | ||
239 | {code} | ||
240 | xwiki.authentication.authclass=com.xpn.xwiki.user.impl.xwiki.AppServerTrustedKerberosAuthServiceImpl | ||
241 | {code} | ||
242 | |||
243 | If you use Firefox, do not forget to whitelist the xwiki URL for HTTP Negotiate in about:config with the "network.negotiate-auth.trusted-uris" property. possible values for this propperty include (without the quotes): "https://" for all secured connections or "example.com" for all example.com subdomains. | ||
244 | |||
245 | |||
246 | |||
247 | 2 JBoss SPNEGO (Kerberos in combination with LDAP) | ||
248 | I changed the code of the XWikiLDAPAuthServiceImpl to be able to detect the sso user. | ||
249 | The authenication already happend by using the SPNEGO module (JAAS). | ||
250 | After that I'm using the ldap synchronisation feature to make sure that the user is up to date. | ||
251 | The combination leads to an automatic login in the xwiki and the user rights are controlled in the Active Directory server. | ||
252 | I hope you can adopt this code or that you can use it for your own projects. | ||
253 | |||
254 | The configuration of ldap; | ||
255 | {code} | ||
256 | xwiki.authentication.authclass=com.wiki.sso.SSOLdapAuthenicationImpl | ||
257 | xwiki.authentication.ldap=1 | ||
258 | xwiki.authentication.ldap.server=<ad-server> | ||
259 | xwiki.authentication.ldap.port=389 | ||
260 | xwiki.authentication.ldap.base_DN=<OU=Users,...............> | ||
261 | #use a fixed user to attach to the ldap database, | ||
262 | #the password is not provided with the SSOLdapAuthenicationImpl | ||
263 | xwiki.authentication.ldap.bind_DN=<domain>\\<user> | ||
264 | xwiki.authentication.ldap.bind_pass=<password> | ||
265 | #Microsoft AD configuration | ||
266 | xwiki.authentication.ldap.UID_attr=sAMAccountName | ||
267 | xwiki.authentication.ldap.fields_mapping=name=sAMAccountName,last_name=sn,first_name=givenName,fullname=displayName,mail=mail,ldap_dn=dn | ||
268 | xwiki.authentication.ldap.group_memberfields=member,uniqueMember | ||
269 | #LDAP group mapping | ||
270 | xwiki.authentication.ldap.group_mapping=XWiki.XWikiAdminGroup=CN=WIKI_Admin,............|\ | ||
271 | XWiki.XWikiAllGroup=CN=WIKI_User,........... | ||
272 | |||
273 | {code} | ||
274 | The java code | ||
275 | {code} | ||
276 | package com.wiki.sso; | ||
277 | |||
278 | |||
279 | import org.apache.commons.logging.Log; | ||
280 | import org.apache.commons.logging.LogFactory; | ||
281 | |||
282 | import com.xpn.xwiki.XWikiContext; | ||
283 | import com.xpn.xwiki.XWikiException; | ||
284 | import com.xpn.xwiki.user.api.XWikiUser; | ||
285 | import com.xpn.xwiki.user.impl.LDAP.XWikiLDAPAuthServiceImpl; | ||
286 | |||
287 | import java.security.Principal; | ||
288 | |||
289 | public class SSOLdapAuthenicationImpl extends XWikiLDAPAuthServiceImpl { | ||
290 | /** | ||
291 | * Logging tool. | ||
292 | */ | ||
293 | private static final Log LOG = LogFactory.getLog(SSOLdapAuthenicationImpl.class); | ||
294 | |||
295 | |||
296 | public XWikiUser checkAuth(XWikiContext context) throws XWikiException { | ||
297 | String user = getRemoteUser(context); | ||
298 | if ((user != null) || !user.equals("")) { | ||
299 | if (LOG.isInfoEnabled()) | ||
300 | LOG.info("Launching create user for " + user); | ||
301 | if ( authenticate(user, context) != null ) { | ||
302 | if (LOG.isInfoEnabled()) | ||
303 | LOG.info("Create user done for " + user); | ||
304 | user = "XWiki." + user; | ||
305 | context.setUser(user); | ||
306 | System.out.println("User is set to:" + user); | ||
307 | return new XWikiUser(user); | ||
308 | } else { | ||
309 | LOG.error( "User " + user + " can't be authenticated against ldap" ); | ||
310 | } | ||
311 | } | ||
312 | return super.checkAuth(context); | ||
313 | } | ||
314 | |||
315 | /** | ||
316 | * We cannot authenticate locally since we need to trust the app server for | ||
317 | * authentication | ||
318 | * | ||
319 | * @param username | ||
320 | * @param password | ||
321 | * @param context | ||
322 | * @return | ||
323 | * @throws XWikiException | ||
324 | */ | ||
325 | public XWikiUser checkAuth(String username, String password, | ||
326 | String rememberme, XWikiContext context) throws XWikiException { | ||
327 | String user = getRemoteUser(context); | ||
328 | if ((user == null) || user.equals("")) { | ||
329 | return super.checkAuth(username, password, rememberme, context); | ||
330 | } | ||
331 | return checkAuth(context); | ||
332 | } | ||
333 | |||
334 | private String getRemoteUser(XWikiContext context) { | ||
335 | String userName = context.getRequest().getHttpServletRequest() | ||
336 | .getRemoteUser(); | ||
337 | if (userName != null) { | ||
338 | // only take the front of the username@domain | ||
339 | String[] elements = userName.split("@", 2); | ||
340 | userName = elements[0]; | ||
341 | } | ||
342 | return userName; | ||
343 | } | ||
344 | |||
345 | public Principal authenticate(String login, XWikiContext context) throws XWikiException | ||
346 | { | ||
347 | if (LOG.isTraceEnabled()) { | ||
348 | LOG.trace("Starting LDAP authentication"); | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | * TODO: Put the next 4 following "if" in common with XWikiAuthService to ensure coherence This method was | ||
353 | * returning null on failure so I preserved that behaviour, while adding the exact error messages to the context | ||
354 | * given as argument. However, the right way to do this would probably be to throw XWikiException-s. | ||
355 | */ | ||
356 | |||
357 | if (login == null) { | ||
358 | // If we can't find the username field then we are probably on the login screen | ||
359 | |||
360 | if (LOG.isDebugEnabled()) { | ||
361 | LOG.debug("The provided user is null." | ||
362 | + " We don't try to authenticate, it probably means the user is in non logged mode."); | ||
363 | } | ||
364 | |||
365 | return null; | ||
366 | } | ||
367 | |||
368 | // Check for empty usernames | ||
369 | if (login.equals("")) { | ||
370 | context.put("message", "nousername"); | ||
371 | |||
372 | if (LOG.isDebugEnabled()) { | ||
373 | LOG.debug("LDAP authentication failed: login empty"); | ||
374 | } | ||
375 | |||
376 | return null; | ||
377 | } | ||
378 | |||
379 | // If we have the context then we are using direct mode | ||
380 | // then we should specify the database | ||
381 | // This is needed for virtual mode to work | ||
382 | Principal principal = null; | ||
383 | |||
384 | // Try authentication against ldap | ||
385 | principal = ldapAuthenticate(login, "", context); | ||
386 | |||
387 | if (LOG.isDebugEnabled()) { | ||
388 | if (principal != null) { | ||
389 | LOG.debug("LDAP authentication succeed with principal [" + principal.getName() + "]"); | ||
390 | } else { | ||
391 | LOG.debug("LDAP authentication failed for user [" + login + "]"); | ||
392 | } | ||
393 | } | ||
394 | |||
395 | return principal; | ||
396 | } | ||
397 | } | ||
398 | {code} |