Social Login Feature

WIP

Depends-On: https://review.opendev.org/c/osf/openstackid/+/772531
Change-Id: I86cef9379fcd6ca5320f080e062fc2abaa36203c
This commit is contained in:
smarcet@gmail.com 2021-05-13 15:55:33 -03:00
parent 85c1a90bc4
commit 4addff2c60
23 changed files with 794 additions and 31 deletions

View File

@ -79,4 +79,9 @@ RABBITMQ_SSL=true
RABBITMQ_SSL_CAFILE=/certs/rabbit/ca-osf.pem
RABBITMQ_SSL_LOCALCERT=/certs/rabbit/client-cert-osf.pem
RABBITMQ_SSL_LOCALKEY=/certs/rabbit/client-key-osf.pem
RABBITMQ_SSL_VERIFY_PEER=false
RABBITMQ_SSL_VERIFY_PEER=false
# 3rd party idps
FACEBOOK_CLIENT_ID=
FACEBOOK_CLIENT_SECRET=
FACEBOOK_REDIRECT_URI=/login/facebook/callback

View File

@ -25,7 +25,6 @@ use OAuth2\Factories\OAuth2AuthorizationRequestFactory;
use OAuth2\OAuth2Message;
use OAuth2\Repositories\IClientRepository;
use OAuth2\Services\IMementoOAuth2SerializerService;
use Sokil\IsoCodes\IsoCodesFactory;
use Exception;
/**
* Class RegisterController

View File

@ -0,0 +1,128 @@
<?php namespace App\Http\Controllers;
/**
* Copyright 2021 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\Services\Auth\IUserService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session;
use Laravel\Socialite\Facades\Socialite;
use models\exceptions\ValidationException;
use Strategies\ILoginStrategy;
use Strategies\ILoginStrategyFactory;
use Utils\Services\IAuthService;
/**
* Class SocialLoginController
* @package App\Http\Controllers
*/
final class SocialLoginController extends Controller
{
/**
* @var IAuthService
*/
private $auth_service;
/**
* @var IUserService
*/
private $user_service;
/**
* @var ILoginStrategy
*/
private $login_strategy;
const ValidProviders = [
'google',
'facebook',
'microsoft',
'apple',
];
/**
* SocialLoginController constructor.
* @param IAuthService $auth_service
* @param IUserService $user_service
* @param ILoginStrategyFactory $login_strategy_factory
*/
public function __construct(
IAuthService $auth_service,
IUserService $user_service,
ILoginStrategyFactory $login_strategy_factory
){
$this->auth_service = $auth_service;
$this->user_service = $user_service;
$this->middleware(function ($request, $next) use($login_strategy_factory){
// we do it here just to ensure that user session is loaded
Log::debug(sprintf("SocialLoginController::middleware"));
$this->login_strategy = $login_strategy_factory->build();
return $next($request);
});
}
/**
* @param $provider
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Symfony\Component\HttpFoundation\RedirectResponse
*/
public function redirect($provider)
{
try {
$memento = Session::has('oauth2.request.state');
if(!in_array($provider, self::ValidProviders))
throw new ValidationException(sprintf("Provider %s is not supported.", $provider));
return Socialite::driver($provider)->redirect();
}
catch (\Exception $ex){
Log::error($ex);
}
return view("auth.register_error");
}
/**
* @param $provider
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|mixed
*/
public function callback($provider)
{
try {
// validate provier
if(!in_array($provider, self::ValidProviders))
throw new ValidationException(sprintf("Provider %s is not supported.", $provider));
$social_user = Socialite::driver($provider)->user();
// try to get user by primary email from our db
$user = $this->auth_service->getUserByUsername($social_user->getEmail());
if (is_null($user)) {
// if does not exists , registered it with email verified and active
$user = $this->user_service->registerUser([
'email' => $social_user->getEmail(),
'full_name' => $social_user->getName(),
'external_pic' => $social_user->getAvatar(),
'external_id' => $social_user->getId(),
'email_verified' => true,
'active' => true,
'external_provider' => $provider
]);
}
// do login
Auth::login($user, true);
// and continue the usual flow
return $this->login_strategy->postLogin([ 'provider'=> $provider ]);
}
catch (\Exception $ex){
Log::error($ex);
}
return view("auth.register_error");
}
}

View File

@ -50,6 +50,11 @@ final class EventServiceProvider extends ServiceProvider
protected $listen = [
'Illuminate\Database\Events\QueryExecuted' => [
],
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
// ... other providers
'SocialiteProviders\\Facebook\\FacebookExtendSocialite@handle',
'SocialiteProviders\\Google\\GoogleExtendSocialite@handle',
],
];
/**

View File

@ -48,11 +48,20 @@ class DefaultLoginStrategy implements ILoginStrategy
return Redirect::action("UserController@getProfile");
}
public function postLogin()
public function postLogin(array $params = [])
{
$user = $this->auth_service->getCurrentUser();
$identifier = $user->getIdentifier();
$this->user_action_service->addUserAction($this->auth_service->getCurrentUser()->getId(), IPHelper::getUserIp(), IUserActionService::LoginAction);
$realm = "From Site";
if(isset($params['provider']))
$realm .= " using ".strtoupper($params['provider']);
$this->user_action_service->addUserAction
(
$this->auth_service->getCurrentUser()->getId(),
IPHelper::getUserIp(),
IUserActionService::LoginAction,
$realm
);
$default_url = URL::action("UserController@getIdentity", array("identifier" => $identifier));
return Redirect::intended($default_url);
}

View File

@ -11,9 +11,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Redirect;
/**
* Class DisplayResponseUserAgentStrategy
* @package Strategies
@ -36,6 +38,10 @@ class DisplayResponseUserAgentStrategy implements IDisplayResponseStrategy
*/
public function getLoginResponse(array $data = [])
{
$provider = $data["provider"]??null;
if(!empty($provider)) {
return redirect()->route('social_login', ['provider' => $provider]);
}
return Response::view("auth.login", $data, 200);
}

View File

@ -11,9 +11,10 @@ interface ILoginStrategy
public function getLogin();
/**
* @param array $params
* @return mixed
*/
public function postLogin();
public function postLogin(array $params = []);
/**
* @return mixed

View File

@ -0,0 +1,23 @@
<?php namespace Strategies;
/**
* Copyright 2015 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use Strategies\ILoginStrategy;
/**
* Interface ILoginStrategyFactory
* @package Strategies
*/
interface ILoginStrategyFactory
{
public function build():ILoginStrategy;
}

View File

@ -0,0 +1,112 @@
<?php namespace Strategies;
/**
* Copyright 2015 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\Services\Auth\IUserService;
use Illuminate\Support\Facades\Log;
use OAuth2\Services\IMementoOAuth2SerializerService;
use OAuth2\Services\ISecurityContextService;
use OpenId\Services\IMementoOpenIdSerializerService;
use Services\IUserActionService;
use Utils\Services\IAuthService;
/**
* Class LoginStrategyFactory
* @package Strategies
*/
final class LoginStrategyFactory implements ILoginStrategyFactory
{
/**
* @var IMementoOpenIdSerializerService
*/
private $openid_memento_service;
/**
* @var IMementoOAuth2SerializerService
*/
private $oauth2_memento_service;
/**
* @var IAuthService
*/
private $auth_service;
/**
* @var IUserService
*/
private $user_service;
/**
* @var IUserActionService
*/
private $user_action_service;
/**
* @var ISecurityContextService
*/
private $security_context_service;
/**
* LoginStrategyFactory constructor.
* @param IMementoOpenIdSerializerService $openid_memento_service
* @param IMementoOAuth2SerializerService $oauth2_memento_service
* @param IAuthService $auth_service
* @param IUserService $user_service
* @param IUserActionService $user_action_service
* @param ISecurityContextService $security_context_service
*/
public function __construct
(
IMementoOpenIdSerializerService $openid_memento_service,
IMementoOAuth2SerializerService $oauth2_memento_service,
IAuthService $auth_service,
IUserService $user_service,
IUserActionService $user_action_service,
ISecurityContextService $security_context_service)
{
$this->openid_memento_service = $openid_memento_service;
$this->oauth2_memento_service = $oauth2_memento_service;
$this->auth_service = $auth_service;
$this->user_service = $user_service;
$this->user_action_service = $user_action_service;
$this->security_context_service = $security_context_service;
}
public function build():ILoginStrategy{
$res = null;
Log::debug(sprintf("LoginStrategyFactory::build"));
if ($this->openid_memento_service->exists())
{
//openid stuff
Log::debug(sprintf("LoginStrategyFactory::build OIDC"));
return new OpenIdLoginStrategy
(
$this->openid_memento_service,
$this->user_action_service,
$this->auth_service
);
}
else if ($this->oauth2_memento_service->exists())
{
Log::debug(sprintf("LoginStrategyFactory::build OAUTH2"));
return new OAuth2LoginStrategy
(
$this->auth_service,
$this->oauth2_memento_service,
$this->user_action_service,
$this->security_context_service
);
}
//default stuff
Log::debug(sprintf("LoginStrategyFactory::build DEFAULT"));
return new DefaultLoginStrategy($this->user_action_service, $this->auth_service);
}
}

View File

@ -76,10 +76,12 @@ class OAuth2LoginStrategy extends DefaultLoginStrategy
$response_strategy = DisplayResponseStrategyFactory::build($auth_request->getDisplay());
return $response_strategy->getLoginResponse();
return $response_strategy->getLoginResponse([
'provider' => $auth_request->getProvider()
]);
}
public function postLogin()
public function postLogin(array $params = [])
{
$auth_request = OAuth2AuthorizationRequestFactory::getInstance()->build(
OAuth2Message::buildFromMemento(
@ -87,8 +89,12 @@ class OAuth2LoginStrategy extends DefaultLoginStrategy
)
);
$realm = "From ".$auth_request->getRedirectUri();
if(isset($params['provider']))
$realm .= " using ".strtoupper($params['provider']);
$this->user_action_service->addUserAction($this->auth_service->getCurrentUser()->getId(), IPHelper::getUserIp(),
IUserActionService::LoginAction, $auth_request->getRedirectUri());
IUserActionService::LoginAction, $realm);
return Redirect::action("OAuth2\OAuth2ProviderController@auth");
}

View File

@ -68,17 +68,21 @@ final class OpenIdLoginStrategy extends DefaultLoginStrategy
return Redirect::action("UserController@getProfile");
}
public function postLogin()
public function postLogin(array $params = [])
{
//go to authentication flow again
$msg = OpenIdMessage::buildFromMemento($this->memento_service->load());
$realm = "From ". $msg->getParam(OpenIdProtocol::OpenIDProtocol_Realm);
if(isset($params['provider']))
$realm .= " using ".strtoupper($params['provider']);
$this->user_action_service->addUserAction
(
$this->auth_service->getCurrentUser()->getId(),
IPHelper::getUserIp(),
IUserActionService::LoginAction,
$msg->getParam(OpenIdProtocol::OpenIDProtocol_Realm)
$realm
);
return Redirect::action("OpenId\OpenIdProviderController@endpoint");

View File

@ -48,6 +48,10 @@ final class StrategyProvider extends ServiceProvider implements DeferrableProvid
// authentication strategies
App::singleton(OAuth2ServiceCatalog::AuthenticationStrategy, \Strategies\OAuth2AuthenticationStrategy::class);
App::singleton(OpenIdServiceCatalog::AuthenticationStrategy, \Strategies\OpenIdAuthenticationStrategy::class);
// factories
App::singleton(ILoginStrategyFactory::class, LoginStrategyFactory::class);
}
public function provides()
@ -61,6 +65,7 @@ final class StrategyProvider extends ServiceProvider implements DeferrableProvid
OAuth2IndirectFragmentResponse::OAuth2IndirectFragmentResponse,
OAuth2ServiceCatalog::AuthenticationStrategy,
OpenIdServiceCatalog::AuthenticationStrategy,
ILoginStrategyFactory::class,
];
}
}

View File

@ -166,6 +166,18 @@ final class UserFactory
if(isset($payload['email_verified']) && boolval($payload['email_verified']) === true && !$user->isEmailVerified())
$user->verifyEmail();
if(isset($payload['full_name']))
$user->setFullName(trim($payload['full_name']));
if(isset($payload['external_id']))
$user->setExternalId(trim($payload['external_id']));
if(isset($payload['external_pic']))
$user->setExternalPic(trim($payload['external_pic']));
if(isset($payload['external_provider']))
$user->setExternalProvider(trim($payload['external_provider']));
return $user;
}
}

View File

@ -306,6 +306,24 @@ class User extends BaseEntity
*/
private $pic;
/**
* @ORM\Column(name="external_id", type="string")
* @var string
*/
private $external_id;
/**
* @ORM\Column(name="external_provider", type="string")
* @var string
*/
private $external_provider;
/**
* @ORM\Column(name="external_pic", type="string")
* @var string
*/
private $external_pic;
// relations
/**
@ -412,6 +430,9 @@ class User extends BaseEntity
$this->spam_type = self::SpamTypeNone;
$this->company = null;
$this->phone_number = null;
$this->external_id = null;
$this->external_provider = null;
$this->external_pic = null;
}
/**
@ -823,6 +844,9 @@ class User extends BaseEntity
if (!empty($this->pic)) {
return Storage::disk('swift')->url(sprintf("%s/%s", self::getProfilePicFolder(), $this->pic));
}
if(!empty($this->external_pic))
return $this->external_pic;
return $this->getGravatarUrl();
}
catch (\Exception $ex) {
@ -1780,4 +1804,61 @@ SQL;
$this->job_title = $job_title;
}
/**
* @return string
*/
public function getExternalProvider(): ?string
{
return $this->external_provider;
}
/**
* @param string $external_provider
*/
public function setExternalProvider(string $external_provider): void
{
$this->external_provider = $external_provider;
}
/**
* @return string
*/
public function getExternalPic(): ?string
{
return $this->external_pic;
}
/**
* @param string $external_pic
*/
public function setExternalPic(string $external_pic): void
{
$this->external_pic = $external_pic;
}
/**
* @return string
*/
public function getExternalId(): string
{
return $this->external_id;
}
/**
* @param string $external_id
*/
public function setExternalId(string $external_id): void
{
$this->external_id = $external_id;
}
/**
* @param string $full_name
*/
public function setFullName(string $full_name):void{
$name_parts = explode(" ", $full_name);
$this->first_name = $name_parts[0];
$this->last_name = $name_parts[1];
}
}

View File

@ -231,6 +231,11 @@ final class OAuth2Protocol implements IOAuth2Protocol
// http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
const OAuth2Protocol_Nonce = 'nonce';
/**
* custom param - social login
*/
const OAuth2Protocol_Provider = 'provider';
/**
* Time when the End-User authentication occurred. Its value is a JSON number representing the number of seconds
* from 1970-01-01T0:0:0Z as measured in UTC until the date/time. When a max_age request is made or when auth_time

View File

@ -37,6 +37,7 @@ class OAuth2AuthenticationRequest extends OAuth2AuthorizationRequest
OAuth2Protocol::OAuth2Protocol_IDTokenHint,
OAuth2Protocol::OAuth2Protocol_LoginHint,
OAuth2Protocol::OAuth2Protocol_ACRValues,
OAuth2Protocol::OAuth2Protocol_Provider,
);
/**
@ -111,6 +112,10 @@ class OAuth2AuthenticationRequest extends OAuth2AuthorizationRequest
return str_contains($this->getScope(), OAuth2Protocol::OfflineAccess_Scope);
}
public function getProvider():?string{
return $this->getParam(OAuth2Protocol::OAuth2Protocol_Provider);
}
/**
* @param OAuth2AuthorizationRequest $auth_request
*/

View File

@ -29,31 +29,34 @@
"php": "^7.3|^8.0",
"ext-json": "*",
"ext-pdo": "*",
"laravel/framework": "^8.0",
"laravel/helpers": "^1.4",
"laravel/tinker": "^2.5",
"laravelcollective/html": "6.2.*",
"fruitcake/laravel-cors": "^2.0",
"laravel-doctrine/orm": "1.7.*",
"laravel-doctrine/extensions": "1.4.*",
"laravel-doctrine/migrations": "2.3.*",
"beberlei/doctrineextensions": "1.3.*",
"behat/transliterator": "^1.2",
"vladimir-yuldashev/laravel-queue-rabbitmq": "v11.1.*",
"s-ichikawa/laravel-sendgrid-driver": "~3.0",
"ezyang/htmlpurifier": "v4.12.0",
"fideloper/proxy": "^4.4",
"fruitcake/laravel-cors": "^2.0",
"get-stream/stream-chat": "^1.1",
"glenscott/url-normalizer": "1.4.0",
"greggilbert/recaptcha": "dev-feature/laravel8.x",
"guzzlehttp/guzzle": "^7.0.1",
"ircmaxell/random-lib": "1.1.0",
"jenssegers/agent": "2.6.3",
"laravel-doctrine/extensions": "1.4.*",
"laravel-doctrine/migrations": "2.3.*",
"laravel-doctrine/orm": "1.7.*",
"laravel/framework": "^8.0",
"laravel/helpers": "^1.4",
"laravel/socialite": "^5.2",
"laravel/tinker": "^2.5",
"laravelcollective/html": "6.2.*",
"php-opencloud/openstack": "dev-feature/guzzle_7_x",
"phpseclib/phpseclib": "2.0.11",
"predis/predis": "v1.1.6",
"s-ichikawa/laravel-sendgrid-driver": "~3.0",
"smarcet/jose4php": "1.0.17",
"socialiteproviders/facebook": "^4.1",
"socialiteproviders/google": "^4.1",
"sokil/php-isocodes": "^3.0",
"vladimir-yuldashev/laravel-queue-rabbitmq": "v11.1.*",
"zendframework/zend-crypt": "3.3.0",
"zendframework/zend-math": "3.1.1"
},

295
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "c28f890e5a6afe1c57a1e232f3be5e5c",
"content-hash": "e015af0bbb4e2dd0a442281900600087",
"packages": [
{
"name": "asm89/stack-cors",
@ -3362,6 +3362,75 @@
},
"time": "2021-02-16T15:27:11+00:00"
},
{
"name": "laravel/socialite",
"version": "v5.2.3",
"source": {
"type": "git",
"url": "https://github.com/laravel/socialite.git",
"reference": "1960802068f81e44b2ae9793932181cf1cb91b5c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/socialite/zipball/1960802068f81e44b2ae9793932181cf1cb91b5c",
"reference": "1960802068f81e44b2ae9793932181cf1cb91b5c",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/guzzle": "^6.0|^7.0",
"illuminate/http": "^6.0|^7.0|^8.0",
"illuminate/support": "^6.0|^7.0|^8.0",
"league/oauth1-client": "^1.0",
"php": "^7.2|^8.0"
},
"require-dev": {
"illuminate/contracts": "^6.0|^7.0",
"mockery/mockery": "^1.0",
"orchestra/testbench": "^4.0|^5.0|^6.0",
"phpunit/phpunit": "^8.0|^9.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.x-dev"
},
"laravel": {
"providers": [
"Laravel\\Socialite\\SocialiteServiceProvider"
],
"aliases": {
"Socialite": "Laravel\\Socialite\\Facades\\Socialite"
}
}
},
"autoload": {
"psr-4": {
"Laravel\\Socialite\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "Laravel wrapper around OAuth 1 & OAuth 2 libraries.",
"homepage": "https://laravel.com",
"keywords": [
"laravel",
"oauth"
],
"support": {
"issues": "https://github.com/laravel/socialite/issues",
"source": "https://github.com/laravel/socialite"
},
"time": "2021-04-06T14:38:16+00:00"
},
{
"name": "laravel/tinker",
"version": "v2.6.1",
@ -3754,6 +3823,81 @@
],
"time": "2021-01-18T20:58:21+00:00"
},
{
"name": "league/oauth1-client",
"version": "v1.9.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/oauth1-client.git",
"reference": "1e7e6be2dc543bf466236fb171e5b20e1b06aee6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/oauth1-client/zipball/1e7e6be2dc543bf466236fb171e5b20e1b06aee6",
"reference": "1e7e6be2dc543bf466236fb171e5b20e1b06aee6",
"shasum": ""
},
"require": {
"ext-json": "*",
"ext-openssl": "*",
"guzzlehttp/guzzle": "^6.0|^7.0",
"php": ">=7.1||>=8.0"
},
"require-dev": {
"ext-simplexml": "*",
"friendsofphp/php-cs-fixer": "^2.17",
"mockery/mockery": "^1.3.3",
"phpstan/phpstan": "^0.12.42",
"phpunit/phpunit": "^7.5||9.5"
},
"suggest": {
"ext-simplexml": "For decoding XML-based responses."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev",
"dev-develop": "2.0-dev"
}
},
"autoload": {
"psr-4": {
"League\\OAuth1\\Client\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ben Corlett",
"email": "bencorlett@me.com",
"homepage": "http://www.webcomm.com.au",
"role": "Developer"
}
],
"description": "OAuth 1.0 Client Library",
"keywords": [
"Authentication",
"SSO",
"authorization",
"bitbucket",
"identity",
"idp",
"oauth",
"oauth1",
"single sign on",
"trello",
"tumblr",
"twitter"
],
"support": {
"issues": "https://github.com/thephpleague/oauth1-client/issues",
"source": "https://github.com/thephpleague/oauth1-client/tree/v1.9.0"
},
"time": "2021-01-20T01:40:53+00:00"
},
{
"name": "mobiledetect/mobiledetectlib",
"version": "2.8.37",
@ -5307,6 +5451,155 @@
},
"time": "2019-07-12T23:35:09+00:00"
},
{
"name": "socialiteproviders/facebook",
"version": "4.1.0",
"source": {
"type": "git",
"url": "https://github.com/SocialiteProviders/Facebook.git",
"reference": "9b94a9334b5d0f61de8f5a20928d63d4d8f4e00d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/SocialiteProviders/Facebook/zipball/9b94a9334b5d0f61de8f5a20928d63d4d8f4e00d",
"reference": "9b94a9334b5d0f61de8f5a20928d63d4d8f4e00d",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": "^7.2 || ^8.0",
"socialiteproviders/manager": "~4.0"
},
"type": "library",
"autoload": {
"psr-4": {
"SocialiteProviders\\Facebook\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Oleksandr Prypkhan (Alex Wells)",
"email": "autaut03@googlemail.com"
}
],
"description": "Facebook (facebook.com) OAuth2 Provider for Laravel Socialite",
"support": {
"source": "https://github.com/SocialiteProviders/Facebook/tree/4.1.0"
},
"time": "2020-12-01T23:10:59+00:00"
},
{
"name": "socialiteproviders/google",
"version": "4.1.0",
"source": {
"type": "git",
"url": "https://github.com/SocialiteProviders/Google-Plus.git",
"reference": "1cb8f6fb2c0dd0fc8b34e95f69865663fdf0b401"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/SocialiteProviders/Google-Plus/zipball/1cb8f6fb2c0dd0fc8b34e95f69865663fdf0b401",
"reference": "1cb8f6fb2c0dd0fc8b34e95f69865663fdf0b401",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": "^7.2 || ^8.0",
"socialiteproviders/manager": "~4.0"
},
"type": "library",
"autoload": {
"psr-4": {
"SocialiteProviders\\Google\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "xstoop",
"email": "myenglishnameisx@gmail.com"
}
],
"description": "Google OAuth2 Provider for Laravel Socialite",
"support": {
"source": "https://github.com/SocialiteProviders/Google-Plus/tree/4.1.0"
},
"time": "2020-12-01T23:10:59+00:00"
},
{
"name": "socialiteproviders/manager",
"version": "4.0.1",
"source": {
"type": "git",
"url": "https://github.com/SocialiteProviders/Manager.git",
"reference": "0f5e82af0404df0080bdc5c105cef936c1711524"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/SocialiteProviders/Manager/zipball/0f5e82af0404df0080bdc5c105cef936c1711524",
"reference": "0f5e82af0404df0080bdc5c105cef936c1711524",
"shasum": ""
},
"require": {
"illuminate/support": "^6.0|^7.0|^8.0",
"laravel/socialite": "~4.0|~5.0",
"php": "^7.2 || ^8.0"
},
"require-dev": {
"mockery/mockery": "^1.2",
"phpunit/phpunit": "^9.0"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"SocialiteProviders\\Manager\\ServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"SocialiteProviders\\Manager\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Andy Wendt",
"email": "andy@awendt.com"
},
{
"name": "Anton Komarev",
"email": "a.komarev@cybercog.su"
},
{
"name": "Miguel Piedrafita",
"email": "soy@miguelpiedrafita.com"
},
{
"name": "atymic",
"email": "atymicq@gmail.com",
"homepage": "https://atymic.dev"
}
],
"description": "Easily add new or override built-in providers in Laravel Socialite.",
"homepage": "https://socialiteproviders.com/",
"support": {
"issues": "https://github.com/SocialiteProviders/Manager/issues",
"source": "https://github.com/SocialiteProviders/Manager/tree/4.0.1"
},
"time": "2020-12-01T23:09:06+00:00"
},
{
"name": "sokil/php-isocodes",
"version": "3.3.4",

View File

@ -170,6 +170,7 @@ return [
LaravelDoctrine\Extensions\BeberleiExtensionsServiceProvider::class,
\App\Models\Utils\MySQLExtensionsServiceProvider::class,
\App\libs\Utils\FileSystem\SwiftServiceProvider::class,
Laravel\Socialite\SocialiteServiceProvider::class,
],
/*
@ -223,6 +224,7 @@ return [
'EntityManager' => LaravelDoctrine\ORM\Facades\EntityManager::class,
'Registry' => LaravelDoctrine\ORM\Facades\Registry::class,
'Doctrine' => LaravelDoctrine\ORM\Facades\Doctrine::class,
'Socialite' => Laravel\Socialite\Facades\Socialite::class,
],
'version' => env('APP_VERSION', 'XX.XX.XX'),

View File

@ -39,4 +39,15 @@ return [
'api_key' => env('SENDGRID_API_KEY'),
],
// 3rd party idps
'facebook' => [
'client_id' => env('FACEBOOK_CLIENT_ID'),
'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
'redirect' => env('FACEBOOK_REDIRECT_URI')
],
'google' => [
'client_id' => env('GOOGLE_CLIENT_ID'),
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
'redirect' => env('GOOGLE_REDIRECT_URI')
],
];

View File

@ -0,0 +1,53 @@
<?php namespace Database\Migrations;
/**
* Copyright 2021 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use Doctrine\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema as Schema;
use LaravelDoctrine\Migrations\Schema\Builder;
use LaravelDoctrine\Migrations\Schema\Table;
/**
* Class Version20210512181715
* @package Database\Migrations
*/
class Version20210512181715 extends AbstractMigration
{
/**
* @param Schema $schema
*/
public function up(Schema $schema): void
{
$builder = new Builder($schema);
if($schema->hasTable("users") && !$builder->hasColumn("users","external_provider") ) {
$builder->table('users', function (Table $table) {
$table->string('external_provider')->setNotnull(false)->setLength(254);
$table->string('external_id')->setNotnull(false)->setLength(254);
$table->string('external_pic')->setNotnull(false)->setLength(254);
});
}
}
/**
* @param Schema $schema
*/
public function down(Schema $schema): void
{
$builder = new Builder($schema);
if($schema->hasTable("users") && $builder->hasColumn("users","external_provider") ) {
$builder->table('users', function (Table $table) {
$table->dropColumn('external_provider');
$table->dropColumn('external_id');
$table->dropColumn('external_pic');
});
}
}
}

10
package-lock.json generated
View File

@ -11270,16 +11270,6 @@
"marked": "*"
}
},
"simplemde": {
"version": "1.11.2",
"resolved": "https://registry.npmjs.org/simplemde/-/simplemde-1.11.2.tgz",
"integrity": "sha1-ojo12XjSxA7wfewAjJLwcNjggOM=",
"requires": {
"codemirror": "*",
"codemirror-spell-checker": "*",
"marked": "*"
}
},
"slash": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",

View File

@ -41,10 +41,15 @@ Route::group(array('middleware' => ['ssl']), function () {
//user interaction
Route::group(array('prefix' => 'auth'), function () {
Route::group(array('prefix' => 'login'), function () {
Route::get('', "UserController@getLogin");
Route::post('', ['middleware' => 'csrf', 'uses' => 'UserController@postLogin']);
Route::get('cancel', "UserController@cancelLogin");
Route::group(array('prefix' => '{provider}'), function () {
Route::get('', 'SocialLoginController@redirect')->name("social_login");
Route::get('callback','SocialLoginController@callback')->name("social_login_callback");
});
});
// registration routes