/tine20/Tinebase/Auth.php
PHP | 397 lines | 176 code | 45 blank | 176 comment | 32 complexity | e286cde03494baa1cb2f9127d95c8e1b MD5 | raw file
1<?php
2/**
3 * Tine 2.0
4 *
5 * @package Tinebase
6 * @subpackage Auth
7 * @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
8 * @copyright Copyright (c) 2007-2010 Metaways Infosystems GmbH (http://www.metaways.de)
9 * @author Lars Kneschke <l.kneschke@metaways.de>
10 */
11
12/**
13 * main authentication class
14 *
15 * @todo 2010-05-20 cweiss: the default option handling looks like a big mess -> someone needs to tidy up here!
16 *
17 * @package Tinebase
18 * @subpackage Auth
19 */
20
21class Tinebase_Auth
22{
23 /**
24 * constant for Sql auth
25 *
26 */
27 const SQL = 'Sql';
28
29 /**
30 * constant for LDAP auth
31 *
32 */
33 const LDAP = 'Ldap';
34
35 /**
36 * constant for IMAP auth
37 *
38 */
39 const IMAP = 'Imap';
40
41 /**
42 * General Failure
43 */
44 const FAILURE = Zend_Auth_Result::FAILURE;
45
46 /**
47 * Failure due to identity not being found.
48 */
49 const FAILURE_IDENTITY_NOT_FOUND = Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND;
50
51 /**
52 * Failure due to identity being ambiguous.
53 */
54 const FAILURE_IDENTITY_AMBIGUOUS = Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS;
55
56 /**
57 * Failure due to invalid credential being supplied.
58 */
59 const FAILURE_CREDENTIAL_INVALID = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID;
60
61 /**
62 * Failure due to uncategorized reasons.
63 */
64 const FAILURE_UNCATEGORIZED = Zend_Auth_Result::FAILURE_UNCATEGORIZED;
65
66 /**
67 * Failure due the account is disabled
68 */
69 const FAILURE_DISABLED = -100;
70
71 /**
72 * Failure due the account is expired
73 */
74 const FAILURE_PASSWORD_EXPIRED = -101;
75
76 /**
77 * Failure due the account is temporarly blocked
78 */
79 const FAILURE_BLOCKED = -102;
80
81 /**
82 * database connection failure
83 */
84 const FAILURE_DATABASE_CONNECTION = -103;
85
86 /**
87 * Authentication success.
88 */
89 const SUCCESS = Zend_Auth_Result::SUCCESS;
90
91 /**
92 * the name of the authenticationbackend
93 *
94 * @var string
95 */
96 protected static $_backendType;
97
98 /**
99 * Holds the backend configuration options.
100 * Property is lazy loaded from {@see Tinebase_Config} on first access via
101 * getter {@see getBackendConfiguration()}
102 *
103 * @var array | optional
104 */
105 private static $_backendConfiguration;
106
107 /**
108 * Holds the backend configuration options.
109 * Property is lazy loaded from {@see Tinebase_Config} on first access via
110 * getter {@see getBackendConfiguration()}
111 *
112 * @var array | optional
113 */
114 private static $_backendConfigurationDefaults = array(
115 self::SQL => array(
116 'tryUsernameSplit' => '1',
117 'accountCanonicalForm' => '2',
118 'accountDomainName' => '',
119 'accountDomainNameShort' => '',
120 ),
121 self::LDAP => array(
122 'host' => '',
123 'username' => '',
124 'password' => '',
125 'bindRequiresDn' => true,
126 'baseDn' => '',
127 'accountFilterFormat' => NULL,
128 'accountCanonicalForm' => '2',
129 'accountDomainName' => '',
130 'accountDomainNameShort' => '',
131 ),
132 self::IMAP => array(
133 'host' => '',
134 'port' => 143,
135 'ssl' => 'tls',
136 'domain' => '',
137 ),
138 );
139
140 /**
141 * the instance of the authenticationbackend
142 *
143 * @var Tinebase_Auth_Interface
144 */
145 protected $_backend;
146
147 /**
148 * the constructor
149 *
150 * don't use the constructor. use the singleton
151 */
152 private function __construct() {
153 $this->setBackend();
154 }
155
156 /**
157 * don't clone. Use the singleton.
158 *
159 */
160 private function __clone() {}
161
162 /**
163 * holds the instance of the singleton
164 *
165 * @var Tinebase_Auth
166 */
167 private static $_instance = NULL;
168
169 /**
170 * the singleton pattern
171 *
172 * @return Tinebase_Auth
173 */
174 public static function getInstance()
175 {
176 if (self::$_instance === NULL) {
177 self::$_instance = new Tinebase_Auth;
178 }
179
180 return self::$_instance;
181 }
182
183 /**
184 * authenticate user
185 *
186 * @param string $_username
187 * @param string $_password
188 * @return Zend_Auth_Result
189 */
190 public function authenticate($_username, $_password)
191 {
192 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Trying to authenticate '. $_username);
193
194 $this->_backend->setIdentity($_username);
195 $this->_backend->setCredential($_password);
196
197 $result = Zend_Auth::getInstance()->authenticate($this->_backend);
198
199 if($result->isValid()) {
200 if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Authentication of '. $_username . ' succeeded');
201 } else {
202 if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Authentication of '. $_username . ' failed');
203 }
204
205 return $result;
206 }
207
208 /**
209 * check if password is valid
210 *
211 * @param string $_username
212 * @param string $_password
213 * @return boolean
214 */
215 public function isValidPassword($_username, $_password)
216 {
217 $this->_backend->setIdentity($_username);
218 $this->_backend->setCredential($_password);
219
220 $result = $this->_backend->authenticate();
221
222 if ($result->isValid()) {
223 return true;
224 }
225
226 return false;
227 }
228
229 /**
230 * returns the configured rs backend
231 *
232 * @return string
233 */
234 public static function getConfiguredBackend()
235 {
236 if (!isset(self::$_backendType)) {
237 if (Setup_Controller::getInstance()->isInstalled('Tinebase')) {
238 self::setBackendType(Tinebase_Config::getInstance()->getConfig(Tinebase_Config::AUTHENTICATIONBACKENDTYPE, null, self::SQL)->value);
239 } else {
240 self::setBackendType(self::SQL);
241 }
242 }
243
244 return self::$_backendType;
245 }
246
247 /**
248 * set the auth backend
249 */
250 public function setBackend()
251 {
252 $backendType = self::getConfiguredBackend();
253 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ .' authentication backend: ' . $backendType);
254 $this->_backend = Tinebase_Auth_Factory::factory($backendType);
255 }
256
257 /**
258 * setter for {@see $_backendType}
259 *
260 * @todo persist in db
261 *
262 * @param string $_backendType
263 * @return void
264 */
265 public static function setBackendType($_backendType)
266 {
267 self::$_backendType = ucfirst($_backendType);
268 }
269
270 /**
271 * Setter for {@see $_backendConfiguration}
272 *
273 * NOTE:
274 * Setting will not be written to Database or Filesystem.
275 * To persist the change call {@see saveBackendConfiguration()}
276 *
277 * @param mixed $_value
278 * @param string optional $_key
279 * @return void
280 */
281 public static function setBackendConfiguration($_value, $_key = null)
282 {
283 $defaultValues = self::$_backendConfigurationDefaults[self::getConfiguredBackend()];
284
285 if (is_null($_key) && !is_array($_value)) {
286 throw new Tinebase_Exception_InvalidArgument('To set backend configuration either a key and value parameter are required or the value parameter should be a hash');
287 } elseif (is_null($_key) && is_array($_value)) {
288 foreach ($_value as $key=> $value) {
289 self::setBackendConfiguration($value, $key);
290 }
291 } else {
292 if ( ! array_key_exists($_key, $defaultValues)) {
293 throw new Tinebase_Exception_InvalidArgument("Cannot set backend configuration option '$_key' for authentication provider " . self::getConfiguredBackend());
294 }
295 self::$_backendConfiguration[$_key] = $_value;
296 }
297 }
298
299 /**
300 * Delete the given config setting or all config settings if {@param $_key} is not specified
301 *
302 * @param string | optional $_key
303 * @return void
304 */
305 public static function deleteBackendConfiguration($_key = null)
306 {
307 if (is_null($_key)) {
308 self::$_backendConfiguration = array();
309 } elseif (array_key_exists($_key, self::$_backendConfiguration)) {
310 unset(self::$_backendConfiguration[$_key]);
311 } else {
312 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' configuration option does not exist: ' . $_key);
313 }
314 }
315
316 /**
317 * Write backend configuration setting {@see $_backendConfigurationSettings} and {@see $_backendType} to
318 * db config table.
319 *
320 * @return void
321 */
322 public static function saveBackendConfiguration()
323 {
324 Tinebase_Config::getInstance()->setConfigForApplication(Tinebase_Config::AUTHENTICATIONBACKEND, Zend_Json::encode(self::getBackendConfiguration()));
325 Tinebase_Config::getInstance()->setConfigForApplication(Tinebase_Config::AUTHENTICATIONBACKENDTYPE, self::getConfiguredBackend());
326 }
327
328 /**
329 * Getter for {@see $_backendConfiguration}
330 *
331 * @param boolean $_getConfiguredBackend
332 * @return mixed [If {@param $_key} is set then only the specified option is returned, otherwise the whole options hash]
333 */
334 public static function getBackendConfiguration($_key = null, $_default = null)
335 {
336 //lazy loading for $_backendConfiguration
337 if (!isset(self::$_backendConfiguration)) {
338 if (Setup_Controller::getInstance()->isInstalled('Tinebase')) {
339 $rawBackendConfiguration = Tinebase_Config::getInstance()->getConfig(Tinebase_Config::AUTHENTICATIONBACKEND, null, array())->value;
340 } else {
341 $rawBackendConfiguration = array();
342 }
343 self::$_backendConfiguration = is_array($rawBackendConfiguration) ? $rawBackendConfiguration : Zend_Json::decode($rawBackendConfiguration);
344 }
345
346 if (isset($_key)) {
347 return array_key_exists($_key, self::$_backendConfiguration) ? self::$_backendConfiguration[$_key] : $_default;
348 } else {
349 return self::$_backendConfiguration;
350 }
351 }
352
353 /**
354 * Returns default configuration for all supported backends
355 * and overrides the defaults with concrete values stored in this configuration
356 *
357 * @param String | optional $_key
358 * @return mixed [If {@param $_key} is set then only the specified option is returned, otherwise the whole options hash]
359 */
360 public static function getBackendConfigurationWithDefaults($_getConfiguredBackend = TRUE)
361 {
362 $config = array();
363 $defaultConfig = self::getBackendConfigurationDefaults();
364 foreach ($defaultConfig as $backendType => $backendConfig) {
365 $config[$backendType] = ($_getConfiguredBackend && $backendType == self::getConfiguredBackend() ? self::getBackendConfiguration() : array());
366 if (is_array($config[$backendType])) {
367 foreach ($backendConfig as $key => $value) {
368 // 2010-05-20 cweiss Zend_Ldap changed and does not longer throw exceptions
369 // on unsupported values, we might skip this cleanup here.
370 if (! array_key_exists($key, $config[$backendType])) {
371 $config[$backendType][$key] = $value;
372 }
373 }
374 } else {
375 $config[$backendType] = $backendConfig;
376 }
377 }
378 return $config;
379 }
380
381 /**
382 * Getter for {@see $_backendConfigurationDefaults}
383 * @param String | optional $_backendType
384 * @return array
385 */
386 public static function getBackendConfigurationDefaults($_backendType = null) {
387 if ($_backendType) {
388 if (!array_key_exists($_backendType, self::$_backendConfigurationDefaults)) {
389 throw new Tinebase_Exception_InvalidArgument("Unknown backend type '$_backendType'");
390 }
391 return self::$_backendConfigurationDefaults[$_backendType];
392 } else {
393 return self::$_backendConfigurationDefaults;
394 }
395 }
396
397}