1
0
mirror of https://github.com/e107inc/e107.git synced 2025-08-08 23:56:58 +02:00

Core modifications to support Hybridauth 3

- MOD: Replaced e107::getPref('social_login') with
       SocialLoginConfigManager::getValidConfiguredProviderConfigs()
- FIX: signup_shortcodes updated with new social login providers
- MOD: e107::filter_request() code de-duplication: HTTP 400 exits
- MOD: Deprecated e107::getHybridAuth() to discourage direct access to
       third-party dependency Hybridauth
- FIX: Updated e_user_provider for Hybridauth 3
- FIX: e_user::tryProviderSession() and Hybridauth 3
- NEW: Dynamic auth provider support in social_adminarea
- NEW: Database migration for social plugin's social_login pref
This commit is contained in:
Nick Liu
2020-02-17 10:36:03 +01:00
parent 46c75ae4d0
commit 91bfc1df23
12 changed files with 1228 additions and 509 deletions

View File

@@ -579,7 +579,7 @@ class UserHandler
$digitLength = strlen($digit) - 1;
// Create alpha numeric [A-Z][a-z]
$alphaNum = $alpha.$digit.chr(45).chr(95); // add support for - and _
$alphaNum = $alpha.$digit.chr(45).chr(95); // add support for - and _
$alphaNumLength = strlen($alphaNum) - 1;
$symbols = "~!@#$%^*-+?;:"; // avoid < > and quotes.
@@ -1081,95 +1081,69 @@ Following fields auto-filled in code as required:
}
}
/**
* Social login provider
*/
class e_user_provider
{
/**
* @var string
*/
protected $_provider;
/**
* Hybridauth adapter
* @var \Hybridauth\Adapter\AdapterInterface
*/
public $adapter;
/**
* Hybridauth object
* @var Hybridauth\Hybridauth
*/
public $hybridauth;
protected $hybridauth;
protected $_config = array();
public function __construct($provider, $config = array())
/**
* @var SocialLoginConfigManager
*/
protected $social_login_config_manager;
public function __construct($provider = null, $config = array())
{
if(!empty($config))
require_once(e_PLUGIN . "social/SocialLoginConfigManager.php");
$this->social_login_config_manager = new SocialLoginConfigManager(e107::getConfig());
if (!empty($config))
{
$this->_config = $config;
}
else
else
{
$this->_config = array(
"callback" => e107::getUrl()->create('system/xup/login', array(), array('full' => true)),
"providers" => e107::getPref('social_login', array()),
"debug_mode" => 'error',
"debug_file" => e_LOG."hybridAuth.log"
"callback" => e107::getUrl()->create(
'system/xup/login',
array('provider' => $provider),
array('full' => true, 'encode' => false)
),
"providers" => $this->social_login_config_manager->getValidConfiguredProviderConfigs(),
"debug_mode" => 'error',
"debug_file" => e_LOG . "hybridAuth.log"
);
}
$this->hybridauth = e107::getHybridAuth($this->_config);
$this->hybridauth = new Hybridauth\Hybridauth($this->_config);
$this->setProvider($provider);
}
public function setProvider($provider)
{
$provider = strtolower($provider);
switch($provider)
{
case 'aol':
$provider = 'AOL';
break;
case 'googleopenid':
$provider = 'GoogleOpenID';
break;
case 'linkedin':
$provider = 'LinkedIn';
break;
case 'myspace':
$provider = 'MySpace';
break;
case 'openid':
$provider = 'OpenID';
break;
default:
$provider = ucfirst($provider);
break;
}
if(isset($this->_config['providers'][$provider]) && $this->_config['providers'][$provider]['enabled'])
{
if($this->_config['providers'][$provider]['enabled'] && vartrue($this->_config['providers'][$provider]['keys']))
{
$valid = true;
foreach ($this->_config['providers'][$provider]['keys'] as $_key => $_value)
{
if(empty($_value)) $valid = false;
}
if($valid) $this->_provider = $provider;
}
}
$this->_provider = $provider;
}
private function log($class,$method,$line)
private function log($class, $method, $line)
{
// e107::getLog()->add('XUP Debug', ($class.':'.$method.'-'.$line), E_LOG_INFORMATIVE, "XUP_DEBUG");
// e107::getLog()->add('XUP Debug', ($class.':'.$method.'-'.$line), E_LOG_INFORMATIVE, "XUP_DEBUG");
}
@@ -1178,110 +1152,179 @@ class e_user_provider
# system/xup/login by default
$this->_config['callback'] = $url;
}
public function getProvider()
{
// $this->log(__CLASS__, __METHOD__, __LINE__);
return $this->_provider;
}
public function getConfig()
{
return $this->_config;
}
public function getUserProfile()
{
if($this->adapter)
if ($this->adapter)
{
return $this->adapter->getUserProfile();
try
{
return $this->adapter->getUserProfile();
}
catch (\Hybridauth\Exception\Exception $e)
{
return null;
}
}
return null;
}
public function userId()
{
if($this->adapter && $this->adapter->getUserProfile()->identifier)
if ($profile = $this->getUserProfile())
{
return $this->getProvider().'_'.$this->adapter->getUserProfile()->identifier;
return $this->getProvider() . '_' . $profile->identifier;
}
return null;
}
/**
* XUP Signup Method (falls-back to XUP login when existing user is detected).
* May be used as a simple XUP login link for existing and non-existing users.
* Get the social login providers for which we have adapters
*
* This function is slow! Please cache the output instead of calling it multiple times.
*
* @return array String list of supported providers. Empty if Hybridauth is broken.
*/
public static function getSupportedProviders()
{
$providers = [];
try
{
$reflector = new ReflectionClass('Hybridauth\Hybridauth');
}
catch (ReflectionException $e)
{
return $providers;
}
$hybridauth_path = $reflector->getFileName();
$hybridauth_providers_path = dirname($hybridauth_path) . "/Provider/";
$fs_iterator = new FilesystemIterator($hybridauth_providers_path);
foreach ($fs_iterator as $file)
{
if (!$file->isFile()) continue;
$provider_source_code = file_get_contents($file);
$provider_source_tokens = token_get_all($provider_source_code);
for ($token_index = 0; isset($provider_source_tokens[$token_index]); $token_index++)
{
if (!isset($provider_source_tokens[$token_index][0])) continue;
if (T_CLASS === $provider_source_tokens[$token_index][0])
{
$token_index += 2;
$providers[] = $provider_source_tokens[$token_index][1];
}
}
}
sort($providers);
return $providers;
}
/**
* Get the type of provider from a provider name
* @param $providerName string Name of the supported social login provider
* @return string|bool "OAuth1", "OAuth2", or "OpenID". If false, the provider name is invalid.
* Other values are technically possible but not supported.
*/
public static function getTypeOf($providerName)
{
$class_name = "Hybridauth\Provider\\{$providerName}";
$parent_class = get_parent_class($class_name);
if (!$parent_class) return false;
$parent_class_split = explode("\\", get_parent_class($class_name));
$type = end($parent_class_split);
if ($type == "AbstractAdapter") return $providerName;
if (!in_array($type, ['OAuth1', 'OAuth2', 'OpenID'])) return self::getTypeOf($type);
return $type;
}
/**
* XUP Signup Method (falls-back to XUP login when existing user is detected).
* May be used as a simple XUP login link for existing and non-existing users.
*/
public function signup($redirectUrl = true, $loginAfterSuccess = true, $emailAfterSuccess = true)
{
if(!e107::getPref('social_login_active', false))
if (!e107::getPref('social_login_active', false))
{
throw new Exception( "Signup failed! This feature is disabled.", 100); // TODO lan
throw new Exception("Signup failed! This feature is disabled.", 100); // TODO lan
}
if(!$this->getProvider())
if (!$this->getProvider())
{
throw new Exception( "Signup failed! Wrong provider.", 2); // TODO lan
throw new Exception("Signup failed! Wrong provider.", 2); // TODO lan
}
if($redirectUrl)
if ($redirectUrl)
{
if(true === $redirectUrl)
if (true === $redirectUrl)
{
$redirectUrl = SITEURL;
}
elseif(strpos($redirectUrl, 'http://') !== 0 && strpos($redirectUrl, 'https://') !== 0)
elseif (strpos($redirectUrl, 'http://') !== 0 && strpos($redirectUrl, 'https://') !== 0)
{
$redirectUrl = e107::getUrl()->create($redirectUrl);
}
}
if(e107::getUser()->isUser())
if (e107::getUser()->isUser())
{
if($redirectUrl)
if ($redirectUrl)
{
e107::getRedirect()->redirect($redirectUrl);
}
return false;
// throw new Exception( "Signup failed! User already signed in. ", 1); // TODO lan
// throw new Exception( "Signup failed! User already signed in. ", 1); // TODO lan
}
$this->adapter = $this->hybridauth->authenticate($this->getProvider());
$profile = $this->adapter->getUserProfile();
$this->log(__CLASS__, __METHOD__, __LINE__);
// returned back, if success...
if($profile->identifier)
if ($profile->identifier)
{
$sql = e107::getDb();
$userMethods = e107::getUserSession();
$plainPwd = $userMethods->generateRandomString('************'); // auto plain passwords
// TODO - auto login name, shouldn't be used if system set to user_email login...
$userdata['user_loginname'] = $this->getProvider().$userMethods->generateUserLogin(e107::getPref('predefinedLoginName', '_..#..#..#'));
$userdata['user_email'] = $sql->escape($profile->emailVerified ? $profile->emailVerified : $profile->email);
$userdata['user_name'] = $sql->escape($profile->displayName);
$userdata['user_login'] = $userdata['user_name'];
$userdata['user_customtitle'] = ''; // not used
$userdata['user_password'] = $userMethods->HashPassword($plainPwd, $userdata['user_loginname']); // pwd
$userdata['user_sess'] = ''; //
$userdata['user_image'] = $profile->photoURL; // avatar
$userdata['user_signature'] = ''; // not used
$userdata['user_hideemail'] = 1; // hide it by default
$userdata['user_xup'] = $sql->escape($this->userId());
$userdata['user_loginname'] = $this->getProvider() . $userMethods->generateUserLogin(e107::getPref('predefinedLoginName', '_..#..#..#'));
$userdata['user_email'] = $sql->escape($profile->emailVerified ? $profile->emailVerified : $profile->email);
$userdata['user_name'] = $sql->escape($profile->displayName);
$userdata['user_login'] = $userdata['user_name'];
$userdata['user_customtitle'] = ''; // not used
$userdata['user_password'] = $userMethods->HashPassword($plainPwd, $userdata['user_loginname']); // pwd
$userdata['user_sess'] = ''; //
$userdata['user_image'] = $profile->photoURL; // avatar
$userdata['user_signature'] = ''; // not used
$userdata['user_hideemail'] = 1; // hide it by default
$userdata['user_xup'] = $sql->escape($this->userId());
$pref = e107::pref('core');
if(!empty($pref['initial_user_classes']))
if (!empty($pref['initial_user_classes']))
{
$userdata['user_class'] = $pref['initial_user_classes'];
}
elseif(!empty($pref['user_new_period']))
elseif (!empty($pref['user_new_period']))
{
$userdata['user_class'] = e_UC_NEWUSER;
}
@@ -1290,37 +1333,38 @@ class e_user_provider
$userdata['user_class'] = '';
}
// print_a($userdata);
// print_a($userdata);
// user_name, user_xup, user_email and user_loginname shouldn't match
$insert = (!empty($userdata['user_email'])) ? "OR user_email='".$userdata['user_email']."' " : "";
$insert = (!empty($userdata['user_email'])) ? "OR user_email='" . $userdata['user_email'] . "' " : "";
$this->log(__CLASS__, __METHOD__, __LINE__);
if($uid = $sql->retrieve("user", "user_id", "user_xup='".$sql->escape($this->userId())."' ".$insert." OR user_loginname='{$userdata['user_loginname']}' OR user_name='{$userdata['user_name']}'"))
if ($uid = $sql->retrieve("user", "user_id", "user_xup='" . $sql->escape($this->userId()) . "' " . $insert . " OR user_loginname='{$userdata['user_loginname']}' OR user_name='{$userdata['user_name']}'"))
{
// $this->login($redirectUrl); // auto-login
e107::getUser()->loginProvider($this->userId());
if($redirectUrl)
if ($redirectUrl)
{
e107::getRedirect()->redirect($redirectUrl);
}
return false;
// throw new Exception( "Signup failed! User already exists. Please use 'login' instead.", 3);
}
if(empty($userdata['user_email']) && e107::getPref('disable_emailcheck', 0)==0) // Allow it if set-up that way.
if (empty($userdata['user_email']) && e107::getPref('disable_emailcheck', 0) == 0) // Allow it if set-up that way.
{
// Twitter will not provide email addresses.
// throw new Exception( "Signup failed! Can't access user email - registration without an email is impossible.".print_a($userdata,true), 4); // TODO lan
// throw new Exception( "Signup failed! Can't access user email - registration without an email is impossible.".print_a($userdata,true), 4); // TODO lan
}
// other fields
$now = time();
$now = time();
$userdata['user_id'] = null;
$userdata['user_image'] = '';
$userdata['user_join'] = $now;
$userdata['user_lastvisit'] = 0;
$userdata['user_currentvisit'] = 0;
@@ -1340,12 +1384,12 @@ class e_user_provider
$user->getExtendedModel(); // init
//$user->setEditor(e107::getSystemUser(1, false));
$user->save(true);
// user model error
if($user->hasError())
if ($user->hasError())
{
e107::getLog()->add('XUP Signup Failure', $userdata, E_LOG_WARNING, "XUP_SIGNUP");
throw new Exception($user->renderMessages(), 5);
throw new Exception($user->renderMessages(), 5);
}
@@ -1354,35 +1398,35 @@ class e_user_provider
$userdata = $user->getData();
$userdata['provider'] = $this->getProvider();
$userdata['callback_data'] = $profile;
// e107::getEvent()->trigger('userveri', $userdata); // Trigger New verified user.
e107::getEvent()->trigger('user_xup_signup', $userdata);
$ret = e107::getEvent()->trigger('usersupprov', $userdata); // XXX - it's time to pass objects instead of array?
$userdata['callback_data'] = $profile;
// e107::getEvent()->trigger('userveri', $userdata); // Trigger New verified user.
e107::getEvent()->trigger('user_xup_signup', $userdata);
$ret = e107::getEvent()->trigger('usersupprov', $userdata); // XXX - it's time to pass objects instead of array?
if (true === $ret) return $this;
if(true === $ret) return $this;
// send email
if($emailAfterSuccess && !empty($userdata['user_email']))
if ($emailAfterSuccess && !empty($userdata['user_email']))
{
$user->set('user_password', $plainPwd)->email('signup');
$user->set('user_password', $plainPwd)->email('signup');
}
e107::getUser()->setProvider($this);
// auto login
if($loginAfterSuccess)
if ($loginAfterSuccess)
{
e107::getUser()->loginProvider($this->userId()); // if not proper after-login, return true so user can see login screen
}
if($redirectUrl)
if ($redirectUrl)
{
e107::getRedirect()->redirect($redirectUrl);
}
return true;
}
@@ -1392,70 +1436,68 @@ class e_user_provider
}
public function login($redirectUrl = true)
{
if(!e107::getPref('social_login_active', false))
if (!e107::getPref('social_login_active', false))
{
throw new Exception( "Signup failed! This feature is disabled.", 100); // TODO lan
throw new Exception("Signup failed! This feature is disabled.", 100); // TODO lan
}
if(!$this->getProvider())
if (!$this->getProvider())
{
throw new Exception( "Login failed! Wrong provider.", 22); // TODO lan
throw new Exception("Login failed! Wrong provider.", 22); // TODO lan
}
if($redirectUrl)
if ($redirectUrl)
{
if(true === $redirectUrl)
if (true === $redirectUrl)
{
$redirectUrl = SITEURL;
}
elseif(strpos($redirectUrl, 'http://') !== 0 && strpos($redirectUrl, 'https://') !== 0)
elseif (strpos($redirectUrl, 'http://') !== 0 && strpos($redirectUrl, 'https://') !== 0)
{
$redirectUrl = e107::getUrl()->create($redirectUrl);
}
}
if(e107::getUser()->isUser())
if (e107::getUser()->isUser())
{
if($redirectUrl)
if ($redirectUrl)
{
e107::getRedirect()->redirect($redirectUrl);
}
return true;
return true;
}
$this->adapter = $this->hybridauth->authenticate($this->getProvider());
$check = e107::getUser()->setProvider($this)->loginProvider($this->userId());
if($redirectUrl)
if ($redirectUrl)
{
e107::getRedirect()->redirect($redirectUrl);
}
return $check;
}
public function init()
{
if(!e107::getPref('social_login_active', false))
if (!e107::getPref('social_login_active', false))
{
return;
}
$this->adapter = null;
$providerId = $this->_provider;
if($providerId && $this->hybridauth->isConnectedWith($providerId))
if ($providerId && $this->hybridauth->isConnectedWith($providerId))
{
$this->adapter = $this->hybridauth->getAdapter($providerId);
}
}
public function logout()
{
if (
@@ -1465,16 +1507,16 @@ class e_user_provider
) return true;
try
{
$this->adapter->logout();
$this->adapter->disconnect();
$this->adapter = null;
}
catch(Exception $e)
catch (Exception $e)
{
return $e->getMessage();
}
return true;
}
}