Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
 
4
/**
5
 * File::Passwd::Authdigest
6
 *
7
 * PHP versions 4 and 5
8
 *
9
 * LICENSE: This source file is subject to version 3.0 of the PHP license
10
 * that is available through the world-wide-web at the following URI:
11
 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
12
 * the PHP License and are unable to obtain it through the web, please
13
 * send a note to license@php.net so we can mail you a copy immediately.
14
 *
15
 * @category   FileFormats
16
 * @package    File_Passwd
17
 * @author     Michael Wallner <mike@php.net>
18
 * @copyright  2003-2005 Michael Wallner
19
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
20
 * @version    CVS: $Id: Authdigest.php,v 1.13 2005/09/27 06:26:08 mike Exp $
21
 * @link       http://pear.php.net/package/File_Passwd
22
 */
23
 
24
/**
25
* Requires File::Passwd::Common
26
*/
27
require_once 'File/Passwd/Common.php';
28
 
29
/**
30
* Manipulate AuthDigestFiles as used for HTTP Digest Authentication.
31
*
32
* <kbd><u>
33
*   Usage Example:
34
* </u></kbd>
35
* <code>
36
*   $htd = &File_Passwd::factory('Authdigest');
37
*   $htd->setFile('/www/mike/auth/.htdigest');
38
*   $htd->load();
39
*   $htd->addUser('mike', 'myRealm', 'secret');
40
*   $htd->save();
41
* </code>
42
*
43
* <kbd><u>
44
*   Output of listUser()
45
* </u></kbd>
46
* <pre>
47
*      array
48
*       + user  => array
49
*                   + realm => crypted_passwd
50
*                   + realm => crypted_passwd
51
*       + user  => array
52
*                   + realm => crypted_passwd
53
* </pre>
54
*
55
* @author   Michael Wallner <mike@php.net>
56
* @package  File_Passwd
57
* @version  $Revision: 1.13 $
58
* @access   public
59
*/
60
class File_Passwd_Authdigest extends File_Passwd_Common
61
{
62
    /**
63
    * Path to AuthDigestFile
64
    *
65
    * @var string
66
    * @access private
67
    */
68
    var $_file = '.htdigest';
69
 
70
    /**
71
    * Constructor
72
    *
73
    * @access public
74
    * @param string $file       path to AuthDigestFile
75
    */
76
    function File_Passwd_Authdigest($file = '.htdigest')
77
    {
78
        parent::__construct($file);
79
    }
80
 
81
    /**
82
    * Fast authentication of a certain user
83
    *
84
    * Returns a PEAR_Error if:
85
    *   o file doesn't exist
86
    *   o file couldn't be opened in read mode
87
    *   o file couldn't be locked exclusively
88
    *   o file couldn't be unlocked (only if auth fails)
89
    *   o file couldn't be closed (only if auth fails)
90
    *
91
    * @static   call this method statically for a reasonable fast authentication
92
    *
93
    * @throws   PEAR_Error
94
    * @access   public
95
    * @return   mixed   true if authenticated, false if not or PEAR_Error
96
    * @param    string  $file   path to passwd file
97
    * @param    string  $user   user to authenticate
98
    * @param    string  $pass   plaintext password
99
    * @param    string  $realm  the realm the user is in
100
    */
101
    function staticAuth($file, $user, $pass, $realm)
102
    {
103
        $line = File_Passwd_Common::_auth($file, $user.':'.$realm);
104
        if (!$line || PEAR::isError($line)) {
105
            return $line;
106
        }
107
        @list(,,$real)= explode(':', $line);
108
        return (md5("$user:$realm:$pass") === $real);
109
    }
110
 
111
    /**
112
    * Apply changes and rewrite AuthDigestFile
113
    *
114
    * Returns a PEAR_Error if:
115
    *   o directory in which the file should reside couldn't be created
116
    *   o file couldn't be opened in write mode
117
    *   o file couldn't be locked exclusively
118
    *   o file couldn't be unlocked
119
    *   o file couldn't be closed
120
    *
121
    * @throws PEAR_Error
122
    * @access public
123
    * @return mixed true on success or a PEAR_Error
124
    */
125
    function save()
126
    {
127
        $content = '';
128
        if (count($this->_users)) {
129
            foreach ($this->_users as $user => $realm) {
130
                foreach ($realm as $r => $pass){
131
                  $content .= "$user:$r:$pass\n";
132
                }
133
            }
134
        }
135
        return $this->_save($content);
136
    }
137
 
138
    /**
139
    * Add an user
140
    *
141
    * Returns a PEAR_Error if:
142
    *   o the user already exists in the supplied realm
143
    *   o the user or realm contain illegal characters
144
    *
145
    * $user and $realm must start with an alphabetical charachter and must NOT
146
    * contain any other characters than alphanumerics, the underline and dash.
147
    *
148
    * @throws PEAR_Error
149
    * @access public
150
    * @return mixed true on success or a PEAR_Error
151
    * @param string $user   the user to add
152
    * @param string $realm  the realm the user should be in
153
    * @param string $pass   the plaintext password
154
    */
155
    function addUser($user, $realm, $pass)
156
    {
157
        if ($this->userInRealm($user, $realm)) {
158
            return PEAR::raiseError(
159
                "User '$user' already exists in realm '$realm'.", 0
160
            );
161
        }
162
        if (!preg_match($this->_pcre, $user)) {
163
            return PEAR::raiseError(
164
                sprintf(FILE_PASSWD_E_INVALID_CHARS_STR, 'User ', $user),
165
                FILE_PASSWD_E_INVALID_CHARS
166
            );
167
        }
168
        if (!preg_match($this->_pcre, $realm)) {
169
            return PEAR::raiseError(
170
                sprintf(FILE_PASSWD_E_INVALID_CHARS_STR, 'Realm ', $realm),
171
                FILE_PASSWD_E_INVALID_CHARS
172
            );
173
        }
174
        $this->_users[$user][$realm] = md5("$user:$realm:$pass");
175
        return true;
176
    }
177
 
178
    /**
179
    * List all user of (a | all) realm(s)
180
    *
181
    * Returns:
182
    *   o associative array of users of ONE realm if $inRealm was supplied
183
    *     <pre>
184
    *       realm1
185
    *        + user1 => pass
186
    *        + user2 => pass
187
    *        + user3 => pass
188
    *     </pre>
189
    *   o associative array of all realms with all users
190
    *     <pre>
191
    *       array
192
    *        + realm1 => array
193
    *                     + user1 => pass
194
    *                     + user2 => pass
195
    *                     + user3 => pass
196
    *        + realm2 => array
197
    *                     + user3 => pass
198
    *        + realm3 => array
199
    *                     + user1 => pass
200
    *                     + user2 => pass
201
    *     </pre>
202
    *
203
    * @access public
204
    * @return array
205
    * @param string $inRealm    the realm to list users of;
206
    *                           if omitted, you'll get all realms
207
    */
208
    function listUserInRealm($inRealm = '')
209
    {
210
        $result = array();
211
        foreach ($this->_users as $user => $realms){
212
            foreach ($realms as $realm => $pass){
213
                if (!empty($inRealm) && ($inRealm !== $realm)) {
214
                    continue;
215
                }
216
                if (!isset($result[$realm])) {
217
                    $result[$realm] = array();
218
                }
219
                $result[$realm][$user] = $pass;
220
            }
221
        }
222
        return $result;
223
    }
224
 
225
    /**
226
    * Change the password of a certain user
227
    *
228
    * Returns a PEAR_Error if:
229
    *   o user doesn't exist in the supplied realm
230
    *   o user or realm contains illegal characters
231
    *
232
    * This method in fact adds the user whith the new password
233
    * after deleting the user.
234
    *
235
    * @throws PEAR_Error
236
    * @access public
237
    * @return mixed true on success or a PEAR_Error
238
    * @param string $user   the user whose password should be changed
239
    * @param string $realm  the realm the user is in
240
    * @param string $pass   the new plaintext password
241
    */
242
    function changePasswd($user, $realm, $pass)
243
    {
244
        if (PEAR::isError($error = $this->delUserInRealm($user, $realm))) {
245
            return $error;
246
        } else {
247
            return $this->addUser($user, $realm, $pass);
248
        }
249
    }
250
 
251
    /**
252
    * Verifiy password
253
    *
254
    * Returns a PEAR_Error if the user doesn't exist in the supplied realm.
255
    *
256
    * @throws PEAR_Error
257
    * @access public
258
    * @return mixed true if passwords equal, false if they don't, or PEAR_Error
259
    * @param string $user   the user whose password should be verified
260
    * @param string $realm  the realm the user is in
261
    * @param string $pass   the plaintext password to verify
262
    */
263
    function verifyPasswd($user, $realm, $pass)
264
    {
265
        if (!$this->userInRealm($user, $realm)) {
266
            return PEAR::raiseError(
267
                sprintf(FILE_PASSWD_E_USER_NOT_IN_REALM_STR, $user, $realm),
268
                FILE_PASSWD_E_USER_NOT_IN_REALM
269
            );
270
        }
271
        return ($this->_users[$user][$realm] === md5("$user:$realm:$pass"));
272
    }
273
 
274
    /**
275
    * Ckeck if a certain user is in a specific realm
276
    *
277
    * @throws PEAR_Error
278
    * @access public
279
    * @return boolean
280
    * @param string $user   the user to check
281
    * @param string $realm  the realm the user shuold be in
282
    */
283
    function userInRealm($user, $realm)
284
    {
285
      return (isset($this->_users[$user][$realm]));
286
    }
287
 
288
    /**
289
    * Delete a certain user in a specific realm
290
    *
291
    * Returns a PEAR_Error if <var>$user</var> doesn't exist <var>$inRealm</var>.
292
    *
293
    * @throws PEAR_Error
294
    * @access public
295
    * @return mixed true on success or PEAR_Error
296
    * @param  string    $user       the user to remove
297
    * @param  string    $inRealm    the realm the user should be in
298
    */
299
    function delUserInRealm($user, $inRealm)
300
    {
301
        if (!$this->userInRealm($user, $inRealm)) {
302
            return PEAR::raiseError(
303
                sprintf(FILE_PASSWD_E_USER_NOT_IN_REALM_STR, $user, $inRealm),
304
                FILE_PASSWD_E_USER_NOT_IN_REALM
305
            );
306
        }
307
        unset($this->_users[$user][$inRealm]);
308
        return true;
309
    }
310
 
311
    /**
312
    * Parse the AuthDigestFile
313
    *
314
    * Returns a PEAR_Error if AuthDigestFile has invalid format.
315
    *
316
    * @throws PEAR_Error
317
    * @access public
318
    * @return mixed true on success or PEAR_Error
319
    */
320
    function parse()
321
    {
322
        $this->_users = array();
323
        foreach ($this->_contents as $line) {
324
            $user = explode(':', $line);
325
            if (count($user) != 3) {
326
                return PEAR::raiseError(
327
                    FILE_PASSWD_E_INVALID_FORMAT_STR,
328
                    FILE_PASSWD_E_INVALID_FORMAT
329
                );
330
            }
331
            list($user, $realm, $pass) = $user;
332
            $this->_users[$user][$realm] = trim($pass);
333
        }
334
        $this->_contents = array();
335
        return true;
336
    }
337
 
338
    /**
339
    * Generate Password
340
    *
341
    * @static
342
    * @access   public
343
    * @return   string  The crypted password.
344
    * @param    string  $user The username.
345
    * @param    string  $realm The realm the user is in.
346
    * @param    string  $pass The plaintext password.
347
    */
348
    function generatePasswd($user, $realm, $pass)
349
    {
350
        return md5("$user:$realm:$pass");
351
    }
352
 
353
    /**
354
     * @ignore
355
     * @deprecated
356
     */
357
    function generatePassword($user, $realm, $pass)
358
    {
359
        return File_Passwd_Authdigest::generatePasswd($user, $realm, $pass);
360
    }
361
}
362
?>