]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/WikiUser/LDAP.php
fix wrong fix from 1.3.13p1
[SourceForge/phpwiki.git] / lib / WikiUser / LDAP.php
1 <?php //-*-php-*-
2 rcs_id('$Id: LDAP.php,v 1.9 2007-06-13 12:48:14 rurban Exp $');
3 /* Copyright (C) 2004,2007 $ThePhpWikiProgrammingTeam
4  * This file is part of PhpWiki. Terms and Conditions see LICENSE. (GPL2)
5  */
6
7 class _LDAPPassUser
8 extends _PassUser
9 /**
10  * Define the vars LDAP_AUTH_HOST and LDAP_BASE_DN in config/config.ini
11  *
12  * Preferences are handled in _PassUser
13  */
14 {
15     function _init() {
16         if ($this->_ldap = ldap_connect(LDAP_AUTH_HOST)) { // must be a valid LDAP server!
17             global $LDAP_SET_OPTION;
18             if (!empty($LDAP_SET_OPTION)) {
19                 foreach ($LDAP_SET_OPTION as $key => $value) {
20                     //if (is_string($key) and defined($key))
21                     //    $key = constant($key);
22                     ldap_set_option($this->_ldap, $key, $value);
23                 }
24             }
25             if (LDAP_AUTH_USER)
26                 if (LDAP_AUTH_PASSWORD)
27                     // Windows Active Directory Server is strict
28                     $r = ldap_bind($this->_ldap, LDAP_AUTH_USER, LDAP_AUTH_PASSWORD); 
29                 else
30                     $r = ldap_bind($this->_ldap, LDAP_AUTH_USER); 
31             else
32                 $r = true; // anonymous bind allowed
33             if (!$r) {
34                 $this->_free();
35                 trigger_error(sprintf(_("Unable to bind LDAP server %s using %s %s"),
36                                       LDAP_AUTH_HOST, LDAP_AUTH_USER, LDAP_AUTH_PASSWORD), 
37                               E_USER_WARNING);
38                 return false;
39             }
40             return $this->_ldap;
41         } else {
42             return false;
43         }
44     }
45     
46     function _free() {
47         if (isset($this->_sr)   and is_resource($this->_sr))   ldap_free_result($this->_sr);
48         if (isset($this->_ldap) and is_resource($this->_ldap)) ldap_close($this->_ldap);
49         unset($this->_sr);
50         unset($this->_ldap);
51     }
52
53     function checkPass($submitted_password) {
54
55         $this->_authmethod = 'LDAP';
56         $userid = $this->_userid;
57         if (!$this->isValidName()) {
58             trigger_error(_("Invalid username."), E_USER_WARNING);
59             $this->_free();
60             return $this->_tryNextPass($submitted_password);
61         }
62         if (!$this->_checkPassLength($submitted_password)) {
63             $this->_free();
64             return WIKIAUTH_FORBIDDEN;
65         }
66         // A LDAP speciality: empty passwords are valid with ldap_bind!!!
67         if (strlen($submitted_password) == 0) {
68             trigger_error(_("Empty password not allowed for LDAP"), E_USER_WARNING);
69             $this->_free();
70             return WIKIAUTH_FORBIDDEN;
71         }
72         if (strstr($userid,'*')) {
73             trigger_error(fmt("Invalid username '%s' for LDAP Auth", $userid), 
74                           E_USER_WARNING);
75             return WIKIAUTH_FORBIDDEN;
76         }
77
78         if ($ldap = $this->_init()) {
79             // Need to set the right root search information. See config/config.ini
80             $st_search = LDAP_SEARCH_FIELD
81                 ? LDAP_SEARCH_FIELD."=$userid"
82                 : "uid=$userid";
83             if (!$this->_sr = ldap_search($ldap, LDAP_BASE_DN, $st_search)) {
84                 trigger_error(_("Could not search in LDAP"), E_USER_WARNING);
85                 $this->_free();
86                 return $this->_tryNextPass($submitted_password);
87             }
88             $info = ldap_get_entries($ldap, $this->_sr); 
89             if (empty($info["count"])) {
90                 if (DEBUG)
91                     trigger_error(_("User not found in LDAP"), E_USER_WARNING);
92                 $this->_free();
93                 return $this->_tryNextPass($submitted_password);
94             }
95             // There may be more hits with this userid.
96             // Of course it would be better to narrow down the BASE_DN
97             for ($i = 0; $i < $info["count"]; $i++) {
98                 $dn = $info[$i]["dn"];
99                 // The password is still plain text.
100                 // LDAP allows all chars but *, (, ), \, NUL
101                 // Quoting is done by \xx (two-digit hexcode). * <=> \2a
102                 // Handling '?' is unspecified
103                 $password = strtr($submitted_password, 
104                                 array("*" => "\\2a",
105                                       "?" => "\\3f",
106                                       "(" => "\\28",
107                                       ")" => "\\29",
108                                       "\\" => "\\5c",
109                                       "\0" => "\\00"));
110                 // On wrong password the ldap server will return: 
111                 // "Unable to bind to server: Server is unwilling to perform"
112                 // The @ catches this error message.
113                 if ($r = @ldap_bind($ldap, $dn, $password)) {
114                     // ldap_bind will return TRUE if everything matches
115                     // Get the mail from ldap
116                     if (!empty($info[$i]["mail"][0])) {
117                         $this->_prefs->_prefs['email']->default_value = $info[$i]["mail"][0];
118                     }
119                     $this->_free();
120                     $this->_level = WIKIAUTH_USER;
121                     return $this->_level;
122                 }
123             }
124             if (DEBUG)
125                 trigger_error(_("Wrong password: ") . 
126                               str_repeat("*",strlen($submitted_password)), 
127                               E_USER_WARNING);
128             $this->_free();
129         } else {
130             $this->_free();
131             trigger_error(_("Could not connect to LDAP"), E_USER_WARNING);
132         }
133
134         return $this->_tryNextPass($submitted_password);
135     }
136
137
138     function isValidName ($userid = false) {
139         if (!$userid) $userid = $this->_userid;
140         // LDAP allows all chars but *, (, ), \, NUL
141         // Quoting is done by \xx (two-digit hexcode). * <=> \2a
142         // We are more restrictive here, but must allow explitly utf-8
143         return preg_match("/^[\-\w_\.@ ]+$/u", $userid) and strlen($userid) < 64;
144     }
145
146     function userExists() {
147         $userid = $this->_userid;
148         if (strstr($userid, '*')) {
149             trigger_error(fmt("Invalid username '%s' for LDAP Auth", $userid),
150                           E_USER_WARNING);
151             return false;
152         }
153         if ($ldap = $this->_init()) {
154             // Need to set the right root search information. see ../index.php
155             $st_search = LDAP_SEARCH_FIELD
156                 ? LDAP_SEARCH_FIELD."=$userid"
157                 : "uid=$userid";
158             if (!$this->_sr = ldap_search($ldap, LDAP_BASE_DN, $st_search)) {
159                 $this->_free();
160                 return $this->_tryNextUser();
161             }
162             $info = ldap_get_entries($ldap, $this->_sr); 
163
164             if ($info["count"] > 0) {
165                 $this->_free();
166                 UpgradeUser($GLOBALS['ForbiddenUser'], $this);
167                 return true;
168             }
169         }
170         $this->_free();
171         return $this->_tryNextUser();
172     }
173
174     function mayChangePass() {
175         return false;
176     }
177
178 }
179
180 // $Log: not supported by cvs2svn $
181 // Revision 1.8  2007/06/07 16:31:33  rurban
182 // Important! Fixes bug #1732882 ldap_bind with empty password
183 // Adds diagnostics on other ldap failures
184 // Fix password quoting
185 //
186 // Revision 1.7  2007/05/30 21:56:17  rurban
187 // Back to default uid for LDAP
188 //
189 // Revision 1.6  2007/05/29 16:56:15  rurban
190 // Allow more password und userid chars. uid => cn: default for certain testusers
191 //
192 // Revision 1.5  2005/10/10 19:43:49  rurban
193 // add DBAUTH_PREF_INSERT: self-creating users. by John Stevens
194 //
195 // Revision 1.4  2004/12/26 17:11:17  rurban
196 // just copyright
197 //
198 // Revision 1.3  2004/12/20 16:05:01  rurban
199 // gettext msg unification
200 //
201 // Revision 1.2  2004/12/19 00:58:02  rurban
202 // Enforce PASSWORD_LENGTH_MINIMUM in almost all PassUser checks,
203 // Provide an errormessage if so. Just PersonalPage and BogoLogin not.
204 // Simplify httpauth logout handling and set sessions for all methods.
205 // fix main.php unknown index "x" getLevelDescription() warning.
206 //
207 // Revision 1.1  2004/11/01 10:43:58  rurban
208 // seperate PassUser methods into seperate dir (memory usage)
209 // fix WikiUser (old) overlarge data session
210 // remove wikidb arg from various page class methods, use global ->_dbi instead
211 // ...
212 //
213
214 // Local Variables:
215 // mode: php
216 // tab-width: 8
217 // c-basic-offset: 4
218 // c-hanging-comment-ender-p: nil
219 // indent-tabs-mode: nil
220 // End:
221 ?>