simple-LDAP-auth / ldap_auth.php

<?php
/**
 * simple class for LDAP authentification
 * 
 Copyright (C) 2013 Petr Palas

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * inspired by http://samjlevy.com/2010/09/php-login-script-using-ldap-verify-group-membership/
 */ 

namespace LDAP;

use Exception;

class auth {
    /**
     * url or ip of ldap server
     * @var type string
     */
    protected $ldap_host;
    /**
     * active directory DN
     * @var type string
     */
    protected $ldap_dn;
    /**
     * target user group
     * @var type string
     */
    protected $ldap_user_group;
    /**
     * manager group (shud contain users with management access)
     * @var type string
     */
    protected $ldap_manager_group;
    /**
     * contains email domain like "@somedomain.com"
     * @var type string
     */
    protected $ldap_usr_dom;
    
    /**
     * countains connection resource
     * @var type resource
     */
    protected $ldap;
    
    /**
     * contains status text
     * if exeption is thrown msg contains this string
     * @var type string
     */
    public $status;
    /**
     * contains result array if ldap_search is succesfull
     * @var type array
     */
    public $result;
    /**
     * contains auth state 0=unathrized 1=authorized
     * @var type int
     */
    public $auth=0;
    /**
     * contains access level 0=none or unathorized 1=user 2=managment acc
     * @var type int
     */
    public $access=0;
    
    /**
     * contains username after user init
     * @var type string
     */
    public $user;
    
    /**
     * contain user password after user init
     * @var type string
     */
    protected $password;
    
    /**
     * Exeptions code constants
     */
    const ERROR_WRONG_USER_GROUP=2;
    const ERROR_CANT_AUTH=1;
    const ERROR_CANT_SEARCH=3;
    const ERROR_IMG_DECODE=4;
    const ERROR_CANT_CONNECT=5;

    /**
     * loads passed configuration in case of the ldap_usr_dom it makes sure that this strings begins with '@' 
     * @param type $ldap_host
     * @param type $ldap_dn
     * @param type $ldap_user_group
     * @param type $ldap_manager_group
     * @param type $ldap_usr_dom
     */
    function __construct($ldap_host,$ldap_dn,$ldap_user_group,$ldap_manager_group,$ldap_usr_dom) {
        $this->ldap_host=$ldap_host;
        $this->ldap_dn=$ldap_dn;
        $this->ldap_user_group=$ldap_user_group;
        $this->ldap_manager_group=$ldap_manager_group;
        $this->ldap_usr_dom=  '@'.trim($ldap_usr_dom,'@');
    }
    
    /**
     * well destructor :P
     * just in case there is opened connection to LDAP while destructing this class
     */
    public function __destruct() {
        @ldap_unbind($this->ldap);
    }
    
    /**
     * dumps result array for debug enclosed in pre tag
     * Wont terminate script!
     */
    public function dump_resut() {
        echo '<pre>';
        print_r($this->result,FALSE);
        echo '</pre>';
    }
    
    /**
     * Inits connection to LDAP server throws exeption on failure
     * @return boolean
     * @throws Exception
     */
    protected function init_connection(){
        $this->ldap=ldap_connect($this->ldap_host,3268);
        if($this->ldap){
            $this->status='connected :)';
            ldap_set_option($this->ldap, LDAP_OPT_PROTOCOL_VERSION,3);
            ldap_set_option($this->ldap, LDAP_OPT_REFERRALS,0);
        }
        else {
            //TODO: PHP actualy dont check if there is LDAP present on the other end nor it will fail if target host is unreachable. So I need some work around that :(
            $this->status='Cant connect to LDAP';
            throw new Exception($this->status,  self::ERROR_CANT_CONNECT);
        }
        return TRUE;
    }
    
    public function userInit($user,$password) {
        $this->user=$user;
        $this->password=$password;
        
        return TRUE;
    }
    
    /**
     * Converts Binary string (like thumbnail from LDAP to base64 datastring for display
     * @param type $file
     * @param type $mime
     * @return type base64 datastring
     */
    protected function data_uri($file, $mime) {  
      $base64   = base64_encode($file); 
      return ('data:' . $mime . ';base64,' . $base64);
    }
    
    /**
     * Gets LDAP thumbnail img
     * @param type $user
     * @param type $password
     * @param type $raw if TRUE method will return raw binary string instead of base64 encoded with mime
     * @return type base64 datatring of the thumbnail
     * @throws Exception
     */
    public function getLDAPimg($user=null,$password=null,$raw=FALSE) {
        $this->refreshCredentials($user, $password);
        //since conection is one off we need to get it
        $this->init_connection();
        
        $bind = @ldap_bind($this->ldap, $user . $this->ldap_usr_dom, $password);//ldap_bind($this->ldap, $this->ldap_dn, $password);
        
        if($bind){
            $filter = "(sAMAccountName=" . $user . ")";
            $attr = array("thumbnailphoto");
            $result = @ldap_search($this->ldap, $this->ldap_dn, $filter, $attr);
            if($result==FALSE){
                throw new Exception("Unable to search LDAP server. Reason: ".  ldap_error($this->ldap),  self::ERROR_CANT_SEARCH);
            }  
            $entry= ldap_first_entry($this->ldap, $result);

            if ($entry) {
                $info = @ldap_get_values_len($this->ldap, $entry, "thumbnailphoto");
                if(!$info){
                   throw new Exception("Unable to decode thumbnail. Error: ".  ldap_error($this->ldap),  self::ERROR_IMG_DECODE);
                }
                //echo '<img src="'.$this->data_uri($info[0], 'image/png').'">';
            }
            
            
            if(!$raw){
                return $this->data_uri($info[0], 'image/png');
            }
            else{
                return $info[0];
            }
        }
        else {
            // invalid name or password
            $this->status='Cant authenticate for search on LDAP';
            throw new Exception($this->status.' '.  ldap_error($this->ldap), self::ERROR_CANT_AUTH);
        }
        ldap_unbind($this->ldap);
    }
    
    /**
     * Tries to authenticate suplied user with suplied pass
     * @param type $user
     * @param type $password
     * @return boolean
     * @throws Exception
     */
    public function authenticate($user=null, $password=null) {
       $this->refreshCredentials($user, $password);
        //since conection is one off we need to get it
        $this->init_connection();
        
        // verify user and password
        $bind = @ldap_bind($this->ldap, $user . $this->ldap_usr_dom, $password);

        
        if($bind) {
            // valid
            // check presence in groups
            $filter = "(sAMAccountName=" . $user . ")";
            $attr = array("memberof");
            $result = @ldap_search($this->ldap, $this->ldap_dn, $filter, $attr);
            if($result==FALSE){
                 throw new Exception("Unable to search LDAP server. Reason: ".  ldap_error($this->ldap),  self::ERROR_CANT_SEARCH);
            }  
            $entries = ldap_get_entries($this->ldap, $result);
            
            //save result for future use
            $this->result=$entries;

            
            
            $access = 0;
            
            // check groups
            foreach($entries[0]['memberof'] as $grps) {
                // is manager, break loop
                if (strpos($grps, $this->ldap_manager_group)) { $access = 2; break; }

                // is user
                if (strpos($grps, $this->ldap_user_group)) $access = 1;
            }

            if ($access != 0) {
                // establish result vars
                
                $this->status='Authenticated';
                $this->access=$access;
                $this->user= $user;
                $this->auth=1;
                return true;
            } else {
                // user has no rights
                $this->access=$access;
                $this->user= $user;
                $this->auth=1;
                $this->status='User exists but not part of the target group';
                throw new Exception($this->status.' '.  ldap_error($this->ldap),  self::ERROR_WRONG_USER_GROUP);
            }

        } else {
            // invalid name or password
            $this->status='Cant authenticate for search on LDAP';
            throw new Exception($this->status.' '.  ldap_error($this->ldap),  self::ERROR_CANT_AUTH);
        }
        ldap_unbind($this->ldap);
    }
    
    /**
     * Saves new credentials if we got new or sets the old ones into referenced vars
     * @param type $user Reference to var that shuld contain username or null
     * @param type $password Reference to var that shuld contain password or null
     */
    private function refreshCredentials(&$user,&$password) {
        $newCredentials=TRUE;
        //since we cant set those in param def
        if($password===null){$password=  $this->password;$newCredentials=FALSE;}
        if($user===null){$user=  $this->user;$newCredentials=FALSE;}
        //store user pass and name for future use
        if($newCredentials){$this->userInit($user, $password);}
    }

}
原文地址:https://www.cnblogs.com/zhangchenliang/p/3935564.html