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 */ 15abstract 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) { 28 $this->site_config = $config; 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) {} 45} 46 47/** 48 * Stub for dynamic authentication 49 */ 50class Hm_Auth_Dynamic extends Hm_Auth { 51 public function check_credentials($user, $pass) { 52 return false; 53 } 54} 55/** 56 * Authenticate against an included DB 57 */ 58class 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 conneciton 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) { 73 $this->connect(); 74 $row = Hm_DB::execute($this->dbh, 'select hash from hm_user where username = ?', array($user)); 75 if ($row && array_key_exists('hash', $row) && $row['hash'] && Hm_Crypt::check_password($pass, $row['hash'])) { 76 return true; 77 } 78 sleep(2); 79 Hm_Debug::add(sprintf('DB AUTH failed for %s', $user)); 80 return false; 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) { 89 $this->connect(); 90 if (Hm_DB::execute($this->dbh, 'delete from hm_user where username = ?', array($user))) { 91 return true; 92 } 93 return false; 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() { 101 $this->dbh = Hm_DB::connect($this->site_config); 102 if ($this->dbh) { 103 return true; 104 } 105 Hm_Debug::add(sprintf('Unable to connect to the DB auth server %s', $this->site_config->get('db_host'))); 106 return false; 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) { 116 $this->connect(); 117 $hash = Hm_Crypt::hash_password($pass); 118 if (Hm_DB::execute($this->dbh, 'update hm_user set hash=? where username=?', array($hash, $user))) { 119 return true; 120 } 121 return false; 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) { 131 $this->connect(); 132 $result = 0; 133 $res = Hm_DB::execute($this->dbh, 'select username from hm_user where username = ?', array($user)); 134 if (!empty($res)) { 135 $result = 1; 136 } 137 else { 138 $hash = Hm_Crypt::hash_password($pass); 139 if (Hm_DB::execute($this->dbh, 'insert into hm_user values(?,?)', array($user, $hash))) { 140 $result = 2; 141 } 142 } 143 return $result; 144 } 145} 146 147/** 148 * Authenticate against an IMAP server 149 */ 150class Hm_Auth_IMAP extends Hm_Auth { 151 152 /** 153 * Assign site config, get required libs 154 * @param object $config site config 155 */ 156 public function __construct($config) { 157 $this->site_config = $config; 158 require_once APP_PATH.'modules/imap/hm-imap.php'; 159 } 160 161 /* IMAP authentication server settings */ 162 private $imap_settings = array(); 163 164 /** 165 * @param object $imap imap connection object 166 * @return boolean 167 */ 168 private function check_connection($imap) { 169 $imap->connect($this->imap_settings); 170 if ($imap->get_state() == 'authenticated') { 171 return true; 172 } 173 elseif ($imap->get_state() != 'connected') { 174 Hm_Debug::add($imap->show_debug(true)); 175 Hm_Debug::add(sprintf('Unable to connect to the IMAP auth server %s', $this->imap_settings['server'])); 176 return false; 177 } 178 else { 179 Hm_Debug::add($imap->show_debug(true)); 180 Hm_Debug::add(sprintf('IMAP AUTH failed for %s', $this->imap_settings['username'])); 181 return false; 182 } 183 } 184 185 /** 186 * Send the username and password to the configured IMAP server for authentication 187 * @param string $user username 188 * @param string $pass password 189 * @return bool true if authentication worked 190 */ 191 public function check_credentials($user, $pass) { 192 $imap = new Hm_IMAP(); 193 list($server, $port, $tls) = get_auth_config($this->site_config, 'imap'); 194 if (!$user || !$pass || !$server || !$port) { 195 Hm_Debug::add($imap->show_debug(true)); 196 Hm_Debug::add('Invalid IMAP auth configuration settings'); 197 return false; 198 } 199 $this->imap_settings = array('server' => $server, 'port' => $port, 200 'tls' => $tls, 'username' => $user, 'password' => $pass, 201 'no_caps' => false, 'blacklisted_extensions' => array('enable') 202 ); 203 return $this->check_connection($imap); 204 } 205 206 /** 207 * Save IMAP server details 208 * @param object $session session object 209 * @return void 210 */ 211 public function save_auth_detail($session) { 212 $session->set('imap_auth_server_settings', $this->imap_settings); 213 } 214} 215 216/** 217 * Authenticate against a POP3 server 218 */ 219class Hm_Auth_POP3 extends Hm_Auth { 220 221 /* POP3 authentication server settings */ 222 private $pop3_settings = array(); 223 224 /** 225 * Assign site config, get required libs 226 * @param object $config site config 227 */ 228 public function __construct($config) { 229 $this->site_config = $config; 230 require_once APP_PATH.'modules/pop3/hm-pop3.php'; 231 } 232 233 /** 234 * @param object $pop3 pop3 connection object 235 * @param string $user username to login with 236 * @param string $pass password to login with 237 * @param string $server server to login to 238 * @return boolean 239 */ 240 private function check_connection($pop3, $user, $pass, $server) { 241 if (!$pop3->connect()) { 242 Hm_Debug::add($pop3->puke()); 243 Hm_Debug::add(sprintf('Unable to connect to the POP3 auth server %s', $server)); 244 return false; 245 } 246 if (!$pop3->auth($user, $pass)) { 247 Hm_Debug::add($pop3->puke()); 248 Hm_Debug::add(sprintf('POP3 AUTH failed for %s', $user)); 249 return false; 250 } 251 return true; 252 } 253 254 /** 255 * Send the username and password to the configured POP3 server for authentication 256 * @param string $user username 257 * @param string $pass password 258 * @return bool true if authentication worked 259 */ 260 public function check_credentials($user, $pass) { 261 $pop3 = new Hm_POP3(); 262 list($server, $port, $tls) = get_auth_config($this->site_config, 'pop3'); 263 if ($user && $pass && $server && $port) { 264 $this->pop3_settings = array( 265 'server' => $server, 266 'port' => $port, 267 'tls' => $tls, 268 'username' => $user, 269 'password' => $pass, 270 'no_caps' => true 271 ); 272 $pop3->server = $server; 273 $pop3->port = $port; 274 $pop3->tls = $tls; 275 return $this->check_connection($pop3, $user, $pass, $server); 276 } 277 Hm_Debug::add($pop3->puke()); 278 Hm_Debug::add('Invalid POP3 auth configuration settings'); 279 return false; 280 } 281 282 /** 283 * Save POP3 server details 284 * @param object $session session object 285 * @return void 286 */ 287 public function save_auth_detail($session) { 288 $session->set('pop3_auth_server_settings', $this->pop3_settings); 289 } 290} 291 292/** 293 * Authenticate against an LDAP server 294 */ 295class Hm_Auth_LDAP extends Hm_Auth { 296 297 protected $config = array(); 298 protected $fh; 299 protected $source = 'ldap'; 300 301 /** 302 * Build connect uri 303 * @return string 304 */ 305 private function connect_details() { 306 $prefix = 'ldaps://'; 307 $server = $this->apply_config_value('server', 'localhost'); 308 $port = $this->apply_config_value('port', 389); 309 if (array_key_exists('enable_tls', $this->config) && !$this->config['enable_tls']) { 310 $prefix = 'ldap://'; 311 } 312 return $prefix.$server.':'.$port; 313 } 314 315 /** 316 * @param string $name 317 * @param mixed $default 318 * @return mixed 319 */ 320 private function apply_config_value($name, $default) { 321 if (array_key_exists($name, $this->config) && trim($this->config[$name])) { 322 return $this->config[$name]; 323 } 324 return $default; 325 } 326 327 /** 328 * Check a username and password 329 * @param string $user username 330 * @param string $pass password 331 * @return boolean 332 */ 333 public function check_credentials($user, $pass) { 334 list($server, $port, $tls) = get_auth_config($this->site_config, 'ldap'); 335 $base_dn = $this->site_config->get('ldap_auth_base_dn', false); 336 if ($server && $port && $base_dn) { 337 $user = sprintf('cn=%s,%s', $user, $base_dn); 338 $this->config = array( 339 'server' => $server, 340 'port' => $port, 341 'enable_tls' => $tls, 342 'base_dn' => $base_dn, 343 'user' => $user, 344 'pass' => $pass 345 ); 346 return $this->connect(); 347 } 348 Hm_Debug::add('Invalid LDAP auth configuration settings'); 349 return false; 350 } 351 352 /** 353 * Connect and auth to the LDAP server 354 * @return boolean 355 */ 356 public function connect() { 357 if (!Hm_Functions::function_exists('ldap_connect')) { 358 return false; 359 } 360 $uri = $this->connect_details(); 361 $this->fh = @ldap_connect($uri); 362 if ($this->fh) { 363 ldap_set_option($this->fh, LDAP_OPT_PROTOCOL_VERSION, 3); 364 return $this->auth(); 365 } 366 Hm_Debug::add(sprintf('Unable to connect to the LDAP auth server %s', $this->config['server'])); 367 return false; 368 } 369 370 /** 371 * Authenticate to the LDAP server 372 * @return boolean 373 */ 374 protected function auth() { 375 $result = @ldap_bind($this->fh, $this->config['user'], $this->config['pass']); 376 ldap_unbind($this->fh); 377 if (!$result) { 378 Hm_Debug::add(sprintf('LDAP AUTH failed for %s', $this->config['user'])); 379 } 380 return $result; 381 } 382} 383 384/* 385 * @param object $config site config object 386 * @param string $prefix settings prefix 387 * @return array 388 */ 389function get_auth_config($config, $prefix) { 390 $server = $config->get($prefix.'_auth_server', false); 391 $port = $config->get($prefix.'_auth_port', false); 392 $tls = $config->get($prefix.'_auth_tls', false); 393 return array($server, $port, $tls); 394} 395