~ubuntu-branches/debian/sid/ampache/sid

« back to all changes in this revision

Viewing changes to lib/class/auth.class.php

  • Committer: Package Import Robot
  • Author(s): Charlie Smotherman
  • Date: 2013-08-27 13:19:48 UTC
  • mfrom: (1.2.9)
  • Revision ID: package-import@ubuntu.com-20130827131948-1czew0zxn6u70dtv
Tags: 3.6-rzb2752+dfsg-1
* New upsteam snapshot.  Contains important bug fixes to the installer.
* Correct typo in ampache-common.postrm.
* Remove courtousy copy of php-getid3, during repack.  Closes: #701526
* Update package to use dh_linktree to make the needed sym links to the
  needed system libs that were removed during repack.
* Update debian/rules to reflect upstreams removing/moving of modules.
* Update debian/ampache-common.install to reflect upstreams removal of files.
* Updated to use new apache2.4 API. Closes: #669756
* Updated /debian/po/de.po thx David Prévot for the patch.  Closes:  #691963
* M3U import is now ordered, fixed upstream.  Closes: #684984
* Text input area has been resized so IPv6 addresses will now fit, fixed
  upstream.  Closes:  #716230
* Added ampache-common.preinst to make sure that the courtousy copies of code
  dirs are empty so dh_linktree can do it's magic on upgrades.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
 
3
/**
 
4
 *
 
5
 * LICENSE: GNU General Public License, version 2 (GPLv2)
 
6
 * Copyright 2001 - 2013 Ampache.org
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU General Public License v2
 
10
 * as published by the Free Software Foundation.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
20
 *
 
21
 */
 
22
 
 
23
/**
 
24
 *
 
25
 * This class handles all of the session related stuff in Ampache
 
26
 * it takes over for the vauth libs, and takes some stuff out of other
 
27
 * classes where it didn't belong.
 
28
 */
 
29
class Auth {
 
30
 
 
31
    /**
 
32
     * Constructor
 
33
     *
 
34
     * This should never be called
 
35
     */
 
36
    private function __construct() {
 
37
        // Rien a faire
 
38
    }
 
39
 
 
40
    /**
 
41
     * logout
 
42
     *
 
43
     * This is called when you want to log out and nuke your session.
 
44
     * This is the function used for the Ajax logouts, if no id is passed
 
45
     * it tries to find one from the session,
 
46
     */
 
47
    public static function logout($key='', $relogin = true) {
 
48
 
 
49
        // If no key is passed try to find the session id
 
50
        $key = $key ? $key : session_id();
 
51
 
 
52
        // Nuke the cookie before all else
 
53
        Session::destroy($key);
 
54
        if ((!$relogin) && Config::get('logout_redirect')) {
 
55
            $target = Config::get('logout_redirect');
 
56
        }
 
57
        else {
 
58
            $target = Config::get('web_path') . '/login.php';
 
59
        }
 
60
 
 
61
        // Do a quick check to see if this is an AJAXed logout request
 
62
        // if so use the iframe to redirect
 
63
        if (defined('AJAX_INCLUDE')) {
 
64
            ob_end_clean();
 
65
            ob_start();
 
66
 
 
67
            /* Set the correct headers */
 
68
            header("Content-type: text/xml; charset=" . Config::get('site_charset'));
 
69
            header("Content-Disposition: attachment; filename=ajax.xml");
 
70
            header("Expires: Tuesday, 27 Mar 1984 05:00:00 GMT");
 
71
            header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
 
72
            header("Cache-Control: no-store, no-cache, must-revalidate");
 
73
            header("Pragma: no-cache");
 
74
 
 
75
            $results['rfc3514'] = '<script type="text/javascript">reloadRedirect("' . $target . '")</script>';
 
76
            echo xml_from_array($results);
 
77
        }
 
78
        else {
 
79
            /* Redirect them to the login page */
 
80
            header('Location: ' . $target);
 
81
        }
 
82
 
 
83
        exit;
 
84
    }
 
85
 
 
86
    /**
 
87
     * login
 
88
     *
 
89
     * This takes a username and password and then returns the results
 
90
     * based on what happens when we try to do the auth.
 
91
     */
 
92
    public static function login($username, $password) {
 
93
        foreach (Config::get('auth_methods') as $method) {
 
94
            $function_name = $method . '_auth';
 
95
 
 
96
            if (!method_exists('Auth', $function_name)) { 
 
97
                continue;
 
98
            }
 
99
 
 
100
            $results = self::$function_name($username, $password);
 
101
            if ($results['success']) { break; }
 
102
        }
 
103
 
 
104
        return $results;
 
105
    }
 
106
 
 
107
    /**
 
108
     * mysql_auth
 
109
     *
 
110
     * This is the core function of our built-in authentication.
 
111
     */
 
112
    private static function mysql_auth($username, $password) {
 
113
 
 
114
        if (strlen($password) && strlen($username)) {
 
115
            $sql = 'SELECT `password` FROM `user` WHERE `username` = ?';
 
116
            $db_results = Dba::read($sql, array($username));
 
117
 
 
118
            if ($row = Dba::fetch_assoc($db_results)) {
 
119
                // Use SHA2 now... cooking with fire.
 
120
                // For backwards compatibility we hash a couple of different
 
121
                // variations of the password. Increases collision chances, but
 
122
                // doesn't break things.
 
123
                // FIXME: Break things in the future.
 
124
                $hashed_password[] = hash('sha256', $password);
 
125
                $hashed_password[] = hash('sha256', 
 
126
                    Dba::escape(stripslashes(htmlspecialchars(strip_tags($password)))));
 
127
 
 
128
                // Automagically update the password if it's old and busted.
 
129
                if ($row['password'] == $hashed_password[1] &&
 
130
                    $hashed_password[0] != $hashed_password[1]) {
 
131
                    $user = User::get_from_username($username);
 
132
                    $user->update_password($password);
 
133
                }
 
134
 
 
135
                if (in_array($row['password'], $hashed_password)) {
 
136
                    return array(
 
137
                        'success' => true,
 
138
                        'type' => 'mysql',
 
139
                        'username' => $username
 
140
                    );
 
141
                }
 
142
            }
 
143
        }
 
144
 
 
145
        return array(
 
146
            'success' => false,
 
147
            'error' => 'MySQL login attempt failed'
 
148
        );
 
149
    }
 
150
 
 
151
    /**
 
152
     * pam_auth
 
153
     *
 
154
     * Check to make sure the pam_auth function is implemented (module is 
 
155
     * installed), then check the credentials.
 
156
     */
 
157
    private static function pam_auth($username, $password) {
 
158
        if (!function_exists('pam_auth')) {
 
159
            $results['success']    = false;
 
160
            $results['error']    = 'The PAM PHP module is not installed';
 
161
            return $results;
 
162
        }
 
163
 
 
164
        $password = scrub_in($password);
 
165
 
 
166
        if (pam_auth($username, $password)) {
 
167
            $results['success']    = true;
 
168
            $results['type']    = 'pam';
 
169
            $results['username']    = $username;
 
170
        }
 
171
        else {
 
172
            $results['success']    = false;
 
173
            $results['error']    = 'PAM login attempt failed';
 
174
        }
 
175
 
 
176
        return $results;
 
177
    }
 
178
 
 
179
    /**
 
180
     * external_auth
 
181
     *
 
182
     * Calls an external program compatible with mod_authnz_external
 
183
     * such as pwauth.
 
184
     */
 
185
    private static function external_auth($username, $password) {
 
186
        $authenticator = Config::get('external_authenticator');
 
187
        if (!$authenticator) {
 
188
            return array(
 
189
                'success' => false,
 
190
                'error' => 'No external authenticator configured'
 
191
            );
 
192
        }
 
193
 
 
194
        //FIXME: should we do input sanitization?
 
195
        $proc = proc_open($authenticator,
 
196
            array(
 
197
                0 => array('pipe', 'r'),
 
198
                1 => array('pipe', 'w'),
 
199
                2 => array('pipe', 'w')
 
200
            ), $pipes);
 
201
 
 
202
        if (is_resource($proc)) {
 
203
            fwrite($pipes[0], $username."\n".$password."\n");
 
204
            fclose($pipes[0]);
 
205
            fclose($pipes[1]);
 
206
            if ($stderr = fread($pipes[2], 8192)) {
 
207
                debug_event('external_auth', $stderr, 5);
 
208
            }
 
209
            fclose($pipes[2]);
 
210
        }
 
211
        else {
 
212
            return array(
 
213
                'success' => false,
 
214
                'error' => 'Failed to run external authenticator'
 
215
            );
 
216
        }
 
217
 
 
218
        if (proc_close($proc) == 0) {
 
219
            return array(
 
220
                'success' => true,
 
221
                'type' => 'external',
 
222
                'username' => $username
 
223
            );
 
224
        }
 
225
 
 
226
        return array(
 
227
            'success' => false,
 
228
            'error' => 'The external authenticator did not accept the login'
 
229
        );
 
230
    }
 
231
 
 
232
    /**
 
233
     * ldap_auth
 
234
     * Step one, connect to the LDAP server and perform a search for the
 
235
     * username provided.
 
236
     * Step two, attempt to bind using that username and the password
 
237
     * provided.
 
238
     * Step three, figure out if they are authorized to use ampache:
 
239
     * TODO: in config but unimplemented:
 
240
     *      * require-dn "Grant access if the DN in the directive matches 
 
241
     *        the DN fetched from the LDAP directory"
 
242
     *      * require-attribute "an attribute fetched from the LDAP 
 
243
     *        directory matches the given value"
 
244
     */
 
245
    private static function ldap_auth($username, $password) {
 
246
 
 
247
        $ldap_username    = Config::get('ldap_username');
 
248
        $ldap_password    = Config::get('ldap_password');
 
249
 
 
250
        $require_group    = Config::get('ldap_require_group');
 
251
 
 
252
        // This is the DN for the users (required)
 
253
        $ldap_dn    = Config::get('ldap_search_dn');
 
254
 
 
255
        // This is the server url (required)
 
256
        $ldap_url    = Config::get('ldap_url');
 
257
 
 
258
        // This is the ldap filter string (required)
 
259
        $ldap_filter    = Config::get('ldap_filter');
 
260
 
 
261
        //This is the ldap objectclass (required)
 
262
        $ldap_class    = Config::get('ldap_objectclass');
 
263
 
 
264
        if (!($ldap_dn && $ldap_url && $ldap_filter && $ldap_class)) {
 
265
            debug_event('ldap_auth', 'Required config value missing', 1);
 
266
            $results['success'] = false;
 
267
            $results['error'] = 'Incomplete LDAP config';
 
268
            return $results;
 
269
        }
 
270
 
 
271
        $ldap_name_field    = Config::get('ldap_name_field');
 
272
        $ldap_email_field    = Config::get('ldap_email_field');
 
273
 
 
274
        if ($ldap_link = ldap_connect($ldap_url) ) {
 
275
 
 
276
            /* Set to Protocol 3 */
 
277
            ldap_set_option($ldap_link, LDAP_OPT_PROTOCOL_VERSION, 3);
 
278
 
 
279
            // bind using our auth if we need to for initial search
 
280
            if (!ldap_bind($ldap_link, $ldap_username, $ldap_password)) {
 
281
                $results['success'] = false;
 
282
                $results['error'] = 'Could not bind to LDAP server.';
 
283
                return $results;
 
284
            } // If bind fails
 
285
 
 
286
            $sr = ldap_search($ldap_link, $ldap_dn, "(&(objectclass=$ldap_class)($ldap_filter=$username))");
 
287
            $info = ldap_get_entries($ldap_link, $sr);
 
288
 
 
289
            if ($info["count"] == 1) {
 
290
                $user_entry = ldap_first_entry($ldap_link, $sr);
 
291
                $user_dn    = ldap_get_dn($ldap_link, $user_entry);
 
292
                $password   = scrub_in($password);
 
293
                // bind using the user..
 
294
                $retval = ldap_bind($ldap_link, $user_dn, $password);
 
295
 
 
296
                if ($retval) {
 
297
                    // When the current user needs to be in
 
298
                    // a specific group to access Ampache,
 
299
                    // check whether the 'member' list of 
 
300
                    // the group contains the DN
 
301
                    if ($require_group) {
 
302
                        $group_result = ldap_read($ldap_link, $require_group, 'objectclass=*', array('member'));
 
303
                        if (!$group_result) {
 
304
                            debug_event('ldap_auth', "Failure reading $require_group", 1);
 
305
                            $results['success'] = false;
 
306
                            $results['error'] = 'The LDAP group could not be read';
 
307
                            return $results;
 
308
                        }
 
309
 
 
310
                        $group_info = ldap_get_entries($ldap_link, $group_result);
 
311
 
 
312
                        if ($group_info['count'] < 1) {
 
313
                            debug_event('ldap_auth', "No members found in $require_group", 1);
 
314
                            $results['success'] = false;
 
315
                            $results['error'] = 'Empty LDAP group';
 
316
                            return $results;
 
317
                        }
 
318
 
 
319
                        $group_match = preg_grep("/^$user_dn\$/i", $group_info[0]['member']);
 
320
                        if (!$group_match) {
 
321
                            debug_event('ldap_auth', "$user_dn is not a member of $require_group",1);
 
322
                            $results['success'] = false;
 
323
                            $results['error'] = 'LDAP login attempt failed';
 
324
                            return $results;
 
325
                        }
 
326
                    }
 
327
                    ldap_close($ldap_link);
 
328
                    $results['success']  = true;
 
329
                    $results['type']     = "ldap";
 
330
                    $results['username'] = $username;
 
331
                    $results['name']     = $info[0][$ldap_name_field][0];
 
332
                    $results['email']    = $info[0][$ldap_email_field][0];
 
333
 
 
334
                    return $results;
 
335
 
 
336
                } // if we get something good back
 
337
 
 
338
            } // if something was sent back
 
339
 
 
340
        } // if failed connect
 
341
 
 
342
        /* Default to bad news */
 
343
        $results['success'] = false;
 
344
        $results['error']   = 'LDAP login attempt failed';
 
345
 
 
346
        return $results;
 
347
 
 
348
    } // ldap_auth
 
349
 
 
350
    /**
 
351
     * http_auth
 
352
     * This auth method relies on HTTP auth from the webserver
 
353
     */
 
354
    private static function http_auth($username, $password) {
 
355
        if (($_SERVER['REMOTE_USER'] == $username) ||
 
356
            ($_SERVER['HTTP_REMOTE_USER'] == $username)) {
 
357
            $results['success']    = true;
 
358
            $results['type']    = 'http';
 
359
            $results['username']    = $username;
 
360
            $results['name']    = $username;
 
361
            $results['email']    = '';
 
362
        }
 
363
        else {
 
364
            $results['success'] = false;
 
365
            $results['error']   = 'HTTP auth login attempt failed';
 
366
        }
 
367
        return $results;
 
368
    } // http_auth
 
369
 
 
370
}
 
371
?>