From 4c100d23b3dca108c402797a09a24c3837f8f09e Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 10 Jun 2018 10:01:59 +0200 Subject: [PATCH 01/12] app/models/Data/User.php: adding getSocialLinks() --- app/models/Data/User.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/models/Data/User.php b/app/models/Data/User.php index 82c438e..a01d346 100644 --- a/app/models/Data/User.php +++ b/app/models/Data/User.php @@ -247,6 +247,17 @@ class User extends Model return $this; } + public function getSocialLinks() + { + $providers = [ + 'github' => $this->getGithubId(), + 'gitlab' => $this->getGitlabId(), + 'google' => $this->getGoogleId() + ]; + + return array_filter($providers); + } + static public function createFromOAuthData(UserDataInterface $data) { $oauth_id = 'set' . $data->getProvider() . 'Id'; From 0db9f91a3e413d29a5fc70b27acfa5c157dec190 Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 10 Jun 2018 10:24:20 +0200 Subject: [PATCH 02/12] app/config/services.php: adding routes for oauth connect/disconnect --- app/config/services.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/config/services.php b/app/config/services.php index 85a2866..b418abd 100644 --- a/app/config/services.php +++ b/app/config/services.php @@ -126,6 +126,10 @@ $di->setShared('router', function() { 'action' => 'oauth' ))->setName('oauth'); + $router->add('/oauth/{provider:([a-z]+)}/connect', 'User::oauthConnect')->setName('oauth-connect'); + $router->add('/oauth/{provider:([a-z]+)}/disconnect', 'User::oauthdisconnect')->setName('oauth-disconnect'); + $router->add('/oauth/{provider:([a-z]+)}/disconnect/{confirm}', 'User::oauthdisconnect')->setName('oauth-disconnect-confirm'); + $router->add('/settings', array( 'controller' => 'user', 'action' => 'settings', From 9ded2f36ad027533f6f9a6c3c7d85f33ac1a65d1 Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 10 Jun 2018 10:24:45 +0200 Subject: [PATCH 03/12] app/views/user/settings.volt: adding social sign-in section --- app/controllers/UserController.php | 1 + app/views/user/settings.volt | 41 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/app/controllers/UserController.php b/app/controllers/UserController.php index 0d038d3..f0c1ba9 100644 --- a/app/controllers/UserController.php +++ b/app/controllers/UserController.php @@ -33,6 +33,7 @@ class UserController extends ControllerBase } } + $this->view->user = $user; $this->view->form = $form; } diff --git a/app/views/user/settings.volt b/app/views/user/settings.volt index e5e74e4..6d7a9a9 100644 --- a/app/views/user/settings.volt +++ b/app/views/user/settings.volt @@ -37,9 +37,50 @@
+
+ +

Social sign-in

+ +
+ +
+
{{ icon('brand/github', [ '3x' ]) }}
+ {% if user.getGithubId() > 0 %} + Disconnect + {% else %} + Connect + {% endif %} +
+ +
+
{{ icon('brand/gitlab', [ '3x' ]) }}
+ {% if user.getGitlabId() > 0 %} + Disconnect + {% else %} + Connect + {% endif %} +
+ +
+
{{ icon('brand/google', [ '3x' ]) }}
+ {% if user.getGoogleId() > 0 %} + Connect + {% else %} + Connect + {% endif %} + +
+ +
+
+ +
+
+
{{ form.render('Save') }}
+ From 29e42c7641e30b29e393939de5d822996a68d6b9 Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 10 Jun 2018 20:13:18 +0200 Subject: [PATCH 04/12] app/controllers/UserController.php: adding oauthDisconnectAction() --- app/controllers/UserController.php | 44 ++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/app/controllers/UserController.php b/app/controllers/UserController.php index f0c1ba9..8177a9a 100644 --- a/app/controllers/UserController.php +++ b/app/controllers/UserController.php @@ -46,4 +46,48 @@ class UserController extends ControllerBase $this->view->page = $paginator->getPaginate(); $this->view->pagination_url = '/user/activity/'; } + + public function oauthDisconnectAction($provider, $last_unlink_confirmed = false) + { + $user = $this->_getAuth()->getUser(); + + // Check if we are unlinking the last provider + if (count($user->getSocialLinks()) <= 1) { + + // If user does not have a password, we wont allow it. + if (strlen($user->getPassword()) < 1) { + $msg = 'Unlinking your last OAuth provider cannot be done ' + . 'if you don\'t have a password as it would be impossible for you to log in.'; + + $this->flash->message('error', $msg); + $this->response->redirect('/settings'); + return; + } + + // Give a warning to the user about password as the only login option. + if ($last_unlink_confirmed == false) { + + $url = $this->url->get([ + 'for' => 'oauth-disconnect-confirm', + 'provider' => $provider, + 'confirm' => 'confirm', + ]); + + $msg = '

You are about to unlink the last OAuth provider.' + . ' Your only login option will be password if you do this.

' + . '

Are you sure? Yes

'; + + $this->flash->message('warning', $msg); + $this->response->redirect('/settings'); + return; + } + } + + $user->{'set' . $provider . 'Id'}(null); + $user->save(); + + $this->flash->message('success', "

{$provider} was disconnected

"); + + $this->response->redirect('/settings'); + } } From adb98241c714f0c7aa9c6776dceb74c5957d364b Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 10 Jun 2018 20:54:02 +0200 Subject: [PATCH 05/12] app/controllers/AuthController.php: in oauthAction() if we have an authed user then we should connect accounts. --- app/controllers/AuthController.php | 40 ++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/app/controllers/AuthController.php b/app/controllers/AuthController.php index 08331e7..fb16ab2 100644 --- a/app/controllers/AuthController.php +++ b/app/controllers/AuthController.php @@ -54,22 +54,40 @@ class AuthController extends ControllerBase // NOTE: Should pass $state here also. $data = $client->authenticate($code); - $result = $this->auth->loginOauth($data); + // If user is authed already, we connect. + $user = $this->auth->getUser(); + if ($user) { - // There was an error when creating the account - if (is_array($result)) { - $msg = ''; - foreach($result as $message) { - $msg .= '
  • ' . $message->getMessage() . '
  • '; + $name = ucfirst($provider_name); + $user->{'set' . $name . 'Id'}($data->getId()); + $user->save(); + + $this->flash->message('success', "{$name} was connected!"); + $this->response->redirect('/settings'); + } + // Perform Auth. + else { + $result = $this->auth->loginOauth($data); + + // There was an error when creating the account + if (is_array($result)) { + $msg = ''; + foreach ($result as $message) { + $msg .= '
  • ' . $message->getMessage() . '
  • '; + } + $this->flash->message('error', "Failed to create account:
      {$msg}
    "); + $this->response->redirect('/login'); + } else { + $this->response->redirect('/'); } - $this->flash->message('error', "Failed to create account:
      {$msg}
    "); - $this->response->redirect('/login'); - } else { - $this->response->redirect('/'); } } catch(\Exception $e) { $this->flash->message('error', 'Failed to authenticate.'); - $this->response->redirect('/login'); + if ($this->auth->getUser()) { + $this->response->redirect('/settings'); + } else { + $this->response->redirect('/login'); + } } } // No code From 95190aa7ab02583176ece62c7d723028004878ef Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 10 Jun 2018 20:54:35 +0200 Subject: [PATCH 06/12] app/views/user/settings.volt: link to the right place for oauth connect. --- app/views/user/settings.volt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/user/settings.volt b/app/views/user/settings.volt index 6d7a9a9..2c0123d 100644 --- a/app/views/user/settings.volt +++ b/app/views/user/settings.volt @@ -49,16 +49,16 @@ {% if user.getGithubId() > 0 %} Disconnect {% else %} - Connect + Connect {% endif %}
    {{ icon('brand/gitlab', [ '3x' ]) }}
    {% if user.getGitlabId() > 0 %} - Disconnect + Disconnect {% else %} - Connect + Connect {% endif %}
    @@ -67,7 +67,7 @@ {% if user.getGoogleId() > 0 %} Connect {% else %} - Connect + Connect {% endif %} From b29350277440e0c4c4fc5fc520b279bedc9cff87 Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 10 Jun 2018 20:54:49 +0200 Subject: [PATCH 07/12] app/config/services.php: remove unused route. --- app/config/services.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/config/services.php b/app/config/services.php index b418abd..c8499ef 100644 --- a/app/config/services.php +++ b/app/config/services.php @@ -126,7 +126,6 @@ $di->setShared('router', function() { 'action' => 'oauth' ))->setName('oauth'); - $router->add('/oauth/{provider:([a-z]+)}/connect', 'User::oauthConnect')->setName('oauth-connect'); $router->add('/oauth/{provider:([a-z]+)}/disconnect', 'User::oauthdisconnect')->setName('oauth-disconnect'); $router->add('/oauth/{provider:([a-z]+)}/disconnect/{confirm}', 'User::oauthdisconnect')->setName('oauth-disconnect-confirm'); From c270bfab0e045f4b9d43e34f2b4cc7f673b6daf4 Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 10 Jun 2018 22:39:47 +0200 Subject: [PATCH 08/12] app/listeners/ActivityLog.php: adding onOAuthConnected() event handler. --- app/listeners/ActivityLog.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/listeners/ActivityLog.php b/app/listeners/ActivityLog.php index 2b62892..f1b118b 100644 --- a/app/listeners/ActivityLog.php +++ b/app/listeners/ActivityLog.php @@ -6,6 +6,7 @@ use Phalcon\Mvc\User\Plugin, Phalcon\Events\Event, App\Model\Data\User, App\Model\Data\ActivityLog as ActivityLogger, + Httpcb\OAuth\UserData\UserDataInterface as OAuthUserDataInterface, Httpcb\Auth; class ActivityLog extends Plugin @@ -45,6 +46,20 @@ class ActivityLog extends Plugin $this->_log($user, "Changed password"); } + /** + * Fired when a user is connected to a OAuth provider. + * + * @param Event $event + * @param User $user + * @param OAuthUserDataInterface $provider + */ + public function onOAuthConnected(Event $event, User $user, OAuthUserDataInterface $provider) + { + $name = $provider->getProvider(); + + $this->_log($user, "OAuth connected ({$name})"); + } + protected function _log(User $user, $message) { $ip = (new \Phalcon\Http\Request())->getClientAddress(); From 4d073468ca4264aae53895f331e3e2ad2f718cc4 Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 10 Jun 2018 22:40:07 +0200 Subject: [PATCH 09/12] app/controllers/AuthController.php: fire onOAuthConnected event. --- app/controllers/AuthController.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/controllers/AuthController.php b/app/controllers/AuthController.php index fb16ab2..08ff5d8 100644 --- a/app/controllers/AuthController.php +++ b/app/controllers/AuthController.php @@ -8,6 +8,13 @@ use App\Form\Login as LoginForm; class AuthController extends ControllerBase { + public function initialize() + { + // We need event manager here from DI. + $eventManager = $this->di->get('eventsManager'); + $this->setEventsManager($eventManager); + } + public function indexAction() { $form = new LoginForm(); @@ -62,6 +69,8 @@ class AuthController extends ControllerBase $user->{'set' . $name . 'Id'}($data->getId()); $user->save(); + $this->getEventsManager()->fire('user:onOAuthConnected', $user, $data); + $this->flash->message('success', "{$name} was connected!"); $this->response->redirect('/settings'); } From 3172f8d4b1c8a6fab756ba93960418142ea524f5 Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 10 Jun 2018 22:42:03 +0200 Subject: [PATCH 10/12] app/controllers/UserController.php: fix provider name. --- app/controllers/UserController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/UserController.php b/app/controllers/UserController.php index 8177a9a..b6e63ef 100644 --- a/app/controllers/UserController.php +++ b/app/controllers/UserController.php @@ -83,6 +83,7 @@ class UserController extends ControllerBase } } + $provider = ucfirst($provider); $user->{'set' . $provider . 'Id'}(null); $user->save(); From f8018c6f7381a19a55a474e68f8a413613c77dd1 Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 10 Jun 2018 22:51:57 +0200 Subject: [PATCH 11/12] app/listeners/ActivityLog.php: adding onOAuthDisconnect() --- app/listeners/ActivityLog.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/listeners/ActivityLog.php b/app/listeners/ActivityLog.php index f1b118b..6202aa4 100644 --- a/app/listeners/ActivityLog.php +++ b/app/listeners/ActivityLog.php @@ -60,6 +60,18 @@ class ActivityLog extends Plugin $this->_log($user, "OAuth connected ({$name})"); } + /** + * Fired when a user is connected to a OAuth provider. + * + * @param Event $event + * @param User $user + * @param string $providerName + */ + public function onOAuthDisconnect(Event $event, User $user, $providerName) + { + $this->_log($user, "OAuth disconnected ({$providerName})"); + } + protected function _log(User $user, $message) { $ip = (new \Phalcon\Http\Request())->getClientAddress(); From b92575202168b9bb1ebf459e4c28cbe31408527e Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 10 Jun 2018 22:52:14 +0200 Subject: [PATCH 12/12] app/controllers/UserController.php: fire onOAuthDisconnect() event. --- app/controllers/UserController.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/controllers/UserController.php b/app/controllers/UserController.php index b6e63ef..e9c5782 100644 --- a/app/controllers/UserController.php +++ b/app/controllers/UserController.php @@ -8,6 +8,13 @@ use App\Controller\ControllerBase, class UserController extends ControllerBase { + public function initialize() + { + // We need event manager here from DI. + $eventManager = $this->di->get('eventsManager'); + $this->setEventsManager($eventManager); + } + public function settingsAction() { $user = $this->_getAuth()->getUser(); @@ -87,6 +94,8 @@ class UserController extends ControllerBase $user->{'set' . $provider . 'Id'}(null); $user->save(); + $this->getEventsManager()->fire('user:onOAuthDisconnect', $user, $provider); + $this->flash->message('success', "

    {$provider} was disconnected

    "); $this->response->redirect('/settings');