user_wcf.php 5.97 KB
Newer Older
1
2
<?php
/**
3
 * Copyright (c) 2013 Fritz Webering <fritz@webering.eu>
4
5
 * This file is licensed under the Affero General Public License version 3 or
 * later.
6
 * See the LICENSE file.
7
8
9
10
 */

namespace OCA\user_wcf;

11
use OC\User\Backend;
12
13
14
15
16
17
18

/**
 * This class authenticates users against a WCF database if they belong to
 * one or more of the groups listed in the $authorizedGroups paramter. The
 * database configuration is imported from the WCF configuration file of
 * the WCF installation given in the $wcfPath paramter.
 */
19
class User_WCF implements \OCP\IUserBackend, \OCP\UserInterface {
Fritz Webering's avatar
Fritz Webering committed
20
21
22
23
    protected $authorizedGroups;
    protected $groupsCondition;
    protected $db = NULL;
    protected $dbUser, $dbHost, $dbPassword, $dbName;
24

25
26
27
    public function __construct() {
        require(\OC_App::getAppPath('user_wcf').'/config/config.php');
        if (!file_exists($wcfPath) || !is_dir($wcfPath)) throw new \Exception('Not a valid WCF path: "'.$wcfPath.'"');
Fritz Webering's avatar
Fritz Webering committed
28
29
30
31
        $this->db = lib\WCF_DB::getInstance($wcfPath);
        $this->db->setAuthorizedGroups($authorizedGroups);
    }

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
    /**
     * Backend name to be shown in user management
     * @return string the name of the backend to be shown
     * @since 8.0.0
     */
    public function getBackendName() {
        return "WCF";
    }

    /**
     * Check if backend implements actions
     * @param int $actions bitwise-or'ed actions
     * @return boolean
     *
     * Returns the supported actions as int to be
     * compared with \OC_User_Backend::CREATE_USER etc.
     * @since 4.5.0
     */
    public function implementsActions($actions) {
        return (bool)((Backend::CHECK_PASSWORD
                | Backend::GET_DISPLAYNAME)
                & $actions);
    }

    /**
     * delete a user
     * @param string $uid The username of the user to delete
     * @return bool
     * @since 4.5.0
     * @todo
     */
    public function deleteUser($uid);

    /**
     * Get a list of all users
     *
     * @param string $search
     * @param null|int $limit
     * @param null|int $offset
     * @return string[] an array of all uids
     * @since 4.5.0
     */
    public function getUsers($search = '', $limit = null, $offset = null) {
        $users = array();
        $params = array();
        $where = NULL;
        $append = 'ORDER BY username';

        if ($search !== '') {
            $where = 'username LIKE ?';
            $params[] = '%'.$search.'%';
        }
        if ($limit !== NULL) {
            $append .= ' LIMIT '.intval($limit);
        }
        if ($offset !== NULL) {
            $append .= ' OFFSET '.intval($offset);;
        }

        $result = $this->db->prepare('username', $where, $append);
        if ($result !== FALSE and $result->execute($params)) {
            if ($result->rowCount() <= 0) {
                $this->warn('No users returned from database.');
            }
            foreach ($result as $row) {
                $users[] = $row['username'];
            }
            $result->closeCursor();
        }
        else {
            $this->warn('Error executing statement to get user list.');
        }

        return $users;
    }

    /**
     * check if a user exists
     * @param string $uid the username
     * @return boolean
     * @since 4.5.0
     */
    public function userExists($uid) {
        $exists = FALSE;
        $result = $this->db->prepare('1', 'username=?');

        if ($result !== FALSE and $result->execute(array($uid))) {
            $exists = ($result->fetch() !== FALSE);
            $result->closeCursor();
        }
        return $exists;
    }

    /**
     * get display name of the user
     * @param string $uid user ID of the user
     * @return string display name
     * @since 4.5.0
     * @todo
     */
    public function getDisplayName($uid);

    /**
     * Get a list of all display names and user ids.
     *
     * @param string $search
     * @param string|null $limit
     * @param string|null $offset
     * @return array an array of all displayNames (value) and the corresponding uids (key)
     * @since 4.5.0
     * @todo
     */
    public function getDisplayNames($search = '', $limit = null, $offset = null);

    /**
     * Check if a user list is available or not
     * @return boolean if users can be listed or not
     * @since 4.5.0
     */
    public function hasUserListings() {
        return true;
153
154
155
156
157
158
159
160
161
162
163
164
    }

    /**
     * @brief Check if the password is correct
     * @param $uid The username
     * @param $password The password
     * @returns string
     *
     * Check if the password is correct without logging in the user
     * returns the user id or false
     */
    public function checkPassword($uid, $password) {
165
        $authenticatedAs = FALSE;
166

Fritz Webering's avatar
Fritz Webering committed
167
168
        $where = 'LOWER(username)=LOWER(?)';
        $result = $this->db->prepare('username, password, salt', $where);
169

Fritz Webering's avatar
Fritz Webering committed
170
171
        if ($result !== FALSE and $result->execute(array($uid))) {
            if (($row = $result->fetch()) !== FALSE) {
172
173
                $doubleSalted = lib\StringUtil::getDoubleSaltedHash(
                    $password, $row['salt']);
174

Fritz Webering's avatar
Fritz Webering committed
175
                if ($doubleSalted === $row['password']) {
176
                    $authenticatedAs = $row['username'];
177
                    $this->debug('User "'.$authenticatedAs.
178
                        '" logged in successfully.');
179
                }
Fritz Webering's avatar
Fritz Webering committed
180
                else {
181
                    $this->info('Invalid password for user '.$uid.'.');
Fritz Webering's avatar
Fritz Webering committed
182
                }
183
184
            }
            else {
Fritz Webering's avatar
Fritz Webering committed
185
                $this->info('User '.$uid.' is not in any authorized group.');
186
            }
Fritz Webering's avatar
Fritz Webering committed
187
188
189
            $result->closeCursor();
        }
        else {
190
            $this->warn('Error while checking password for user '.$uid);
191
192
        }

193
        return $authenticatedAs;
194
195
    }

Fritz Webering's avatar
Fritz Webering committed
196
197
    public static function info($text) {
        \OCP\Util::writeLog('user_wcf', $text, \OCP\Util::INFO);
Fritz Webering's avatar
Fritz Webering committed
198
199
    }

Fritz Webering's avatar
Fritz Webering committed
200
    public static function warn($text) {
Fritz Webering's avatar
Fritz Webering committed
201
        \OCP\Util::writeLog('user_wcf', $text, \OCP\Util::WARN);
202
203
    }

Fritz Webering's avatar
Fritz Webering committed
204
    public static function debug($text) {
205
206
207
        \OCP\Util::writeLog('user_wcf', $text, \OCP\Util::DEBUG);
    }
}