LdapAuthenticationPlugin.php 5.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Plugin to enable LDAP Authentication and Authorization
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Plugin
 * @package   StatusNet
 * @author    Craig Andrews <candrews@integralblue.com>
 * @copyright 2009 Craig Andrews http://candrews.integralblue.com
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

34
require_once INSTALLDIR.'/plugins/Authentication/AuthenticationPlugin.php';
35
require_once 'Net/LDAP2.php';
36

Craig Andrews's avatar
Craig Andrews committed
37
class LdapAuthenticationPlugin extends AuthenticationPlugin
38
{
39 40 41 42 43 44 45 46 47 48 49
    public $host=null;
    public $port=null;
    public $version=null;
    public $starttls=null;
    public $binddn=null;
    public $bindpw=null;
    public $basedn=null;
    public $options=null;
    public $filter=null;
    public $scope=null;
    public $attributes=array();
50

51 52 53 54 55 56 57 58 59 60 61 62 63 64
    function onInitializePlugin(){
        parent::onInitializePlugin();
        if(!isset($this->host)){
            throw new Exception("must specify a host");
        }
        if(!isset($this->basedn)){
            throw new Exception("must specify a basedn");
        }
        if(!isset($this->attributes['nickname'])){
            throw new Exception("must specify a nickname attribute");
        }
        if(!isset($this->attributes['username'])){
            throw new Exception("must specify a username attribute");
        }
65
    }
66 67
    
    //---interface implementation---//
68

69
    function checkPassword($username, $password)
70
    {
71 72
        $ldap = $this->ldap_get_connection();
        if(!$ldap){
Craig Andrews's avatar
Craig Andrews committed
73 74
            return false;
        }
75
        $entry = $this->ldap_get_user($username);
76
        if(!$entry){
Craig Andrews's avatar
Craig Andrews committed
77
            return false;
78 79 80 81 82 83 84 85 86
        }else{
            $config = $this->ldap_get_config();
            $config['binddn']=$entry->dn();
            $config['bindpw']=$password;
            if($this->ldap_get_connection($config)){
                return true;
            }else{
                return false;
            }
Craig Andrews's avatar
Craig Andrews committed
87 88 89
        }
    }

90
    function autoRegister($username)
Craig Andrews's avatar
Craig Andrews committed
91
    {
92
        $entry = $this->ldap_get_user($username,$this->attributes);
Craig Andrews's avatar
Craig Andrews committed
93 94
        if($entry){
            $registration_data = array();
95
            foreach($this->attributes as $sn_attribute=>$ldap_attribute){
96 97 98 99
                $registration_data[$sn_attribute]=$entry->getValue($ldap_attribute,'single');
            }
            if(isset($registration_data['email']) && !empty($registration_data['email'])){
                $registration_data['email_confirmed']=true;
Craig Andrews's avatar
Craig Andrews committed
100
            }
Craig Andrews's avatar
Craig Andrews committed
101 102
            //set the database saved password to a random string.
            $registration_data['password']=common_good_rand(16);
103
            return User::register($registration_data);
104 105
        }else{
            //user isn't in ldap, so we cannot register him
106
            return false;
107
        }
108
    }
Craig Andrews's avatar
Craig Andrews committed
109

110
    function changePassword($username,$oldpassword,$newpassword)
Craig Andrews's avatar
Craig Andrews committed
111 112
    {
        //TODO implement this
113
        throw new Exception(_('Sorry, changing LDAP passwords is not supported at this time'));
Craig Andrews's avatar
Craig Andrews committed
114 115 116

        return false;
    }
117 118 119 120 121 122 123
    
    //---utility functions---//
    function ldap_get_config(){
        $config = array();
        $keys = array('host','port','version','starttls','binddn','bindpw','basedn','options','filter','scope');
        foreach($keys as $key){
            $value = $this->$key;
124
            if($value!==null){
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
                $config[$key]=$value;
            }
        }
        return $config;
    }
    
    function ldap_get_connection($config = null){
        if($config == null){
            $config = $this->ldap_get_config();
        }
        
        //cannot use Net_LDAP2::connect() as StatusNet uses
        //PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'handleError');
        //PEAR handling can be overridden on instance objects, so we do that.
        $ldap = new Net_LDAP2($config);
        $ldap->setErrorHandling(PEAR_ERROR_RETURN);
        $err=$ldap->bind();
        if (Net_LDAP2::isError($err)) {
            common_log(LOG_WARNING, 'Could not connect to LDAP server: '.$err->getMessage());
            return false;
        }
        return $ldap;
    }
    
    /**
     * get an LDAP entry for a user with a given username
     * 
     * @param string $username
     * $param array $attributes LDAP attributes to retrieve
     * @return string DN
     */
    function ldap_get_user($username,$attributes=array()){
        $ldap = $this->ldap_get_connection();
158
        $filter = Net_LDAP2_Filter::create($this->attributes['username'], 'equals',  $username);
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
        $options = array(
            'scope' => 'sub',
            'attributes' => $attributes
        );
        $search = $ldap->search(null,$filter,$options);
        
        if (PEAR::isError($search)) {
            common_log(LOG_WARNING, 'Error while getting DN for user: '.$search->getMessage());
            return false;
        }

        if($search->count()==0){
            return false;
        }else if($search->count()==1){
            $entry = $search->shiftEntry();
            return $entry;
        }else{
            common_log(LOG_WARNING, 'Found ' . $search->count() . ' ldap user with the username: ' . $username);
            return false;
        }
    }
180
}