5 * Copyright (C) 2008 Vincent Tunru
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
20 * @license http://www.fsf.org/licensing/licenses/info/GPLv2.html GPL v.2
21 * @category PivipModulesDefault
22 * @package Module_Openid
23 * @copyright (C) 2008 Vincent Tunru
24 * @author Vincent Tunru <email@vincentt.org>
28 * Manage the Openid module
30 * The Openid module allows for authentication using OpenID.
32 * @see /library/Pivip/Module/Abstract.php
33 * @link http://openid.net/ OpenID.net
35 class Openid_Module
extends Pivip_Module_Abstract
38 * @var Vogel_Config_Ini The OpenID configuration
40 protected static $_config;
43 * Load the OpenID configuration
45 protected static function _loadConfig()
47 if(empty(self
::$_config))
49 self
::$_config = new Vogel_Config_Ini('./modules/openid/config.ini');
51 return self
::$_config;
55 * Defines the dependencies
57 * Openid depends on Pivip and the Page module
59 public function __construct()
64 * Checks whether the OpenID database table exists
66 * Will check whether a superuser is defined and whether the database tables
69 * @return boolean Whether Openid is already installed.
71 public static function isInstalled()
73 $config = self
::_loadConfig();
74 if(empty($config->administration
->superuser
))
78 // We need to be able to connect to the database for OpenID to work
79 if(null === Pivip_Db_Table_Abstract
::getDefaultAdapter())
85 $openid = new Openid();
86 } catch(Exception
$e) {
93 * Communicate that Openid needs configuration if true
95 * If the superuser has not been defined, returns true.
97 * @return boolean True if OpenID still needs to be configured
99 public static function needsConfiguring()
101 $config = self
::_loadConfig();
102 if(empty($config->administration
->superuser
))
110 * Create and process a form to configure the OpenID module
112 * @param string $action The action of the form
113 * @return Zend_Form The form to configure the OpenID module
114 * @todo Display error messages instead of silently failing
115 * @todo Check the superuser from the db instead of a configuration file
117 public static function configure($action)
119 $translate = Zend_Registry
::get('Zend_Translate');
120 $logger = Zend_Registry
::get('logger');
121 $flashMessenger = new Zend_Controller_Action_Helper_FlashMessenger();
122 $config = self
::_loadConfig();
123 $request = Zend_Controller_Front
::getInstance()->getRequest();
124 $requirements = array('nickname' => true, 'email' => false,
125 'fullname' => false, 'dob' => false,
126 'gender' => false, 'postcode' => false,
127 'country' => false, 'language' => false,
128 'timezone' => false);
129 $sreg = new Zend_OpenId_Extension_Sreg($requirements, null, 1.1);
130 if($request->isPost())
132 $id = $request->getParam('superuser');
133 $consumer = new Zend_OpenId_Consumer();
134 if(!$consumer->login($id, null, null, $sreg))
136 $error = sprintf($translate->_('OpenID %s is invalid.'), $id);
137 $logger->err($error);
138 $flashMessenger->setNamespace('error')->addMessage($error);
141 if('id_res' == $request->getParam('openid_mode'))
143 $consumer = new Zend_OpenId_Consumer();
144 if($consumer->verify($request->getParams(), $id, $sreg))
146 $config->administration
->superuser
= $id;
147 $details = $sreg->getProperties();
148 $details['id'] = $id;
149 if(!empty($details['nickname']))
151 $data = $this->sregToProperties($details);
154 $openid = new Openid();
155 foreach($data as $k => $v)
160 } catch(Exception
$e) {
161 $error = $translate->_(
162 'Could not save OpenID data to the database.');
163 $logger->err($error);
164 $flashMessenger->setNamespace('error')->addMessage($error);
170 $success = $translate->_('OpenID set.');
171 $flashMessenger->resetNamespace()->addMessage($success);
173 } catch(Exception
$e) {
174 $error = $translate->_(
175 'Could not save the OpenID configuration to file.');
176 $logger->err($error);
177 $flashMessenger->setNamespace('error')->addMessage($error);
180 $error = sprintf($translate->_('Could not authenticate OpenID %s.'),
182 $logger->err($error);
183 $flashMessenger->setNamespace('error')->addMessage($error);
186 $superuser = new Zend_Form_Element_Text('superuser');
187 $superuser->setLabel('Administration OpenID')
189 $form = new Zend_Form();
190 $form->setAction($action)
192 ->setAttrib('id', 'configureOpenid')
193 ->setAttrib('class', 'install configure openid')
194 ->addElement($superuser);
195 $submit = new Zend_Form_Element_Submit('submit');
196 $submit->setLabel('Configure');
197 $form->addElement($submit);
198 $data['superuser'] = $config->administration
->superuser
;
199 $form->populate($data);
204 * Creates the table in the database and perform the first authentication
206 * @throws Pivip_Install_Exception
207 * @return boolean Whether the installation succeeded
209 public function install()
214 * Remove the table from the database
216 * @throws Pivip_Install_Exception
217 * @return boolean Whether uninstallation succeeded
219 public function uninstall()
224 * Convert OpenID's to cache ID's
226 * @param string $openid OpenID
227 * @return string Cache id
229 public static function openidToCacheId($openid)
231 return 'openid_id_' .
232 str_replace(':', '__colon__',
233 str_replace('.', '__fullstop__',
234 str_replace(';', '__semicolon__',
235 str_replace('%', '__percent__',
236 str_replace('/', '__fwdslash__',
237 str_replace('\\', '__bwdslash__',
238 str_replace('#', '__hash__',
239 str_replace('?', '__qmark__',
240 str_replace('&', '__amp__',
241 str_replace('-', '__hyphen__',
242 str_replace('=', '__equal__',
243 Zend_Filter
::get($openid, 'HtmlEntities'))))))))))));
247 * Change details retreived using Sreg to the Identity Properties format
249 * @param array $details Details retrieved using Sreg
250 * @return array Array containing the Identity Properties
252 public static function sregToProperties(array $details)
254 if(empty($details['nickname']) ||
empty($details['id']))
256 throw new InvalidArgumentException();
258 $data = array('nickname' => $details['nickname'],
259 'uid' => $details['id']);
260 if(!empty($details['fullname']))
262 $data['fn'] = $details['fullname'];
264 $data['fn'] = $details['nickname'];
266 if(!empty($details['email']))
268 $data['email'] = $details['email'];
270 if(!empty($details['dob']) && 10 == strlen($details['dob']))
272 $data['bday'] = $details['dob'];
274 if(!empty($details['gender']))
276 $data['sex'] = strtolower($details['gender']);
278 if(!empty($details['postcode']))
280 $data['adr'] = ';;;;;' . $details['postcode'];
282 $data['adr'] = ';;;;;';
284 if(!empty($details['country']))
286 $locale = new Zend_Locale();
287 $data['adr'] .= ';' . $locale->getCountryTranslation(
288 $details['country']);
292 if(!empty($details['language']))
294 $data['locale'] = $details['language'];
295 if(!empty($details['country']))
297 $data['locale'] .= '_' . $details['country'];
300 if(!empty($details['timezone']))
302 $data['tz'] = 'VALUE=text:' . $details['timezone'];
308 * Load the OpenID cache
312 public static function loadCache()
314 $cacheConfig = Zend_Registry
::get('cacheConfig');
315 $options = $cacheConfig->toArray();
317 if('/' != substr($options['cache']['cache_root'], -1))
321 $options['backendOptions']['cache_dir'] = $options['cache']['cache_root']
324 $frontendOptions = array('cache_id_prefix' => 'openid_',
325 'automatic_serialization' => true);
326 $cache = Zend_Cache
::factory('Page',
327 $cacheConfig->cache
->backend
,
329 $options['backendOptions']);
336 * Register the OpenID Authentication adapter with Zend_Auth, process a login
337 * form if submitted and, if no superuser has been set yet, prompt the user
340 * @todo Allow the admins to edit the ACL.
342 public static function bootstrap()
344 if(!self
::isInstalled())
348 $openid = new Openid();
349 $params = array('target' => 'openid');
350 $nextRequest = new Zend_Controller_Request_Simple('modules',
354 self
::_pushStack($nextRequest);
355 } catch(Exception
$e) {
356 // Could not connect to the database, do not install this module
360 $nextRequest = new Zend_Controller_Request_Simple('process',
363 self
::_pushStack($nextRequest);
365 $options = array('module' => 'openid', 'controller' => 'authentication',
366 'action' => 'logout');
367 $route = new Zend_Controller_Router_Route_Static('account/logout',
369 $router = Zend_Controller_Front
::getInstance()->getRouter();
370 $router->addRoute('openidLogout', $route);