diff --git a/e107_core/controllers/system/xup.php b/e107_core/controllers/system/xup.php
index 04fe190ce..fcd8203ea 100644
--- a/e107_core/controllers/system/xup.php
+++ b/e107_core/controllers/system/xup.php
@@ -20,8 +20,18 @@ class core_system_xup_controller extends eController
{
var $backUrl = null;
-
-
+ /**
+ * @var SocialLoginConfigManager
+ */
+ private $social_login_config_manager;
+
+ public function __construct(eRequest $request, eResponse $response = null)
+ {
+ parent::__construct($request, $response);
+ require_once(e_PLUGIN."social/SocialLoginConfigManager.php");
+ $this->social_login_config_manager = new SocialLoginConfigManager(e107::getConfig());
+ }
+
public function init()
{
//$back = 'system/xup/test';
@@ -113,9 +123,11 @@ class core_system_xup_controller extends eController
echo ' '.LAN_XUP_ERRM_11.' '.(e107::getUser()->isUser() && !empty($profileData) ? 'true' : 'false');
- $testUrl = SITEURL."?route=system/xup/test";
- $providers = e107::getPref('social_login', array());
-
+ $testUrl = SITEURL."?route=system/xup/test";
+ require_once(e_PLUGIN . "social/SocialLoginConfigManager.php");
+ $manager = new SocialLoginConfigManager(e107::getConfig());
+ $providers = $manager->getValidConfiguredProviderConfigs();
+
foreach($providers as $key=>$var)
{
if($var['enabled'] == 1)
diff --git a/e107_core/shortcodes/batch/signup_shortcodes.php b/e107_core/shortcodes/batch/signup_shortcodes.php
index a7e6ee732..3f871b958 100755
--- a/e107_core/shortcodes/batch/signup_shortcodes.php
+++ b/e107_core/shortcodes/batch/signup_shortcodes.php
@@ -75,26 +75,34 @@ class signup_shortcodes extends e_shortcode
if(!empty($pref))
{
$text = "";
- $providers = e107::getPref('social_login');
+ $manager = new SocialLoginConfigManager(e107::getConfig());
+ $providers = $manager->getValidConfiguredProviderConfigs();
foreach($providers as $p=>$v)
{
- $p = strtolower($p);
if($v['enabled'] == 1)
{
// $text .= "
";
$ic = strtolower($p);
-
- if($ic == 'live')
+
+ switch ($ic)
{
- $ic = 'windows';
+ case 'windowslive':
+ $ic = 'windows';
+ break;
}
-
- // 'signup' Creates a new XUP user if not found, otherwise it logs the person in.
-
- $button = (defset('FONTAWESOME')) ? $tp->toGlyph('fa-'.$ic, array('size'=>$size, 'fw'=>true)) : "
";
+
+ // 'signup' Creates a new XUP user if not found, otherwise it logs the person in.
+
+ if (defset('FONTAWESOME') && in_array($ic, e107::getMedia()->getGlyphs()))
+ $button = "" . $tp->toGlyph('fa-' . $ic, array('size' => $size, 'fw' => true)) . "";
+ elseif (is_file(e107::getFolder('images') . "xup/{$ic}.png"))
+ $button = "
";
+ else
+ $button = "$p";
+
$text .= " ".$button." ";
}
//TODO different icon options. see: http://zocial.smcllns.com/
@@ -116,8 +124,9 @@ class signup_shortcodes extends e_shortcode
if(!empty($pref))
{
$text = "";
- $providers = e107::pref('core', 'social_login');
-
+ $manager = new SocialLoginConfigManager(e107::getConfig());
+ $providers = $manager->getValidConfiguredProviderConfigs();
+
$size = empty($parm['size']) ? '2x' : $parm['size'];
$class = empty($parm['class']) ? 'btn btn-primary' : $parm['class'] ;
@@ -129,22 +138,25 @@ class signup_shortcodes extends e_shortcode
foreach($providers as $p=>$v)
{
-
-
- $p = strtolower($p);
if($v['enabled'] == 1)
{
$ic = strtolower($p);
-
- if($ic == 'live')
+
+ switch ($ic)
{
- $ic = 'windows';
+ case 'windowslive':
+ $ic = 'windows';
+ break;
}
- $button = (defset('FONTAWESOME')) ? "".$tp->toGlyph('fa-'.$ic, array('size'=>$size, 'fw'=>true))."" : "
";
-
- $text .= " ".$button." ";
- }
+ if (defset('FONTAWESOME') && in_array($ic, e107::getMedia()->getGlyphs()))
+ $button = "" . $tp->toGlyph('fa-' . $ic, array('size' => $size, 'fw' => true)) . "";
+ elseif (is_file(e107::getFolder('images') . "xup/{$ic}.png"))
+ $button = "
";
+ else
+ $button = "$p";
+ $text .= " " . $button . " ";
+ }
//TODO different icon options. see: http://zocial.smcllns.com/
}
diff --git a/e107_handlers/e107_class.php b/e107_handlers/e107_class.php
index a7b62dce9..c5b671d2c 100644
--- a/e107_handlers/e107_class.php
+++ b/e107_handlers/e107_class.php
@@ -286,6 +286,18 @@ class e107
//register_shutdown_function(array($this, 'destruct'));
}
+ private static function die_http_400()
+ {
+ header('HTTP/1.0 400 Bad Request', true, 400);
+ header('Content-Type: text/plain');
+ if (deftrue('e_DEBUG'))
+ {
+ echo "Bad Request: ";
+ debug_print_backtrace(0, 1);
+ }
+ exit();
+ }
+
/**
* Cloning is not allowed
*
@@ -1695,14 +1707,22 @@ class e107
* Create a new Hybridauth object based on the provided configuration
*
* @return Hybridauth\Hybridauth
+ * @throws \Hybridauth\Exception\InvalidArgumentException
+ * @deprecated v2.3.0 Use the e_user_provider interfaces instead (e107::getUser()->getProvider()).
+ * Hybridauth features are only available if the user is associated with a social login.
+ * @see e107::getUser() for getting a user object that may or may not have a social login.
+ * @see e_user_provider for social login features, only if enabled on the user.
*/
public static function getHybridAuth($config = null)
{
if(null === $config)
{
+ require_once(e_PLUGIN . "social/SocialLoginConfigManager.php");
+ $manager = new SocialLoginConfigManager(e107::getConfig());
+
$config = array(
'callback' => self::getUrl()->create('system/xup/login', array(), array('full' => true)),
- 'providers' => self::getPref('social_login', array()),
+ 'providers' => $manager->getValidConfiguredProviderConfigs(),
'debug_mode' => false,
'debug_file' => ''
);
@@ -3938,57 +3958,32 @@ class e107
$regex = "/(base64_decode|chr|php_uname|fwrite|fopen|fputs|passthru|popen|proc_open|shell_exec|exec|proc_nice|proc_terminate|proc_get_status|proc_close|pfsockopen|apache_child_terminate|posix_kill|posix_mkfifo|posix_setpgid|posix_setsid|posix_setuid|phpinfo) *?\((.*) ?\;?/i";
if(preg_match($regex,$input))
{
- header('HTTP/1.0 400 Bad Request', true, 400);
- if(deftrue('e_DEBUG'))
- {
- echo "Bad Request: ".__METHOD__." : ". __LINE__;
- }
- exit();
+ self::die_http_400();
}
// Check for XSS JS
$regex = "/(document\.location|document\.write|document\.cookie)/i";
if(preg_match($regex,$input))
{
- header('HTTP/1.0 400 Bad Request', true, 400);
- if(deftrue('e_DEBUG'))
- {
- echo "Bad Request: ".__METHOD__." : ". __LINE__;
- }
- exit();
+ self::die_http_400();
}
// Suspicious HTML.
if(strpos($input, '
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;
}
-
+
}
diff --git a/e107_handlers/user_model.php b/e107_handlers/user_model.php
index 5241e02a1..17d6c85ea 100644
--- a/e107_handlers/user_model.php
+++ b/e107_handlers/user_model.php
@@ -1497,12 +1497,13 @@ class e_user extends e_user_model
private $_parent_config = null;
/**
- * @var Hybrid_Provider_Model
+ * @var e_user_provider|null
*/
protected $_provider;
public function __construct()
{
+ parent::__construct();
$this->setSessionData() // retrieve data from current session
->load() // load current user from DB
->setEditor($this); // reference to self
@@ -1531,7 +1532,7 @@ class e_user extends e_user_model
/**
* Init external user login/signup provider
- * @return e_system_user
+ * @return e_user
*/
public function initProvider()
{
@@ -1544,11 +1545,13 @@ class e_user extends e_user_model
$this->_provider = new e_user_provider($providerId);
$this->_provider->init();
}
+
+ return $this;
}
/**
* Get external user provider
- * @return Hybrid_Provider_Model
+ * @return e_user_provider|null
*/
public function getProvider()
{
@@ -1750,10 +1753,17 @@ class e_user extends e_user_model
foreach ($connected as $providerId)
{
$adapter = $hybrid->getAdapter($providerId);
-
- if(!$adapter->getUserProfile()->identifier) continue;
- $profile = $adapter->getUserProfile();
+ try
+ {
+ $profile = $adapter->getUserProfile();
+ }
+ catch (\Hybridauth\Exception\Exception $e)
+ {
+ continue;
+ }
+
+ if (!$profile->identifier) continue;
$userdata['user_name'] = $sql->escape($profile->displayName);
$userdata['user_image'] = $profile->photoURL; // avatar
@@ -1762,7 +1772,8 @@ class e_user extends e_user_model
$id = $providerId.'_'.$profile->identifier;
$where[] = "user_xup='".$sql->escape($id)."'";
}
-
+ // no active session found
+ if(empty($where)) return $this;
$where = implode(' OR ', $where);
if($sql->select('user', 'user_id, user_name, user_email, user_image, user_password, user_xup', $where))
diff --git a/e107_plugins/social/SocialLoginConfigManager.php b/e107_plugins/social/SocialLoginConfigManager.php
new file mode 100644
index 000000000..d512af199
--- /dev/null
+++ b/e107_plugins/social/SocialLoginConfigManager.php
@@ -0,0 +1,223 @@
+config = $config;
+ }
+
+ /**
+ * Checks whether the specified social login provider is enabled
+ * @param $providerName string The un-normalized name of the provider to check
+ * @return bool Whether the specified provider is enabled
+ */
+ public function isProviderEnabled($providerName)
+ {
+ $result = $this->getProviderConfig($providerName, "/enabled");
+ return (bool)$result;
+ }
+
+ /**
+ * Disable and remove the specified social login provider
+ * @param $providerName string The un-normalized name of the provider to forget
+ */
+ public function forgetProvider($providerName)
+ {
+ $this->config->removePref(self::SOCIAL_LOGIN_PREF . '/' . $this->normalizeProviderName($providerName));
+ }
+
+ /**
+ * Overwrite the entire social login provider configuration with the specified options
+ *
+ * Does not commit to database.
+ *
+ * @param $providerName string The un-normalized name of the social login provider
+ * @param $options array Associative array of options
+ * $options['enabled'] bool Whether the social login provider is enabled
+ * $options['keys'] array Authentication app keys
+ * $options['keys']['id'] string The OAuth1 client key or OAuth2 client ID
+ * $options['keys']['secret'] string The OAuth1 or OAuth2 client secret
+ * $options['scope'] string OAuth2 scopes, space-delimited
+ * @see SocialLoginConfigManager::saveProviderConfig() to commit to database.
+ *
+ */
+ public function setProviderConfig($providerName, $options)
+ {
+ $config = $this->getSocialLoginConfig();
+ if (!is_array($config)) $this->config->set(self::SOCIAL_LOGIN_PREF, []);
+
+ self::array_unset_empty_recursive($options);
+
+ if (empty($options)) $this->forgetProvider($providerName);
+ else $this->config->setPref(
+ self::SOCIAL_LOGIN_PREF . '/' . $this->normalizeProviderName($providerName),
+ $options
+ );
+ }
+
+ private static function array_unset_empty_recursive(&$array)
+ {
+ foreach ($array as $key => &$value)
+ {
+ if (is_array($value))
+ {
+ $arraySize = self::array_unset_empty_recursive($value);
+ if (!$arraySize)
+ {
+ unset($array[$key]);
+ }
+ }
+ else if (empty($array[$key]))
+ {
+ unset($array[$key]);
+ }
+ }
+ return count($array);
+ }
+
+ public function saveProviderConfig()
+ {
+ $this->config->save(true, false, false);
+ }
+
+ /**
+ * Get the social login provider configuration currently stored in the database
+ * @param $providerName string The un-normalized name of the social login provider
+ * @param $path string Nested array keys, slash-delimited ("/")
+ * @return array|mixed The configuration of the specified provider, or the value of the $path
+ */
+ public function getProviderConfig($providerName, $path = "")
+ {
+ if (empty($path)) $path = "";
+ elseif (substr($path, 0, 1) !== "/") $path = "/$path";
+
+ $pref = $this->config->getPref(
+ self::SOCIAL_LOGIN_PREF . '/' . $this->normalizeProviderName($providerName) . $path
+ );
+
+ return $pref;
+ }
+
+ /**
+ * Get configs of providers that are supported and configured
+ * @return array Associative array where the key is the denormalized provider name and the value is its config
+ */
+ public function getValidConfiguredProviderConfigs()
+ {
+ $supported_providers = $this->getSupportedProviders();
+ $configured_providers = $this->getConfiguredProviders();
+ $unsupported_providers = array_diff($configured_providers, $supported_providers);
+ $configured_providers = array_diff($configured_providers, $unsupported_providers);
+
+ $provider_configs = [];
+ foreach ($configured_providers as $configured_provider)
+ {
+ $provider_configs[$configured_provider] =
+ $this->getProviderConfig($configured_provider);
+ }
+
+ return $provider_configs;
+ }
+
+ /**
+ * Get the social login providers for which we have adapters
+ * @return array String list of supported providers. Empty if Hybridauth is broken.
+ */
+ public function getSupportedProviders()
+ {
+ if ($this->supportedProvidersCache === null)
+ $this->supportedProvidersCache = e_user_provider::getSupportedProviders();
+ return $this->supportedProvidersCache;
+ }
+
+ /**
+ * 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 function getTypeOfProvider($providerName)
+ {
+ return e_user_provider::getTypeOf($providerName);
+ }
+
+ /**
+ * Get the providers that are currently configured in the core preferences
+ * @return array String list of configured provider names
+ */
+ public function getConfiguredProviders()
+ {
+ $output = [];
+ $social_login_config = $this->getSocialLoginConfig();
+ $configured_providers = array_keys($social_login_config);
+ foreach ($configured_providers as $configured_provider)
+ {
+ $output[] = $this->denormalizeProviderName($configured_provider);
+ }
+ sort($output);
+ return $output;
+ }
+
+ protected function getSocialLoginConfig()
+ {
+ return $this->config->get(self::SOCIAL_LOGIN_PREF);
+ }
+
+ /**
+ * Turn a provider name into one fit for storage in the database (core preferences)
+ * @return string Normalized social login provider name
+ */
+ public function normalizeProviderName($providerName)
+ {
+ $normalizedProviderName = $providerName;
+ foreach ($this->getSupportedProviders() as $providerProperCaps)
+ {
+ if (mb_strtolower($providerName) == mb_strtolower($providerProperCaps))
+ {
+ $normalizedProviderName = $providerProperCaps;
+ break;
+ }
+ }
+ $providerType = $this->getTypeOfProvider($normalizedProviderName);
+ $normalizedProviderName = preg_replace('/(OpenID|OAuth1|OAuth2)$/i', '', $normalizedProviderName);
+ if (empty($normalizedProviderName) && !empty($providerType) || $providerName == $providerType)
+ return $providerType;
+ elseif ($providerType)
+ return "{$normalizedProviderName}-{$providerType}";
+ return $providerName;
+ }
+
+ /**
+ * Turn a normalized provider name into a Hybridauth-compatible adapter name
+ * @param $normalizedProviderName string Provider name stored in the database
+ * @return string Hybridauth-compatible adapter name. May not necessarily exist in Hybridauth.
+ */
+ public function denormalizeProviderName($normalizedProviderName)
+ {
+ list($provider_name, $provider_type) = array_pad(explode("-", $normalizedProviderName), 2, "");
+ if ($provider_type != $this->getTypeOfProvider($provider_name)) $provider_name .= $provider_type;
+ return $provider_name;
+ }
+}
\ No newline at end of file
diff --git a/e107_plugins/social/admin_config.php b/e107_plugins/social/admin_config.php
index 84435b7ca..986c46f60 100644
--- a/e107_plugins/social/admin_config.php
+++ b/e107_plugins/social/admin_config.php
@@ -3,7 +3,7 @@
// Generated e107 Plugin Admin Area
require_once('../../class2.php');
-if (!getperms('P'))
+if (!getperms('P'))
{
e107::redirect('admin');
exit;
@@ -15,63 +15,63 @@ e107::lan('social',false, true);
class social_adminarea extends e_admin_dispatcher
{
- protected $modes = array(
-
+ protected $modes = array(
+
'main' => array(
'controller' => 'social_ui',
'path' => null,
'ui' => 'social_form_ui',
'uipath' => null
),
-
- );
-
-
+
+ );
+
+
protected $adminMenu = array(
// 'main/list' => array('caption'=> LAN_MANAGE, 'perm' => 'P'),
// 'main/create' => array('caption'=> LAN_CREATE, 'perm' => 'P'),
'main/configure' => array('caption'=> LAN_CONFIGURE, 'perm' => 'P'),
- 'main/prefs' => array('caption'=> LAN_PREFS, 'perm' => 'P'),
+ 'main/prefs' => array('caption'=> LAN_PREFS, 'perm' => 'P'),
);
protected $adminMenuAliases = array(
- 'main/edit' => 'main/list'
- );
-
+ 'main/edit' => 'main/list'
+ );
+
protected $menuTitle = LAN_PLUGIN_SOCIAL_NAME;
}
+require_once("SocialLoginConfigManager.php");
-
class social_ui extends e_admin_ui
{
-
+
protected $pluginTitle = LAN_PLUGIN_SOCIAL_NAME;
protected $pluginName = 'social';
// protected $eventName = 'social-social'; // remove comment to enable event triggers in admin.
// protected $table = 'social';
// protected $pid = 'interview_id';
- protected $perPage = 10;
+ protected $perPage = 10;
protected $batchDelete = true;
// protected $batchCopy = true;
// protected $sortField = 'somefield_order';
// protected $orderStep = 10;
// protected $tabs = array('Tabl 1','Tab 2'); // Use 'tab'=>0 OR 'tab'=>1 in the $fields below to enable.
-
+
// protected $listQry = "SELECT * FROM `#tableName` WHERE field != '' "; // Example Custom Query. LEFT JOINS allowed. Should be without any Order or Limit.
-
+
protected $listOrder = '';
-
+
protected $fields = array();
-
+
protected $fieldpref = array();
-
+
protected $preftabs = array(LAN_LOGIN, LAN_SOCIAL_ADMIN_14, LAN_SOCIAL_ADMIN_15, LAN_SOCIAL_ADMIN_16, LAN_SOCIAL_ADMIN_17, LAN_SOCIAL_ADMIN_37);
@@ -107,16 +107,25 @@ class social_ui extends e_admin_ui
);
protected $social_logins = array();
+ /**
+ * @var SocialLoginConfigManager
+ */
+ protected $social_login_config_manager;
protected $social_external = array();
public function init()
{
+ $this->social_login_config_manager = new SocialLoginConfigManager(e107::getConfig());
+
if(!empty($_POST['save_social']) )
{
$cfg = e107::getConfig();
- $cfg->setPref('social_login', $_POST['social_login']);
+ foreach ($_POST['social_login'] as $provider_name => $raw_updated_social_login)
+ {
+ $this->social_login_config_manager->setProviderConfig($provider_name, $raw_updated_social_login);
+ }
$cfg->setPref('social_login_active', $_POST['social_login_active']);
$cfg->setPref('xurl', $_POST['xurl']);
$cfg->save(true, true, true);
@@ -132,96 +141,6 @@ class social_ui extends e_admin_ui
{
$this->prefs['sharing_providers']['writeParms']['optArray'][$k] = $k;
}
- // print_a($bla);
-
-
-
-// Single/ Social Login / / copied from hybridAuth config.php so it's easy to add more.
-// Used Below.
-
- $this->social_logins = array (
- // openid providers
-
-
- "AOL" => array (
- "enabled" => true
- ),
-
- "Facebook" => array (
- "enabled" => true,
- "keys" => array ( "id" => "", "secret" => "" ),
- "trustForwarded" => false,
- // A comma-separated list of permissions you want to request from the user. See the Facebook docs for a full list of available permissions: http://developers.facebook.com/docs/reference/api/permissions.
- "scope" => "email",
-
- // The display context to show the authentication page. Options are: page, popup, iframe, touch and wap. Read the Facebook docs for more details: http://developers.facebook.com/docs/reference/dialogs#display. Default: page
- "display" => ""
- ),
-
- "Foursquare" => array (
- "enabled" => true,
- "keys" => array ( "id" => "", "secret" => "" )
- ),
-
- "Github" => array (
- "enabled" => true,
- "keys" => array ( "id" => "", "secret" => "" ),
- "scope" => "user:email",
- ),
-
- "Google" => array (
- "enabled" => true,
- "keys" => array ( "id" => "", "secret" => "" ),
- "scope" => "email"
- ),
-/*
- "Instagram" => array (
- "enabled" => true,
- "keys" => array ( "id" => "", "secret" => "" )
- ),*/
-
- "LinkedIn" => array (
- "enabled" => true,
- "keys" => array ( "id" => "", "secret" => "" )
- ),
-
- // windows live
- "Live" => array (
- "enabled" => true,
- "keys" => array ( "id" => "", "secret" => "" )
- ),
-
- /*
- "MySpace" => array (
- "enabled" => true,
- "keys" => array ( "key" => "", "secret" => "" )
- ),
- */
-
- "OpenID" => array (
- "enabled" => true
- ),
-
- "Steam" => array (
- "enabled" => true,
- "keys" => array ( "key" => "" )
- ),
-
- "Twitter" => array (
- "enabled" => true,
- "keys" => array ( "key" => "", "secret" => "" ),
- "includeEmail" => true,
- ),
-
-
- "Yahoo" => array (
- "enabled" => true,
- "keys" => array ( "id" => "", "secret" => "" ),
- ),
-
-
- );
-
$this->social_external = array(
"Facebook" => "https://developers.facebook.com/apps",
@@ -230,7 +149,7 @@ class social_ui extends e_admin_ui
"Live" => "https://manage.dev.live.com/ApplicationOverview.aspx",
"LinkedIn" => "https://www.linkedin.com/secure/developer",
"Foursquare" => "https://www.foursquare.com/oauth/",
- "Github" => "https://github.com/settings/applications/new",
+ "GitHub" => "https://github.com/settings/applications/new",
"Steam" => "http://steamcommunity.com/dev/apikey",
"Instagram" => "http://instagram.com/developer"
);
@@ -238,14 +157,14 @@ class social_ui extends e_admin_ui
}
-
+
// ------- Customize Create --------
-
- public function beforeCreate($new_data)
+
+ public function beforeCreate($new_data, $old_data)
{
return $new_data;
}
-
+
public function afterCreate($new_data, $old_data, $id)
{
// do something
@@ -253,12 +172,12 @@ class social_ui extends e_admin_ui
public function onCreateError($new_data, $old_data)
{
- // do something
- }
-
-
+ // do something
+ }
+
+
// ------- Customize Update --------
-
+
public function beforeUpdate($new_data, $old_data, $id)
{
return $new_data;
@@ -266,14 +185,14 @@ class social_ui extends e_admin_ui
public function afterUpdate($new_data, $old_data, $id)
{
- // do something
+ // do something
}
-
+
public function onUpdateError($new_data, $old_data, $id)
{
- // do something
- }
-
+ // do something
+ }
+
function renderHelp()
{
$this->testUrl = SITEURL."?route=system/xup/test";
@@ -288,18 +207,19 @@ class social_ui extends e_admin_ui
}
- // optional - a custom page.
+ // optional - a custom page.
public function configurePage()
{
$ns = e107::getRender();
$frm = e107::getForm();
$pref = e107::pref('core');
-
-
-
- // e107::getMessage()->addInfo($notice);
-
+ require_once("social_setup.php");
+ $social_setup = new social_setup();
+ if ($social_setup->upgrade_required())
+ {
+ return "" . LAN_SOCIAL_UPDATE_REQUIRED . "
";
+ }
$text = "
";
-
-
// -------------------------------
//
//
@@ -454,7 +283,7 @@ class social_ui extends e_admin_ui
'twitter' => array('label'=>"Twitter", "placeholder"=>"eg. https://twitter.com/e107"),
'youtube' => array('label'=>"Youtube", "placeholder"=>"eg.https://youtube.com/e107Inc"),
'linkedin' => array('label'=>"LinkedIn", "placeholder"=>"eg. http://www.linkedin.com/groups?home=&gid=1782682"),
- 'github' => array('label'=>"Github", "placeholder"=>"eg. https://github.com/e107inc"),
+ 'github' => array('label'=>"GitHub", "placeholder"=>"eg. https://github.com/e107inc"),
'flickr' => array('label'=>"Flickr", "placeholder"=>""),
'instagram' => array('label'=>"Instagram", "placeholder"=>""),
'pinterest' => array('label'=>"Pinterest", "placeholder"=>""),
@@ -506,17 +335,133 @@ class social_ui extends e_admin_ui
return $ret;
}
-
+ /**
+ * @param $text
+ * @param array $provider_names
+ * @return string
+ */
+ private function generateSocialLoginSection($section_name, $section_explanation, $provider_names)
+ {
+ if (empty($provider_names)) return "";
+
+ $text = "
+
+
+ $section_name
+ $section_explanation
+
+
+
+
+
+
+
+
+
+
+
+ " . LAN_SOCIAL_ADMIN_04 . " |
+ " . LAN_SOCIAL_ADMIN_AUTH_TYPE . " |
+ " . LAN_SOCIAL_ADMIN_05 . " |
+ " . LAN_SOCIAL_ADMIN_06 . " |
+ " . LAN_SOCIAL_ADMIN_38 . " |
+ " . LAN_SOCIAL_ADMIN_03 . " |
+
+
+ ";
+
+ foreach ($provider_names as $provider_name)
+ {
+ $text .= $this->generateSocialLoginRow($provider_name);
+ }
+
+ $text .= "
+ |
+
";
+
+ return $text;
+ }
+
+ /**
+ * @param $provider_name
+ * @return string Text to append
+ */
+ private function generateSocialLoginRow($provider_name)
+ {
+ $slcm = $this->social_login_config_manager;
+ $provider_type = $slcm->getTypeOfProvider($provider_name);
+ if (empty($provider_type)) $provider_type = "" . LAN_SOCIAL_ADMIN_AUTH_TYPE_UNKNOWN . "";
+
+ $normalized_provider_name = $slcm->normalizeProviderName($provider_name);
+ list($pretty_provider_name,) = array_pad(explode("-", $normalized_provider_name), 2, "");
+
+ $frm = e107::getForm();
+ $textKeys = '';
+ $textScope = '';
+ $label = varset($this->social_external[$provider_name]) ? "" . $pretty_provider_name . "" : $pretty_provider_name;
+ $radio_label = strtolower($provider_name);
+ $text = "
+
+ |
+ $provider_type |
+ ";
+
+ if ($provider_type == "OpenID")
+ {
+ $openid_identifier = $slcm->getProviderConfig($provider_name, '/openid_identifier');
+ $frm_options = ['size' => 'block-level'];
+ if (empty($openid_identifier))
+ {
+ try
+ {
+ $class = "\Hybridauth\Provider\\$provider_name";
+ $reflection = new ReflectionClass($class);
+ $properties = $reflection->getDefaultProperties();
+ $frm_options['placeholder'] = $properties['openidIdentifier'];
+ }
+ catch (Exception $e)
+ {
+ $openid_identifier = "";
+ }
+ }
+ $textKeys .= "" .
+ $frm->text("social_login[$provider_name][openid_identifier]", $openid_identifier, 256, $frm_options) .
+ " | | | ";
+ }
+ else
+ {
+ $textKeys .= "" . $frm->text("social_login[$provider_name][keys][id]", $slcm->getProviderConfig($provider_name, '/keys/id'), 128, ['size' => 'block-level']);
+ $textKeys .= " | " . $frm->text("social_login[$provider_name][keys][secret]", $slcm->getProviderConfig($provider_name, '/keys/secret'), 128, ['size' => 'block-level']);
+ if ($provider_type == "OAuth2" || $slcm->getProviderConfig($provider_name, '/scope'))
+ {
+ $textKeys .= " | " . $frm->text("social_login[$provider_name][scope]", $slcm->getProviderConfig($provider_name, '/scope'), 128, ['size' => 'block-level']);
+ }
+ else
+ {
+ $textKeys .= " | | ";
+ }
+ }
+
+ $textEnabled = $frm->radio_switch("social_login[$provider_name][enabled]", $slcm->isProviderEnabled($provider_name), '', '', ['class' => 'e-expandit']);
+
+ $text .= $textKeys . $textScope . "" . $textEnabled . " | ";
+
+ $text .= "
+
+ ";
+
+ return $text;
+ }
}
-
+
class social_form_ui extends e_admin_form_ui
{
-}
-
-
+}
+
+
new social_adminarea();
require_once(e_ADMIN."auth.php");
diff --git a/e107_plugins/social/languages/English/English_admin.php b/e107_plugins/social/languages/English/English_admin.php
index d20309ac5..eaee772cc 100644
--- a/e107_plugins/social/languages/English/English_admin.php
+++ b/e107_plugins/social/languages/English/English_admin.php
@@ -50,3 +50,28 @@ define("LAN_SOCIAL_ADMIN_39", "Providers");
define("LAN_SOCIAL_ADMIN_40", "Update User Display Name");
define("LAN_SOCIAL_ADMIN_41", "Update User Avatar");
define("LAN_SOCIAL_ADMIN_42", "Custom Image");
+define("LAN_SOCIAL_ADMIN_AUTH_TYPE", "Type");
+define("LAN_SOCIAL_ADMIN_AUTH_TYPE_UNKNOWN", "Unknown");
+
+define("LAN_SOCIAL_UPDATE_REQUIRED",
+ "A database update is required to continue using this plugin."
+);
+
+define("LAN_SOCIAL_LOGIN_SECTION_UNSUPPORTED", "Broken Configured Providers");
+define("LAN_SOCIAL_LOGIN_SECTION_CONFIGURED", "Manage Existing Providers");
+define("LAN_SOCIAL_LOGIN_SECTION_UNCONFIGURED", "Add New Providers");
+
+define("LAN_SOCIAL_LOGIN_SECTION_UNSUPPORTED_DESCRIPTION",
+ "These social login providers were configured in the past but no longer have an adapter that can support them. " .
+ "This may be due to them no longer existing or being replaced by a different provider."
+);
+define("LAN_SOCIAL_LOGIN_SECTION_CONFIGURED_DESCRIPTION",
+ "These social login providers are currently configured. " .
+ "If the master switch \"" . LAN_SOCIAL_ADMIN_02 . "\" is toggled on, each provider in this table that is " .
+ "also toggled on may be used for user registration and login. If you empty the fields of a provider here and save, " .
+ "it will move to the \"" . LAN_SOCIAL_LOGIN_SECTION_UNCONFIGURED . "\" section."
+);
+define("LAN_SOCIAL_LOGIN_SECTION_UNCONFIGURED_DESCRIPTION",
+ "These are the available social login providers, which have not been configured. " .
+ "Once you configure and save a provider here, it will move to the \"" . LAN_SOCIAL_LOGIN_SECTION_CONFIGURED . "\" section."
+);
\ No newline at end of file
diff --git a/e107_plugins/social/social_setup.php b/e107_plugins/social/social_setup.php
new file mode 100644
index 000000000..8e13b84aa
--- /dev/null
+++ b/e107_plugins/social/social_setup.php
@@ -0,0 +1,87 @@
+getPref(SocialLoginConfigManager::SOCIAL_LOGIN_PREF);
+ $normalizedProviderNames = array_keys($providerConfig);
+ foreach ($normalizedProviderNames as $normalizedProviderName)
+ {
+ $actualNormalizedProviderName =
+ $manager->normalizeProviderName($manager->denormalizeProviderName($normalizedProviderName));
+ if ($actualNormalizedProviderName !== $normalizedProviderName) return true;
+ }
+ return false;
+ }
+
+ public function upgrade_pre()
+ {
+ $coreConfig = e107::getConfig();
+ $logger = e107::getMessage();
+ $manager = new SocialLoginConfigManager($coreConfig);
+
+ $providerConfig = $coreConfig->getPref(SocialLoginConfigManager::SOCIAL_LOGIN_PREF);
+
+ foreach ($providerConfig as $oldNormalizedProviderName => $oldOptions)
+ {
+ $denormalizedProviderName = $manager->denormalizeProviderName($oldNormalizedProviderName);
+ $denormalizedProviderName = $this->upgradeDenormalizedProviderQuirks($denormalizedProviderName);
+ $actualNormalizedProviderName = $manager->normalizeProviderName($denormalizedProviderName);
+
+ $newOptions = $oldOptions;
+ if (isset($newOptions['keys']['key']))
+ {
+ $newOptions['keys']['id'] = $newOptions['keys']['key'];
+ unset($newOptions['keys']['key']);
+ }
+
+ if ($newOptions != $oldOptions)
+ {
+ $manager->setProviderConfig($denormalizedProviderName, $newOptions);
+ $logger->addSuccess(
+ "Updated configuration format of social login provider $denormalizedProviderName"
+ );
+ }
+
+ if ($actualNormalizedProviderName !== $oldNormalizedProviderName)
+ {
+ $manager->setProviderConfig($denormalizedProviderName, $newOptions);
+ $coreConfig->removePref(
+ SocialLoginConfigManager::SOCIAL_LOGIN_PREF . '/' . $oldNormalizedProviderName
+ );
+ $logger->addSuccess(
+ "Updated name of social login provider $oldNormalizedProviderName → $actualNormalizedProviderName"
+ );
+ }
+ }
+
+ $manager->saveProviderConfig();
+ }
+
+ private function upgradeDenormalizedProviderQuirks($denormalizedProviderName)
+ {
+ switch ($denormalizedProviderName)
+ {
+ case 'AOL':
+ $denormalizedProviderName = 'AOLOpenID';
+ break;
+ case 'Live':
+ $denormalizedProviderName = 'WindowsLive';
+ break;
+ }
+ return $denormalizedProviderName;
+ }
+}
\ No newline at end of file
diff --git a/e107_tests/tests/unit/e_user_providerTest.php b/e107_tests/tests/unit/e_user_providerTest.php
new file mode 100644
index 000000000..30392747b
--- /dev/null
+++ b/e107_tests/tests/unit/e_user_providerTest.php
@@ -0,0 +1,60 @@
+e_user_provider = $this->make('e_user_provider');
+ }
+ catch (Exception $e)
+ {
+ $this->fail("Couldn't load e_user_provider object: {$e}");
+ }
+ }
+
+ public function testGetSupportedProviders()
+ {
+ $result = e_user_provider::getSupportedProviders();
+ $this->assertIsArray($result);
+ $this->assertContains("Facebook", $result);
+ $this->assertContains("Twitter", $result);
+ $this->assertCount(42, $result,
+ "The number of Hybridauth providers has changed! If this is intentional, note the change " .
+ "in Hybridauth providers in the release changelog and update the count in this test."
+ );
+ }
+
+ public function testGetProviderType()
+ {
+ $result = e_user_provider::getTypeOf("NotARealProvider");
+ $this->assertFalse($result);
+
+ $result = e_user_provider::getTypeOf("Steam");
+ $this->assertEquals("OpenID", $result);
+
+ $result = e_user_provider::getTypeOf("StackExchangeOpenID");
+ $this->assertEquals("OpenID", $result);
+
+ $result = e_user_provider::getTypeOf("Twitter");
+ $this->assertEquals("OAuth1", $result);
+
+ $result = e_user_provider::getTypeOf("WordPress");
+ $this->assertEquals("OAuth2", $result);
+ }
+}
diff --git a/e107_tests/tests/unit/plugins/social/SocialLoginConfigManagerTest.php b/e107_tests/tests/unit/plugins/social/SocialLoginConfigManagerTest.php
new file mode 100644
index 000000000..3117c1983
--- /dev/null
+++ b/e107_tests/tests/unit/plugins/social/SocialLoginConfigManagerTest.php
@@ -0,0 +1,215 @@
+pref = $this->make('e_pref');
+ $this->pref->set('social_login', [
+ 'Twitter-OAuth1' => [
+ 'enabled' => true,
+ 'keys' => [
+ 'id' => 'ID',
+ 'secret' => 'SECRET',
+ ],
+ ],
+ 'StackExchange-OpenID' => [
+ 'enabled' => false,
+ ],
+ 'GitHub-OAuth2' => [
+ 'enabled' => true,
+ 'keys' => [
+ 'id' => 'ID',
+ 'secret' => 'SECRET',
+ ],
+ 'scope' => 'identity',
+ ],
+ 'OpenID' => [
+ 'enabled' => true,
+ ],
+ ]);
+ $this->manager = new SocialLoginConfigManager($this->pref);
+ }
+
+ public function testIsProviderEnabled()
+ {
+ $this->assertTrue($this->manager->isProviderEnabled('Twitter'));
+ $this->assertFalse($this->manager->isProviderEnabled('StackExchangeOpenID'));
+ $this->assertTrue($this->manager->isProviderEnabled('GitHub'));
+ $this->assertTrue($this->manager->isProviderEnabled('OpenID'));
+ }
+
+ public function testForgetProvider()
+ {
+ $this->manager->forgetProvider('OpenID');
+ $result = $this->manager->getConfiguredProviders();
+ $this->assertCount(3, $result);
+
+ $this->manager->forgetProvider('StackExchangeOpenID');
+ $result = $this->manager->getConfiguredProviders();
+ $this->assertCount(2, $result);
+
+ $this->manager->forgetProvider('FakeProvider');
+ $result = $this->manager->getConfiguredProviders();
+ $this->assertCount(2, $result);
+ }
+
+ public function testSetProviderConfig()
+ {
+ $this->manager->setProviderConfig('MyEnabledProvider', ['enabled' => true]);
+ $result = $this->manager->getConfiguredProviders();
+ $this->assertContains('MyEnabledProvider', $result);
+ $this->assertTrue($this->manager->isProviderEnabled('MyEnabledProvider'));
+
+ $this->manager->setProviderConfig('MyDisabledProvider', ['garbage' => 'nonsense']);
+ $result = $this->manager->getConfiguredProviders();
+ $this->assertContains('MyDisabledProvider', $result);
+ $this->assertFalse($this->manager->isProviderEnabled('MyDisabledProvider'));
+ }
+
+ public function testSetProviderConfigForgetsProviderIfEmpty()
+ {
+ $this->manager->setProviderConfig('EmptyProvider', [
+ 'enabled' => null,
+ 'keys' => [
+ 'id' => '',
+ 'secret' => 0,
+ ],
+ 'scope' => false,
+ ]);
+ $result = $this->manager->getConfiguredProviders();
+ $this->assertNotContains('EmptyProvider', $result);
+ }
+
+ public function testSetProviderConfigDiscardsEmptyOptions()
+ {
+ $this->manager->setProviderConfig('MiscProvider', [
+ 'enabled' => true,
+ 'openid_identifier' => '',
+ 'keys' => [
+ 'id' => null,
+ 'secret' => 0,
+ ],
+ 'scope' => false,
+ ]);
+ $result = $this->manager->getProviderConfig('MiscProvider');
+ $this->assertEquals(['enabled' => true], $result);
+ }
+
+ public function testGetProviderConfig()
+ {
+ $result = $this->manager->getProviderConfig('Twitter');
+ $this->assertTrue($result['enabled']);
+ $this->assertArrayHasKey('keys', $result);
+ $this->assertArrayNotHasKey('scope', $result);
+
+ $result = $this->manager->getProviderConfig('Twitter', 'keys/id');
+ $this->assertEquals('ID', $result);
+
+ $result = $this->manager->getProviderConfig('Twitter', '/keys/secret');
+ $this->assertEquals('SECRET', $result);
+
+ $result = $this->manager->getProviderConfig('Twitter', '/fake');
+ $this->assertNull($result);
+
+ $result = $this->manager->getProviderConfig('StackExchangeOpenID');
+ $this->assertFalse($result['enabled']);
+ $this->assertArrayNotHasKey('keys', $result);
+ $this->assertArrayNotHasKey('scope', $result);
+
+ $result = $this->manager->getProviderConfig('GitHub');
+ $this->assertEquals('identity', $result['scope']);
+ }
+
+ public function testGetConfiguredProviders()
+ {
+ $result = $this->manager->getConfiguredProviders();
+
+ $this->assertCount(4, $result);
+ $this->assertContains('Twitter', $result);
+ $this->assertContains('StackExchangeOpenID', $result);
+ $this->assertContains('GitHub', $result);
+ $this->assertContains('OpenID', $result);
+ }
+
+ public function testNormalizeProviderNameFixesCapitalization()
+ {
+ $output = $this->manager->normalizeProviderName("Github");
+ $this->assertEquals("GitHub-OAuth2", $output);
+ }
+
+ public function testNormalizeProviderNamePassesThroughUnknownName()
+ {
+ $output = $this->manager->normalizeProviderName("iPhone");
+ $this->assertEquals("iPhone", $output);
+ }
+
+ public function testNormalizeProviderNameRemovesTypeFromName()
+ {
+ $output = $this->manager->normalizeProviderName("StackExchangeOpenID");
+ $this->assertEquals("StackExchange-OpenID", $output);
+
+ $output = $this->manager->normalizeProviderName("aolOPENid");
+ $this->assertEquals("AOL-OpenID", $output);
+ }
+
+ public function testNormalizeProviderNameFindsCorrectType()
+ {
+ $output = $this->manager->normalizeProviderName("StackExchange");
+ $this->assertEquals("StackExchange-OAuth2", $output);
+
+ $output = $this->manager->normalizeProviderName("Telegram");
+ $this->assertEquals("Telegram", $output);
+ }
+
+ public function testNormalizeProviderNameGeneric()
+ {
+ $output = $this->manager->normalizeProviderName("openid");
+ $this->assertEquals("OpenID", $output);
+ }
+
+ public function testNormalizeProviderNameFakeGeneric()
+ {
+ $output = $this->manager->normalizeProviderName("OAuth2");
+ $this->assertEquals("OAuth2", $output);
+ }
+
+ public function testDenormalizeProviderName()
+ {
+ $output = $this->manager->denormalizeProviderName("OpenID");
+ $this->assertEquals("OpenID", $output);
+
+ $output = $this->manager->denormalizeProviderName("StackExchange-OAuth1");
+ $this->assertEquals("StackExchangeOAuth1", $output);
+
+ $output = $this->manager->denormalizeProviderName("StackExchange-OAuth2");
+ $this->assertEquals("StackExchange", $output);
+
+ $output = $this->manager->denormalizeProviderName("StackExchange-OpenID");
+ $this->assertEquals("StackExchangeOpenID", $output);
+ }
+}
\ No newline at end of file
diff --git a/e107_tests/tests/unit/plugins/social/social_setupTest.php b/e107_tests/tests/unit/plugins/social/social_setupTest.php
new file mode 100644
index 000000000..e06854d39
--- /dev/null
+++ b/e107_tests/tests/unit/plugins/social/social_setupTest.php
@@ -0,0 +1,127 @@
+set(SocialLoginConfigManager::SOCIAL_LOGIN_PREF, SOCIAL_LOGIN_LEGACY_DATA);
+ $social_setup = new social_setup();
+ $this->assertTrue($social_setup->upgrade_required());
+ $this->assertIsArray(e107::getConfig()->getPref(SocialLoginConfigManager::SOCIAL_LOGIN_PREF . "/AOL"));
+ $this->assertIsNotArray(e107::getConfig()->getPref(SocialLoginConfigManager::SOCIAL_LOGIN_PREF . "/AOL-OpenID"));
+
+ $social_setup->upgrade_pre();
+ $this->assertFalse($social_setup->upgrade_required());
+ $this->assertIsNotArray(e107::getConfig()->getPref(SocialLoginConfigManager::SOCIAL_LOGIN_PREF . "/AOL"));
+ $this->assertIsArray(e107::getConfig()->getPref(SocialLoginConfigManager::SOCIAL_LOGIN_PREF . "/AOL-OpenID"));
+ }
+}
+const SOCIAL_LOGIN_LEGACY_DATA =
+array(
+ 'FakeProviderNeverExisted' =>
+ array(
+ 'enabled' => '1',
+ ),
+ 'AOL' =>
+ array(
+ 'enabled' => '1',
+ ),
+ 'Facebook' =>
+ array(
+ 'keys' =>
+ array(
+ 'id' => 'a',
+ 'secret' => 'b',
+ ),
+ 'scope' => 'c',
+ 'enabled' => '1',
+ ),
+ 'Foursquare' =>
+ array(
+ 'keys' =>
+ array(
+ 'id' => 'a',
+ 'secret' => 'b',
+ ),
+ 'enabled' => '1',
+ ),
+ 'Github' =>
+ array(
+ 'keys' =>
+ array(
+ 'id' => 'a',
+ 'secret' => 'b',
+ ),
+ 'scope' => 'c',
+ 'enabled' => '1',
+ ),
+ 'Google' =>
+ array(
+ 'keys' =>
+ array(
+ 'id' => 'a',
+ 'secret' => 'b',
+ ),
+ 'scope' => 'c',
+ 'enabled' => '1',
+ ),
+ 'LinkedIn' =>
+ array(
+ 'keys' =>
+ array(
+ 'id' => 'a',
+ 'secret' => 'b',
+ ),
+ 'enabled' => '1',
+ ),
+ 'Live' =>
+ array(
+ 'keys' =>
+ array(
+ 'id' => 'a',
+ 'secret' => 'b',
+ ),
+ 'enabled' => '1',
+ ),
+ 'OpenID' =>
+ array(
+ 'enabled' => '1',
+ ),
+ 'Steam' =>
+ array(
+ 'keys' =>
+ array(
+ 'key' => 'a',
+ ),
+ 'enabled' => '1',
+ ),
+ 'Twitter' =>
+ array(
+ 'keys' =>
+ array(
+ 'key' => 'a',
+ 'secret' => 'b',
+ ),
+ 'enabled' => '1',
+ ),
+ 'Yahoo' =>
+ array(
+ 'keys' =>
+ array(
+ 'id' => 'a',
+ 'secret' => 'b',
+ ),
+ 'enabled' => '1',
+ ),
+);
\ No newline at end of file