tiki-login_openid.php 11.2 KB
Newer Older
1
<?php
changi67's avatar
changi67 committed
2 3 4
/**
 * @package tikiwiki
 */
5
// (c) Copyright 2002-2016 by authors of the Tiki Wiki CMS Groupware Project
6
//
7 8
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
9
// $Id$
changi67's avatar
changi67 committed
10

lphuberdeau's avatar
lphuberdeau committed
11 12 13
// As a side note beyond the standard heading. Most of the code in this file was taken
// directly from the OpenID library example files. The code was modified to suit the
// specific needs.
14
require_once ('tiki-setup.php');
15 16 17 18 19 20 21 22 23 24 25 26 27
require_once "vendor_extra/pear/Auth/OpenID/HMAC.php";
require_once "vendor_extra/pear/Auth/OpenID/Consumer.php";
require_once "vendor_extra/pear/Auth/OpenID/FileStore.php";
require_once "vendor_extra/pear/Auth/OpenID/Message.php";
require_once "vendor_extra/pear/Auth/OpenID/BigMath.php";
require_once "vendor_extra/pear/Auth/OpenID/Association.php";
require_once "vendor_extra/pear/Auth/OpenID/SReg.php";
require_once "vendor_extra/pear/Auth/OpenID/Discover.php";
require_once "vendor_extra/pear/Auth/Yadis/XRI.php";
require_once "vendor_extra/pear/Auth/Yadis/Misc.php";
require_once "vendor_extra/pear/Auth/OpenID/URINorm.php";
require_once "vendor_extra/pear/Auth/Yadis/XML.php";
require_once "vendor_extra/pear/Auth/OpenID/Nonce.php";
28
if ($prefs['auth_method'] != 'openid') {
29
	$smarty->assign('msg', tra("Authentication method is not OpenID"));
30 31 32
	$smarty->display("error.tpl");
	die;
}
33 34 35 36
function setupFromAddress() // {{{
{
	global $url_scheme, $url_host, $url_port, $base_url;
	// Remember where the page was requested from (from tiki-login.php)
changi67's avatar
changi67 committed
37 38
	if (!isset($_SESSION['loginfrom'])) {
		$_SESSION['loginfrom'] = (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $prefs['tikiIndex']);
39
		if (!preg_match('/^http/', $_SESSION['loginfrom'])) {
changi67's avatar
changi67 committed
40 41 42 43
			if ($_SESSION['loginfrom'] {
				0
			} == '/') $_SESSION['loginfrom'] = $url_scheme . '://' . $url_host . (($url_port != '') ? ":$url_port" : '') . $_SESSION['loginfrom'];
			else $_SESSION['loginfrom'] = $base_url . $_SESSION['loginfrom'];
44 45
		}
	}
changi67's avatar
changi67 committed
46
	if (strpos($_SESSION['loginfrom'], 'openid') !== false) $_SESSION['loginfrom'] = $base_url;
47
} // }}}
48 49 50 51
/**
 * @param $identifier
 * @return array
 */
changi67's avatar
changi67 committed
52
function getAccountsMatchingIdentifier($identifier) // {{{
lphuberdeau's avatar
lphuberdeau committed
53 54
{
	global $tikilib;
changi67's avatar
changi67 committed
55
	$result = $tikilib->query("SELECT login FROM users_users WHERE openid_url = ?", array($identifier));
lphuberdeau's avatar
lphuberdeau committed
56
	$userlist = array();
changi67's avatar
changi67 committed
57
	while ($row = $result->fetchRow()) $userlist[] = $row['login'];
lphuberdeau's avatar
lphuberdeau committed
58 59
	return $userlist;
} // }}}
60 61 62
/**
 * @param $identifier
 */
changi67's avatar
changi67 committed
63
function loginUser($identifier) // {{{
lphuberdeau's avatar
lphuberdeau committed
64
{
65 66
	global $user_cookie_site;
	$userlib = TikiLib::lib('user');
67
	$userlib->update_lastlogin($identifier);
68
	$userlib->update_expired_groups();
69
	$_SESSION[$user_cookie_site] = $identifier;
changi67's avatar
changi67 committed
70 71
	header('location: ' . $_SESSION['loginfrom']);
	unset($_SESSION['loginfrom']);
72
	exit;
lphuberdeau's avatar
lphuberdeau committed
73
} // }}}
74 75 76 77
/**
 * @param $data
 * @param $messages
 */
changi67's avatar
changi67 committed
78
function filterExistingInformation(&$data, &$messages) // {{{
lphuberdeau's avatar
lphuberdeau committed
79 80
{
	global $tikilib;
changi67's avatar
changi67 committed
81 82 83
	$result = $tikilib->query("SELECT COUNT(*) FROM users_users WHERE login = ?", array($data['nickname']));
	$count = reset($result->fetchRow());
	if ($count > 0) {
lphuberdeau's avatar
lphuberdeau committed
84
		$data['nickname'] = '';
changi67's avatar
changi67 committed
85
		$messages[] = tra('Your default nickname is already in use. A new one has to be selected.');
lphuberdeau's avatar
lphuberdeau committed
86 87
	}
} // }}}
88 89 90 91
/**
 * @param $data
 * @param $messages
 */
changi67's avatar
changi67 committed
92 93
function displayRegisatrationForms($data, $messages) // {{{
{
94 95 96 97
	global $prefs;
	$userlib = TikiLib::lib('user');
	$smarty = TikiLib::lib('smarty');
	$registrationlib = TikiLib::lib('registration');
98 99 100 101 102

	if (is_a($registrationlib->merged_prefs, "RegistrationError")) {
		register_error($registrationlib->merged_prefs->msg);
	}
	$smarty->assign_by_ref('merged_prefs', $registrationlib->merged_prefs);
103 104


changi67's avatar
changi67 committed
105 106 107 108 109 110
	// Default values for the registration form
	$smarty->assign('username', $data['nickname']);
	$smarty->assign('email', $data['email']);
	// Changing some system values to get the login box to display properly in the context
	$smarty->assign('rememberme', 'disabled');
	$smarty->assign('forgotPass', 'n');
111
	$smarty->assign('allowRegister', ($prefs['allowRegister'] != 'y' || ($prefs['feature_intertiki'] == 'y' && !empty($prefs['feature_intertiki_mymaster']))) ? 'n' : 'y');
changi67's avatar
changi67 committed
112 113 114
	$smarty->assign('change_password', 'n');
	$smarty->assign('auth_method', 'tiki');
	$smarty->assign('feature_switch_ssl_mode', 'n');
115 116 117 118

	$listgroups = $userlib->get_groups(0, -1, 'groupName_asc', '', '', 'n');
	$nbChoiceGroups = 0;
	$mandatoryChoiceGroups = true;
119
	foreach ($listgroups['data'] as $gr) {
120 121 122 123 124 125 126 127 128 129 130 131 132
		if ($gr['registrationChoice'] == 'y') {
			++$nbChoiceGroups;
			$theChoiceGroup = $gr['groupName'];
			if ($gr['groupName'] == 'Registered') $mandatoryChoiceGroups = false;
		}
	}
	if ($nbChoiceGroups) {
		$smarty->assign('listgroups', $listgroups['data']);
		if ($nbChoiceGroups == 1) {
			$smarty->assign_by_ref('theChoiceGroup', $theChoiceGroup);
		}
	}

changi67's avatar
changi67 committed
133
	// Display
134 135
	$smarty->assign('mid', 'tiki-register.tpl');
	$smarty->assign('openid_associate', 'y');
136
	$smarty->assign('registration', 'y');
changi67's avatar
changi67 committed
137
	$smarty->display('tiki.tpl');
138
	exit;
changi67's avatar
changi67 committed
139
} // }}}
140 141 142 143
/**
 * @param $data
 * @param $messages
 */
changi67's avatar
changi67 committed
144 145
function displaySelectionList($data, $messages) // {{{
{
146
	$smarty = TikiLib::lib('smarty');
changi67's avatar
changi67 committed
147 148 149
	// Display
	$smarty->assign('mid', 'tiki-openid_select.tpl');
	$smarty->display('tiki.tpl');
150
	exit;
changi67's avatar
changi67 committed
151
} // }}}
152 153 154
/**
 * @param $message
 */
changi67's avatar
changi67 committed
155 156
function displayError($message)
{ // {{{
157
	$smarty = TikiLib::lib('smarty');
158
	$smarty->assign('msg', tra("Failure:") . " " . $message);
159
	$smarty->assign('errortype', 'login');
lphuberdeau's avatar
lphuberdeau committed
160 161 162
	$smarty->display("error.tpl");
	die;
} // }}}
163 164 165
/**
 * @return Auth_OpenID_FileStore
 */
changi67's avatar
changi67 committed
166 167
function getStore()
{ // {{{
168
	$store_path = "temp/openid_consumer";
changi67's avatar
changi67 committed
169 170 171 172 173
	if (!file_exists($store_path) && !mkdir($store_path)) {
		print "Could not create the FileStore directory '$store_path'. " . " Please check the effective permissions.";
		exit(0);
	}
	return new Auth_OpenID_FileStore($store_path);
lphuberdeau's avatar
lphuberdeau committed
174
} // }}}
175 176 177
/**
 * @return Auth_OpenID_Consumer
 */
changi67's avatar
changi67 committed
178 179
function getConsumer()
{ // {{{
180

changi67's avatar
changi67 committed
181 182 183 184 185 186
	/**
	 * Create a consumer object using the store object created
	 * earlier.
	 */
	$store = getStore();
	return new Auth_OpenID_Consumer($store);
lphuberdeau's avatar
lphuberdeau committed
187
} // }}}
changi67's avatar
changi67 committed
188 189
function getOpenIDURL()
{ // {{{
changi67's avatar
changi67 committed
190 191 192 193 194 195
	// Render a default page if we got a submission without an openid
	// value.
	if (empty($_GET['openid_url'])) {
		displayError('Call the page properly');
	}
	return $_GET['openid_url'];
lphuberdeau's avatar
lphuberdeau committed
196
} // }}}
197 198 199
/**
 * @return string
 */
changi67's avatar
changi67 committed
200 201
function getScheme()
{ // {{{
changi67's avatar
changi67 committed
202 203 204 205 206
	$scheme = 'http';
	if (isset($_SERVER['HTTPS']) and $_SERVER['HTTPS'] == 'on') {
		$scheme.= 's';
	}
	return $scheme;
lphuberdeau's avatar
lphuberdeau committed
207
} // }}}
208 209 210
/**
 * @return string
 */
changi67's avatar
changi67 committed
211 212 213
function getReturnTo()
{ // {{{
	$path = str_replace('\\', '/', dirname($_SERVER['PHP_SELF']));
214
	$string = sprintf("%s://%s:%s%s/tiki-login_openid.php?action=return", getScheme(), $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $path == '/' ? '' : $path);
changi67's avatar
changi67 committed
215
	if (isset($_GET['action']) && $_GET['action'] == 'force') $string.= '&force=true';
216
	return $string;
lphuberdeau's avatar
lphuberdeau committed
217
} // }}}
218 219 220
/**
 * @return string
 */
changi67's avatar
changi67 committed
221 222 223
function getTrustRoot()
{ // {{{
	return sprintf("%s://%s:%s%s", getScheme(), $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], str_replace('\\', '/', dirname($_SERVER['PHP_SELF'])));
lphuberdeau's avatar
lphuberdeau committed
224
} // }}}
changi67's avatar
changi67 committed
225 226
function runAuth()
{ // {{{
227
	setupFromAddress();
changi67's avatar
changi67 committed
228 229 230 231
	$openid = getOpenIDURL();
	$consumer = getConsumer();
	// Begin the OpenID authentication process.
	$auth_request = $consumer->begin($openid);
232
	// 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.
changi67's avatar
changi67 committed
233
	if (!$auth_request) {
234
		displayError(tra("Authentication error; probably not a valid OpenID."));
changi67's avatar
changi67 committed
235 236
	}
	$sreg_request = Auth_OpenID_SRegRequest::build(
237 238 239 240
		// Required
		array(),
		// Optional
		array('nickname', 'email')
changi67's avatar
changi67 committed
241
	);
changi67's avatar
changi67 committed
242 243 244 245 246 247 248 249 250 251 252 253 254
	if ($sreg_request) {
		$auth_request->addExtension($sreg_request);
	}
	// Redirect the user to the OpenID server for authentication.
	// Store the token for this authentication so we can verify the
	// response.
	// For OpenID 1, send a redirect.  For OpenID 2, use a Javascript
	// form to send a POST request to the server.
	if ($auth_request->shouldSendRedirect()) {
		$redirect_url = $auth_request->redirectURL(getTrustRoot(), getReturnTo());
		// If the redirect URL can't be built, display an error
		// message.
		if (Auth_OpenID::isFailure($redirect_url)) {
255
			displayError(tra("Could not redirect to server: ") . $redirect_url->message);
changi67's avatar
changi67 committed
256 257 258 259 260
		} else {
			// Send redirect.
			header("Location: " . $redirect_url);
		}
	} else {
261 262
		// Generate form markup and render it.
		$form_id = 'openid_message';
changi67's avatar
changi67 committed
263
		$form_html = $auth_request->htmlMarkup(getTrustRoot(), getReturnTo(), false, array('id' => $form_id));
264 265 266
		// Display an error if the form markup couldn't be generated;
		// otherwise, render the HTML.
		if (Auth_OpenID::isFailure($form_html)) {
267
			displayError(tra("Could not redirect to server: ") . $form_html->message);
268 269 270
		} else {
			print $form_html;
		}
changi67's avatar
changi67 committed
271
	}
lphuberdeau's avatar
lphuberdeau committed
272
} // }}}
changi67's avatar
changi67 committed
273 274
function runFinish()
{ // {{{
275
	$smarty = TikiLib::lib('smarty');
changi67's avatar
changi67 committed
276 277 278 279 280 281 282
	$consumer = getConsumer();
	// Complete the authentication process using the server's
	// response.
	$response = $consumer->complete(getReturnTo());
	// Check the response status.
	if ($response->status == Auth_OpenID_CANCEL) {
		// This means the authentication was cancelled.
283
		displayError(tra('Verification cancelled.'));
changi67's avatar
changi67 committed
284 285
	} else if ($response->status == Auth_OpenID_FAILURE) {
		// Authentication failed; display the error message.
286
		displayError(tra("OpenID authentication failed: ") . $response->message);
changi67's avatar
changi67 committed
287 288 289 290 291 292 293
	} else if ($response->status == Auth_OpenID_SUCCESS) {
		// This means the authentication succeeded; extract the
		// identity URL and Simple Registration data (if it was
		// returned).
		$data = array('identifier' => $response->identity_url, 'email' => '', 'fullname' => '', 'nickname' => '',);
		$sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($response);
		$sreg = $sreg_resp->contents();
lphuberdeau's avatar
lphuberdeau committed
294
		// Sanitize identifier. Just consider slashes at the end are never good.
changi67's avatar
changi67 committed
295 296 297
		if (substr($data['identifier'], -1) == '/') $data['identifier'] = substr($data['identifier'], 0, -1);
		if (@$sreg['email']) $data['email'] = $sreg['email'];
		if (@$sreg['nickname']) $data['nickname'] = $sreg['nickname'];
298
		$_SESSION['openid_url'] = $data['identifier'];
299
		// If OpenID identifier exists in the database
changi67's avatar
changi67 committed
300
		$list = getAccountsMatchingIdentifier($data['identifier']);
301
		$_SESSION['openid_userlist'] = $list;
changi67's avatar
changi67 committed
302 303
		$smarty->assign('openid_userlist', $list);
		if (count($list) > 0 && !isset($_GET['force'])) {
304
			// If Single account
changi67's avatar
changi67 committed
305
			if (count($list) == 1) {
306
				// Login the user
changi67's avatar
changi67 committed
307
				loginUser($list[0]);
changi67's avatar
changi67 committed
308
			} else {
changi67's avatar
changi67 committed
309
			// Else Multiple account
310
				// Display user selection list
changi67's avatar
changi67 committed
311
				displaySelectionList($list);
312
			}
changi67's avatar
changi67 committed
313
		} else {
314 315
			$messages = array();
			// Check for entries that already exist in the database and filter them out
changi67's avatar
changi67 committed
316
			filterExistingInformation($data, $messages);
317
			// Display register and attach forms
changi67's avatar
changi67 committed
318
			displayRegisatrationForms($data, $messages);
319
		}
changi67's avatar
changi67 committed
320
	}
lphuberdeau's avatar
lphuberdeau committed
321
} // }}}
322 323 324 325
function runSelect() // {{{
{
	setupFromAddress();
	$user = $_GET['select'];
changi67's avatar
changi67 committed
326 327
	if (in_array($user, $_SESSION['openid_userlist'])) loginUser($user);
	else displayError(tra('The selected account is not associated with your identity.'));
328
} // }}}
changi67's avatar
changi67 committed
329 330 331 332 333 334
if (isset($_GET['action'])) {
	if ($_GET['action'] == 'return') runFinish();
	elseif ($_GET['action'] == 'select' && isset($_GET['select'])) runSelect();
	elseif ($_GET['action'] == 'force') runAuth();
	else displayError(tra('unknown action'));
} else runAuth();