| Title: LDAP Authentication |
| Notice: Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| . |
| http://www.apache.org/licenses/LICENSE-2.0 |
| . |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| |
| [TOC] |
| |
| ## Why LDAP Authentication? |
| |
| Authenticating your users to VCL via LDAP allows you to use your enterprise managed |
| accounts to log in to the VCL web site. Additionally, you can mirror certain user |
| groups from your LDAP system into VCL so that you do not need to manage the user |
| group memberships both in your enterprise system and in VCL. |
| |
| ## Overview |
| |
| First, you need an LDAP server with SSL enabled. You already have this if you have |
| an Active Directory system set up. Next, you (probably) need to add an affiliation |
| to VCL so that users logging in via the new LDAP connection will all be associated |
| together. Finally, you need to modify the web code conf.php file to have information |
| about how to connect to the LDAP server. You will also need to make sure your web |
| server can trust the SSL certificate and access it through any firewalls. |
| |
| ## Prerequisites for your LDAP server: |
| |
| * SSL must be enabled on your LDAP server |
| * An LDAP account that can look up these items for users: |
| * first name |
| * last name |
| * user id |
| * email (optional) |
| |
| This will be referred to as 'vcllookup' on |
| this page. You can skip this step if anonymous binds are enabled on your LDAP server |
| and an anonymous bind will be able to look up the listed items. |
| |
| * If your LDAP server is behind a firewall, you will need to allow your VCL web |
| server to access tcp port 636 on your LDAP server |
| |
| ## Prerequisites for your VCL web server: |
| |
| * **php-ldap** needs to be installed |
| * **SSL certificate** - If your LDAP server's SSL certificate is self-signed, your VCL web server needs |
| to have the root CA certificate that was used to sign the LDAP server certificate |
| installed. The PEM formatted certificate needs to be added to the ca-bundle.crt file. |
| On CentOS, the file is located at /etc/pki/tls/certs/ca-bundle.crt |
| ([example](/docs/ldap-ca-bundle-ex.html)). The hostname in |
| the certificate must match the hostname entered in the conf.php file further down. |
| If your certificate does not have the correct hostname in it, you must put an entry |
| in /etc/hosts for the hostname in the certificate ([viewing the hostname in the |
| certificate](/docs/ldap-showhostname.html)). |
| |
| * After adding the certificate, restart httpd: |
| |
| service httpd restart |
| |
| * You can verify that the certificate is properly installed using this command: |
| |
| openssl s_client -showcerts -CAfile /etc/pki/tls/certs/ca-bundle.crt -connect |
| your.ldap.server.here:636 |
| |
| If you see "Verify return code: 0 (ok)" at the end of the output then it is |
| installed correctly. If you see a different return code, then you'll need to |
| troubleshoot the problem. |
| |
| * You may need to add a line to **/etc/openldap/ldap.conf** to point to the |
| ca-bundle.crt file. If so, add the following: |
| |
| TLS_CACERT /etc/pki/tls/certs/ca-bundle.crt |
| |
| ## Adding LDAP Authentication to the Web Code |
| |
| * You will need to manually add an entry to the affiliation table in the VCL |
| database. Choose a name for the affiliation. This will be appended to all userids |
| for the affiliation to distinguish them from other affiliations you may configure |
| later. **Do not** use the Global affiliation for this. Initials or a short name of |
| your organization are a good idea. The affiliation name cannot contain spaces. Use |
| the following to add the affiliation, replacing 'EXAMPLE' with the name you chose. |
| Take note of the id from the 2nd SQL statement as you will need it later. It is the |
| numerical id for this affiliation. |
| |
| mysql vcl |
| |
| INSERT INTO affiliation (name) VALUES ('EXAMPLE'); |
| |
| SELECT id FROM affiliation WHERE name = 'EXAMPLE'; |
| |
| exit |
| |
| * Edit *conf.php* and search for "EXAMPLE1 LDAP" |
| * Uncomment the "EXAMPLE1 LDAP" section by removing the '/\*' before it and the '\*/' |
| at the end of 'to use this login mechanism' |
| * Change 'EXAMPLE1 LDAP' to something to match your location, for example at NCSU, |
| it is 'NCSU LDAP'. This string is what users will see where they select the |
| authentication mechanism to use when logging in. |
| * Modify the following fields: |
| * **server** - this is the hostname of your LDAP server - this must match the |
| hostname in the certificate. |
| * **binddn** - typically, you'll want to use the base DN of your LDAP server; for |
| Active Directory, this is usually dc= for each of your domain name components. For |
| example, your your domain name was ad.example.org, it would be |
| "dc=ad,dc=example,dc=org" |
| * **userid** - this is a string that is added to the userid a user enters on the |
| login page. Place a '%s' where the entered userid should go. Some examples are: |
| * %s@example.org |
| * %s@ad.example.org |
| * uid=%s,ou=accounts,dc=example,dc=org' |
| * **unityid** \- this is the ldap field that contains a user's login id (for Active |
| Directory, this is usually sAMAccountName) |
| * **firstname** \- this is the ldap field that contains a user's first name |
| * **lastname** \- this is the ldap field that contains a user's last name |
| * **email** \- this is the ldap field that contains a user's email address |
| * **defaultemail** \- if an email address is not provided by the ldap server, this |
| will be appended to the end of the userid to create an email address. In this case, |
| email notifications will be disabled by default. |
| * **masterlogin** \- this is the vcllookup account referred to in the "Prerequisites |
| for your LDAP server" section - comment out this line if using anonymous binds |
| * **masterpwd** \- password for the masterlogin account - comment out this line if |
| using anonymous binds |
| * **affiliationid** \- this is the id from the SELECT statement in the first step |
| * **lookupuserbeforeauth** \- Some LDAP servers will only allow the full DN of a |
| user to be used when authenticating. If this is the case, you will need to set this |
| to 1 and set a value for *lookupuserfield*. You can probably start out with this set |
| to 0. If your LDAP server has users in multiple containers, you will probably need |
| to set this to 1. |
| * **lookupuserfield** \- If you need to set *lookupuserbeforeauth* to 1, set |
| this to the attribute to use to search for the user in ldap. Typical values are 'cn', |
| 'uid', and 'samaccountname'. |
| * **help** \- this is some text that will show up on the page where users select the |
| authentication method explaining why they would select this option |
| * Uncomment the **require_once** line for **ldapauth.php** toward the bottom of the file |
| |
| ## Mirroring LDAP User Groups |
| This part is a little more complicated because it actually requires modifying some |
| of the VCL code. Before modifying VCL, you first need to create user groups in your |
| LDAP system and configure things so that a lookup of a user in your LDAP system will |
| list the groups of which the user is a member. Doing these items is beyond the scope |
| of this document. |
| |
| In the vcl/.ht-inc/authmethods/ldapauth.php file, there is an example function at |
| the end named **updateEXAMPLE1Groups**. In a previous step, you modified conf.php |
| and changed **EXAMPLE1 LDAP** to something to match your location. **NCSU LDAP** |
| was used as an example. We'll continue using that here. |
| |
| You need to change the name of **updateEXAMPLE1Groups** to match your location. |
| We'll change it to **updateNCSUGroups** for our example. Next, on the 2nd line of |
| the function, change **EXAMPLE1 LDAP** to match your location (ex. **NCSU LDAP**). |
| Next, you need to determine what attribute is used when looking up users in your |
| LDAP system to reference user group memberships. For Active Directory, this is typically |
| **memberof**. Now, if needed, change the two references in the function from **memberof** |
| to the attribute used in your LDAP system. Finally, there are three example regular |
| expressions in the **for** loop at the bottom of the function that match various |
| example names of user groups. You'll need to modify these to match the OU structure |
| of your LDAP system. |
| |
| These are the three example rules in VCL 2.3: |
| |
| ^CN=(.+),OU=CourseRolls,DC=example1,DC=com |
| ^CN=(Students_Enrolled),OU=Students,DC=example1,DC=com$ |
| ^CN=(Staff),OU=IT,DC=example1,DC=com$ |
| |
| The first one matches any groups under the CourseRolls OU. The second one specifically |
| matches the **Students_Enrolled** group under the Students OU. The third one matches |
| the **Staff** group under the IT OU. If you need help creating regular expressions |
| to match your LDAP system, please feel free to ask on our user email list or via IRC. |
| |
| Finally, you'll also need to modify the updateLDAPUser function in the same file. |
| Toward the end of the function is a **switch** statement based on affiliation names. |
| Change the **EXAMPLE1** entry to the affiliation you created for your site. Then, |
| change the name of the function called for that affiliation to your new name for the |
| **updateEXAMPLE1Groups** function. Here is an example of that part of the function: |
| |
| switch(getAffiliationName($affilid)) { |
| case 'NCSU': |
| updateNCSUGroups($user); |
| break; |
| default: |
| //TODO possibly add to a default group |
| } |
| |
| |
| |
| Here is an example function using NCSU instead of EXAMPLE1, and using an Active |
| Directory LDAP system: |
| |
| function updateNCSUGroups($user) { |
| global $authMechs; |
| $auth = $authMechs['NCSU LDAP']; |
| $ds = ldap_connect("ldaps://{$auth['server']}/"); |
| if(! $ds) |
| return 0; |
| ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3); |
| ldap_set_option($ds, LDAP_OPT_REFERRALS, 0); |
| |
| $res = ldap_bind($ds, $auth['masterlogin'], |
| $auth['masterpwd']); |
| if(! $res) |
| return 0; |
| |
| $search = ldap_search($ds, |
| $auth['binddn'], |
| "{$auth['unityid']}={$user['unityid']}", |
| array('memberof'), 0, 10, 15); |
| if(! $search) |
| return 0; |
| |
| $data = ldap_get_entries($ds, $search); |
| $newusergroups = array(); |
| if(! array_key_exists('memberof', $data[0])) |
| return; |
| for($i = 0; $i < $data[0]['memberof']['count']; $i++) { |
| if(preg_match('/^CN=(.+),OU=VCLGroups,DC=ad,DC=ncsu,DC=edu/', $data[0]['memberof'][$i], $match)) |
| array_push($newusergroups, getUserGroupID($match[1], $user['affiliationid'])); |
| } |
| $newusergroups = array_unique($newusergroups); |
| updateGroups($newusergroups, $user["id"]); |
| } |
| |
| If you add other affiliations that need to be tied in with LDAP, you can copy this |
| function and rename things in a similar fashion to match the new LDAP system. |
| |
| ### Some things to be aware of with mirrored groups |
| There are a few things to be aware of when working with mirrored groups in VCL. A |
| group isn't mirrored in to VCL until someone that is a member of the group logs in |
| to VCL, or a user with the membership is looked up using the **User Lookup** page. |
| So, what is generally suggest is to create an LDAP user that you make a member of |
| all user groups. Then, when you need to get a new group in to VCL, you can force |
| a lookup of that user on the **User Lookup** page. |
| |
| The second gotcha is that VCL |
| caches a user's LDAP information for up to 24 hours. So, if you log in to VCL, then add |
| yourself to a group on your LDAP server, you will have to wait for up to 24 hours |
| before VCL looks up your LDAP information again. Alternatively, you can |
| force a lookup on the **User Lookup** page. |
| |
| ### Debugging LDAP Configuration |
| If you run in to problems getting an LDAP configuration to work, |
| you can download a [LDAP Debug Script](/docs/generic.php.txt) and save it as generic.php (remove .txt |
| from the name) somewhere you can access it on you web server. There |
| are 5 variables at the top of the script that need to be set |
| according to your site's configuration. There is a comment in the |
| file explaining what each variable needs to be set to. Once you get |
| the script to show you search results, you should have a good idea |
| what you need to set the variables to in conf.php. |