[{ALLOW comment All}]
[{ALLOW modify davidgjm,Authenticated}]
%%(text-align:center;padding:2em;font-size:160%;font-weight: bold;)
Web Container Authentication via LDAP
%%

[{TableOfContents numbered='false'}]
\\

!!! Planning your use case
By Default, JSPWiki uses XML user database files for authentication. This is good for small standalone applications but in enterprise environments, user accounts are centrally stored in systems like Active Directory, Lotus Domino, LDAP Servers (i.e.: OpenLDAP, Sun One Directory Server, etc.). So in an enterprise environment, you can use an LDAP service to manage your wiki users and groups. If you are running Tomcat as your servlet container, you can configure your JSPWiki to use Tomcat JNDIRealm feature so that LDAP users can log into JSPWiki system without any additional efforts.

In order to achieve this, you need to have enough information about your LDAP environment, Tomcat configuration details, and JSPWiki application web.xml. You need several steps to make this happen:
# Setup a working LDAP Server if you don't already have one.
# Change the configuration of tomcat to work with LDAP
# Change the configuration of JSPWiki to let LDAP users log in successfully

!! Environment Setup for this tutorial
||LDAP Server|OpenLDAP Server 2.3.43 (cygwin)
||Tomcat|Tomcat 6.0.30
||JSPWiki|JSPWiki 2.8.4
||LDAP Directory Information|[{Image src='ldap_tree_structure.png' align='center' }]

!!! LDAP Server Configuration
If you do not have a working LDAP server, you can install from scratch. There are lot of LDAP servers you can choose from, open source or commercial. OpenLDAP is one of the most popular LDAP Servers. You can get the latest build, docs from its website: [http://www.openldap.org]. You can get enough information from the web about how to setup/configure an LDAP server. The focus here is on configuration details of your LDAP server.

!! LDAP Configuration and Directory Information Tree
You need to have some entries on your LDAP instance, both users and groups. You need to get the following information about your LDAP server and directory information. Please consult your LDAP administrator if you don't know.
||Item||Note||Example
|LDAP Host|LDAP server host name or IP address|{{localhost}}
|LDAP Port|389 for ldap:// (''default value'')\\636 for ldaps:// (''default value'')|
|Base DN| The root DN of your DIT. All the entries are created under this entry. |{{dc=example,dc=com}}
|User Base| The DN where all your user entries are created|{{ou=people,dc=example,dc=com}}
|Group Base| The DN where all group entries are created|{{ou=groups,dc=example,dc=com}}
|root DN|The DN of the administrator. This may be used later| {{cn=Manager,dc=example,dc=com}}
|root DN password| Password for the admin|

%%warning
If all your users and groups are created under the same parent entry, use the same parent DN for group base and user base.
%%
!! Get to know about access control
Try to get the current configuration for LDAP access control. This is quite useful for later debugging. The following is an example of ACL definition in OpenLDAP. You can use it as a template.
{{{
access to dn.sub="ou=groups,dc=example,dc=com"
	by self write
	by * read

access to dn.base="" by * read
access to dn.base="cn=Subschema" by * read

access to *
	by self write
	by users read
	by anonymous search
}}}

Where:
* For entries under ''ou=groups,dc=example,dc=com'', __read __access is granted to roles except ''self''. Anonymous user can read group members under this configuration
* For other entries, the currently logged in user can edit entries of their own. Other authenticated users can read the values while anonymous only has search privilege.
----
!!! Tomcat Configuration
The LDAP support is implemented by __JNDIRealm__ in Tomcat. You can add a Realm element to your Tomcat server.xml file. You can add the node in the XML elements below:
* Inside an ''<Engine>'' element - This Realm will be shared across ALL web applications on ALL virtual hosts, UNLESS it is overridden by a Realm element nested inside a subordinate <Host> or <Context> element.
* Inside a ''<Host>'' element - This Realm will be shared across ALL web applications for THIS virtual host, UNLESS it is overridden by a Realm element nested inside a subordinate <Context> element.
* Inside a ''<Context>'' element - This Realm will be used ONLY for THIS web application.

For more information about Tomcat Realm and JNDIRealm, please refer to Tomcat 6.0 documentation [http://tomcat.apache.org/tomcat-6.0-doc/realm-howto.html].

!! bind mode v.s. comparison mode
Tomcat can use either bind mode or comparison mode for authenticating user. You need to make the right choice for this.
%%warning
This configuration in this tutorial uses bind mode for now. Comparison mode configuration is not available.
%%
For detailed information about these two modes, please check Tomcat documentation: [http://tomcat.apache.org/tomcat-6.0-doc/realm-howto.html#JNDIRealm].

!!Editing Tomcat __server.xml__ 
In this tutorial, the JNDIRealm will be added inside __<Engine>__ element.
! Open your Tomcat configuration file
Tomcat configuration file __server.xml__ is located in <CATALINA_HOME>/conf. Open it with your favourite text editor. Go to the XML section below ''Engine/Realm''. You can find there by looking for text below:
%%prettify
{{{
      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"/>
}}}
%%

! Add JNDI Realm Element
Add one extra Realm element just after the ''UserDatabase'' node. The XML fragment of JNDIRealm configuration is like below:
%%prettify 
{{{
	<Realm className="org.apache.catalina.realm.JNDIRealm"  debug="99"
		connectionURL="ldap://localhost:389"
		userPattern="cn={0},ou=people,dc=example,dc=com"
		roleBase="ou=groups,dc=example,dc=com"
		roleSubtree="true"
		roleSearch="(member={0})"
		roleName="cn"
		roleNested="true"
	/>
}}}
/%

where
* __connectionURL__The LDAP server connection w/ port. The template is ''(ldap://|ldaps://)<LDAP_Host>~[:<LDAP_Port]>''.
* __userPattern__ The DN pattern for LDAP users. This attribute can be used for case like all users are stored under the same parent entry.  __{0}__ will be replaced with each user's actual login.
* __roleBase__ Base DN of your group base
* __roleSubtree__ Search sub entries if enabled.
* __roleSearch__ the LDAP search filter for selecting role entries. It optionally includes pattern replacements "{0}" for the distinguished name(i.e.:(''uid=user,ou=People, dc=example,dc=com'')) and/or "{1}" for the username of the authenticated user. The attribute name depends on which object class you use for your groups. Here are a few attribute names for common groups:
** __member}}__ for objectClass ''groupOfNames'' 
** __uniqueMember__ objectClass ''groupOfUniqueNames''
** __memberUid__ objectClass ''posixGroup''
* __roleName__ the attribute in a role entry containing the name of that role.
* __roleNested__ enable nested groups. Set to true if you want to nest groups in groups.

!! JNDIRealm Configuration Samples
The JNDIRealm configuration is basically the same for most LDAP servers. The variants may be attribute names for user logins, group member attribute names, etc.
! ~OpenLDAP Server
%%prettify 
{{{
	<Realm className="org.apache.catalina.realm.JNDIRealm"  debug="99"
		connectionURL="ldap://localhost:389"
		userPattern="cn={0},ou=people,dc=example,dc=com"
		roleBase="ou=groups,dc=example,dc=com"
		roleSubtree="true"
		roleSearch="(member={0})"
		roleName="cn"
		roleNested="true"
	/>
}}}
/%

! Configuration for Active Directory
%%prettify
{{{
<Realm className="org.apache.catalina.realm.JNDIRealm"
  	 connectionURL="ldap://domaincontroller-host:389"
     	 connectionName="CN=Ldaplogin,OU=EDP Login,OU=All Users XP,DC=poison,DC=in"
         connectionPassword="***secret***" 
         userBase="OU=All Users XP,DC=domain" 
         userSubtree="true"
         userSearch="(userPrincipalName={0}@yourdomain.com)" 
         userRoleName="memberOf"
         roleBase="CN=Groups,DC=domain" 
         roleName="cn" 
         roleSubtree="true"
         roleSearch="(member={0})" 
       />
 }}}
/%
userSearch can be set to any property that uniquely identifies a user.
In this case it is set to identify with your email. It can also be set to
%%prettify
{{{
    userSearch="(sAMAccountName={0})"
}}}
/%

I am currently trying to figure out a way to authenticate through domain trusts. ''-[JoergMeyer]''
----

!!! JSPWiki Configuration
Now that your Tomcat can start work with your LDAP, the next step is to configure JSPWiki for LDAP authentication through Tomcat.
!! LDAP groups and wiki groups
You can also map LDAP groups to wiki groups if you want to enforce JSPWiki ACL to LDAP user groups. You need to change the web.xml to include your wanted groups if you want to use LDAP groups. You can do so by assigning proper privileges to LDAP groups in your JSPWiki policy file.

!!Editing JSPWiki __web.xml__

Open your wiki's web.xml in an editor, and uncomment the CONTAINER-MANAGED AUTH section like below:
%%prettify
{{{
   <security-constraint>
       <web-resource-collection>
           <web-resource-name>Administrative Area</web-resource-name>
           <url-pattern>/Delete.jsp</url-pattern>
       </web-resource-collection>
       <auth-constraint>
           <role-name>wiki-admin</role-name>
       </auth-constraint>
       <!--
       <user-data-constraint>
           <transport-guarantee>CONFIDENTIAL</transport-guarantee>
       </user-data-constraint>
       -->
   </security-constraint>
      
   <security-constraint>
       <web-resource-collection>
           <web-resource-name>Authenticated area</web-resource-name>
           <url-pattern>/Edit.jsp</url-pattern>
           <url-pattern>/Comment.jsp</url-pattern>
           <url-pattern>/Login.jsp</url-pattern>
           <url-pattern>/NewGroup.jsp</url-pattern>
           <url-pattern>/Rename.jsp</url-pattern>
           <url-pattern>/Upload.jsp</url-pattern>
           <http-method>DELETE</http-method>
           <http-method>GET</http-method>
           <http-method>HEAD</http-method>
           <http-method>POST</http-method>
           <http-method>PUT</http-method>
       </web-resource-collection>

       <web-resource-collection>
           <web-resource-name>Read-only Area</web-resource-name>
           <url-pattern>/attach</url-pattern>
           <http-method>DELETE</http-method>
           <http-method>POST</http-method>
           <http-method>PUT</http-method>
       </web-resource-collection>

       <auth-constraint>
           <role-name>wiki-admin</role-name>
           <role-name>wiki-users</role-name>

       </auth-constraint>
	  <!--
       <user-data-constraint>
           <transport-guarantee>CONFIDENTIAL</transport-guarantee>
       </user-data-constraint>
       -->
   </security-constraint>

   <login-config>
       <auth-method>FORM</auth-method>
       <form-login-config>
           <form-login-page>/LoginForm.jsp</form-login-page>
           <form-error-page>/LoginForm.jsp</form-error-page>
       </form-login-config>
   </login-config>

   <security-role>
       <description>
           This logical role includes all authenticated users
       </description>
       <role-name>wiki-users</role-name>
   </security-role>

   <security-role>
       <description>
           This logical role includes all administrative users
       </description>
       <role-name>wiki-admin</role-name>
   </security-role>
}}}
/%
where:\\
* ''wiki-admin'' is the LDAP group whose members will have the wiki admin privileges
* ''wiki-users'' is the LDAP group whose members will be normal authenticated wiki users.

I commented the ''user-data-constraint'' section since I failed to enable SSL in tomcat.

!! Updating ''jspwiki.properties''
You need to uncomment the ~WebContainerAuthorizer property to use web container authorization. See below
%%prettify
{{{
#  AUTHORIZATION (EXTERNAL)
#  For authorization, JSPWiki has a two-tier system. When we want to
#  determine whether a user has permission to perform a certain action,
#  we first consult an external "authorizer" to determine if the user
#  is a member of the required role. By default, JSPWiki uses the
#  servlet container's authorization service for this (that is, it
#  calls HttpServletRequest.isUserInRole(String) ).
#  However, you can use another Authorizer if you wish; specify that
#  class here.

jspwiki.authorizer =com.ecyrd.jspwiki.auth.authorize.WebContainerAuthorizer
}}}
%%

!! Update JSPWiki security policy
If you would like to set permissions to LDAP groups, you can simply add policy entries on ''authorize.Role''. The following is an entry for ''wiki-admin'' group (from LDAP).
%%prettify
{{{
grant principal com.ecyrd.jspwiki.auth.authorize.Role "wiki-admin" {
    permission com.ecyrd.jspwiki.auth.permissions.AllPermission "*";
};
}}}
%%
----
!!! References
* [http://tomcat.apache.org/tomcat-6.0-doc/realm-howto.html]
* [http://www.openldap.org/doc/admin24/access-control.html]
----