1<?php 2/** 3 * @package tikiwiki 4 */ 5// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project 6// 7// All Rights Reserved. See copyright.txt for details and a complete list of authors. 8// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 9// $Id$ 10 11// As a side note beyond the standard heading. Most of the code in this file was taken 12// directly from the OpenID library example files. The code was modified to suit the 13// specific needs. 14require_once('tiki-setup.php'); 15require_once "vendor_extra/pear/Auth/OpenID/HMAC.php"; 16require_once "vendor_extra/pear/Auth/OpenID/Consumer.php"; 17require_once "vendor_extra/pear/Auth/OpenID/FileStore.php"; 18require_once "vendor_extra/pear/Auth/OpenID/Message.php"; 19require_once "vendor_extra/pear/Auth/OpenID/BigMath.php"; 20require_once "vendor_extra/pear/Auth/OpenID/Association.php"; 21require_once "vendor_extra/pear/Auth/OpenID/SReg.php"; 22require_once "vendor_extra/pear/Auth/OpenID/Discover.php"; 23require_once "vendor_extra/pear/Auth/Yadis/XRI.php"; 24require_once "vendor_extra/pear/Auth/Yadis/Misc.php"; 25require_once "vendor_extra/pear/Auth/OpenID/URINorm.php"; 26require_once "vendor_extra/pear/Auth/Yadis/XML.php"; 27require_once "vendor_extra/pear/Auth/OpenID/Nonce.php"; 28if ($prefs['auth_method'] != 'openid') { 29 $smarty->assign('msg', tra("Authentication method is not OpenID")); 30 $smarty->display("error.tpl"); 31 die; 32} 33function setupFromAddress() // {{{ 34{ 35 global $url_scheme, $url_host, $url_port, $base_url; 36 // Remember where the page was requested from (from tiki-login.php) 37 if (! isset($_SESSION['loginfrom'])) { 38 $_SESSION['loginfrom'] = (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $prefs['tikiIndex']); 39 if (! preg_match('/^http/', $_SESSION['loginfrom'])) { 40 if ($_SESSION['loginfrom'] { 41 0 42 } == '/') { 43 $_SESSION['loginfrom'] = $url_scheme . '://' . $url_host . (($url_port != '') ? ":$url_port" : '') . $_SESSION['loginfrom']; 44 } else { 45 $_SESSION['loginfrom'] = $base_url . $_SESSION['loginfrom']; 46 } 47 } 48 } 49 if (strpos($_SESSION['loginfrom'], 'openid') !== false) { 50 $_SESSION['loginfrom'] = $base_url; 51 } 52} // }}} 53/** 54 * @param $identifier 55 * @return array 56 */ 57function getAccountsMatchingIdentifier($identifier) // {{{ 58{ 59 global $tikilib; 60 $result = $tikilib->query("SELECT login FROM users_users WHERE openid_url = ?", [$identifier]); 61 $userlist = []; 62 while ($row = $result->fetchRow()) { 63 $userlist[] = $row['login']; 64 } 65 return $userlist; 66} // }}} 67/** 68 * @param $identifier 69 */ 70function loginUser($identifier) // {{{ 71{ 72 global $user_cookie_site; 73 $userlib = TikiLib::lib('user'); 74 $userlib->update_lastlogin($identifier); 75 $userlib->update_expired_groups(); 76 $_SESSION[$user_cookie_site] = $identifier; 77 header('location: ' . $_SESSION['loginfrom']); 78 unset($_SESSION['loginfrom']); 79 exit; 80} // }}} 81/** 82 * @param $data 83 * @param $messages 84 */ 85function filterExistingInformation(&$data, &$messages) // {{{ 86{ 87 global $tikilib; 88 $result = $tikilib->query("SELECT COUNT(*) FROM users_users WHERE login = ?", [$data['nickname']]); 89 $count = reset($result->fetchRow()); 90 if ($count > 0) { 91 $data['nickname'] = ''; 92 $messages[] = tra('Your default nickname is already in use. A new one has to be selected.'); 93 } 94} // }}} 95/** 96 * @param $data 97 * @param $messages 98 */ 99function displayRegisatrationForms($data, $messages) // {{{ 100{ 101 global $prefs; 102 $userlib = TikiLib::lib('user'); 103 $smarty = TikiLib::lib('smarty'); 104 $registrationlib = TikiLib::lib('registration'); 105 106 if (is_a($registrationlib->merged_prefs, "RegistrationError")) { 107 register_error($registrationlib->merged_prefs->msg); 108 } 109 $smarty->assign_by_ref('merged_prefs', $registrationlib->merged_prefs); 110 111 112 // Default values for the registration form 113 $smarty->assign('username', $data['nickname']); 114 $smarty->assign('email', $data['email']); 115 // Changing some system values to get the login box to display properly in the context 116 $smarty->assign('rememberme', 'disabled'); 117 $smarty->assign('forgotPass', 'n'); 118 $smarty->assign('allowRegister', ($prefs['allowRegister'] != 'y' || ($prefs['feature_intertiki'] == 'y' && ! empty($prefs['feature_intertiki_mymaster']))) ? 'n' : 'y'); 119 $smarty->assign('change_password', 'n'); 120 $smarty->assign('auth_method', 'tiki'); 121 $smarty->assign('feature_switch_ssl_mode', 'n'); 122 123 $listgroups = $userlib->get_groups(0, -1, 'groupName_asc', '', '', 'n'); 124 $nbChoiceGroups = 0; 125 $mandatoryChoiceGroups = true; 126 foreach ($listgroups['data'] as $gr) { 127 if ($gr['registrationChoice'] == 'y') { 128 ++$nbChoiceGroups; 129 $theChoiceGroup = $gr['groupName']; 130 if ($gr['groupName'] == 'Registered') { 131 $mandatoryChoiceGroups = false; 132 } 133 } 134 } 135 if ($nbChoiceGroups) { 136 $smarty->assign('listgroups', $listgroups['data']); 137 if ($nbChoiceGroups == 1) { 138 $smarty->assign_by_ref('theChoiceGroup', $theChoiceGroup); 139 } 140 } 141 142 // Display 143 $smarty->assign('mid', 'tiki-register.tpl'); 144 $smarty->assign('openid_associate', 'y'); 145 $smarty->assign('registration', 'y'); 146 $smarty->display('tiki.tpl'); 147 exit; 148} // }}} 149/** 150 * @param $data 151 * @param $messages 152 */ 153function displaySelectionList($data, $messages) // {{{ 154{ 155 $smarty = TikiLib::lib('smarty'); 156 // Display 157 $smarty->assign('mid', 'tiki-openid_select.tpl'); 158 $smarty->display('tiki.tpl'); 159 exit; 160} // }}} 161/** 162 * @param $message 163 */ 164function displayError($message) 165{ 166 // {{{ 167 $smarty = TikiLib::lib('smarty'); 168 $smarty->assign('msg', tra("Failure:") . " " . $message); 169 $smarty->assign('errortype', 'login'); 170 $smarty->display("error.tpl"); 171 die; 172} // }}} 173/** 174 * @return Auth_OpenID_FileStore 175 */ 176function getStore() 177{ 178 // {{{ 179 $store_path = "temp/openid_consumer"; 180 if (! file_exists($store_path) && ! mkdir($store_path)) { 181 print "Could not create the FileStore directory '$store_path'. " . " Please check the effective permissions."; 182 exit(0); 183 } 184 return new Auth_OpenID_FileStore($store_path); 185} // }}} 186/** 187 * @return Auth_OpenID_Consumer 188 */ 189function getConsumer() 190{ 191 // {{{ 192 193 /** 194 * Create a consumer object using the store object created 195 * earlier. 196 */ 197 $store = getStore(); 198 return new Auth_OpenID_Consumer($store); 199} // }}} 200function getOpenIDURL() 201{ 202 // {{{ 203 // Render a default page if we got a submission without an openid 204 // value. 205 if (empty($_GET['openid_url'])) { 206 displayError('Call the page properly'); 207 } 208 return $_GET['openid_url']; 209} // }}} 210/** 211 * @return string 212 */ 213function getScheme() 214{ 215 // {{{ 216 $scheme = 'http'; 217 if (isset($_SERVER['HTTPS']) and $_SERVER['HTTPS'] == 'on') { 218 $scheme .= 's'; 219 } 220 return $scheme; 221} // }}} 222/** 223 * @return string 224 */ 225function getReturnTo() 226{ 227 // {{{ 228 $path = str_replace('\\', '/', dirname($_SERVER['PHP_SELF'])); 229 $string = sprintf("%s://%s:%s%s/tiki-login_openid.php?action=return", getScheme(), $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $path == '/' ? '' : $path); 230 if (isset($_GET['action']) && $_GET['action'] == 'force') { 231 $string .= '&force=true'; 232 } 233 return $string; 234} // }}} 235/** 236 * @return string 237 */ 238function getTrustRoot() 239{ 240 // {{{ 241 return sprintf("%s://%s:%s%s", getScheme(), $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], str_replace('\\', '/', dirname($_SERVER['PHP_SELF']))); 242} // }}} 243function runAuth() 244{ 245 // {{{ 246 setupFromAddress(); 247 $openid = getOpenIDURL(); 248 $consumer = getConsumer(); 249 // Begin the OpenID authentication process. 250 $auth_request = $consumer->begin($openid); 251 // No auth request means we can't begin OpenID. Usually this is because the OpenID is invalid. Sometimes this is because the OpenID server's certificate isn't trusted. 252 if (! $auth_request) { 253 displayError(tra("Authentication error; probably not a valid OpenID.")); 254 } 255 $sreg_request = Auth_OpenID_SRegRequest::build( 256 // Required 257 [], 258 // Optional 259 ['nickname', 'email'] 260 ); 261 if ($sreg_request) { 262 $auth_request->addExtension($sreg_request); 263 } 264 // Redirect the user to the OpenID server for authentication. 265 // Store the token for this authentication so we can verify the 266 // response. 267 // For OpenID 1, send a redirect. For OpenID 2, use a JavaScript 268 // form to send a POST request to the server. 269 if ($auth_request->shouldSendRedirect()) { 270 $redirect_url = $auth_request->redirectURL(getTrustRoot(), getReturnTo()); 271 // If the redirect URL can't be built, display an error 272 // message. 273 if (Auth_OpenID::isFailure($redirect_url)) { 274 displayError(tra("Could not redirect to server: ") . $redirect_url->message); 275 } else { 276 // Send redirect. 277 header("Location: " . $redirect_url); 278 } 279 } else { 280 // Generate form markup and render it. 281 $form_id = 'openid_message'; 282 $form_html = $auth_request->htmlMarkup(getTrustRoot(), getReturnTo(), false, ['id' => $form_id]); 283 // Display an error if the form markup couldn't be generated; 284 // otherwise, render the HTML. 285 if (Auth_OpenID::isFailure($form_html)) { 286 displayError(tra("Could not redirect to server: ") . $form_html->message); 287 } else { 288 print $form_html; 289 } 290 } 291} // }}} 292function runFinish() 293{ 294 // {{{ 295 $smarty = TikiLib::lib('smarty'); 296 $consumer = getConsumer(); 297 // Complete the authentication process using the server's 298 // response. 299 $response = $consumer->complete(getReturnTo()); 300 // Check the response status. 301 if ($response->status == Auth_OpenID_CANCEL) { 302 // This means the authentication was cancelled. 303 displayError(tra('Verification cancelled.')); 304 } elseif ($response->status == Auth_OpenID_FAILURE) { 305 // Authentication failed; display the error message. 306 displayError(tra("OpenID authentication failed: ") . $response->message); 307 } elseif ($response->status == Auth_OpenID_SUCCESS) { 308 // This means the authentication succeeded; extract the 309 // identity URL and Simple Registration data (if it was 310 // returned). 311 $data = ['identifier' => $response->identity_url, 'email' => '', 'fullname' => '', 'nickname' => '',]; 312 $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($response); 313 $sreg = $sreg_resp->contents(); 314 // Sanitize identifier. Just consider slashes at the end are never good. 315 if (substr($data['identifier'], -1) == '/') { 316 $data['identifier'] = substr($data['identifier'], 0, -1); 317 } 318 if (@$sreg['email']) { 319 $data['email'] = $sreg['email']; 320 } 321 if (@$sreg['nickname']) { 322 $data['nickname'] = $sreg['nickname']; 323 } 324 $_SESSION['openid_url'] = $data['identifier']; 325 // If OpenID identifier exists in the database 326 $list = getAccountsMatchingIdentifier($data['identifier']); 327 $_SESSION['openid_userlist'] = $list; 328 $smarty->assign('openid_userlist', $list); 329 if (count($list) > 0 && ! isset($_GET['force'])) { 330 // If Single account 331 if (count($list) == 1) { 332 // Login the user 333 loginUser($list[0]); 334 } else { 335 // Else Multiple account 336 // Display user selection list 337 displaySelectionList($list); 338 } 339 } else { 340 $messages = []; 341 // Check for entries that already exist in the database and filter them out 342 filterExistingInformation($data, $messages); 343 // Display register and attach forms 344 displayRegisatrationForms($data, $messages); 345 } 346 } 347} // }}} 348function runSelect() // {{{ 349{ 350 setupFromAddress(); 351 $user = $_GET['select']; 352 if (in_array($user, $_SESSION['openid_userlist'])) { 353 loginUser($user); 354 } else { 355 displayError(tra('The selected account is not associated with your identity.')); 356 } 357} // }}} 358if (isset($_GET['action'])) { 359 if ($_GET['action'] == 'return') { 360 runFinish(); 361 } elseif ($_GET['action'] == 'select' && isset($_GET['select'])) { 362 runSelect(); 363 } elseif ($_GET['action'] == 'force') { 364 runAuth(); 365 } else { 366 displayError(tra('unknown action')); 367 } 368} else { 369 runAuth(); 370} 371