Ticket #543: AuthenticatorActiveDirectory.php.txt

File AuthenticatorActiveDirectory.php.txt, 12.6 KB (added by benoitg, 3 years ago)

Attached the file so it isn't lost

Line 
1<?php
2
3/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5// +-------------------------------------------------------------------+
6// | WiFiDog Authentication Server                                     |
7// | =============================                                     |
8// |                                                                   |
9// | The WiFiDog Authentication Server is part of the WiFiDog captive  |
10// | portal suite.                                                     |
11// +-------------------------------------------------------------------+
12// | PHP version 5 required.                                           |
13// +-------------------------------------------------------------------+
14// | Homepage:     http://www.wifidog.org/                             |
15// | Source Forge: http://sourceforge.net/projects/wifidog/            |
16// +-------------------------------------------------------------------+
17// | This program is free software; you can redistribute it and/or     |
18// | modify it under the terms of the GNU General Public License as    |
19// | published by the Free Software Foundation; either version 2 of    |
20// | the License, or (at your option) any later version.               |
21// |                                                                   |
22// | This program is distributed in the hope that it will be useful,   |
23// | but WITHOUT ANY WARRANTY; without even the implied warranty of    |
24// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     |
25// | GNU General Public License for more details.                      |
26// |                                                                   |
27// | You should have received a copy of the GNU General Public License |
28// | along with this program; if not, contact:                         |
29// |                                                                   |
30// | Free Software Foundation           Voice:  +1-617-542-5942        |
31// | 59 Temple Place - Suite 330        Fax:    +1-617-542-2652        |
32// | Boston, MA  02111-1307,  USA       gnu@gnu.org                    |
33// |                                                                   |
34// +-------------------------------------------------------------------+
35
36/**
37 * @package    WiFiDogAuthServer
38 * @subpackage Authenticators
39 * @author     Ricardo Jose Guevara Ochoa <rjguevara@gmail.com>
40 * @author     Max Horváth <max.horvath@freenet.de>
41 * @author     Scott E. Barasch <scott<DOT>e<DOT>barasch(AT)gmail(dot)com>
42 * @copyright  2006 Ricardo Jose Guevara Ochoa
43 * @copyright  2006 Max Horváth, Horvath Web Consulting
44 * @copyright  2009 Scott E. Barasch
45 * @version    Subversion $Id: AuthenticatorLocalUser.php 915 2006-01-23 05:26:20Z max-horvath $
46 * @link       http://www.wifidog.org/
47 *
48 * To use this Authenticator in Wifidog, change the Network authenticator class to
49 * "AuthenticatorActiveDirectory" and use the following Authenticator parameters as a
50 * guide for creating your own parameters:
51 *
52 * '<network id>','<AD server to which you will bind>','<full DN to service account user>'
53 * ,'<password to service account user>','<base dn for all users that will bind>',
54 * '<attribute which will be used to bind>'
55 *
56 * Note: The Distinguished names for the above parameters can be found using adsiedit.msc on
57 * your Windows Server 2003 / 2008 Domain Controller. Also, the attribute for binding using
58 * usernames is commonly "sAMAccountName".
59 */
60
61/**
62 * Load include files
63 */
64require_once('classes/Authenticator.php');
65require_once('classes/Dependency.php');
66require_once('classes/Security.php');
67require_once('classes/User.php');
68
69/**
70 * Internal wifidog user database authentication source using LDAP
71 *
72 * @package    WiFiDogAuthServer
73 * @subpackage Authenticators
74 * @author     Ricardo Jose Guevara Ochoa <rjguevara@gmail.com>
75 * @author     Max Horváth <max.horvath@freenet.de>
76 * @author     Scott E. Barasch <scott<DOT>e<DOT>barasch(AT)gmail(dot)com>
77 * @copyright  2006 Ricardo Jose Guevara Ochoa
78 * @copyright  2006 Max Horváth, Horvath Web Consulting
79 * @copyright  2009 Scott E. Barasch
80 */
81class AuthenticatorLDAP extends Authenticator
82{
83    /**
84     * Hostname of the AD  server
85     *
86     * @var string
87
88     */
89    private $mldap_hostname;
90
91    /**
92     * The Relative Distinguished Name of the AD server
93     *
94     * @var string
95
96     */
97    private $mldap_rdn;
98
99    /**
100     * The password of the AD server
101     *
102     * @var string
103
104     */
105    private $mldap_pass;
106
107    /**
108     * The base dn of the server
109     *
110     * @var string
111
112     */
113    private $mldap_o;
114
115    /**
116     * It's the field that will be used in the LDAP search, i.e.: sAMAccountName, uid, mail
117     *
118     *
119     * @var string
120
121     */
122    private $mldap_filter;
123
124    /**
125     * AuthenticatorLDAP constructor
126     *
127     * Example: new AuthenticatorLDAP(IDRC_ACCOUNT_ORIGIN, '192.168.0.11',
128     * 'cn=serviceAccount,ou=users,dc=example,dc=com', 'password',
129     * 'cn=serviceAccount,ou=users,dc=example,dc=com', 'sAMAccountName');
130     *
131     * @param string $account_orgin The network ID
132     * @param string $host          Hostname of the AD  server
133     * @param string $rdn           The Relative Distinguished Name of the AD
134     *                              server service account
135     * @param string $pass          The password of the AD server service account
136     * @param string $o             The base dn of the AD users that will authenticate
137     * @param string $filter        It's the field that will be used in the
138     *                              LDAP search, i.e.: uid, mail, sAMAccountName
139     *
140     * @return void
141     */
142    public function __construct($account_orgin, $host, $rdn, $pass, $o, $filter)
143    {
144        // Call parent constructor
145        parent::__construct($account_orgin);
146
147        $this->mldap_hostname = $host;
148        $this->mldap_filter = $filter;
149        $this->mldap_o = $o;
150        $this->mldap_rdn = trim($rdn);
151        $this->mldap_pass = trim($pass);
152    }
153
154    /**
155     * Callback function used to check AD accounts
156     *
157     * @param string $username    Username of user
158     * @param string $password    Clear text password of user
159     * @param string $ldap_server Hostname of LDAP server
160     * @param strong $o           The base dn string of the AD server (possibly including o=)
161     * @param string $f           It's the field that will be used in the
162     *                            AD search, i.e.: uid, mail, name server
163     * @param string $errmsg      Reference of error message
164     *
165     * @return bool True if the parameter refers to a Local User account origin
166
167     */
168    private function checkLdapUser($username, $password, $ldap_server, $o, $f, &$errmsg = null )
169    {
170        // Init values
171        $rtval = true;
172
173        // Check if php-ldap extension is loaded
174        if (Dependency::check("ldap", $errmsg)) {
175            if ($connect = @ldap_connect($ldap_server)) {
176                // if connected to ldap server
177                ldap_set_option($connect, LDAP_OPT_PROTOCOL_VERSION, 3);
178
179                // bind to ldap connection
180                if (strlen(trim($this->mldap_rdn)) == 0) {
181                    if (($bind = @ldap_bind($connect)) == false) {
182                        $errmsg = _("Error while connecting to the LDAP server.");
183                        return false;
184                    }
185                } else {
186                    if (($bind = @ldap_bind($connect, $this->mldap_rdn, $this->mldap_pass )) == false) {
187                        $errmsg = _("Error while connecting to the LDAP server.");
188                        return false;
189                    }
190                }
191
192                // search for user
193                if (($res_id = ldap_search($connect, $o, "($f=$username)", array($f) )) == false)  {
194                    $errmsg = _("Error while obtaining your LDAP information.");
195                   
196                    return false;
197                }
198
199                if (ldap_count_entries($connect, $res_id) != 1) {
200                    $errmsg = _("Error while obtaining your username or password from the LDAP server.");
201
202                    return false;
203                }
204
205                if (($entry_id = ldap_first_entry($connect, $res_id)) == false) {
206                    $errmsg = _("Error while obtaining your username or password from the LDAP server.");
207
208                    return false;
209                }
210
211                if (($user_dn = ldap_get_dn($connect, $entry_id)) == false) {
212                    $errmsg = _("Error while obtaining your username or password from the LDAP server.");
213
214                    return false;
215                }
216
217                //Authenticate the User
218                if (($link_id = ldap_bind($connect, $user_dn, $password)) == false) {
219                    $errmsg = _("Error in username or password.");
220
221                    return false;
222                }
223
224                return true;
225            } else {
226                $errmsg = _("Error connecting to the LDAP Server.");
227            }
228
229            ldap_close($connect);
230        } else {
231            $rtval = false;
232        }
233    }
234
235    /**
236     * Attempts to login a user against the authentication source
237     *
238     * If successfull, returns a User object
239     *
240     * @param string $username A valid identifying token for the source. Not
241     *                         necessarily unique.
242     * @param string $password Clear text password.
243     * @param string $errmsg   Reference of error message
244     *
245     * @return object The actual User object if login was successfull, false
246     *                otherwise.
247     */
248    public function login($username, $password, &$errmsg = null)
249    {
250         
251        $db = AbstractDb::getObject();
252
253        // Init values
254        $retval = false;
255        $username = $db->EscapeString($username);
256        $password = $db->EscapeString($password);
257
258        // Check if php-ldap extension is loaded
259        if (Dependency::check("ldap", $errmsg)) {
260            if ($this->checkLdapUser($username, $password, $this->mldap_hostname, $this->mldap_o, $this->mldap_filter, $errmsg)) {
261                //LDAP Authentication Successful
262                $sql = "SELECT user_id, pass FROM users WHERE (username='$username') AND account_origin='".$this->getNetwork()->getId()."'";
263
264                $db->ExecSqlUniqueRes($sql, $user_info, false);
265
266                if ($user_info != null) {
267                    $user = User::getObject($user_info['user_id']);
268
269                    if ($user->isUserValid($errmsg)) {
270                        $retval = $user;
271                        User::setCurrentUser($user);
272                        $errmsg = _("Login successfull");
273                    } else {
274                        $retval = false;
275                        //Error already been set
276                    }
277                } else {
278                    $user = User::createUser(get_guid(), $username, $this->getNetwork(), "", "");
279                    $retval = &$user;
280                    $user->setAccountStatus(ACCOUNT_STATUS_ALLOWED);
281
282                    $errmsg = _("Login successfull");
283                }
284            } else {
285                $retval = false;
286                //Error already been set
287            }
288        }
289        User::setCurrentUser($retval);
290        return $retval;
291    }
292
293    /**
294     * Start accounting traffic for the user
295     *
296     * @param string $conn_id The connection id for the connection to work on
297     * @param string $errmsg  Reference of error message
298     *
299     * @return bool Returns always true
300     */
301    public function acctStart($conn_id, &$errmsg = null)
302    {
303        // Call parent method
304        parent::acctStart($conn_id);
305
306        return true;
307    }
308
309    /**
310     * Update traffic counters
311     *
312     * @param string $conn_id  The connection id for the connection to work on
313     * @param int    $incoming Incoming traffic in bytes
314     * @param int    $outgoing Outgoing traffic in bytes
315     * @param string $errmsg   Reference of error message
316     *
317     * @return bool Returns always true
318     */
319    public function acctUpdate($conn_id, $incoming, $outgoing, &$errmsg = null)
320    {
321        // Call parent method
322        parent::acctUpdate($conn_id, $incoming, $outgoing);
323
324        return true;
325    }
326
327    /**
328     * Final update and stop accounting
329     *
330     * @param string $conn_id The connection id (the token id) for the
331     *                        connection to work on
332     * @param string $errmsg  Reference of error message
333     *
334     * @return bool Returns always true
335     */
336    public function acctStop($conn_id, &$errmsg = null)
337    {
338        // Call parent method
339        parent::acctStop($conn_id);
340
341        return true;
342    }
343
344}
345
346/*
347 * Local variables:
348 * tab-width: 4
349 * c-basic-offset: 4
350 * c-hanging-comment-ender-p: nil
351 * End:
352 */
353