diff --git a/app/Config/Aauth.php b/app/Config/Aauth.php
index 1bd3584..305bffc 100644
--- a/app/Config/Aauth.php
+++ b/app/Config/Aauth.php
@@ -292,6 +292,49 @@ class Aauth extends BaseConfig
public $captchaSiteKey = '';
public $captchaSecret = '';
+ /*
+ |--------------------------------------------------------------------------
+ | Social Login Variables
+ |--------------------------------------------------------------------------
+ |
+ | 'socialEnabled'
+ |
+ | Enables the oAuth2 functionalities to login or createUser trough social
+ | logins like google, facebook, twitter, github and many more.
+ | (default: false)
+ |
+ | 'socialRemeber'
+ |
+ | Remember social login user.
+ | Available Options:
+ | - false (disabled)
+ | - true (use social expires date)
+ | - Relative date format (e.g. '+ 1 week', '+ 1 month') for details
+ | see http://php.net/manual/de/datetime.formats.relative.php
+ | (default: true)
+ |
+ | 'socialProviders'
+ |
+ | Social Provider list
+ | (default: [])
+ |
+ */
+ public $socialEnabled = false;
+ public $socialRemember = true;
+ public $socialProviders = [];
+
+ // public $socialEnabled = true;
+ // public $socialRemember = true;
+ // public $socialProviders = [
+ // 'Facebook' => [
+ // 'enabled' => true,
+ // 'keys' => [
+ // 'id' => '307655649901891',
+ // 'secret' => 'fb814dea3a38d36aa66222efab35c337',
+ // ],
+ // ],
+ // ];
+
/*
|--------------------------------------------------------------------------
| Group Variables
diff --git a/app/Controllers/Account/Edit.php b/app/Controllers/Account/Edit.php
index 8287528..d24277a 100644
--- a/app/Controllers/Account/Edit.php
+++ b/app/Controllers/Account/Edit.php
@@ -85,6 +85,16 @@ class Edit extends Controller
}
}
+ if ($this->config->socialEnabled)
+ {
+ $data['providers'] = [];
+
+ foreach ($this->aauth->getProviders() as $provider)
+ {
+ $data['providers'][$provider] = $this->aauth->getSocialIdentifier($provider, $userId);
+ }
+ }
+
$data['useUsername'] = $this->config->loginUseUsername;
echo view('Account/Edit', $data);
diff --git a/app/Controllers/Account/Home.php b/app/Controllers/Account/Home.php
index 7ab1d27..7c3394e 100644
--- a/app/Controllers/Account/Home.php
+++ b/app/Controllers/Account/Home.php
@@ -53,6 +53,16 @@ class Home extends Controller
{
$data['user'] = $this->aauth->getUser();
+ if ($this->config->socialEnabled)
+ {
+ $data['providers'] = [];
+
+ foreach ($this->aauth->getProviders() as $provider)
+ {
+ $data['providers'][$provider] = $this->aauth->getSocialIdentifier($provider, $data['user']['id']);
+ }
+ }
+
echo view('Account/Home', $data);
}
}
diff --git a/app/Controllers/Account/Login.php b/app/Controllers/Account/Login.php
index b992074..3e8db26 100644
--- a/app/Controllers/Account/Login.php
+++ b/app/Controllers/Account/Login.php
@@ -71,6 +71,11 @@ class Login extends Controller
'/assets/css/login.css'
];
+ if ($this->config->socialEnabled)
+ {
+ $data['providers'] = $this->aauth->getProviders();
+ }
+
echo view('Account/Login', $data);
}
}
diff --git a/app/Controllers/Account/Register.php b/app/Controllers/Account/Register.php
index 06ef87b..9c63310 100644
--- a/app/Controllers/Account/Register.php
+++ b/app/Controllers/Account/Register.php
@@ -74,6 +74,11 @@ class Register extends Controller
'/assets/css/login.css'
];
+ if ($this->config->socialEnabled)
+ {
+ $data['providers'] = $this->aauth->getProviders();
+ }
+
echo view('Account/Register', $data);
}
}
diff --git a/app/Controllers/Account/Social.php b/app/Controllers/Account/Social.php
new file mode 100644
index 0000000..ef78e40
--- /dev/null
+++ b/app/Controllers/Account/Social.php
@@ -0,0 +1,170 @@
+config = new AauthConfig();
+ $this->aauth = new Aauth();
+ $this->request = Services::request();
+ helper('form');
+ }
+
+ /**
+ * Index
+ *
+ * @param string $provider Provider Name
+ *
+ * @return redirect
+ */
+ public function connect(string $provider = null)
+ {
+ if ($provider)
+ {
+ session()->setFlashdata('social_provider', $provider);
+ }
+ else
+ {
+ $provider = session('social_provider');
+ }
+
+ if ($userId = $this->aauth->getUserId())
+ {
+ if ($this->aauth->authenticateProvider($provider, 'account/social/connect/'))
+ {
+ if ($userId = $this->aauth->getUserId())
+ {
+ helper('text');
+ $userProfile = $this->aauth->getSocialDetails($provider);
+ $password = random_string('alnum', (config('Aauth')->passwordMin + 2));
+ $username = preg_replace('/[^A-Za-z0-9]/', '', $userProfile->displayName);
+
+ $this->aauth->linkSocial($userId, $provider);
+ }
+ }
+
+ return redirect()->to(site_url('/account'));
+ }
+
+ return redirect()->to('/');
+ }
+ /**
+ * Index
+ *
+ * @param string $provider Provider Name
+ *
+ * @return redirect
+ */
+ public function disconnect(string $provider)
+ {
+ if ($userId = $this->aauth->getUserId())
+ {
+ $this->aauth->unlinkSocial($userId, $provider);
+
+ return redirect()->to(site_url('/account'));
+ }
+
+ return redirect()->to('/');
+ }
+
+ /**
+ * Index
+ *
+ * @param string $provider Provider Name
+ *
+ * @return redirect
+ */
+ public function login(string $provider = null)
+ {
+ if ($provider)
+ {
+ session()->setFlashdata('social_provider', $provider);
+ }
+ else
+ {
+ $provider = session('social_provider');
+ }
+
+ if ($this->aauth->authenticateProvider($provider, 'account/social/login/'))
+ {
+ if ($this->aauth->loginSocial($provider))
+ {
+ return redirect()->to(site_url('/account'));
+ }
+ }
+
+ return redirect()->to(site_url('/account/login'))->with('errors', lang('Aauth.notFoundUser'));
+ }
+
+ /**
+ * Index
+ *
+ * @param string $provider Provider Name
+ *
+ * @return redirect
+ */
+ public function register(string $provider = null)
+ {
+ if ($provider)
+ {
+ session()->setFlashdata('social_provider', $provider);
+ }
+ else
+ {
+ $provider = session('social_provider');
+ }
+
+ if ($this->aauth->authenticateProvider($provider, 'account/social/register/'))
+ {
+ if (! $this->aauth->loginSocial($provider))
+ {
+ helper('text');
+ $userProfile = $this->aauth->getSocialDetails($provider);
+ $password = random_string('alnum', (config('Aauth')->passwordMin + 2));
+ $username = preg_replace('/[^A-Za-z0-9]/', '', $userProfile->displayName);
+
+ if ($userId = $this->aauth->createUser($userProfile->email, $password, $username))
+ {
+ $this->aauth->linkSocial($userId, $provider);
+ $this->aauth->loginSocial($provider);
+
+ return redirect()->to(site_url('/account'));
+ }
+
+ return redirect()->to(site_url('/account/register'))->with('errors', $this->aauth->printErrors('
', true));
+ }
+
+ return redirect()->to(site_url('/account'));
+ }
+ }
+}
diff --git a/app/Language/en/Account.php b/app/Language/en/Account.php
index c86098a..973dd3b 100644
--- a/app/Language/en/Account.php
+++ b/app/Language/en/Account.php
@@ -28,12 +28,15 @@ return [
'homeText' => 'Account Details',
'homeLabelUsername' => 'Username',
'homeLabelEmail' => 'Email address',
+ 'homeLabelSocial' => 'Connected Social Accounts',
'editHeader' => 'Edit Profile',
'editLabelUsername' => 'Username',
'editLabelEmail' => 'Email address',
'editLabelPassword' => 'Password',
'editLabelSubmit' => 'Save changes',
+ 'editLabelSocialConnect' => 'Connect with ',
+ 'editLabelSocialDisconnect' => 'Disconnect with ',
'linkBackToLogin' => 'Back to Login',
'linkLogin' => 'Login',
@@ -46,6 +49,7 @@ return [
'loginLabelPassword' => 'Password',
'loginLabelRemember' => 'Remember me',
'loginLabelSubmit' => 'Login',
+ 'loginLabelSocial' => 'Login with ',
'registerHeader' => 'Create new Account',
'registerLabelUsername' => 'Username',
@@ -53,6 +57,7 @@ return [
'registerLabelPassword' => 'Password',
'registerLabelRemember' => 'Remember me',
'registerLabelSubmit' => 'Create Account',
+ 'registerLabelSocial' => 'Create Account with ',
'registerRequired' => 'Required',
'verificationHeader' => 'Account Verification',
diff --git a/app/Libraries/Aauth.php b/app/Libraries/Aauth.php
index db76d14..463698d 100644
--- a/app/Libraries/Aauth.php
+++ b/app/Libraries/Aauth.php
@@ -131,6 +131,10 @@ class Aauth
if ($this->config->totpEnabled)
{
$this->modules = array_merge($this->config->modules, ['TOTP']);
+
+ if ($this->config->socialEnabled)
+ {
+ $this->modules = array_merge($this->modules, ['Social']);
}
$this->cachePermIds = [];
@@ -378,23 +382,7 @@ class Aauth
if ($remember)
{
- helper('text');
- $expire = $this->config->loginRemember;
- $userId = base64_encode($user['id']);
- $randomString = random_string('alnum', 32);
- $selectorString = random_string('alnum', 16);
-
- $cookieData['name'] = $this->config->loginRememberCookie;
- $cookieData['value'] = $userId . ';' . $randomString . ';' . $selectorString;
- $cookieData['expire'] = YEAR;
-
- $tokenData['user_id'] = $user['id'];
- $tokenData['random_hash'] = password_hash($randomString, PASSWORD_DEFAULT);
- $tokenData['selector_hash'] = password_hash($selectorString, PASSWORD_DEFAULT);
- $tokenData['expires_at'] = date('Y-m-d H:i:s', strtotime($expire));
-
- set_cookie($cookieData);
- $loginTokenModel->insert($tokenData);
+ $this->generateRemember($user['id']);
}
$userModel->updateLastLogin($user['id']);
@@ -428,6 +416,43 @@ class Aauth
}
}
+ /**
+ * Generate Remember
+ *
+ * @param integer $userId User Id
+ * @param string|integer $expire Expire Date, relative Date or Timestamp
+ *
+ * @return void
+ */
+ protected function generateRemember(int $userId, string $expire = null)
+ {
+ helper('cookie');
+ helper('text');
+
+ if (! $expire)
+ {
+ $expire = $this->config->loginRemember;
+ }
+
+ $userIdEncoded = base64_encode($userId);
+ $randomString = random_string('alnum', 32);
+ $selectorString = random_string('alnum', 16);
+
+ $cookieData['name'] = $this->config->loginRememberCookie;
+ $cookieData['value'] = $userIdEncoded . ';' . $randomString . ';' . $selectorString;
+ $cookieData['expire'] = YEAR;
+
+ \Config\Services::response()->setCookie($cookieData)->send();
+
+ $tokenData['user_id'] = $userId;
+ $tokenData['random_hash'] = password_hash($randomString, PASSWORD_DEFAULT);
+ $tokenData['selector_hash'] = password_hash($selectorString, PASSWORD_DEFAULT);
+ $tokenData['expires_at'] = date('Y-m-d H:i:s', strtotime($expire));
+
+ $loginTokenModel = $this->getModel('LoginToken');
+ $loginTokenModel->insert($tokenData);
+ }
+
/**
* Logout
*
@@ -515,6 +540,11 @@ class Aauth
{
$loginTokenModel->update($loginToken['id']);
+ if ($this->config->socialEnabled && $this->config->socialRemember)
+ {
+ $this->rebuildSocialStorage($loginToken['user_id']);
+ }
+
return $this->loginFast($loginToken['user_id']);
}
else
diff --git a/app/Libraries/Aauth/Social.php b/app/Libraries/Aauth/Social.php
new file mode 100644
index 0000000..d72c1ec
--- /dev/null
+++ b/app/Libraries/Aauth/Social.php
@@ -0,0 +1,286 @@
+configHybridAuth['providers'] = $config->socialProviders;
+ $this->configHybridAuth['callback'] = site_url();
+ }
+
+ /**
+ * Login Social
+ *
+ * @param string $provider Provider Name
+ *
+ * @return boolean|object
+ */
+ public function loginSocial(string $provider = null)
+ {
+ $userProfile = $this->getSocialDetails($provider);
+
+ if ($userId = $this->getSocialUserId($provider, $userProfile->identifier))
+ {
+ $session = service('session');
+ $storage = $session->get($this->storageHybridAuth);
+
+ $this->updateSocialProviderIdentifier($userId, 'storage', json_encode($storage));
+
+ if ($this->config->socialRemember)
+ {
+ $expires = $this->config->socialRemember;
+
+ if ($expires === true)
+ {
+ $expires = $storage[strtolower($provider) . '.expires_at'];
+ }
+
+ $this->generateRemember($userId, $expires);
+ }
+ return $this->loginFast($userId);
+ }
+
+ return false;
+ }
+
+ /**
+ * Link Social
+ *
+ * @param integer $userId User Id
+ * @param string $provider Provider Name
+ *
+ * @return boolean
+ */
+ public function linkSocial(int $userId, string $provider)
+ {
+ $userProfile = $this->getSocialDetails($provider);
+ $this->updateSocialStorage($userId);
+
+ return $this->updateSocialProviderIdentifier($userId, $provider, $userProfile->identifier);
+ }
+
+ /**
+ * Unlink Social
+ *
+ * @param integer $userId User Id
+ * @param string $provider Provider Name
+ *
+ * @return boolean
+ */
+ public function unlinkSocial(int $userId, string $provider)
+ {
+ $session = service('session');
+ $session->remove($this->storageHybridAuth);
+
+ $userVariableModel = $this->getModel('UserVariable');
+ $userVariableModel->delete($userId, 'social_storage', true);
+
+ return $userVariableModel->delete($userId, 'social_' . strtolower($provider), true);
+ }
+
+ /**
+ * Rebuild Social Storage
+ *
+ * @param integer $userId User Id
+ *
+ * @return void
+ */
+ public function rebuildSocialStorage(int $userId)
+ {
+ $userVariableModel = $this->getModel('UserVariable');
+ $providers = $this->getProviders();
+
+ if ($storedData = $userVariableModel->find($userId, 'social_storage', true))
+ {
+ $storedData = json_decode($storedData, true);
+
+ foreach ($providers as $provider)
+ {
+ if ($storedData[strtolower($provider) . '.expires_at'] > time())
+ {
+ $session = service('session');
+ $session->set($this->storageHybridAuth, $storedData);
+ }
+ }
+ }
+ }
+
+ /**
+ * Get Social User Id
+ *
+ * @param string $provider Provider Name
+ * @param string $identifier Identifier
+ *
+ * @return integer|boolean
+ */
+ public function getSocialUserId(string $provider, string $identifier)
+ {
+ $userVariableModel = $this->getModel('UserVariable');
+ $whereArray = [
+ 'data_key' => 'social_' . strtolower($provider),
+ 'data_value' => $identifier,
+ 'system' => 1,
+ ];
+
+ if ($user = $userVariableModel->select('user_id')->where($whereArray)->first())
+ {
+ return (int) $user['user_id'];
+ }
+
+ return false;
+ }
+
+ /**
+ * Get Social Identifier
+ *
+ * @param string $provider Provider Name
+ * @param integer $userId User Id
+ *
+ * @return integer|boolean
+ */
+ public function getSocialIdentifier(string $provider, int $userId)
+ {
+ $userVariableModel = $this->getModel('UserVariable');
+ $whereArray = [
+ 'data_key' => 'social_' . strtolower($provider),
+ 'user_id' => $userId,
+ 'system' => 1,
+ ];
+
+ if ($user = $userVariableModel->select('data_value')->where($whereArray)->first())
+ {
+ return $user['data_value'];
+ }
+
+ return false;
+ }
+
+ /**
+ * Get Social Details
+ *
+ * @param string $provider Provider Name
+ *
+ * @return \Hybridauth\User\Profile
+ */
+ public function getSocialDetails(string $provider)
+ {
+ $hybridauth = new \Hybridauth\Hybridauth($this->configHybridAuth);
+
+ $adapter = $hybridauth->getAdapter($provider);
+
+ return $adapter->getUserProfile();
+ }
+
+ /**
+ * Get Providers
+ *
+ * @return array
+ */
+ public function getProviders()
+ {
+ $hybridauth = new \Hybridauth\Hybridauth($this->configHybridAuth);
+
+ return $hybridauth->getProviders();
+ }
+
+ /**
+ * Authenticate Provider
+ *
+ * @param string $provider Provider Name
+ * @param string $callbackUrl Callback Link
+ *
+ * @return \Hybridauth\Adapter\AdapterInterface
+ */
+ public function authenticateProvider(string $provider, string $callbackUrl)
+ {
+ $this->configHybridAuth['callback'] = site_url($callbackUrl);
+
+ $hybridauth = new \Hybridauth\Hybridauth($this->configHybridAuth);
+ $adapter = $hybridauth->authenticate($provider);
+
+ return $adapter;
+ }
+
+ /**
+ * Update Social Storage
+ *
+ * @param integer $userId User Id
+ *
+ * @return void
+ */
+ private function updateSocialStorage(int $userId)
+ {
+ $session = service('session');
+ $storage = $session->get($this->storageHybridAuth);
+
+ $this->updateSocialProviderIdentifier($userId, 'storage', json_encode($storage));
+ }
+
+ /**
+ * Update Social Provider Identifier
+ *
+ * @param integer $userId User Id
+ * @param string $provider Provider Name
+ * @param string $identifier Identifier
+ *
+ * @return boolean
+ */
+ private function updateSocialProviderIdentifier(int $userId, string $provider, string $identifier)
+ {
+ $userVariableModel = $this->getModel('UserVariable');
+
+ return $userVariableModel->save($userId, 'social_' . strtolower($provider), $identifier, true);
+ }
+}
diff --git a/app/Views/Account/Edit.php b/app/Views/Account/Edit.php
index 590c3a0..b85100b 100644
--- a/app/Views/Account/Edit.php
+++ b/app/Views/Account/Edit.php
@@ -31,6 +31,16 @@
= form_close() ?>
+
+