ona  18.1.1
About: OpenNetAdmin provides a database managed inventory of your IP network (with Web and CLI interface).
  Fossies Dox: ona-18.1.1.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

ldap.class.php
Go to the documentation of this file.
1 <?php
10 class auth_ldap extends auth_local {
11  var $cnf = null;
12  var $con = null;
13  var $bound = 0; // 0: anonymous, 1: user, 2: superuser
14  var $founduser = false;
15 
19  function auth_ldap(){
20  global $conf,$base;
21 
22  // load in system default ldap config
23  $ldap_conf="{$base}/config/auth_ldap.config.php";
24  if (file_exists($ldap_conf)) { require_once($ldap_conf); }
25 
26  // Load any user specific entries and add them to the list
27  // If you re-define an existing entry, it will override the default
28  $ldap_conf="{$base}/local/config/auth_ldap.config.php";
29  if (file_exists($ldap_conf)) { require_once($ldap_conf); }
30 
31 
32  $this->cnf = $conf['auth']['ldap'];
33 
34  // ldap extension is needed
35  if(!function_exists('ldap_connect')) {
36  if ($this->cnf['debug'])
37  printmsg("ERROR => auth_ldap err: PHP LDAP extension not found.",0);
38  $this->success = false;
39  return;
40  }
41 
42  if(empty($this->cnf['groupkey'])) $this->cnf['groupkey'] = 'cn';
43 
44  // auth_ldap currently just handles authentication
45  }
46 
57  function checkPass($user,$pass){
58  // reject empty password
59  if(empty($pass)) return false;
60  if(!$this->_openLDAP()) return false;
61 
62  // indirect user bind
63  if($this->cnf['binddn'] && $this->cnf['bindpw']){
64  // use superuser credentials
65  if(!@ldap_bind($this->con,$this->cnf['binddn'],$this->cnf['bindpw'])){
66  if($this->cnf['debug'])
67  printmsg('DEBUG => auth_ldap: LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)),1);
68  return false;
69  }
70  $this->bound = 2;
71  }else if($this->cnf['binddn'] &&
72  $this->cnf['usertree'] &&
73  $this->cnf['userfilter']) {
74  // special bind string
75  $dn = $this->_makeFilter($this->cnf['binddn'],
76  array('user'=>$user,'server'=>$this->cnf['server']));
77 
78  }else if(strpos($this->cnf['usertree'], '%{user}')) {
79  // direct user bind
80  $dn = $this->_makeFilter($this->cnf['usertree'],
81  array('user'=>$user,'server'=>$this->cnf['server']));
82 
83  }else{
84  // Anonymous bind
85  if(!@ldap_bind($this->con)){
86  printmsg("ERROR => auth_ldap: can not bind anonymously",0);
87  if($this->cnf['debug'])
88  printmsg('DEBUG => auth_ldap: LDAP anonymous bind: '.htmlspecialchars(ldap_error($this->con)),1);
89  return false;
90  }
91  }
92 
93  // Try to bind to with the dn if we have one.
94  if(!empty($dn)) {
95  printmsg("DEBUG => auth_ldap: binding with DN: $dn", 5);
96  // User/Password bind
97  if(!@ldap_bind($this->con,$dn,$pass)){
98  if($this->cnf['debug']){
99  printmsg("ERROR => auth_ldap: bind with $dn failed", 1);
100  printmsg('DEBUG => auth_ldap: LDAP user dn bind: '.htmlspecialchars(ldap_error($this->con)),1);
101  }
102  return false;
103  }
104  $this->bound = 1;
105  $this->founduser = true;
106  return true;
107  }else{
108  // See if we can find the user
109  $info = $this->getUserData($user,true);
110  if(empty($info['dn'])) {
111  return false;
112  } else {
113  $dn = $info['dn'];
114  }
115 
116  // Try to bind with the dn provided
117  if(!@ldap_bind($this->con,$dn,$pass)){
118  if($this->cnf['debug']){
119  printmsg("ERROR => auth_ldap: bind with $dn failed", 1);
120  printmsg('DEBUG => auth_ldap: LDAP user bind: '.htmlspecialchars(ldap_error($this->con)),1);
121  }
122  return false;
123  }
124  $this->bound = 1;
125  $this->founduser = true;
126  return true;
127  }
128 
129  return false;
130  }
131 
156  function getUserData($user,$inbind=false) {
157  global $conf;
158  if(!$this->_openLDAP()) return false;
159 
160  // force superuser bind if wanted and not bound as superuser yet
161  if($this->cnf['binddn'] && $this->cnf['bindpw'] && $this->bound < 2){
162  // use superuser credentials
163  if(!@ldap_bind($this->con,$this->cnf['binddn'],$this->cnf['bindpw'])){
164  if($this->cnf['debug'])
165  printmsg('DEBUG => auth_ldap: LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)),1);
166  return false;
167  }
168  $this->bound = 2;
169  }elseif($this->bound == 0 && !$inbind) {
170  // in some cases getUserData is called outside the authentication workflow
171  // eg. for sending email notification on subscribed pages. This data might not
172  // be accessible anonymously, so we try to rebind the current user here
174  //$this->checkPass($_SESSION[DOKU_COOKIE]['auth']['user'], $pass);
175  }
176 
177  $info['username'] = $user;
178  $info['user'] = $user;
179  $info['server'] = $this->cnf['server'];
180 
181  //get info for given user
182  $base = $this->_makeFilter($this->cnf['usertree'], $info);
183  if(!empty($this->cnf['userfilter'])) {
184  $filter = $this->_makeFilter($this->cnf['userfilter'], $info);
185  } else {
186  $filter = "(ObjectClass=*)";
187  }
188 
189  $sr = @ldap_search($this->con, $base, $filter);
190  $result = @ldap_get_entries($this->con, $sr);
191  if($this->cnf['debug']){
192  printmsg('DEBUG => auth_ldap: LDAP user search: '.htmlspecialchars(ldap_error($this->con)),1);
193  printmsg('DEBUG => auth_ldap: LDAP search at: '.htmlspecialchars($base.' '.$filter),1);
194  }
195 
196  // Don't accept more or less than one response
197  if(!is_array($result) || $result['count'] != 1){
198  return false; //user not found
199  }
200 
201  $user_result = $result[0];
202  ldap_free_result($sr);
203  $g = 0;
204 
205  // general user info
206  $info['dn'] = $user_result['dn'];
207  $info['gid'] = $user_result['gidnumber'][0];
208  $info['mail'] = $user_result['mail'][0];
209  $info['name'] = $user_result['cn'][0];
210  $info['grps'] = array();
211 
212  // overwrite if other attribs are specified.
213  if(is_array($this->cnf['mapping'])){
214  foreach($this->cnf['mapping'] as $localkey => $key) {
215  if(is_array($key)) {
216  // use regexp to clean up user_result
217  list($key, $regexp) = each($key);
218  if($user_result[$key]) foreach($user_result[$key] as $grp){
219  if (preg_match($regexp,$grp,$match)) {
220  if($localkey == 'grps') {
221  $info[$localkey][$match[1]] = $g++;
222  } else {
223  $info[$localkey] = $match[1];
224  }
225  }
226  }
227  } else {
228  $info[$localkey] = $user_result[$key][0];
229  }
230  }
231  }
232  $user_result = array_merge($info,$user_result);
233 
234  //get groups for given user if grouptree is given
235  if ($this->cnf['grouptree'] && $this->cnf['groupfilter']) {
236  $g = 0;
237  $base = $this->_makeFilter($this->cnf['grouptree'], $user_result);
238  $filter = $this->_makeFilter($this->cnf['groupfilter'], $user_result);
239  $sr = @ldap_search($this->con, $base, $filter, array($this->cnf['groupkey']));
240  if(!$sr){
241  printmsg("ERROR => auth_ldap: Reading group memberships failed",0);
242  if($this->cnf['debug']){
243  printmsg('DEBUG => auth_ldap: LDAP group search: '.htmlspecialchars(ldap_error($this->con)),1);
244  printmsg('DEBUG => auth_ldap: LDAP search at: '.htmlspecialchars($base.' '.$filter),1);
245  }
246  return false;
247  }
248  $result = ldap_get_entries($this->con, $sr);
249  ldap_free_result($sr);
250 
251  if(is_array($result)) foreach($result as $grp){
252  if(!empty($grp[$this->cnf['groupkey']][0])){
253  if($this->cnf['debug'])
254  printmsg('DEBUG => auth_ldap: LDAP usergroup: '.htmlspecialchars($grp[$this->cnf['groupkey']][0]),2);
255  $info['grps'][$grp[$this->cnf['groupkey']][0]] = $g++;
256  }
257  }
258  }
259 
260  return $info;
261  }
262 
266  function isCaseSensitive(){
267  return false;
268  }
269 
282  function _makeFilter($filter, $placeholders) {
283  preg_match_all("/%{([^}]+)/", $filter, $matches, PREG_PATTERN_ORDER);
284  //replace each match
285  foreach ($matches[1] as $match) {
286  //take first element if array
287  if(is_array($placeholders[$match])) {
288  $value = $placeholders[$match][0];
289  } else {
290  $value = $placeholders[$match];
291  }
292  $value = $this->_filterEscape($value);
293  $filter = str_replace('%{'.$match.'}', $value, $filter);
294  }
295  return $filter;
296  }
297 
305  function _filterEscape($string){
306  // see https://github.com/adldap/adLDAP/issues/22
307  return preg_replace_callback(
308  '/([\x00-\x1F\*\(\)\\\\])/',
309  function ($matches) {
310  return "\\".join("", unpack("H2", $matches[1]));
311  },
312  $string
313  );
314  }
315 
322  function _openLDAP(){
323  if($this->con) return true; // connection already established
324 
325  $this->bound = 0;
326 
327  $port = ($this->cnf['port']) ? $this->cnf['port'] : 389;
328  $this->con = @ldap_connect($this->cnf['server'],$port);
329  if(!$this->con){
330  printmsg("ERROR => auth_ldap: couldn't connect to LDAP server",0);
331  return false;
332  }
333 
334  //set protocol version and dependend options
335  if($this->cnf['version']){
336  if(!@ldap_set_option($this->con, LDAP_OPT_PROTOCOL_VERSION,
337  $this->cnf['version'])){
338  printmsg('ERROR => auth_ldap: Setting LDAP Protocol version '.$this->cnf['version'].' failed',0);
339  if($this->cnf['debug'])
340  printmsg('DEBUG => auth_ldap: LDAP version set: '.htmlspecialchars(ldap_error($this->con)),1);
341  }else{
342  //use TLS (needs version 3)
343  if($this->cnf['starttls']) {
344  if (!@ldap_start_tls($this->con)){
345  printmsg('ERROR => auth_ldap: Starting TLS failed',0);
346  if($this->cnf['debug'])
347  printmsg('DEBUG => auth_ldap: LDAP TLS set: '.htmlspecialchars(ldap_error($this->con)),1);
348  }
349  }
350  // needs version 3
351  if(isset($this->cnf['referrals'])) {
352  if(!@ldap_set_option($this->con, LDAP_OPT_REFERRALS,
353  $this->cnf['referrals'])){
354  printmsg('ERROR => auth_ldap: Setting LDAP referrals to off failed',0);
355  if($this->cnf['debug'])
356  printmsg('DEBUG => auth_ldap: LDAP referal set: '.htmlspecialchars(ldap_error($this->con)),1);
357  }
358  }
359  }
360  }
361 
362  //set deref mode
363  if($this->cnf['deref']){
364  if(!@ldap_set_option($this->con, LDAP_OPT_DEREF, $this->cnf['deref'])){
365  printmsg('ERROR => auth_ldap: Setting LDAP Deref mode '.$this->cnf['deref'].' failed',0);
366  if($this->cnf['debug'])
367  printmsg('DEBUG => auth_ldap: LDAP deref set: '.htmlspecialchars(ldap_error($this->con)),1);
368  }
369  }
370 
371  return true;
372  }
373 }
374 
375 //Setup VIM: ex: et ts=4 enc=utf-8 :
auth_local\$user
$user
Definition: local.class.php:15
auth_ldap\$con
$con
Definition: ldap.class.php:12
auth_ldap\auth_ldap
auth_ldap()
Definition: ldap.class.php:19
auth_local
Definition: local.class.php:11
auth_ldap\$founduser
$founduser
Definition: ldap.class.php:14
auth_ldap\_openLDAP
_openLDAP()
Definition: ldap.class.php:322
printmsg
if(6<=$conf['debug']) printmsg($msg="", $debugLevel=0)
Definition: functions_general.inc.php:48
auth_ldap
Definition: ldap.class.php:10
auth_ldap\$cnf
$cnf
Definition: ldap.class.php:11
auth_ldap\checkPass
checkPass($user, $pass)
Definition: ldap.class.php:57
$conf
global $conf
Definition: 2-to-3.php:15
auth_ldap\isCaseSensitive
isCaseSensitive()
Definition: ldap.class.php:266
$base
$base
Definition: 2-to-3.php:8
auth_ldap\_filterEscape
_filterEscape($string)
Definition: ldap.class.php:305
auth_ldap\$bound
$bound
Definition: ldap.class.php:13
auth_ldap\_makeFilter
_makeFilter($filter, $placeholders)
Definition: ldap.class.php:282
auth_ldap\getUserData
getUserData($user, $inbind=false)
Definition: ldap.class.php:156