Move OpenID login handling into separate class
This commit is contained in:
parent
14640ed8a5
commit
1ab3c45d71
33
src/SemanticScuttle/Exception.php
Normal file
33
src/SemanticScuttle/Exception.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
require_once 'SemanticScuttle/Exception/User.php';
|
||||
|
||||
class SemanticScuttle_Exception extends Exception
|
||||
{
|
||||
/**
|
||||
* Returns an error message that can be shown to the user.
|
||||
*
|
||||
* FIXME: maybe move that method to somewhere else
|
||||
*
|
||||
* @return string Error message to display to the user
|
||||
*/
|
||||
public static function getErrorMessage(Exception $e)
|
||||
{
|
||||
if ($e instanceof SemanticScuttle_Exception_User) {
|
||||
if (isset($GLOBALS['debugMode']) && $GLOBALS['debugMode']) {
|
||||
$prev = $e->getPrevious();
|
||||
if ($prev) {
|
||||
$msg = $prev->getMessage();
|
||||
} else {
|
||||
$msg = $e->getMessage();
|
||||
}
|
||||
} else {
|
||||
$msg = $e->getMessage();
|
||||
}
|
||||
} else {
|
||||
$msg = $e->getMessage();
|
||||
}
|
||||
|
||||
return $msg;
|
||||
}
|
||||
}
|
||||
?>
|
10
src/SemanticScuttle/Exception/User.php
Normal file
10
src/SemanticScuttle/Exception/User.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
/**
|
||||
* Exception class whose message may be displayed to users in the frontend.
|
||||
*
|
||||
* The detailled message is in the previous exception (getPrevious()).
|
||||
*/
|
||||
class SemanticScuttle_Exception_User extends Exception
|
||||
{
|
||||
}
|
||||
?>
|
212
src/SemanticScuttle/Service/OpenID.php
Normal file
212
src/SemanticScuttle/Service/OpenID.php
Normal file
@ -0,0 +1,212 @@
|
||||
<?php
|
||||
/**
|
||||
* SemanticScuttle - your social bookmark manager.
|
||||
*
|
||||
* PHP version 5.
|
||||
*
|
||||
* @category Bookmarking
|
||||
* @package SemanticScuttle
|
||||
* @author Christian Weiske <cweiske@cweiske.de>
|
||||
* @license AGPL http://www.gnu.org/licenses/agpl.html
|
||||
* @link http://sourceforge.net/projects/semanticscuttle
|
||||
*/
|
||||
|
||||
require_once 'SemanticScuttle/Exception/User.php';
|
||||
require_once 'OpenID.php';
|
||||
require_once 'OpenID/RelyingParty.php';
|
||||
require_once 'OpenID/Extension/SREG11.php';
|
||||
|
||||
/**
|
||||
* SemanticScuttle OpenID verification and management
|
||||
*
|
||||
* @category Bookmarking
|
||||
* @package SemanticScuttle
|
||||
* @author Christian Weiske <cweiske@cweiske.de>
|
||||
* @license AGPL http://www.gnu.org/licenses/agpl.html
|
||||
* @link http://sourceforge.net/projects/semanticscuttle
|
||||
*/
|
||||
class SemanticScuttle_Service_OpenID extends SemanticScuttle_DbService
|
||||
{
|
||||
/**
|
||||
* Creates a new instance, sets database variable and table name.
|
||||
*
|
||||
* @param sql_db $db Database object
|
||||
*/
|
||||
protected function __construct($db)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->tablename = $GLOBALS['tableprefix'] . 'users_openids';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the single service instance
|
||||
*
|
||||
* @param sql_db $db Database object
|
||||
*
|
||||
* @return SemanticScuttle_Service_OpenID
|
||||
*/
|
||||
public static function getInstance($db)
|
||||
{
|
||||
static $instance;
|
||||
if (!isset($instance)) {
|
||||
$instance = new self($db);
|
||||
}
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Part 1 of the OpenID login process: Send user to his identity provider.
|
||||
*
|
||||
* This method exits the PHP process.
|
||||
*
|
||||
* @param string $identifier OpenID URL
|
||||
* @param string $returnUrl URL the identity provider shall send the user
|
||||
* back to
|
||||
*
|
||||
* @return void No return value needed since it exits.
|
||||
*
|
||||
* @throws SemanticScuttle_Exception_User When something goes wrong
|
||||
*/
|
||||
public function sendIdRequest($identifier, $returnUrl)
|
||||
{
|
||||
//send request to ID provider
|
||||
try {
|
||||
$identifier = OpenID::normalizeIdentifier($identifier);
|
||||
} catch (OpenID_Exception $e) {
|
||||
throw new SemanticScuttle_Exception_User(
|
||||
'Invalid OpenID identifier', 11, $e
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$rp = new OpenID_RelyingParty(
|
||||
$returnUrl,
|
||||
addProtocolToUrl(ROOT)/* realm */,
|
||||
$identifier
|
||||
);
|
||||
$authRequest = $rp->prepare();
|
||||
|
||||
//FIXME: when user exists already, use immediate mode first and
|
||||
// fall back to normal when it fails
|
||||
//FIXME: (?) when user exists already, don't request details
|
||||
|
||||
$sreg = new OpenID_Extension_SREG11(OpenID_Extension::REQUEST);
|
||||
//$sreg->set('required', 'email');
|
||||
$sreg->set('optional', 'email,nickname,fullname');
|
||||
$authRequest->addExtension($sreg);
|
||||
//$auth->setMode(OpenID::MODE_CHECKID_IMMEDIATE);
|
||||
header('Location: ' . $authRequest->getAuthorizeURL());
|
||||
exit();
|
||||
} catch (OpenID_Exception $e) {
|
||||
throw new SemanticScuttle_Exception_User(
|
||||
'Error communicating with OpenID identity server', 12, $e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Part 2 of the OpenID login process: Handle the IDP response
|
||||
*
|
||||
* @param string $returnUrl URL the identity provider shall send the user
|
||||
* back to
|
||||
*
|
||||
* @return array Array with user data. Keys:
|
||||
* - identifier - OpenID URL/identifier
|
||||
* - userId - Local user ID from database
|
||||
* - email - OpenID-submitted email
|
||||
* - nickname - OpenID-submitted nickname
|
||||
* - fullname - OpenID-submitted full name
|
||||
*
|
||||
* @throws SemanticScuttle_Exception_User When something goes wrong
|
||||
*/
|
||||
public function handleIdResponse($returnUrl)
|
||||
{
|
||||
$rp = new OpenID_RelyingParty(
|
||||
$returnUrl,
|
||||
addProtocolToUrl(ROOT)/* realm */
|
||||
);
|
||||
|
||||
if (!count($_POST)) {
|
||||
list(, $queryString) = explode('?', $_SERVER['REQUEST_URI']);
|
||||
} else {
|
||||
$queryString = file_get_contents('php://input');
|
||||
}
|
||||
|
||||
try {
|
||||
$request = new Net_URL2($returnUrl . '?' . $queryString);
|
||||
$message = new OpenID_Message($queryString, OpenID_Message::FORMAT_HTTP);
|
||||
$mode = $message->get('openid.mode');
|
||||
|
||||
if ($mode == 'cancel') {
|
||||
throw new SemanticScuttle_Exception_User(
|
||||
'OpenID login cancelled', 10
|
||||
);
|
||||
} else if ($mode == 'setup_needed') {
|
||||
throw new SemanticScuttle_Exception_User(
|
||||
'Immediate OpenID login not possible', 12
|
||||
);
|
||||
}
|
||||
|
||||
$result = $rp->verify($request, $message);
|
||||
if (!$result->success()) {
|
||||
throw new SemanticScuttle_Exception_User(
|
||||
'OpenID verification failed', 13
|
||||
);
|
||||
}
|
||||
|
||||
$identifier = $message->get('openid.claimed_id');
|
||||
} catch (OpenID_Exception $e) {
|
||||
//FIXME: report error
|
||||
var_dump($e);die();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
try {
|
||||
$identifier = OpenID::normalizeIdentifier($identifier);
|
||||
} catch (OpenID_Exception $e) {
|
||||
throw new SemanticScuttle_Exception_User(
|
||||
'Invalid OpenID identifier', 11, $e
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'identifier' => $identifier,
|
||||
'userId' => $this->getUserId($identifier),
|
||||
'email' => $message->get('openid.sreg.email'),
|
||||
'nickname' => $message->get('openid.sreg.nickname'),
|
||||
'fullname' => $message->get('openid.sreg.fullname'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user ID for the given OpenID identifier.
|
||||
*
|
||||
* @param string $identifier OpenID identifier (URL)
|
||||
*
|
||||
* @return integer User ID or NULL if not found
|
||||
*
|
||||
* @throws SemanticScuttle_Exception_User When the identifier is invalid
|
||||
*/
|
||||
public function getUserId($identifier)
|
||||
{
|
||||
$query = 'SELECT sc_users_openids.uId'
|
||||
. ' FROM sc_users_openids JOIN sc_users USING (uId)'
|
||||
. ' WHERE url = "' . $this->db->sql_escape($identifier) . '"';
|
||||
|
||||
if (!($dbresult = $this->db->sql_query($query))) {
|
||||
message_die(
|
||||
GENERAL_ERROR,
|
||||
'Could not get user',
|
||||
'', __LINE__, __FILE__, $query, $this->db
|
||||
);
|
||||
}
|
||||
$row = $this->db->sql_fetchrow($dbresult);
|
||||
$this->db->sql_freeresult($dbresult);
|
||||
if (!$row) {
|
||||
//OpenID not found in database.
|
||||
return null;
|
||||
}
|
||||
return $row['uId'];
|
||||
}
|
||||
}
|
||||
?>
|
@ -538,101 +538,6 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to authenticate and login a user with his OpenID
|
||||
*
|
||||
* @param string $identifier OpenID URL, may be null if $return is active
|
||||
* @param boolean $return If the request is the answer from the provider
|
||||
* @param boolean $remember If a long-time cookie shall be set
|
||||
*
|
||||
* @return boolean True if the user could be authenticated,
|
||||
* false if not.
|
||||
*/
|
||||
public function loginOpenId($identifier, $return, $remember = false)
|
||||
{
|
||||
require_once 'OpenID.php';
|
||||
require_once 'OpenID/RelyingParty.php';
|
||||
require_once 'OpenID/Extension/SREG11.php';
|
||||
|
||||
$returnUrl = addProtocolToUrl(createURL('login', 'openidreturn'));
|
||||
if ($identifier !== null) {
|
||||
$identifier = OpenID::normalizeIdentifier($identifier);
|
||||
}
|
||||
$rp = new OpenID_RelyingParty(
|
||||
$returnUrl/*returnTo*/,
|
||||
addProtocolToUrl(ROOT)/* realm */,
|
||||
$identifier
|
||||
);
|
||||
|
||||
if ($return) {
|
||||
//answer from ID provider
|
||||
if (!count($_POST)) {
|
||||
list(, $queryString) = explode('?', $_SERVER['REQUEST_URI']);
|
||||
} else {
|
||||
$queryString = file_get_contents('php://input');
|
||||
}
|
||||
try {
|
||||
$request = new Net_URL2($returnUrl . '?' . $queryString);
|
||||
$message = new OpenID_Message($queryString, OpenID_Message::FORMAT_HTTP);
|
||||
|
||||
$result = $rp->verify($request, $message);
|
||||
if (!$result->success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$identifier = $message->get('openid.claimed_id');
|
||||
} catch (Exception $e) {
|
||||
//FIXME: report error
|
||||
return false;
|
||||
}
|
||||
|
||||
//FIXME: join user table to be sure the user exists
|
||||
$query = 'SELECT uId'
|
||||
. ' FROM sc_users_openids'
|
||||
. ' WHERE url = "' . $this->db->sql_escape($identifier) . '"';
|
||||
|
||||
if (!($dbresult = $this->db->sql_query($query))) {
|
||||
message_die(
|
||||
GENERAL_ERROR,
|
||||
'Could not get user',
|
||||
'', __LINE__, __FILE__, $query, $this->db
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$row = $this->db->sql_fetchrow($dbresult);
|
||||
$this->db->sql_freeresult($dbresult);
|
||||
if (!$row) {
|
||||
//OpenID not found in database. FIXME: Need to register
|
||||
return false;
|
||||
}
|
||||
$this->setCurrentUserId($row['uId'], true);
|
||||
//FIXME: update email and name
|
||||
//FIXME: remember login setting
|
||||
return true;
|
||||
}
|
||||
|
||||
//send request to ID provider
|
||||
try {
|
||||
$authRequest = $rp->prepare();
|
||||
|
||||
//FIXME: when user exists already, use immediate mode first and
|
||||
// fall back to normal when it fails
|
||||
//FIXME: (?) when user exists already, don't request details
|
||||
|
||||
$sreg = new OpenID_Extension_SREG11(OpenID_Extension::REQUEST);
|
||||
//$sreg->set('required', 'email');
|
||||
$sreg->set('optional', 'email,nickname,fullname');
|
||||
$authRequest->addExtension($sreg);
|
||||
//$auth->setMode(OpenID::MODE_CHECKID_IMMEDIATE);
|
||||
header('Location: ' . $authRequest->getAuthorizeURL());
|
||||
exit();
|
||||
} catch (Exception $e) {
|
||||
//FIXME: throw user exception
|
||||
var_dump($e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to authenticate via the privateKey
|
||||
*
|
||||
|
@ -98,6 +98,7 @@ if (DEBUG_MODE) {
|
||||
|
||||
// 2 // Second requirements part which could display bugs
|
||||
// (must come after debug management)
|
||||
require_once 'SemanticScuttle/Exception.php';
|
||||
require_once 'SemanticScuttle/Service.php';
|
||||
require_once 'SemanticScuttle/DbService.php';
|
||||
require_once 'SemanticScuttle/Service/Factory.php';
|
||||
|
@ -39,20 +39,31 @@ $keeppass = (POST_KEEPPASS=='yes')?true:false;
|
||||
|
||||
|
||||
$login = false;
|
||||
if ($method == 'openidreturn') {
|
||||
$login = $userservice->loginOpenId(null, true);
|
||||
if (!$login) {
|
||||
$tplVars['error'] = T_('OpenID login error');
|
||||
}
|
||||
} else if (POST_SUBMITTED != ''
|
||||
&& isset($_POST['openid_identifier']) && $_POST['openid_identifier'] != ''
|
||||
if ($method == 'openidreturn'
|
||||
|| (POST_SUBMITTED != ''
|
||||
&& isset($_POST['openid_identifier']) && $_POST['openid_identifier'] != ''
|
||||
)
|
||||
) {
|
||||
$login = $userservice->loginOpenId(
|
||||
$_POST['openid_identifier'], false, POST_KEEPPASS
|
||||
);
|
||||
if (!$login) {
|
||||
//may be an exception with the ID
|
||||
$tplVars['error'] = T_('OpenID login error');
|
||||
$oids = SemanticScuttle_Service_Factory::get('OpenID');
|
||||
$returnUrl = addProtocolToUrl(createURL('login', 'openidreturn'));
|
||||
try {
|
||||
if ($method == 'openidreturn') {
|
||||
//part 2: handle response
|
||||
$ret = $oids->handleIdResponse($returnUrl);
|
||||
if ($ret['userId'] === null) {
|
||||
//FIXME: ask to register
|
||||
$tplVars['error'] = T_('OpenID login error');
|
||||
} else {
|
||||
$userservice->setCurrentUserId($ret['userId'], true);
|
||||
$login = true;
|
||||
}
|
||||
//FIXME POST_KEEPPASS
|
||||
} else {
|
||||
//part 1: send request
|
||||
$oids->sendIdRequest($_POST['openid_identifier'], $returnUrl);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$tplVars['error'] = SemanticScuttle_Exception::getErrorMessage($e);
|
||||
}
|
||||
} else if (POST_SUBMITTED!='' && POST_USERNAME!='' && POST_PASSWORD!='') {
|
||||
$posteduser = trim(utf8_strtolower(POST_USERNAME));
|
||||
@ -61,6 +72,7 @@ if ($method == 'openidreturn') {
|
||||
$tplVars['error'] = T_('The details you have entered are incorrect. Please try again.');
|
||||
}
|
||||
}
|
||||
|
||||
if ($login) {
|
||||
if (POST_QUERY)
|
||||
header('Location: '. createURL('bookmarks', $posteduser .'?'. POST_QUERY));
|
||||
|
Loading…
Reference in New Issue
Block a user