wp-auth-ldap
Signed-off-by: Jeff <jeff@gotenzing.com>
Showing
9 changed files
with
1236 additions
and
0 deletions
wp-content/plugins/wp-auth-ldap/.gitignore
0 → 100644
wp-content/plugins/wp-auth-ldap/README.md
0 → 100644
| 1 | # authLDAP | ||
| 2 | |||
| 3 | [](https://gitter.im/heiglandreas/authLdap?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | ||
| 4 | |||
| 5 | Use your existing LDAP as authentication-backend for your wordpress! | ||
| 6 | |||
| 7 | [](https://travis-ci.org/heiglandreas/authLdap) | ||
| 8 | [](https://wordpress.org/plugins/authldap/stats/) | ||
| 9 | [](https://wordpress.org/plugins/authldap/) | ||
| 10 | [](https://wordpress.org/plugins/authldap/) | ||
| 11 | [](https://codeclimate.com/github/heiglandreas/authLdap) | ||
| 12 | [](https://codeclimate.com/github/heiglandreas/authLdap) | ||
| 13 | |||
| 14 | So what are the differences to other Wordpress-LDAP-Authentication-Plugins? | ||
| 15 | |||
| 16 | * **Flexible**: You are totaly free in which LDAP-backend to use. Due to the extensive configuration you can | ||
| 17 | freely decide how to do the authentication of your users. It simply depends on your | ||
| 18 | filters | ||
| 19 | * **Independent**: As soon as a user logs in, it is added/updated to the Wordpress' user-database | ||
| 20 | to allow wordpress to always use the correct data. You only have to administer your users once. | ||
| 21 | * **Failsafe**: Due to the users being created in Wordpress' User-database they can | ||
| 22 | also log in when the LDAP-backend currently is gone. | ||
| 23 | * **Role-Aware**: You can map Wordpress' roles to values of an existing LDAP-attribute. | ||
| 24 | |||
| 25 | ## How does the plugin work? | ||
| 26 | |||
| 27 | Well, as a matter of fact it is rather simple. The plugin verifies, that the user | ||
| 28 | seeking authentification can bind to the LDAP using the provided password. | ||
| 29 | |||
| 30 | If that is so, the user is either created or updated in the wordpress-user-database. | ||
| 31 | This update includes the provided password (so the wordpress can authenticate users | ||
| 32 | even without the LDAP), the users name according to the authLDAP-preferences and | ||
| 33 | the status of the user depending on the groups-settings of the authLDAP-preferences | ||
| 34 | |||
| 35 | Writing this plugin would not have been as easy as it has been, without the | ||
| 36 | wonderfull plugin of Alistair Young from http://www.weblogs.uhi.ac.uk/sm00ay/?p=45 | ||
| 37 | |||
| 38 | ## Configuration | ||
| 39 | |||
| 40 | ### Usage Settings | ||
| 41 | |||
| 42 | * **Enable Authentication via LDAP** Whether you want to enable authLdap for login or not | ||
| 43 | * **debug authLdap** When you have problems with authentication via LDAP you can enable a debugging mode here. | ||
| 44 | * **Save entered Password** Decide whether passwords will be cached in your wordpress-installation. **Attention:** Without the cache your users will not be able to log into your site when your LDAP is down! | ||
| 45 | |||
| 46 | ### Server Settings | ||
| 47 | |||
| 48 | * **LDAP Uri** This is the URI where your ldap-backend can be reached. More information are actually on the Configuration page | ||
| 49 | * **Filter** This is the real McCoy! The filter you define here specifies how a user will be found. Before applying the filter a %s will be replaced with the given username. This means, when a user logs in using ‘foobar’ as username the following happens: | ||
| 50 | |||
| 51 | * **uid=%s** check for any LDAP-Entry that has an attribute ‘uid’ with value ‘foobar’ | ||
| 52 | * **(&(objectclass=posixAccount)((!(uid=%s)(mail=%s)))** check for any LDAP-Entry that has an attribute ‘objectclass’ with value ‘posixAccout’ and either a UID- or a mail-attribute with value ‘foobar’ | ||
| 53 | |||
| 54 | This filter is rather powerfull if used wisely. | ||
| 55 | |||
| 56 | ### Creating Users | ||
| 57 | |||
| 58 | * **Name-Attribute** Which Attribute from the LDAP contains the Full or the First name of the user trying to log in. This defaults to name | ||
| 59 | * **Second Name Attribute** If the above Name-Attribute only contains the First Name of the user you can here specify an Attribute that contains the second name. This field is empty by default | ||
| 60 | * **User-ID Attribute** This field will be used as login-name for wordpress. Please give the Attribute, that is used to identify the user. This should be the same as you used in the above Filter-Option. This field defaults to uid | ||
| 61 | * **Mail Attribute** Which Attribute holds the eMail-Address of the user? If more than one eMail-Address are stored in the LDAP, only the first given is used. This field defaults to mail | ||
| 62 | * **Web-Attribute** If your users have a personal page (URI) stored in the LDAP, it can be provided here. This field is empty by default | ||
| 63 | |||
| 64 | ### User-Groups for Roles | ||
| 65 | |||
| 66 | * **Group-Attribute** This is the attribute that defines the Group-ID that can be matched against the Groups defined further down This field defaults to gidNumber. | ||
| 67 | * **Group-Filter** Here you can add the filter for selecting groups for the currentlly logged in user The Filter should contain the string %s which will be replaced by the login-name of the currently logged in | ||
| 68 | |||
| 69 | |||
| 70 | ## FAQ | ||
| 71 | |||
| 72 | <dl> | ||
| 73 | <dt>Can I change a users password with this plugin?</dt> | ||
| 74 | <dd>Short Answer: <strong>No</strong>!<br>Long Answer: As the users credentials are not | ||
| 75 | only used for a wordpress-site when you authenticate against an LDAP but for | ||
| 76 | many other services also chances are great that there is a centralized place | ||
| 77 | where password-changes shall be made. We'll later allow inclusion of a link | ||
| 78 | to such a place but currently it's not available. And as password-hashing and | ||
| 79 | where to store it requires deeper insight into the LDAP-Server then most users | ||
| 80 | have and admins are willing to give, password changes are out of scope of this | ||
| 81 | plugin. If you know exactyl what you do, you might want to have a look at | ||
| 82 | <a href="https://github.com/heiglandreas/authLdap/issues/54#issuecomment-125851029"> | ||
| 83 | issue 54</a> | ||
| 84 | wherer a way of adding it is described! | ||
| 85 | </dd> | ||
| 86 | <dt>Can I add a user to the LDAP when she creates a user-account on wordpress?</dt> | ||
| 87 | <dd>Short Answer: <strong>No</strong>!<br>Long Answer: Even though that is technically possible | ||
| 88 | it's not in the scope of this plugin. As creating a user in an LDAP often involves | ||
| 89 | an administrative process that has already been implemented in your departments | ||
| 90 | administration it doesn't make sense to rebuild that - in most cases highly | ||
| 91 | individual - process in this plugin. If you know exactly what you do, have a look at | ||
| 92 | <a href="https://github.com/heiglandreas/authLdap/issues/65">issue 65</a> | ||
| 93 | where <a href="https://github.com/wtfiwtz">wtfiwtz</a> shows how to implement that feature. | ||
| 94 | </dd> | ||
| 95 | </dl> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
wp-content/plugins/wp-auth-ldap/VERSION
0 → 100644
| 1 | 1.4.20 | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | { | ||
| 2 | "name" : "lampo/wp-auth-ldap", | ||
| 3 | "type" : "wordpress-plugin", | ||
| 4 | "description": "Fork of http://github.com/heiglandreas/authLdap, moves settings to defined constants.", | ||
| 5 | "keywords": ["ldap","authenticate", "auth", "wordpress"], | ||
| 6 | "homepage": "http://github.com/lampo/wp-auth-ldap", | ||
| 7 | "license": "MIT", | ||
| 8 | "authors": [{ | ||
| 9 | "name": "Andreas Heigl", | ||
| 10 | "email": "andreas@heigl.org", | ||
| 11 | "homepage": "http://andreas.heigl.org", | ||
| 12 | "role": "Developer" | ||
| 13 | },{ | ||
| 14 | "name": "Micah Flatt", | ||
| 15 | "email": "mflatt@flattware.net", | ||
| 16 | "role": "Developer" | ||
| 17 | }], | ||
| 18 | "require" : { | ||
| 19 | "php": ">=5.4", | ||
| 20 | "composer/installers": "~1.0" | ||
| 21 | }, | ||
| 22 | "autoload" : { | ||
| 23 | "psr-4" : { | ||
| 24 | "Org_Heigl\\AuthLdap\\" : "./" | ||
| 25 | } | ||
| 26 | } | ||
| 27 | } |
wp-content/plugins/wp-auth-ldap/ldap.php
0 → 100644
| 1 | <?php | ||
| 2 | /** | ||
| 3 | * $Id: ldap.php 381646 2011-05-06 09:37:31Z heiglandreas $ | ||
| 4 | * | ||
| 5 | * authLdap - Authenticate Wordpress against an LDAP-Backend. | ||
| 6 | * Copyright (c) 2008 Andreas Heigl<andreas@heigl.org> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU General Public License | ||
| 10 | * as published by the Free Software Foundation; either version 2 | ||
| 11 | * of the License, or (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
| 21 | * | ||
| 22 | * This file handles the basic LDAP-Tasks | ||
| 23 | * | ||
| 24 | * @author Andreas Heigl<andreas@heigl.org> | ||
| 25 | * @package authLdap | ||
| 26 | * @category authLdap | ||
| 27 | * @since 2008 | ||
| 28 | */ | ||
| 29 | namespace Org_Heigl\AuthLdap; | ||
| 30 | |||
| 31 | use Exception; | ||
| 32 | |||
| 33 | class LDAP | ||
| 34 | { | ||
| 35 | private $_server = ''; | ||
| 36 | |||
| 37 | private $_scheme = 'ldap'; | ||
| 38 | |||
| 39 | private $_port = 389; | ||
| 40 | |||
| 41 | private $_baseDn = ''; | ||
| 42 | |||
| 43 | private $_debug = false; | ||
| 44 | /** | ||
| 45 | * This property contains the connection handle to the ldap-server | ||
| 46 | * | ||
| 47 | * @var Ressource | ||
| 48 | */ | ||
| 49 | private $_ch = null; | ||
| 50 | |||
| 51 | private $_username = ''; | ||
| 52 | |||
| 53 | private $_password = ''; | ||
| 54 | |||
| 55 | private $_starttls = false; | ||
| 56 | |||
| 57 | public function __construct($URI, $debug = false, $starttls = false) | ||
| 58 | { | ||
| 59 | $this->_debug=$debug; | ||
| 60 | $array = parse_url($URI); | ||
| 61 | if (! is_array($array)) { | ||
| 62 | throw new Exception($URI . ' seems not to be a valid URI'); | ||
| 63 | } | ||
| 64 | $url = array_map(function ($item) { return urldecode($item); }, $array); | ||
| 65 | if (false === $url) { | ||
| 66 | throw new Exception($URI . ' is an invalid URL'); | ||
| 67 | } | ||
| 68 | if (! isset ( $url['scheme'] )) { | ||
| 69 | throw new Exception($URI . ' does not provide a scheme'); | ||
| 70 | } | ||
| 71 | if (0 !== strpos($url['scheme'], 'ldap')) { | ||
| 72 | throw new Exception($URI . ' is an invalid LDAP-URI'); | ||
| 73 | } | ||
| 74 | if (! isset ( $url['host'] )) { | ||
| 75 | throw new Exception($URI . ' does not provide a server'); | ||
| 76 | } | ||
| 77 | if (! isset ( $url['path'] )) { | ||
| 78 | throw new Exception($URI . ' does not provide a search-base'); | ||
| 79 | } | ||
| 80 | if (1 == strlen($url['path'])) { | ||
| 81 | throw new Exception($URI . ' does not provide a valid search-base'); | ||
| 82 | } | ||
| 83 | $this -> _server = $url['host']; | ||
| 84 | $this -> _scheme = $url['scheme']; | ||
| 85 | $this -> _baseDn = substr($url['path'], 1); | ||
| 86 | if (isset ( $url['user'] )) { | ||
| 87 | $this -> _username = $url['user']; | ||
| 88 | } | ||
| 89 | if ('' == trim($this -> _username)) { | ||
| 90 | $this -> _username = 'anonymous'; | ||
| 91 | } | ||
| 92 | if (isset ( $url['pass'] )) { | ||
| 93 | $this -> _password = $url['pass']; | ||
| 94 | } | ||
| 95 | if (isset ( $url['port'] )) { | ||
| 96 | $this -> _port = $url['port']; | ||
| 97 | } | ||
| 98 | $this->_starttls = $starttls; | ||
| 99 | } | ||
| 100 | |||
| 101 | /** | ||
| 102 | * Connect to the given LDAP-Server | ||
| 103 | * | ||
| 104 | * @return LDAP | ||
| 105 | * @throws AuthLdap_Exception | ||
| 106 | */ | ||
| 107 | public function connect() | ||
| 108 | { | ||
| 109 | $this -> disconnect(); | ||
| 110 | if ('ldaps' == $this->_scheme && 389 == $this->_port) { | ||
| 111 | $this->_port = 636; | ||
| 112 | } | ||
| 113 | |||
| 114 | $this->_ch = @ldap_connect($this->_scheme . '://' . $this->_server . ':' . $this -> _port); | ||
| 115 | if (! $this->_ch) { | ||
| 116 | throw new AuthLDAP_Exception('Could not connect to the server'); | ||
| 117 | } | ||
| 118 | ldap_set_option($this->_ch, LDAP_OPT_PROTOCOL_VERSION, 3); | ||
| 119 | ldap_set_option($this->_ch, LDAP_OPT_REFERRALS, 0); | ||
| 120 | //if configured try to upgrade encryption to tls for ldap connections | ||
| 121 | if ($this->_starttls) { | ||
| 122 | ldap_start_tls($this->_ch); | ||
| 123 | } | ||
| 124 | return $this; | ||
| 125 | } | ||
| 126 | |||
| 127 | /** | ||
| 128 | * Disconnect from a resource if one is available | ||
| 129 | * | ||
| 130 | * @return LDAP | ||
| 131 | */ | ||
| 132 | public function disconnect() | ||
| 133 | { | ||
| 134 | if (is_resource($this->_ch)) { | ||
| 135 | @ldap_unbind($this->_ch); | ||
| 136 | } | ||
| 137 | $this->_ch = null; | ||
| 138 | return $this; | ||
| 139 | } | ||
| 140 | |||
| 141 | /** | ||
| 142 | * Bind to an LDAP-Server with the given credentials | ||
| 143 | * | ||
| 144 | * @return LDAP | ||
| 145 | * @throw AuthLdap_Exception | ||
| 146 | */ | ||
| 147 | public function bind() | ||
| 148 | { | ||
| 149 | if (! $this->_ch) { | ||
| 150 | $this->connect(); | ||
| 151 | } | ||
| 152 | if (! is_resource($this->_ch)) { | ||
| 153 | throw new AuthLDAP_Exception('No Resource-handle given'); | ||
| 154 | } | ||
| 155 | $bind = false; | ||
| 156 | if (( ( $this->_username ) | ||
| 157 | && ( $this->_username != 'anonymous') ) | ||
| 158 | && ( $this->_password != '' ) ) { | ||
| 159 | $bind = @ldap_bind($this->_ch, $this->_username, $this->_password); | ||
| 160 | } else { | ||
| 161 | $bind = @ldap_bind($this->_ch); | ||
| 162 | } | ||
| 163 | if (! $bind) { | ||
| 164 | throw new AuthLDAP_Exception('bind was not successfull: ' . ldap_error($this->_ch)); | ||
| 165 | } | ||
| 166 | return $this; | ||
| 167 | } | ||
| 168 | |||
| 169 | public function getErrorNumber() | ||
| 170 | { | ||
| 171 | return @ldap_errno($this->_ch); | ||
| 172 | } | ||
| 173 | |||
| 174 | public function getErrorText() | ||
| 175 | { | ||
| 176 | return @ldap_error($this->_ch); | ||
| 177 | } | ||
| 178 | |||
| 179 | /** | ||
| 180 | * This method does the actual ldap-serch. | ||
| 181 | * | ||
| 182 | * This is using the filter <var>$filter</var> for retrieving the attributes | ||
| 183 | * <var>$attributes</var> | ||
| 184 | * | ||
| 185 | * | ||
| 186 | * @param string $filter | ||
| 187 | * @param array $attributes | ||
| 188 | * @return array | ||
| 189 | */ | ||
| 190 | public function search($filter, $attributes = array('uid')) | ||
| 191 | { | ||
| 192 | if (! is_Resource($this->_ch)) { | ||
| 193 | throw new AuthLDAP_Exception('No resource handle avbailable'); | ||
| 194 | } | ||
| 195 | $result = @ldap_search($this->_ch, $this->_baseDn, $filter, $attributes); | ||
| 196 | if ($result === false) { | ||
| 197 | throw new AuthLDAP_Exception('no result found'); | ||
| 198 | } | ||
| 199 | $this->_info = @ldap_get_entries($this->_ch, $result); | ||
| 200 | if ($this->_info === false) { | ||
| 201 | throw new AuthLDAP_Exception('invalid results found'); | ||
| 202 | } | ||
| 203 | return $this -> _info; | ||
| 204 | } | ||
| 205 | |||
| 206 | /** | ||
| 207 | * This method sets debugging to ON | ||
| 208 | */ | ||
| 209 | public function debugOn() | ||
| 210 | { | ||
| 211 | $this->_debug = true; | ||
| 212 | return $this; | ||
| 213 | } | ||
| 214 | |||
| 215 | /** | ||
| 216 | * This method sets debugging to OFF | ||
| 217 | */ | ||
| 218 | public function debugOff() | ||
| 219 | { | ||
| 220 | $this->_debug = false; | ||
| 221 | return $this; | ||
| 222 | } | ||
| 223 | |||
| 224 | /** | ||
| 225 | * This method authenticates the user <var>$username</var> using the | ||
| 226 | * password <var>$password</var> | ||
| 227 | * | ||
| 228 | * @param string $username | ||
| 229 | * @param string $password | ||
| 230 | * @param string $filter OPTIONAL This parameter defines the Filter to be used | ||
| 231 | * when searchin for the username. This MUST contain the string '%s' which | ||
| 232 | * will be replaced by the vaue given in <var>$username</var> | ||
| 233 | * @return boolean true or false depending on successfull authentication or not | ||
| 234 | */ | ||
| 235 | public function authenticate($username, $password, $filter = '(uid=%s)') | ||
| 236 | { | ||
| 237 | //return true; | ||
| 238 | $this->connect(); | ||
| 239 | $this->bind(); | ||
| 240 | $res = $this->search(sprintf($filter, $username)); | ||
| 241 | if (! $res || ! is_array($res) || ( $res ['count'] != 1 )) { | ||
| 242 | return false; | ||
| 243 | } | ||
| 244 | $dn = $res[0]['dn']; | ||
| 245 | if ($username && $password) { | ||
| 246 | if (@ldap_bind($this->_ch, $dn, $password)) { | ||
| 247 | return true; | ||
| 248 | } | ||
| 249 | } | ||
| 250 | return false; | ||
| 251 | } | ||
| 252 | /** | ||
| 253 | * $this method loggs errors if debugging is set to ON | ||
| 254 | */ | ||
| 255 | public function logError() | ||
| 256 | { | ||
| 257 | if ($this->_debug) { | ||
| 258 | $_v = debug_backtrace(); | ||
| 259 | throw new AuthLDAP_Exception('[LDAP_ERROR]' . ldap_errno($this->_ch) . ':' . ldap_error($this->_ch), $_v[0]['line']); | ||
| 260 | } | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 264 | class AuthLDAP_Exception extends Exception | ||
| 265 | { | ||
| 266 | public function __construct($message, $line = null) | ||
| 267 | { | ||
| 268 | parent :: __construct($message); | ||
| 269 | if ($line) { | ||
| 270 | $this -> line = $line; | ||
| 271 | } | ||
| 272 | } | ||
| 273 | } |
wp-content/plugins/wp-auth-ldap/readme.txt
0 → 100644
| 1 | === authLdap === | ||
| 2 | Contributors: heiglandreas | ||
| 3 | Tags: ldap, auth | ||
| 4 | Requires at least: 2.5.0 | ||
| 5 | Tested up to: 4.6.1 | ||
| 6 | Stable tag: trunk | ||
| 7 | |||
| 8 | Use your existing LDAP flexible as authentication backend for WordPress | ||
| 9 | |||
| 10 | == Description == | ||
| 11 | |||
| 12 | Use your existing LDAP as authentication-backend for your wordpress! | ||
| 13 | |||
| 14 | So what are the differences to other Wordpress-LDAP-Authentication-Plugins? | ||
| 15 | |||
| 16 | * Flexible: You are totaly free in which LDAP-backend to use. Due to the extensive configuration you can | ||
| 17 | freely decide how to do the authentication of your users. It simply depends on your | ||
| 18 | filters | ||
| 19 | * Independent: As soon as a user logs in, it is added/updated to the Wordpress' user-database | ||
| 20 | to allow wordpress to always use the correct data. You only have to administer your users once. | ||
| 21 | * Failsafe: Due to the users being created in Wordpress' User-database they can | ||
| 22 | also log in when the LDAP-backend currently is gone. | ||
| 23 | * Role-Aware: You can map Wordpress' roles to values of an existing LDAP-attribute. | ||
| 24 | |||
| 25 | For more Information on the configuration have a look at https://github.com/heiglandreas/authLdap | ||
| 26 | |||
| 27 | == Installation == | ||
| 28 | |||
| 29 | 1. Upload the extracted folder `authLdap` to the `/wp-content/plugins/` directory | ||
| 30 | 2. Activate the plugin through the 'Plugins' menu in WordPress | ||
| 31 | 3. Configure the Plugin via the 'authLdap'-Configuration-Page. | ||
| 32 | |||
| 33 | == Frequently Asked Questions == | ||
| 34 | |||
| 35 | = Where can I find more Informations about the plugin? = | ||
| 36 | |||
| 37 | Go to https://github.com/heiglandreas/authLdap | ||
| 38 | |||
| 39 | = Where can I report issues with the plugin? = | ||
| 40 | |||
| 41 | Please use the issuetracker at https://github.com/heiglandreas/authLdap/issues | ||
| 42 | |||
| 43 | == Changelog == | ||
| 44 | = 1.4.20 = | ||
| 45 | * Allows multiple LDAP-servers to be queried (given that they use the same attributes) | ||
| 46 | * Fixes issue with URL-Encoded informations (see https://github.com/heiglandreas/authLdap/issues/108) | ||
| 47 | |||
| 48 | = 1.4.19 = | ||
| 49 | * Adds support for TLS | ||
| 50 | |||
| 51 | = 1.4.14 = | ||
| 52 | * Update to showing password-fields check (thanks to @chaplina) | ||
| 53 | |||
| 54 | = 1.4.13 = | ||
| 55 | * Removed generation of default email-address (thanks to @henryk) | ||
| 56 | * Fixes password-hashing when caching passwords (thanks to @litinoveweedle) | ||
| 57 | * Removes the possibility to reset a password for LDAP-based users (thanks to @chaplina) | ||
| 58 | * Removes the password-change-Email from 4.3 on (thanks to @litinoveweedle) | ||
| 59 | * Fixes double authentication-attempt (that resulted in failed authentication) (thanks to @litinoveweedle) | ||
| 60 | |||
| 61 | = 1.4.10 = | ||
| 62 | * Cleanup by removing deprecated code | ||
| 63 | * Fixes issues with undefined variables | ||
| 64 | * Enables internal option-versioning | ||
| 65 | * Setting users nickname initially to the realname instead of the uid | ||
| 66 | * Fixes display of password-change possibility in users profile-page | ||
| 67 | = 1.4.9 = | ||
| 68 | * Fixed an issue with changing display name on every login | ||
| 69 | * Use proper way of looking up user-roles in setups w/o DB-prefix | ||
| 70 | = 1.4.8 = | ||
| 71 | * Updated version string | ||
| 72 | = 1.4.7 = | ||
| 73 | * Use default user to retrieve group menberships and not logging in user. | ||
| 74 | * return the UID from the LDAP instead of the value given by the user | ||
| 75 | * remove unnecessary checkbox | ||
| 76 | * Adds a testsuite | ||
| 77 | * Fixes PSR2 violations | ||
| 78 | |||
| 79 | […] | ||
| 80 | |||
| 81 | = 1.2.1 = | ||
| 82 | * Fixed an issue with group-ids | ||
| 83 | * Moved the code to GitHub (https://github.com/heiglandreas/authLdap) | ||
| 84 | = 1.1.0 = | ||
| 85 | * Changed the login-process. Now users that are not allowed to login due to | ||
| 86 | missing group-memberships are not created within your blog as was the standard | ||
| 87 | until Version 1.0.3 - Thanks to alex@tayts.com | ||
| 88 | * Changed the default mail-address that is created when no mail-address can be | ||
| 89 | retrieved from the LDAP from me@example.com to $username@example.com so that | ||
| 90 | a new user can be created even though the mail address already exists in your | ||
| 91 | blog - Also thanks to alex@tayts.com | ||
| 92 | * Added support for WordPress-Table-prefixes as the capabilities of a user | ||
| 93 | are interlany stored in a field that is named "$tablePrefix_capabilities" - | ||
| 94 | again thanks to alex@tayts.com and also to sim0n of silicium.mine.nu |
| 1 | <?php | ||
| 2 | /** | ||
| 3 | * Copyright (c) Andreas Heigl<andreas@heigl.org> | ||
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 5 | * of this software and associated documentation files (the "Software"), to deal | ||
| 6 | * in the Software without restriction, including without limitation the rights | ||
| 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 8 | * copies of the Software, and to permit persons to whom the Software is | ||
| 9 | * furnished to do so, subject to the following conditions: | ||
| 10 | * The above copyright notice and this permission notice shall be included in | ||
| 11 | * all copies or substantial portions of the Software. | ||
| 12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 13 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 14 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 15 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 16 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 18 | * THE SOFTWARE. | ||
| 19 | * | ||
| 20 | * @author Andreas Heigl<andreas@heigl.org> | ||
| 21 | * @copyright Andreas Heigl | ||
| 22 | * @license http://www.opensource.org/licenses/mit-license.php MIT-License | ||
| 23 | * @since 07.07.2016 | ||
| 24 | * @link http://github.com/heiglandreas/authLDAP | ||
| 25 | */ | ||
| 26 | |||
| 27 | namespace Org_Heigl\AuthLdap; | ||
| 28 | |||
| 29 | class LdapList | ||
| 30 | { | ||
| 31 | /** | ||
| 32 | * @var \LDAP[] | ||
| 33 | */ | ||
| 34 | protected $items = []; | ||
| 35 | |||
| 36 | public function addLdap(LDAP $ldap) | ||
| 37 | { | ||
| 38 | $this->items[] = $ldap; | ||
| 39 | } | ||
| 40 | |||
| 41 | public function authenticate($username, $password, $filter = '(uid=%s)') | ||
| 42 | { | ||
| 43 | foreach ($this->items as $key => $item) { | ||
| 44 | if (! $item->authenticate($username, $password, $filter)) { | ||
| 45 | unset ($this->items[$key]); | ||
| 46 | continue; | ||
| 47 | } | ||
| 48 | return true; | ||
| 49 | } | ||
| 50 | |||
| 51 | return false; | ||
| 52 | } | ||
| 53 | |||
| 54 | public function bind() | ||
| 55 | { | ||
| 56 | $allFailed = true; | ||
| 57 | foreach ($this->items as $key => $item) { | ||
| 58 | try { | ||
| 59 | $item->bind(); | ||
| 60 | } catch (\Exception $e) { | ||
| 61 | unset($this->items[$key]); | ||
| 62 | continue; | ||
| 63 | } | ||
| 64 | $allFailed = false; | ||
| 65 | } | ||
| 66 | |||
| 67 | if ($allFailed) { | ||
| 68 | throw new AuthLDAP_Exception('No bind successfull'); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | public function search($filter, $attributes = array('uid')) | ||
| 73 | { | ||
| 74 | foreach ($this->items as $item) { | ||
| 75 | try { | ||
| 76 | $result = $item->search($filter, $attributes); | ||
| 77 | return $result; | ||
| 78 | } catch (Exception $e) { | ||
| 79 | throw $e; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | throw new \AuthLDAP_Exception('No Results found'); | ||
| 84 | } | ||
| 85 | } | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | <?php | ||
| 2 | /* | ||
| 3 | Plugin Name: Lampo-AuthLDAP | ||
| 4 | Plugin URI: https://github.com/lampo/wp-auth-ldap | ||
| 5 | Description: This plugin allows you to use your existing LDAP as authentication base for WordPress | ||
| 6 | Version: 1.4.20 | ||
| 7 | Author: Andreas Heigl <a.heigl@wdv.de> | ||
| 8 | Author URI: http://andreas.heigl.org | ||
| 9 | */ | ||
| 10 | |||
| 11 | require_once dirname(__FILE__) . '/ldap.php'; | ||
| 12 | |||
| 13 | function authLdap_debug($message) | ||
| 14 | { | ||
| 15 | if (authLdap_get_option('Debug')) { | ||
| 16 | error_log('[AuthLDAP] ' . $message, 0); | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | |||
| 21 | function authLdap_get_post($name, $default = '') | ||
| 22 | { | ||
| 23 | return isset($_POST[$name]) ? $_POST[$name] : $default; | ||
| 24 | } | ||
| 25 | |||
| 26 | |||
| 27 | /** | ||
| 28 | * get a LDAP server object | ||
| 29 | * | ||
| 30 | * throws exception if there is a problem connecting | ||
| 31 | * | ||
| 32 | * @conf boolean authLDAPDebug true, if debugging should be turned on | ||
| 33 | * @conf string authLDAPURI LDAP server URI | ||
| 34 | * | ||
| 35 | * @return LDAP LDAP server object | ||
| 36 | */ | ||
| 37 | function authLdap_get_server() | ||
| 38 | { | ||
| 39 | static $_ldapserver = null; | ||
| 40 | if (is_null($_ldapserver)) { | ||
| 41 | $authLDAPDebug = authLdap_get_option('Debug'); | ||
| 42 | $authLDAPURI = explode( | ||
| 43 | authLdap_get_option('URISeparator', ' '), | ||
| 44 | authLdap_get_option('URI') | ||
| 45 | ); | ||
| 46 | $authLDAPStartTLS = authLdap_get_option('StartTLS'); | ||
| 47 | |||
| 48 | //$authLDAPURI = 'ldap:/foo:bar@server/trallala'; | ||
| 49 | authLdap_debug('connect to LDAP server'); | ||
| 50 | require_once dirname(__FILE__) . '/src/LdapList.php'; | ||
| 51 | $_ldapserver = new \Org_Heigl\AuthLdap\LdapList(); | ||
| 52 | foreach ($authLDAPURI as $uri) { | ||
| 53 | $_ldapserver->addLdap(new \Org_Heigl\AuthLdap\LDAP($uri, $authLDAPDebug, $authLDAPStartTLS)); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | return $_ldapserver; | ||
| 57 | } | ||
| 58 | |||
| 59 | |||
| 60 | /** | ||
| 61 | * This method authenticates a user using either the LDAP or, if LDAP is not | ||
| 62 | * available, the local database | ||
| 63 | * | ||
| 64 | * For this we store the hashed passwords in the WP_Database to ensure working | ||
| 65 | * conditions even without an LDAP-Connection | ||
| 66 | * | ||
| 67 | * @param null|WP_User|WP_Error | ||
| 68 | * @param string $username | ||
| 69 | * @param string $password | ||
| 70 | * @param boolean $already_md5 | ||
| 71 | * @return boolean true, if login was successfull or false, if it wasn't | ||
| 72 | * @conf boolean authLDAP true, if authLDAP should be used, false if not. Defaults to false | ||
| 73 | * @conf string authLDAPFilter LDAP filter to use to find correct user, defaults to '(uid=%s)' | ||
| 74 | * @conf string authLDAPNameAttr LDAP attribute containing user (display) name, defaults to 'name' | ||
| 75 | * @conf string authLDAPSecName LDAP attribute containing second name, defaults to '' | ||
| 76 | * @conf string authLDAPMailAttr LDAP attribute containing user e-mail, defaults to 'mail' | ||
| 77 | * @conf string authLDAPUidAttr LDAP attribute containing user id (the username we log on with), defaults to 'uid' | ||
| 78 | * @conf string authLDAPWebAttr LDAP attribute containing user website, defaults to '' | ||
| 79 | * @conf string authLDAPDefaultRole default role for authenticated user, defaults to '' | ||
| 80 | * @conf boolean authLDAPGroupEnable true, if we try to map LDAP groups to Wordpress roles | ||
| 81 | * @conf boolean authLDAPGroupOverUser true, if LDAP Groups have precedence over existing user roles | ||
| 82 | */ | ||
| 83 | function authLdap_login($user, $username, $password, $already_md5 = false) | ||
| 84 | { | ||
| 85 | // don't do anything when authLDAP is disabled | ||
| 86 | if (! authLdap_get_option('Enabled')) { | ||
| 87 | authLdap_debug('LDAP disabled in AuthLDAP plugin options (use the first option in the AuthLDAP options to enable it)'); | ||
| 88 | return $user; | ||
| 89 | } | ||
| 90 | |||
| 91 | // If the user has already been authenticated (only in that case we get a | ||
| 92 | // WP_User-Object as $user) we skip LDAP-authentication and simply return | ||
| 93 | // the existing user-object | ||
| 94 | if ($user instanceof WP_User) { | ||
| 95 | authLdap_debug(sprintf( | ||
| 96 | 'User %s has already been authenticated - skipping LDAP-Authentication', | ||
| 97 | $user->get('nickname'))); | ||
| 98 | return $user; | ||
| 99 | } | ||
| 100 | |||
| 101 | authLdap_debug("User '$username' logging in"); | ||
| 102 | |||
| 103 | if ($username == 'admin') { | ||
| 104 | authLdap_debug('Doing nothing for possible local user admin'); | ||
| 105 | return $user; | ||
| 106 | } | ||
| 107 | |||
| 108 | global $wpdb, $error; | ||
| 109 | try { | ||
| 110 | $authLDAP = authLdap_get_option('Enabled'); | ||
| 111 | $authLDAPFilter = authLdap_get_option('Filter'); | ||
| 112 | $authLDAPNameAttr = authLdap_get_option('NameAttr'); | ||
| 113 | $authLDAPSecName = authLdap_get_option('SecName'); | ||
| 114 | $authLDAPMailAttr = authLdap_get_option('MailAttr'); | ||
| 115 | $authLDAPUidAttr = authLdap_get_option('UidAttr'); | ||
| 116 | $authLDAPWebAttr = authLdap_get_option('WebAttr'); | ||
| 117 | $authLDAPDefaultRole = authLdap_get_option('DefaultRole'); | ||
| 118 | $authLDAPGroupEnable = authLdap_get_option('GroupEnable'); | ||
| 119 | $authLDAPGroupOverUser = authLdap_get_option('GroupOverUser'); | ||
| 120 | |||
| 121 | if (! $username) { | ||
| 122 | authLdap_debug('Username not supplied: return false'); | ||
| 123 | return false; | ||
| 124 | } | ||
| 125 | |||
| 126 | if (! $password) { | ||
| 127 | authLdap_debug('Password not supplied: return false'); | ||
| 128 | $error = __('<strong>Error</strong>: The password field is empty.'); | ||
| 129 | return false; | ||
| 130 | } | ||
| 131 | // First check for valid values and set appropriate defaults | ||
| 132 | if (! $authLDAPFilter) { | ||
| 133 | $authLDAPFilter = '(uid=%s)'; | ||
| 134 | } | ||
| 135 | if (! $authLDAPNameAttr) { | ||
| 136 | $authLDAPNameAttr = 'name'; | ||
| 137 | } | ||
| 138 | if (! $authLDAPMailAttr) { | ||
| 139 | $authLDAPMailAttr = 'mail'; | ||
| 140 | } | ||
| 141 | if (! $authLDAPUidAttr) { | ||
| 142 | $authLDAPUidAttr = 'uid'; | ||
| 143 | } | ||
| 144 | |||
| 145 | // If already_md5 is TRUE, then we're getting the user/password from the cookie. As we don't want to store LDAP passwords in any | ||
| 146 | // form, we've already replaced the password with the hashed username and LDAP_COOKIE_MARKER | ||
| 147 | if ($already_md5) { | ||
| 148 | if ($password == md5($username).md5($ldapCookieMarker)) { | ||
| 149 | authLdap_debug('cookie authentication'); | ||
| 150 | return true; | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | // No cookie, so have to authenticate them via LDAP | ||
| 155 | $result = false; | ||
| 156 | try { | ||
| 157 | authLdap_debug('about to do LDAP authentication'); | ||
| 158 | $result = authLdap_get_server()->Authenticate($username, $password, $authLDAPFilter); | ||
| 159 | } catch (Exception $e) { | ||
| 160 | authLdap_debug('LDAP authentication failed with exception: ' . $e->getMessage()); | ||
| 161 | return false; | ||
| 162 | } | ||
| 163 | |||
| 164 | // Rebind with the default credentials after the user has been loged in | ||
| 165 | // Otherwise the credentials of the user trying to login will be used | ||
| 166 | // This fixes #55 | ||
| 167 | authLdap_get_server()->bind(); | ||
| 168 | |||
| 169 | if (true !== $result) { | ||
| 170 | authLdap_debug('LDAP authentication failed'); | ||
| 171 | // TODO what to return? WP_User object, true, false, even an WP_Error object... all seem to fall back to normal wp user authentication | ||
| 172 | return; | ||
| 173 | } | ||
| 174 | |||
| 175 | authLdap_debug('LDAP authentication successfull'); | ||
| 176 | $attributes = array_values( | ||
| 177 | array_filter( | ||
| 178 | array( | ||
| 179 | $authLDAPNameAttr, | ||
| 180 | $authLDAPSecName, | ||
| 181 | $authLDAPMailAttr, | ||
| 182 | $authLDAPWebAttr, | ||
| 183 | $authLDAPUidAttr | ||
| 184 | ) | ||
| 185 | ) | ||
| 186 | ); | ||
| 187 | |||
| 188 | try { | ||
| 189 | $attribs = authLdap_get_server()->search( | ||
| 190 | sprintf($authLDAPFilter, $username), | ||
| 191 | $attributes | ||
| 192 | ); | ||
| 193 | // First get all the relevant group informations so we can see if | ||
| 194 | // whether have been changes in group association of the user | ||
| 195 | if (! isset($attribs[0]['dn'])) { | ||
| 196 | authLdap_debug('could not get user attributes from LDAP'); | ||
| 197 | throw new UnexpectedValueException('dn has not been returned'); | ||
| 198 | } | ||
| 199 | if (! isset($attribs[0][strtolower($authLDAPUidAttr)][0])) { | ||
| 200 | authLdap_debug('could not get user attributes from LDAP'); | ||
| 201 | throw new UnexpectedValueException('The user-ID attribute has not been returned'); | ||
| 202 | |||
| 203 | } | ||
| 204 | |||
| 205 | $dn = $attribs[0]['dn']; | ||
| 206 | $realuid = $attribs[0][strtolower($authLDAPUidAttr)][0]; | ||
| 207 | } catch (Exception $e) { | ||
| 208 | authLdap_debug('Exception getting LDAP user: ' . $e->getMessage()); | ||
| 209 | return false; | ||
| 210 | } | ||
| 211 | |||
| 212 | $uid = authLdap_get_uid($realuid); | ||
| 213 | $role = ''; | ||
| 214 | |||
| 215 | // we only need this if either LDAP groups are disabled or | ||
| 216 | // if the WordPress role of the user overrides LDAP groups | ||
| 217 | if (!$authLDAPGroupEnable || !$authLDAPGroupOverUser) { | ||
| 218 | $role = authLdap_user_role($uid); | ||
| 219 | } | ||
| 220 | |||
| 221 | // do LDAP group mapping if needed | ||
| 222 | // (if LDAP groups override worpress user role, $role is still empty) | ||
| 223 | if (empty($role) && $authLDAPGroupEnable) { | ||
| 224 | $role = authLdap_groupmap($realuid, $dn); | ||
| 225 | authLdap_debug('role from group mapping: ' . $role); | ||
| 226 | } | ||
| 227 | |||
| 228 | // if we don't have a role yet, use default role | ||
| 229 | if (empty($role) && !empty($authLDAPDefaultRole)) { | ||
| 230 | authLdap_debug('no role yet, set default role'); | ||
| 231 | $role = $authLDAPDefaultRole; | ||
| 232 | } | ||
| 233 | |||
| 234 | if (empty($role)) { | ||
| 235 | // Sorry, but you are not in any group that is allowed access | ||
| 236 | trigger_error('no group found'); | ||
| 237 | authLdap_debug('user is not in any group that is allowed access'); | ||
| 238 | return false; | ||
| 239 | } else { | ||
| 240 | $roles = new WP_Roles(); | ||
| 241 | // not sure if this is needed, but it can't hurt | ||
| 242 | if (!$roles->is_role($role)) { | ||
| 243 | trigger_error('no group found'); | ||
| 244 | authLdap_debug('role is invalid'); | ||
| 245 | return false; | ||
| 246 | } | ||
| 247 | } | ||
| 248 | |||
| 249 | // from here on, the user has access! | ||
| 250 | // now, lets update some user details | ||
| 251 | $user_info = array(); | ||
| 252 | $user_info['user_login'] = $realuid; | ||
| 253 | $user_info['role'] = $role; | ||
| 254 | $user_info['user_email'] = ''; | ||
| 255 | |||
| 256 | // first name | ||
| 257 | if (isset($attribs[0][strtolower($authLDAPNameAttr)][0])) { | ||
| 258 | $user_info['first_name'] = $attribs[0][strtolower($authLDAPNameAttr)][0]; | ||
| 259 | } | ||
| 260 | |||
| 261 | // last name | ||
| 262 | if (isset($attribs[0][strtolower($authLDAPSecName)][0])) { | ||
| 263 | $user_info['last_name'] = $attribs[0][strtolower($authLDAPSecName)][0]; | ||
| 264 | } | ||
| 265 | |||
| 266 | // mail address | ||
| 267 | if (isset($attribs[0][strtolower($authLDAPMailAttr)][0])) { | ||
| 268 | $user_info['user_email'] = $attribs[0][strtolower($authLDAPMailAttr)][0]; | ||
| 269 | } | ||
| 270 | |||
| 271 | // website | ||
| 272 | if (isset($attribs[0][strtolower($authLDAPWebAttr)][0])) { | ||
| 273 | $user_info['user_url'] = $attribs[0][strtolower($authLDAPWebAttr)][0]; | ||
| 274 | } | ||
| 275 | |||
| 276 | // display name, nickname, nicename | ||
| 277 | if (array_key_exists('first_name', $user_info)) { | ||
| 278 | $user_info['display_name'] = $user_info['first_name']; | ||
| 279 | $user_info['nickname'] = $user_info['first_name']; | ||
| 280 | $user_info['user_nicename'] = sanitize_title_with_dashes($user_info['first_name']); | ||
| 281 | if (array_key_exists('last_name', $user_info)) { | ||
| 282 | $user_info['display_name'] .= ' ' . $user_info['last_name']; | ||
| 283 | $user_info['nickname'] .= ' ' . $user_info['last_name']; | ||
| 284 | $user_info['user_nicename'] .= '_' . sanitize_title_with_dashes($user_info['last_name']); | ||
| 285 | } | ||
| 286 | } | ||
| 287 | |||
| 288 | // optionally store the password into the wordpress database | ||
| 289 | if (authLdap_get_option('CachePW')) { | ||
| 290 | // Password will be hashed inside wp_update_user or wp_insert_user | ||
| 291 | $user_info['user_pass'] = $password; | ||
| 292 | } else { | ||
| 293 | // clear the password | ||
| 294 | $user_info['user_pass'] = ''; | ||
| 295 | } | ||
| 296 | |||
| 297 | // add uid if user exists | ||
| 298 | if ($uid) { | ||
| 299 | // found user in the database | ||
| 300 | authLdap_debug('The LDAP user has an entry in the WP-Database'); | ||
| 301 | $user_info['ID'] = $uid; | ||
| 302 | unset ($user_info['display_name'], $user_info['nickname']); | ||
| 303 | $userid = wp_update_user($user_info); | ||
| 304 | } else { | ||
| 305 | // new wordpress account will be created | ||
| 306 | authLdap_debug('The LDAP user does not have an entry in the WP-Database, a new WP account will be created'); | ||
| 307 | |||
| 308 | $userid = wp_insert_user($user_info); | ||
| 309 | } | ||
| 310 | |||
| 311 | // if the user exists, wp_insert_user will update the existing user record | ||
| 312 | if (is_wp_error($userid)) { | ||
| 313 | authLdap_debug('Error creating user : ' . $userid->get_error_message()); | ||
| 314 | trigger_error('Error creating user: ' . $userid->get_error_message()); | ||
| 315 | return $userid; | ||
| 316 | } | ||
| 317 | |||
| 318 | authLdap_debug('user id = ' . $userid); | ||
| 319 | |||
| 320 | // flag the user as an ldap user so we can hide the password fields in the user profile | ||
| 321 | update_user_meta($userid, 'authLDAP', true); | ||
| 322 | |||
| 323 | // return a user object upon positive authorization | ||
| 324 | return new WP_User($userid); | ||
| 325 | } catch (Exception $e) { | ||
| 326 | authLdap_debug($e->getMessage() . '. Exception thrown in line ' . $e->getLine()); | ||
| 327 | trigger_error($e->getMessage() . '. Exception thrown in line ' . $e->getLine()); | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | /** | ||
| 332 | * Get user's user id | ||
| 333 | * | ||
| 334 | * Returns null if username not found | ||
| 335 | * | ||
| 336 | * @param string $username username | ||
| 337 | * @param string user id, null if not found | ||
| 338 | */ | ||
| 339 | function authLdap_get_uid($username) | ||
| 340 | { | ||
| 341 | global $wpdb; | ||
| 342 | |||
| 343 | // find out whether the user is already present in the database | ||
| 344 | $uid = $wpdb->get_var( | ||
| 345 | $wpdb->prepare( | ||
| 346 | "SELECT ID FROM {$wpdb->users} WHERE user_login = %s", | ||
| 347 | $username | ||
| 348 | ) | ||
| 349 | ); | ||
| 350 | if ($uid) { | ||
| 351 | authLdap_debug("Existing user, uid = {$uid}"); | ||
| 352 | return $uid; | ||
| 353 | } else { | ||
| 354 | return null; | ||
| 355 | } | ||
| 356 | } | ||
| 357 | |||
| 358 | /** | ||
| 359 | * Get the user's current role | ||
| 360 | * | ||
| 361 | * Returns empty string if not found. | ||
| 362 | * | ||
| 363 | * @param int $uid wordpress user id | ||
| 364 | * @return string role, empty if none found | ||
| 365 | */ | ||
| 366 | function authLdap_user_role($uid) | ||
| 367 | { | ||
| 368 | global $wpdb; | ||
| 369 | |||
| 370 | if (!$uid) { | ||
| 371 | return ''; | ||
| 372 | } | ||
| 373 | |||
| 374 | $meta_value = $wpdb->get_var("SELECT meta_value FROM {$wpdb->usermeta} WHERE meta_key = '{$wpdb->prefix}capabilities' AND user_id = {$uid}"); | ||
| 375 | |||
| 376 | if (!$meta_value) { | ||
| 377 | return ''; | ||
| 378 | } | ||
| 379 | |||
| 380 | $capabilities = unserialize($meta_value); | ||
| 381 | $roles = is_array($capabilities) ? array_keys($capabilities) : array(''); | ||
| 382 | $role = $roles[0]; | ||
| 383 | |||
| 384 | authLdap_debug("Existing user's role: {$role}"); | ||
| 385 | return $role; | ||
| 386 | } | ||
| 387 | |||
| 388 | /** | ||
| 389 | * Get LDAP groups for user and map to role | ||
| 390 | * | ||
| 391 | * @param string $username | ||
| 392 | * @param string $dn | ||
| 393 | * @return string role, empty string if no mapping found, first found role otherwise | ||
| 394 | * @conf array authLDAPGroups, associative array, role => ldap_group | ||
| 395 | * @conf string authLDAPGroupAttr, ldap attribute that holds name of group | ||
| 396 | * @conf string authLDAPGroupFilter, LDAP filter to find groups. can contain %s and %dn% placeholders | ||
| 397 | */ | ||
| 398 | function authLdap_groupmap($username, $dn) | ||
| 399 | { | ||
| 400 | $authLDAPGroups = authLdap_sort_roles_by_capabilities( | ||
| 401 | authLdap_get_option('Groups') | ||
| 402 | ); | ||
| 403 | $authLDAPGroupAttr = authLdap_get_option('GroupAttr'); | ||
| 404 | $authLDAPGroupFilter = authLdap_get_option('GroupFilter'); | ||
| 405 | $authLDAPGroupSeparator = authLdap_get_option('GroupSeparator'); | ||
| 406 | if (! $authLDAPGroupAttr) { | ||
| 407 | $authLDAPGroupAttr = 'gidNumber'; | ||
| 408 | } | ||
| 409 | if (! $authLDAPGroupFilter) { | ||
| 410 | $authLDAPGroupFilter = '(&(objectClass=posixGroup)(memberUid=%s))'; | ||
| 411 | } | ||
| 412 | if (! $authLDAPGroupSeparator) { | ||
| 413 | $authLDAPGroupSeparator = ','; | ||
| 414 | } | ||
| 415 | |||
| 416 | if (!is_array($authLDAPGroups) || count(array_filter(array_values($authLDAPGroups))) == 0) { | ||
| 417 | authLdap_debug('No group names defined'); | ||
| 418 | return ''; | ||
| 419 | } | ||
| 420 | |||
| 421 | try { | ||
| 422 | // To allow searches based on the DN instead of the uid, we replace the | ||
| 423 | // string %dn% with the users DN. | ||
| 424 | $authLDAPGroupFilter = str_replace('%dn%', $dn, $authLDAPGroupFilter); | ||
| 425 | authLdap_debug('Group Filter: ' . json_encode($authLDAPGroupFilter)); | ||
| 426 | $groups = authLdap_get_server()->search(sprintf($authLDAPGroupFilter, $username), array($authLDAPGroupAttr)); | ||
| 427 | } catch (Exception $e) { | ||
| 428 | authLdap_debug('Exception getting LDAP group attributes: ' . $e->getMessage()); | ||
| 429 | return ''; | ||
| 430 | } | ||
| 431 | |||
| 432 | $grp = array(); | ||
| 433 | for ($i = 0; $i < $groups ['count']; $i++) { | ||
| 434 | for ($k = 0; $k < $groups[$i][strtolower($authLDAPGroupAttr)]['count']; $k++) { | ||
| 435 | $grp[] = $groups[$i][strtolower($authLDAPGroupAttr)][$k]; | ||
| 436 | } | ||
| 437 | } | ||
| 438 | |||
| 439 | authLdap_debug('LDAP groups: ' . json_encode($grp)); | ||
| 440 | |||
| 441 | // Check whether the user is member of one of the groups that are | ||
| 442 | // allowed acces to the blog. If the user is not member of one of | ||
| 443 | // The groups throw her out! ;-) | ||
| 444 | // If the user is member of more than one group only the first one | ||
| 445 | // will be taken into account! | ||
| 446 | |||
| 447 | $role = ''; | ||
| 448 | foreach ($authLDAPGroups as $key => $val) { | ||
| 449 | $currentGroup = explode($authLDAPGroupSeparator, $val); | ||
| 450 | // Remove whitespaces around the group-ID | ||
| 451 | $currentGroup = array_map('trim', $currentGroup); | ||
| 452 | if (0 < count(array_intersect($currentGroup, $grp))) { | ||
| 453 | $role = $key; | ||
| 454 | break; | ||
| 455 | } | ||
| 456 | } | ||
| 457 | |||
| 458 | authLdap_debug("Role from LDAP group: {$role}"); | ||
| 459 | return $role; | ||
| 460 | } | ||
| 461 | |||
| 462 | /** | ||
| 463 | * This function disables the password-change fields in the users preferences. | ||
| 464 | * | ||
| 465 | * It does not make sense to authenticate via LDAP and then allow the user to | ||
| 466 | * change the password only in the wordpress database. And changing the password | ||
| 467 | * LDAP-wide can not be the scope of Wordpress! | ||
| 468 | * | ||
| 469 | * Whether the user is an LDAP-User or not is determined using the authLDAP-Flag | ||
| 470 | * of the users meta-informations | ||
| 471 | * | ||
| 472 | * @return false, if the user whose prefs are viewed is an LDAP-User, true if | ||
| 473 | * he isn't | ||
| 474 | * @conf boolean authLDAP | ||
| 475 | */ | ||
| 476 | function authLdap_show_password_fields($return, $user) | ||
| 477 | { | ||
| 478 | if (! $user) { | ||
| 479 | return true; | ||
| 480 | } | ||
| 481 | |||
| 482 | if (get_user_meta($user->ID, 'authLDAP')) { | ||
| 483 | return false; | ||
| 484 | } | ||
| 485 | |||
| 486 | return $return; | ||
| 487 | } | ||
| 488 | |||
| 489 | /** | ||
| 490 | * This function disables the password reset for a user. | ||
| 491 | * | ||
| 492 | * It does not make sense to authenticate via LDAP and then allow the user to | ||
| 493 | * reset the password only in the wordpress database. And changing the password | ||
| 494 | * LDAP-wide can not be the scope of Wordpress! | ||
| 495 | * | ||
| 496 | * Whether the user is an LDAP-User or not is determined using the authLDAP-Flag | ||
| 497 | * of the users meta-informations | ||
| 498 | * | ||
| 499 | * @author chaplina (https://github.com/chaplina) | ||
| 500 | * @conf boolean authLDAP | ||
| 501 | * @return false, if the user is an LDAP-User, true if he isn't | ||
| 502 | */ | ||
| 503 | function authLdap_allow_password_reset($return, $userid) | ||
| 504 | { | ||
| 505 | if (!(isset($userid))) { | ||
| 506 | return true; | ||
| 507 | } | ||
| 508 | |||
| 509 | if (get_user_meta($userid, 'authLDAP')) { | ||
| 510 | return false; | ||
| 511 | } | ||
| 512 | return $return; | ||
| 513 | } | ||
| 514 | |||
| 515 | /** | ||
| 516 | * Sort the given roles by number of capabilities | ||
| 517 | * | ||
| 518 | * @param array $roles | ||
| 519 | * | ||
| 520 | * @return array | ||
| 521 | */ | ||
| 522 | function authLdap_sort_roles_by_capabilities($roles) | ||
| 523 | { | ||
| 524 | global $wpdb; | ||
| 525 | $myRoles = get_option($wpdb->get_blog_prefix() . 'user_roles'); | ||
| 526 | |||
| 527 | authLdap_debug(print_r($roles, true)); | ||
| 528 | uasort($myRoles, 'authLdap_sortByCapabilitycount'); | ||
| 529 | |||
| 530 | $return = array(); | ||
| 531 | |||
| 532 | foreach ($myRoles as $key => $role) { | ||
| 533 | if (isset($roles[$key])) { | ||
| 534 | $return[$key] = $roles[$key]; | ||
| 535 | } | ||
| 536 | } | ||
| 537 | |||
| 538 | authLdap_debug(print_r($return, true)); | ||
| 539 | return $return; | ||
| 540 | } | ||
| 541 | |||
| 542 | /** | ||
| 543 | * Sort according to the number of capabilities | ||
| 544 | * | ||
| 545 | * @param $a | ||
| 546 | * @param $b | ||
| 547 | */ | ||
| 548 | function authLdap_sortByCapabilitycount($a, $b) | ||
| 549 | { | ||
| 550 | if (count($a['capabilities']) > count($b['capabilities'])) { | ||
| 551 | return -1; | ||
| 552 | } | ||
| 553 | if (count($a['capabilities']) < count($b['capabilities'])) { | ||
| 554 | return 1; | ||
| 555 | } | ||
| 556 | |||
| 557 | return 0; | ||
| 558 | } | ||
| 559 | |||
| 560 | /** | ||
| 561 | * Load AuthLDAP Options | ||
| 562 | * | ||
| 563 | * Sets and stores defaults if options are not up to date | ||
| 564 | */ | ||
| 565 | function authLdap_load_options($reload = false) | ||
| 566 | { | ||
| 567 | static $options = null; | ||
| 568 | |||
| 569 | if( empty($options) || $reload){ | ||
| 570 | // the current version for options | ||
| 571 | $option_version_plugin = 1; | ||
| 572 | // defaults for all options | ||
| 573 | $options = array( | ||
| 574 | 'Enabled' => false, | ||
| 575 | 'CachePW' => false, | ||
| 576 | 'URI' => '', | ||
| 577 | 'URISeparator' => ' ', | ||
| 578 | 'Filter' => '', // '(uid=%s)' | ||
| 579 | 'NameAttr' => '', // 'name' | ||
| 580 | 'SecName' => '', | ||
| 581 | 'UidAttr' => '', // 'uid' | ||
| 582 | 'MailAttr' => '', // 'mail' | ||
| 583 | 'WebAttr' => '', | ||
| 584 | 'Groups' => array(), | ||
| 585 | 'Debug' => false, | ||
| 586 | 'GroupAttr' => '', // 'gidNumber' | ||
| 587 | 'GroupFilter' => '', // '(&(objectClass=posixGroup)(memberUid=%s))' | ||
| 588 | 'DefaultRole' => '', | ||
| 589 | 'GroupEnable' => true, | ||
| 590 | 'GroupOverUser' => true, | ||
| 591 | 'Version' => $option_version_plugin, | ||
| 592 | ); | ||
| 593 | |||
| 594 | // 2016-12-23 MLF (why we forked) Set any options we can find via defined constants | ||
| 595 | foreach($options as $option_name => $option_value) { | ||
| 596 | $constant_name = 'AUTHLDAP_'.strtoupper($option_name); | ||
| 597 | if( defined($constant_name) ){ | ||
| 598 | $options[$option_name] = constant($constant_name); | ||
| 599 | } | ||
| 600 | } | ||
| 601 | } | ||
| 602 | |||
| 603 | return $options; | ||
| 604 | } | ||
| 605 | |||
| 606 | /** | ||
| 607 | * Get an individual option | ||
| 608 | */ | ||
| 609 | function authLdap_get_option($optionname, $default = null) | ||
| 610 | { | ||
| 611 | $options = authLdap_load_options(); | ||
| 612 | if (isset($options[$optionname]) && $options[$optionname]) { | ||
| 613 | return $options[$optionname]; | ||
| 614 | } | ||
| 615 | |||
| 616 | if (null !== $default) { | ||
| 617 | return $default; | ||
| 618 | } | ||
| 619 | |||
| 620 | //authLdap_debug('option name invalid: ' . $optionname); | ||
| 621 | return null; | ||
| 622 | } | ||
| 623 | |||
| 624 | |||
| 625 | /** | ||
| 626 | * Do not send an email after changing the password or the email of the user! | ||
| 627 | * | ||
| 628 | * @param boolean $result The initial resturn value | ||
| 629 | * @param array $user The old userdata | ||
| 630 | * @param array $newUserData The changed userdata | ||
| 631 | * | ||
| 632 | * @return bool | ||
| 633 | */ | ||
| 634 | function authLdap_send_change_email($result, $user, $newUserData) | ||
| 635 | { | ||
| 636 | if (get_usermeta($user['ID'], 'authLDAP')) { | ||
| 637 | return false; | ||
| 638 | } | ||
| 639 | |||
| 640 | return $result; | ||
| 641 | } | ||
| 642 | |||
| 643 | add_filter('show_password_fields', 'authLdap_show_password_fields', 10, 2); | ||
| 644 | add_filter('allow_password_reset', 'authLdap_allow_password_reset', 10, 2); | ||
| 645 | add_filter('authenticate', 'authLdap_login', 10, 3); | ||
| 646 | /** This only works from WP 4.3.0 on */ | ||
| 647 | add_filter('send_password_change_email', 'authLdap_send_change_email', 10, 3); | ||
| 648 | add_filter('send_email_change_email', 'authLdap_send_change_email', 10, 3); |
-
Please register or sign in to post a comment