Wiki source code of Authentication
Version 33.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 | 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. | ||
95 | |||
96 | Here are some LDAP client for checking your configuration: | ||
97 | * [Apache Directory Studio>http://directory.apache.org/studio/] | ||
98 | * [LDAP Browser/Editor>http://www-unix.mcs.anl.gov/~gawor/ldap/] | ||
99 | |||
100 | 1.1.1 Detailed use cases | ||
101 | |||
102 | See [LDAP configuration uses cases>LDAPAuthenticationUseCases] for some detailed use cases. | ||
103 | |||
104 | 1.1.1 Enable LDAP debug log | ||
105 | |||
106 | See [AdminGuide.Logging]. The specific targets for LDAP authentication are: | ||
107 | {code} | ||
108 | log4j.logger.com.xpn.xwiki.plugin.ldap=debug | ||
109 | log4j.logger.com.xpn.xwiki.user.impl.LDAP=debug | ||
110 | {code} | ||
111 | |||
112 | |||
113 | 1.1 eXo Authentication | ||
114 | |||
115 | The eXo authentication is used automatically by adding/editing the ~~xwiki.exo=1~~ property in ~~WEB-INF/xwiki.cfg~~. | ||
116 | |||
117 | 1.1 Custom Authentication | ||
118 | |||
119 | This allows plugging to any existing authentication mechanism such as SiteMinder, etc. To configure a custom authentication do the following: | ||
120 | # 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. | ||
121 | # Edit the ~~WEB-INF/xwiki.cfg~~ file and add a ~~xwiki.authentication.authclass~~ property pointing to your class. For example: | ||
122 | |||
123 | {code} | ||
124 | xwiki.authentication.authclass = com.acme.MyCustomAuthenticationService | ||
125 | {code} | ||
126 | |||
127 | 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/]. | ||
128 | |||
129 | 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: | ||
130 | {code} | ||
131 | xwiki.authentication.rightsclass = com.acme.MyCustomRightsService | ||
132 | {code} | ||
133 | |||
134 | 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]: | ||
135 | |||
136 | {code} | ||
137 | xwiki.authentication.groupclass = com.acme.MyCustomGroupService | ||
138 | {code} | ||
139 | |||
140 | 1.1.1 Custom Authentication using a Groovy script in a wiki page | ||
141 | |||
142 | Start by specifying you want to use the Groovy Authenticator: | ||
143 | |||
144 | {code} | ||
145 | xwiki.authentication.authclass = com.xpn.xwiki.user.impl.xwiki.GroovyAuthServiceImpl | ||
146 | {code} | ||
147 | |||
148 | Then add another configuration parameter to specify in which wiki page the authenticator is: | ||
149 | |||
150 | {code} | ||
151 | xwiki.authentication.groovy.pagename = MySpace.MyPage | ||
152 | {code} | ||
153 | |||
154 | Then in a wiki page put some Groovy code that returns a XWikiAuthService object. | ||
155 | |||
156 | 1.1 Authentication parameters | ||
157 | |||
158 | You can set each of these parameters by setting: | ||
159 | |||
160 | {code} | ||
161 | xwiki.authentication.~~param_name~~=~~param_value~~ | ||
162 | {code} | ||
163 | |||
164 | {table} | ||
165 | Name | Optional | Allowed values | Default value | Description | ||
166 | 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. | ||
167 | 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. | ||
168 | 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 | ||
169 | cookielife | Yes | Number | 14 | Number of days cookies take to expire | ||
170 | 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~~ | ||
171 | default_page | Yes | String | /bin/view/ Main/WebHome | Page to redirect to if xredirect parameter is not set | ||
172 | encryptionalgorithm | Yes | ? | ? | Set the Encryption Algorithm used to encrypt and decrypt cookies | ||
173 | encryptionmode | Yes | ? | ? | Set the Encryption Mode used to encrypt and decrypt cookies | ||
174 | encryptionpadding | Yes | ? | ? | Set the Encryption Padding used to encrypt and decrypt cookies | ||
175 | errorpage | Yes | String | /bin/loginerror/ XWiki/XWikiLogin | Page to redirect to if there is an error logging in | ||
176 | loginpage | Yes | String | /bin/login/ XWiki/XWikiLogin | Page to redirect to when not logged in | ||
177 | loginsubmitpage | Yes | String | /loginsubmit/ XWiki/XWikiLogin | ? | ||
178 | logoutpage | Yes | String | /bin/logout/ XWiki/XWikiLogout | Page to redirect to after logged out | ||
179 | realmname | Yes | String | XWiki | Sets the realm name | ||
180 | protection | Yes | all, validation, encryption, none | all | Protection level for the "remember me" cookie functionality | ||
181 | unauthorized_code | Yes | ? | ? | ? | ||
182 | 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. | ||
183 | {table} | ||
184 | # Only required if protection = encryption or all (default) | ||
185 | # Only required if protection = validation or all (default) | ||
186 | |||
187 | 1.1 Kerberos SSO Authentication | ||
188 | |||
189 | #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!") | ||
190 | |||
191 | 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. | ||
192 | |||
193 | First of all you need to create a principal and keytab for the webserver: | ||
194 | {code} | ||
195 | # kadmin | ||
196 | kadmin> addprinc -randkey HTTP/wiki.example.com | ||
197 | kadmin> ktadd -k /etc/apache2/ssl/wiki.keytab HTTP/wiki.example.com | ||
198 | kadmin> quit | ||
199 | {code} | ||
200 | |||
201 | Make sure the keytab has the right permissions and ownership: | ||
202 | {code} | ||
203 | chown www-data:www-data /etc/apache2/ssl/wiki.keytab | ||
204 | chmod 400 /etc/apache2/ssl/wiki.keytab | ||
205 | {code} | ||
206 | |||
207 | Install mod_auth_kerb in your linux installation. On Debian or Ubuntu this would be achieved by running: | ||
208 | {code} | ||
209 | aptitude install libapache2-mod-auth-kerb | ||
210 | {code} | ||
211 | Of course the installation procedure varies per Linux distribution. | ||
212 | |||
213 | If your xwiki installation is mounted in Apache HTTPD under /xwiki, add the following to the virtual host configuration: | ||
214 | {code} | ||
215 | <Location /xwiki/> | ||
216 | AuthType Kerberos | ||
217 | AuthName "Kerberos Login" | ||
218 | KrbAuthRealms EXAMPLE.COM | ||
219 | Krb5Keytab "/etc/apache2/ssl/wiki.keytab" | ||
220 | KrbMethodK5Passwd off | ||
221 | KrbMethodNegotiate on | ||
222 | KrbSaveCredentials on | ||
223 | require valid-user | ||
224 | </Location> | ||
225 | {code} | ||
226 | |||
227 | 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): | ||
228 | {code} | ||
229 | <Connector port="8009" address="127.0.0.1" enableLookups="false" tomcatAuthentication="false" redirectPort="8443" protocol="AJP/1.3" /> | ||
230 | {code} | ||
231 | |||
232 | Place the authkerb.jar jar in the WEB-INF/lib directory of Xwiki in Apache Tomcat. | ||
233 | |||
234 | Have Xwiki use the authentication module by changing the "xwiki.authentication.authclass" property in WEB-INF/lib/xwiki.cfg file. | ||
235 | {code} | ||
236 | xwiki.authentication.authclass=com.xpn.xwiki.user.impl.xwiki.AppServerTrustedKerberosAuthServiceImpl | ||
237 | {code} | ||
238 | |||
239 | 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. | ||
240 | |||
241 | |||
242 | |||
243 | 2 JBoss SPNEGO (Kerberos in combination with LDAP) | ||
244 | I changed the code of the XWikiLDAPAuthServiceImpl to be able to detect the sso user. | ||
245 | The authenication already happend by using the SPNEGO module (JAAS). | ||
246 | After that I'm using the ldap synchronisation feature to make sure that the user is up to date. | ||
247 | The combination leads to an automatic login in the xwiki and the user rights are controlled in the Active Directory server. | ||
248 | I hope you can adopt this code or that you can use it for your own projects. | ||
249 | |||
250 | The configuration of ldap; | ||
251 | {code} | ||
252 | xwiki.authentication.authclass=com.wiki.sso.SSOLdapAuthenicationImpl | ||
253 | xwiki.authentication.ldap=1 | ||
254 | xwiki.authentication.ldap.server=<ad-server> | ||
255 | xwiki.authentication.ldap.port=389 | ||
256 | xwiki.authentication.ldap.base_DN=<OU=Users,...............> | ||
257 | #use a fixed user to attach to the ldap database, | ||
258 | #the password is not provided with the SSOLdapAuthenicationImpl | ||
259 | xwiki.authentication.ldap.bind_DN=<domain>\\<user> | ||
260 | xwiki.authentication.ldap.bind_pass=<password> | ||
261 | #Microsoft AD configuration | ||
262 | xwiki.authentication.ldap.UID_attr=sAMAccountName | ||
263 | xwiki.authentication.ldap.fields_mapping=name=sAMAccountName,last_name=sn,first_name=givenName,fullname=displayName,mail=mail,ldap_dn=dn | ||
264 | xwiki.authentication.ldap.group_memberfields=member,uniqueMember | ||
265 | #LDAP group mapping | ||
266 | xwiki.authentication.ldap.group_mapping=XWiki.XWikiAdminGroup=CN=WIKI_Admin,............|\ | ||
267 | XWiki.XWikiAllGroup=CN=WIKI_User,........... | ||
268 | |||
269 | {code} | ||
270 | The java code | ||
271 | {code} | ||
272 | package com.wiki.sso; | ||
273 | |||
274 | |||
275 | import org.apache.commons.logging.Log; | ||
276 | import org.apache.commons.logging.LogFactory; | ||
277 | |||
278 | import com.xpn.xwiki.XWikiContext; | ||
279 | import com.xpn.xwiki.XWikiException; | ||
280 | import com.xpn.xwiki.user.api.XWikiUser; | ||
281 | import com.xpn.xwiki.user.impl.LDAP.XWikiLDAPAuthServiceImpl; | ||
282 | |||
283 | import java.security.Principal; | ||
284 | |||
285 | public class SSOLdapAuthenicationImpl extends XWikiLDAPAuthServiceImpl { | ||
286 | /** | ||
287 | * Logging tool. | ||
288 | */ | ||
289 | private static final Log LOG = LogFactory.getLog(SSOLdapAuthenicationImpl.class); | ||
290 | |||
291 | |||
292 | public XWikiUser checkAuth(XWikiContext context) throws XWikiException { | ||
293 | String user = getRemoteUser(context); | ||
294 | if ((user != null) || !user.equals("")) { | ||
295 | if (LOG.isInfoEnabled()) | ||
296 | LOG.info("Launching create user for " + user); | ||
297 | if ( authenticate(user, context) != null ) { | ||
298 | if (LOG.isInfoEnabled()) | ||
299 | LOG.info("Create user done for " + user); | ||
300 | user = "XWiki." + user; | ||
301 | context.setUser(user); | ||
302 | System.out.println("User is set to:" + user); | ||
303 | return new XWikiUser(user); | ||
304 | } else { | ||
305 | LOG.error( "User " + user + " can't be authenticated against ldap" ); | ||
306 | } | ||
307 | } | ||
308 | return super.checkAuth(context); | ||
309 | } | ||
310 | |||
311 | /** | ||
312 | * We cannot authenticate locally since we need to trust the app server for | ||
313 | * authentication | ||
314 | * | ||
315 | * @param username | ||
316 | * @param password | ||
317 | * @param context | ||
318 | * @return | ||
319 | * @throws XWikiException | ||
320 | */ | ||
321 | public XWikiUser checkAuth(String username, String password, | ||
322 | String rememberme, XWikiContext context) throws XWikiException { | ||
323 | String user = getRemoteUser(context); | ||
324 | if ((user == null) || user.equals("")) { | ||
325 | return super.checkAuth(username, password, rememberme, context); | ||
326 | } | ||
327 | return checkAuth(context); | ||
328 | } | ||
329 | |||
330 | private String getRemoteUser(XWikiContext context) { | ||
331 | String userName = context.getRequest().getHttpServletRequest() | ||
332 | .getRemoteUser(); | ||
333 | if (userName != null) { | ||
334 | // only take the front of the username@domain | ||
335 | String[] elements = userName.split("@", 2); | ||
336 | userName = elements[0]; | ||
337 | } | ||
338 | return userName; | ||
339 | } | ||
340 | |||
341 | public Principal authenticate(String login, XWikiContext context) throws XWikiException | ||
342 | { | ||
343 | if (LOG.isTraceEnabled()) { | ||
344 | LOG.trace("Starting LDAP authentication"); | ||
345 | } | ||
346 | |||
347 | /* | ||
348 | * TODO: Put the next 4 following "if" in common with XWikiAuthService to ensure coherence This method was | ||
349 | * returning null on failure so I preserved that behaviour, while adding the exact error messages to the context | ||
350 | * given as argument. However, the right way to do this would probably be to throw XWikiException-s. | ||
351 | */ | ||
352 | |||
353 | if (login == null) { | ||
354 | // If we can't find the username field then we are probably on the login screen | ||
355 | |||
356 | if (LOG.isDebugEnabled()) { | ||
357 | LOG.debug("The provided user is null." | ||
358 | + " We don't try to authenticate, it probably means the user is in non logged mode."); | ||
359 | } | ||
360 | |||
361 | return null; | ||
362 | } | ||
363 | |||
364 | // Check for empty usernames | ||
365 | if (login.equals("")) { | ||
366 | context.put("message", "nousername"); | ||
367 | |||
368 | if (LOG.isDebugEnabled()) { | ||
369 | LOG.debug("LDAP authentication failed: login empty"); | ||
370 | } | ||
371 | |||
372 | return null; | ||
373 | } | ||
374 | |||
375 | // If we have the context then we are using direct mode | ||
376 | // then we should specify the database | ||
377 | // This is needed for virtual mode to work | ||
378 | Principal principal = null; | ||
379 | |||
380 | // Try authentication against ldap | ||
381 | principal = ldapAuthenticate(login, "", context); | ||
382 | |||
383 | if (LOG.isDebugEnabled()) { | ||
384 | if (principal != null) { | ||
385 | LOG.debug("LDAP authentication succeed with principal [" + principal.getName() + "]"); | ||
386 | } else { | ||
387 | LOG.debug("LDAP authentication failed for user [" + login + "]"); | ||
388 | } | ||
389 | } | ||
390 | |||
391 | return principal; | ||
392 | } | ||
393 | } | ||
394 | {code} |