• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cypht-org / cypht / 26230827274

21 May 2026 02:01PM UTC coverage: 72.803% (-5.4%) from 78.201%
26230827274

push

travis-ci

web-flow
Merge pull request #1972 from IrAlfred/remove-duplicate-testdox-flag-in-coverage-report

fix(workflow): remove duplicate --testdox flag causing coverage job exit code 1

4797 of 6589 relevant lines covered (72.8%)

7.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.64
/lib/auth.php
1
<?php
2

3
/**
4
 * Authentication classes
5
 * @package framework
6
 * @subpackage auth
7
 */
8

9
/**
10
 * Base class for authentication
11
 * Creating a new authentication method requires extending this class
12
 * and overriding the check_credentials method
13
 * @abstract
14
 */
15
abstract class Hm_Auth {
16

17
    /* site configuration object */
18
    protected $site_config;
19

20
    /* bool flag defining if users are internal */
21
    static public $internal_users = false;
22

23
    /**
24
     * Assign site config
25
     * @param object $config site config
26
     */
27
    public function __construct($config) {
8✔
28
        $this->site_config = $config;
8✔
29
    }
30

31
    /**
32
     * This is the method new auth mechs need to override.
33
     * @param string $user username
34
     * @param string $pass password
35
     * @return bool true if the user is authenticated, false otherwise
36
     */
37
    abstract public function check_credentials($user, $pass);
38

39
    /**
40
     * Optional method for auth mech to save login details
41
     * @param object $session session object
42
     * @return void
43
     */
44
    public function save_auth_detail($session) {}
2✔
45
}
46

47
/**
48
 * Stub for dynamic authentication
49
 */
50
class Hm_Auth_Dynamic extends Hm_Auth {
51
    public function check_credentials($user, $pass) {
1✔
52
        return false;
1✔
53
    }
54
}
55
/**
56
 * Authenticate against an included DB
57
 */
58
class Hm_Auth_DB extends Hm_Auth {
59

60
    /* bool flag indicating this is an internal user setup */
61
    static public $internal_users = true;
62

63
    /* database connection handle */
64
    public $dbh;
65

66
    /**
67
     * Send the username and password to the configured DB for authentication
68
     * @param string $user username
69
     * @param string $pass password
70
     * @return bool true if authentication worked
71
     */
72
    public function check_credentials($user, $pass) {
4✔
73
        $this->connect();
4✔
74
        $row = Hm_DB::execute($this->dbh, 'select hash from hm_user where username = ?', [$user]);
4✔
75
        if ($row && !empty($row['hash']) && Hm_Crypt::check_password($pass, $row['hash'])) {
4✔
76
            return true;
4✔
77
        }
78
        sleep(2);
3✔
79
        Hm_Debug::add(sprintf('DB AUTH failed for %s', $user));
3✔
80
        return false;
3✔
81
    }
82

83
    /**
84
     * Delete a user account from the db
85
     * @param string $user username
86
     * @return bool true if successful
87
     */
88
    public function delete($user) {
2✔
89
        $this->connect();
2✔
90
        if (Hm_DB::execute($this->dbh, 'delete from hm_user where username = ?', [$user])) {
2✔
91
            return true;
2✔
92
        }
93
        return false;
1✔
94
    }
95

96
    /**
97
     * Create a new or re-use an existing DB connection
98
     * @return bool true if the connection is available
99
     */
100
    protected function connect() {
8✔
101
        $this->dbh = Hm_DB::connect($this->site_config);
8✔
102
        if ($this->dbh) {
8✔
103
            return true;
8✔
104
        }
105
        Hm_Debug::add(sprintf('Unable to connect to the DB auth server %s', $this->site_config->get('db_host')));
2✔
106
        return false;
2✔
107
    }
108

109
    /**
110
     * Change the password for a user in the DB
111
     * @param string $user username
112
     * @param string $pass password
113
     * @return bool true on success
114
     */
115
    public function change_pass($user, $pass) {
2✔
116
        $this->connect();
2✔
117
        $hash = Hm_Crypt::hash_password($pass);
2✔
118
        if (Hm_DB::execute($this->dbh, 'update hm_user set hash=? where username=?', [$hash, $user])) {
2✔
119
            return true;
2✔
120
        }
121
        return false;
1✔
122
    }
123

124
    /**
125
     * Create a new user in the DB
126
     * @param string $user username
127
     * @param string $pass password
128
     * @return integer
129
     */
130
    public function create($user, $pass) {
3✔
131
        $this->connect();
3✔
132
        $result = 0;
3✔
133
        $res = Hm_DB::execute($this->dbh, 'select username from hm_user where username = ?', [$user]);
3✔
134
        if (!empty($res)) {
3✔
135
            //this var will prevent showing print in phpuni tests
136
            if(!defined('CYPHT_PHPUNIT_TEST_MODE')) {
2✔
137
                print("user {$user} already exists\n");
×
138
            }
139
            $result = 1;
2✔
140
        }
141
        else {
142
            $hash = Hm_Crypt::hash_password($pass);
2✔
143
            if (Hm_DB::execute($this->dbh, 'insert into hm_user values(?,?)', [$user, $hash])) {
2✔
144
                $result = 2;
2✔
145
            }
146
        }
147
        return $result;
3✔
148
    }
149
}
150

151
/**
152
 * Authenticate against an IMAP server
153
 */
154
class Hm_Auth_IMAP extends Hm_Auth {
155

156
    /**
157
     * Assign site config, get required libs
158
     * @param object $config site config
159
     */
160
    public function __construct($config) {
1✔
161
        $this->site_config = $config;
1✔
162
        require_once APP_PATH.'modules/imap/hm-imap.php';
1✔
163
        include_once APP_PATH.'modules/sievefilters/hm-sieve.php';
1✔
164
    }
165

166
    /* IMAP authentication server settings */
167
    private $imap_settings = [];
168

169
    /**
170
     * @param object $imap imap connection object
171
     * @return boolean
172
     */
173
    private function check_connection($imap) {
1✔
174
        $imap->connect($this->imap_settings);
1✔
175
        if ($imap->get_state() == 'authenticated') {
1✔
176
            return true;
1✔
177
        }
178
        elseif ($imap->get_state() != 'connected') {
1✔
179
            Hm_Debug::add($imap->show_debug(true));
1✔
180
            Hm_Debug::add(sprintf('Unable to connect to the IMAP auth server %s', $this->imap_settings['server']));
1✔
181
            return false;
1✔
182
        }
183
        else {
184
            Hm_Debug::add($imap->show_debug(true));
1✔
185
            Hm_Debug::add(sprintf('IMAP AUTH failed for %s', $this->imap_settings['username']));
1✔
186
            return false;
1✔
187
        }
188
    }
189

190
    /**
191
     * Send the username and password to the configured IMAP server for authentication
192
     * @param string $user username
193
     * @param string $pass password
194
     * @return bool true if authentication worked
195
     */
196
    public function check_credentials($user, $pass) {
1✔
197
        $imap = new Hm_IMAP();
1✔
198
        list($server, $port, $tls, $sieve_config, $sieve_tls_mode) = get_auth_config($this->site_config, 'imap');
1✔
199
        if (!$user || !$pass || !$server || !$port) {
1✔
200
            Hm_Debug::add($imap->show_debug(true));
1✔
201
            Hm_Debug::add('Invalid IMAP auth configuration settings', 'danger');
1✔
202
            return false;
1✔
203
        }
204
        $this->imap_settings = ['server' => $server, 'port' => $port,
1✔
205
            'tls' => $tls, 'username' => $user, 'password' => $pass,
1✔
206
            'no_caps' => false, 'blacklisted_extensions' => ['enable'],
1✔
207
            'sieve_config_host' => $sieve_config,
1✔
208
            'sieve_tls' => $sieve_tls_mode
1✔
209
        ];
1✔
210
        return $this->check_connection($imap);
1✔
211
    }
212

213
    /**
214
     * Save IMAP server details
215
     * @param object $session session object
216
     * @return void
217
     */
218
    public function save_auth_detail($session) {
1✔
219
        $session->set('imap_auth_server_settings', $this->imap_settings);
1✔
220
    }
221
}
222

223
/**
224
 * Authenticate against an LDAP server
225
 */
226
class Hm_Auth_LDAP extends Hm_Auth {
227

228
    protected $config = [];
229
    protected $fh;
230
    protected $source = 'ldap';
231

232
    /**
233
     * Build connect uri
234
     * @return string
235
     */
236
    private function connect_details() {
1✔
237
        $prefix = 'ldaps://';
1✔
238
        $server = $this->apply_config_value('server', 'localhost');
1✔
239
        $port = $this->apply_config_value('port', 389);
1✔
240
        if (
241
            empty($this->config['enable_tls']) ||
1✔
242
            $this->config['enable_tls'] === false ||
×
243
            strtolower($this->config['enable_tls']) === "false"
1✔
244
        ) {
245
            $prefix = 'ldap://';
1✔
246
        }
247
        return $prefix.$server.':'.$port;
1✔
248
    }
249

250
    /**
251
     * @param string $name
252
     * @param mixed $default
253
     * @return mixed
254
     */
255
    private function apply_config_value($name, $default) {
1✔
256
        return !empty($this->config[$name]) ? $this->config[$name] : $default;
1✔
257
    }
258

259
    /**
260
     * Check a username and password
261
     * @param string $user username
262
     * @param string $pass password
263
     * @return boolean
264
     */
265
    public function check_credentials($user, $pass) {
1✔
266
        list($server, $port, $tls) = get_auth_config($this->site_config, 'ldap');
1✔
267
        $base_dn = $this->site_config->get('ldap_auth_base_dn', false);
1✔
268
        $uid_auth_attr = $this->site_config->get('ldap_auth_uid_attr', false);
1✔
269
        if ($server && $port && $base_dn) {
1✔
270
            if (strpos($user, '@') !== false || strpos($user, '\\') !== false) {
1✔
271
                $bind_dn = $user;
×
272
            } else {
273
                $bind_dn = sprintf('%s=%s,%s', $uid_auth_attr, $user, $base_dn);
1✔
274
            }
275
            $this->config = [
1✔
276
                'server' => $server,
1✔
277
                'port' => $port,
1✔
278
                'enable_tls' => $tls,
1✔
279
                'base_dn' => $base_dn,
1✔
280
                'user' => $bind_dn,
1✔
281
                'pass' => $pass
1✔
282
            ];
1✔
283
            return $this->connect();
1✔
284
        }
285
        Hm_Debug::add('Invalid LDAP auth configuration settings', 'danger');
1✔
286
        return false;
1✔
287
    }
288

289
    /**
290
     * Connect and auth to the LDAP server
291
     * @return boolean
292
     */
293
    public function connect() {
1✔
294
        if (!Hm_Functions::function_exists('ldap_connect')) {
1✔
295
            return false;
1✔
296
        }
297
        $uri = $this->connect_details();
1✔
298
        $this->fh = @ldap_connect($uri);
1✔
299
        if ($this->fh) {
1✔
300
            ldap_set_option($this->fh, LDAP_OPT_PROTOCOL_VERSION, 3);
1✔
301
            // Disable LDAP referral following: Active Directory may return referrals for searches
302
            // across domains or special partitions, but for authentication we should keep the check
303
            // local to the connected server without following referrals to other DCs
304
            ldap_set_option($this->fh, LDAP_OPT_REFERRALS, 0);
1✔
305
            return $this->auth();
1✔
306
        }
307
        Hm_Debug::add(sprintf('Unable to connect to the LDAP auth server %s', $this->config['server']));
1✔
308
        return false;
1✔
309
    }
310

311
    /**
312
     * Authenticate to the LDAP server
313
     * @return boolean
314
     */
315
    protected function auth() {
1✔
316
        $result = @ldap_bind($this->fh, $this->config['user'], $this->config['pass']);
1✔
317
        if (!$result) {
1✔
318
            Hm_Debug::add(sprintf('LDAP AUTH failed for %s', $this->config['user']));
1✔
319
        }
320
        return $result;
1✔
321
    }
322
}
323

324
/*
325
 * @param object $config site config object
326
 * @param string $prefix settings prefix
327
 * @return array
328
 */
329
function get_auth_config($config, $prefix) {
330
    $server = $config->get($prefix.'_auth_server', false);
1✔
331
    $port = $config->get($prefix.'_auth_port', false);
1✔
332
    $tls = $config->get($prefix.'_auth_tls', false);
1✔
333
    $ret = [$server, $port, $tls];
1✔
334
    if ($prefix == 'imap') {
1✔
335
        $ret[] = $config->get($prefix.'_auth_sieve_conf_host', false);
1✔
336
        $ret[] = $config->get($prefix.'_auth_sieve_tls_mode', false);
1✔
337
    }
338
    return $ret;
1✔
339
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc