Dynamic social app credentials in socialite package in Laravel - laravel

I'm trying to build a multi tenant app, where I have configured the database, the views folder, I know there must be some way out to configure the credentials of social app login for socialite. Well I tried few things to set it dynamically.
STEP 1
I created a class with the name of socialite in a separate folder and when the social login is called I'm implementing the following in my controller:
public function redirectSocialLogin()
{
$social = new SocialiteProvider();
$fb = $social->makeFacebookDriver();
return $fb->redirect();
}
and while callback I used following:
public function callbackSocialLogin($media)
{
$user = Socialite::driver($media)->user();
$data['name'] = $user->getName();
$data['email'] = $user->getEmail();
dd($data);
}
In my class I've following codes:
public function makeFacebookDriver()
{
$config['client_id'] = 'XXXXXXXXXXXXXXX';
$config['client_secret'] = 'XXXXXXXXXXXXXXX';
$config['redirect'] = 'http://XXXXXXXXXXXX/auth/facebook/callback';
return Socialite::buildProvider('\Laravel\Socialite\Two\FacebookProvider', $config);
}
It redirects perfectly to the social page but while getting a callback I'm getting an error, It again fetches the services.php file for configuration and doesn't get any.
STEP 2
I made a ServiceProvider under the name of SocialiteServiceProvider and extended the core SocialiteServiceProvider and placed the following codes:
protected function createFacebookDriver()
{
$config['client_id'] = 'XXXXXXXXXXXXXXX';
$config['client_secret'] = 'XXXXXXXXXXXXXXXXXXXX';
$config['redirect'] = 'http://XXXXXXXXXXX/auth/facebook/callback';
return $this->buildProvider(
'Laravel\Socialite\Two\FacebookProvider', $config
);
}
But again it throws back error which says driver is not setup. Help me out in this.
Thanks.

In your STEP 1, update the callback as below mentioned & try. $media is actually Request. So when initialising Socialite::driver($media) you are actually passing Request where you have to pass Facebook.
public function callbackSocialLogin(Request $request) {
$fbDriver = (new SocialiteProvider())->makeFacebookDriver();
$user = $fbDriver->user();
$data['name'] = $user->getName();
$data['email'] = $user->getEmail();
...
}

Related

Laravel\Socialite\Two\InvalidStateException

Hi i am using laravel socialite for social logins with facebook and google and it absoultely working fine on my local server but when i deploy this on my web hosting it gives me error
Laravel\Socialite\Two\InvalidStateException
it is only for when i try to login with google in my app but it is working fine for facebook i tried many solutions as add stateless() in both google redirect method and callback method and single single too but all in vain i also tried to change in config/session where domain shows as null to my site name but again got same issue here is my code for google redirect and callback
public function redirectToGoogle()
{
return Socialite::driver('google')->redirect();
}
public function handleGoogleCallback()
{
$user = Socialite::driver('google')->user();
$this->_registerOrLoginUser($user);
return redirect()->route('home');
}
protected function _registerOrLoginUser($data)
{
$user = User::where('email','=',$data->email)->first();
if(!$user){
$user = new User();
$user->first_name = $data->name;
$user->email = $data->email;
// $user->provider_id = $data->provider_id;
$user->avatar = $data->avatar;
$user->save();
}
Auth::login($user);
}
please let me know if i'm missing something or doing wrong i'll appreciate your response in advance thank you

Laravel SAML - user automatically logged out after log in

I have connected my Laravel app to the Azure, and I'm using the SAML2 protocol for user authentication. The issue which i have is that user is logged in application (Auth::login($user)), and after that when printing auth()->user() i get logged in user object. However, somehow user session is destroyed after that, and the user is redirected to the login page. Callback for SAML response is located in a service provider boot() method and looks like this:
public function boot()
{
Event::listen('Aacotroneo\Saml2\Events\Saml2LoginEvent', function (Saml2LoginEvent $event) {
$messageId = $event->getSaml2Auth()->getLastMessageId();
// Add your own code preventing reuse of a $messageId to stop replay attacks
$user = $event->getSaml2User();
$userMap = config('saml2_settings.user_map');
$emailAddress = $user->getAttribute($userMap['email']);
$laravelUser = User::where('email', '=', $emailAddress[0])->first();
if ($laravelUser) {
Auth::login($laravelUser);
return;
}
$azureService = new AzureService();
$newUser = $azureService->createNewUserFromSaml($userMap, $user);
if ($newUser){
Auth::login($newUser);
}
});
}

Attach authenticated user to create

I'm trying to attach the currently logged in user to this request, so that I can save it in the database. Can someone point me in the right direction, please?
public function store(CreateLeadStatusRequest $request)
{
$input = $request->all();
$leadStatus = $this->leadStatusRepository->create($input);
Flash::success('Lead Status saved successfully.');
return redirect(route('lead-statuses.index'));
}
So, I have come up with the following using array_merge, but there must be a better way, surely?
public function store(CreateLeadStatusRequest $request)
{
$input = $request->all();
$userDetails = array('created_by' => Auth::user()->id, 'modified_by' => Auth::user()->id);
$merged_array = array_merge($input, $userDetails);
$leadStatus = $this->leadStatusRepository->create($merged_array);
Flash::success('Lead Status saved successfully.');
return redirect(route('lead-statuses.index'));
}
So you can use Auth Facade to get information of currently logged user.
For Laravel 5 - 5.1
\Auth::user() \\It will give you nice json of current authenticated user
For Laravel 5.2 to latest
\Auth::guard('guard_name')->user() \\Result is same
In laravel 5.2, there is new feature called Multi-Authentication which can help you to use multiple tables for multiple authentication out of the box that is why the guard('guard_name') function is use to get authenticated user.
This is the best approach to handle these type of scenario instead of attaching or joining.
public function store(CreateLeadStatusRequest $request)
{
$input = $request->all();
$userDetails = \Auth::user(); //Or \Auth::guard('guard_name')->user()
$leadStatus = $this->leadStatusRepository->create($input);
Flash::success('Lead Status saved successfully.');
return redirect(route('lead-statuses.index'));
}
Hope this helps.

Laravel: change log path to include user folder

I use Laravel 5.1 and I am trying to intercept the default logger configuration (Monolog) and save logs to a different path that includes user name.
The current logs are saved to storage/logs/laravel.log.
The wanted paths are as follows
Authenticated Users: storage/logs/[username]/[date]_[api_path].log
Other user logs can be saved under storage/logs/guest/[date]_[api_path].log
ServiceProvider Approach
Have a LogServiceProvider and where I can modify each request and set the path as wanted.
public function boot(Request $request)
{
$log = new Logger('View Logs');
$user = \Auth::User()->getName(); // ERROR - uninitialized
$path = 'storage/logs/'.$user.'/mylogfile.log'; // doesn't matter API path
$log ->pushHandler(new StreamHandler($path, Logger::INFO));
...
}
The problem with this approach, the Auth::user() seems to be uninitialized.
Why does this happen and how do I solve this?
You might need to wrap it in an if statement, such as:
if ( Auth::check() ) {
// Do auth stuff
}
else {
// Do unauth stuff
}
Does that solve your problem?
This is because Auth has not been initialized and it is too early to call.
There is example way to solve:
Create log initializer, and call it from middleware (or from wherever you want):
class UserLogger
{
public function init()
{
$logger = new Logger('order');
$currUserId = Auth::id();
$logPath = storage_path('logs/by_user/' . $currUserId . '/' . Carbon::now()->toDateString() . '.log');
$logger->pushHandler(new StreamHandler($logPath, Logger::INFO));
return $logger;
}
}
//app\Http\Middleware\Authenticate.php
class Authenticate
{
public function handle($request, Closure $next, $guard = null)
{
$userLogger = new UserLogger();
$logger = $userLogger->init();
$context = ['some context data' => 'data'];
$logger->info('custom user actions', $context);
//...
Laravel 8 version can be viewed here

Using Different Session Namespaces with Zend Framework 2 Authentication Component

I'm planning to use ZF2 in a future project, so I'm trying Zend Framework 2 RC1 now. I started with authentication step, and noticed that when i chose a different name than 'Zend_Auth' for session storage namespace, i can't access to object stored in session (AuthenticationService class' hasIdentity method returned false, despite User object data set in session).
<?php
namespace Application\Controller;
use Zend\Authentication\Adapter\DbTable as AuthAdapter;
use Zend\Authentication\AuthenticationService;
use Zend\Authentication\Storage\Session as SessionStorage;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Application\Model\User;
use Application\Form\LoginForm;
class LoginController extends AbstractActionController
{
public function indexAction()
{
$auth = new AuthenticationService();
if ($auth->hasIdentity()) {
return $this->redirect()->toRoute('application');
}
$form = new LoginForm();
return array('form' => $form);
}
public function loginAction()
{
$auth = new AuthenticationService();
$form = new LoginForm();
$form->get('submit')->setAttribute('value', 'Add');
$request = $this->getRequest();
if ($request->isPost()) {
$user = new User();
$form->setInputFilter($user->getInputFilter('login'));
$form->setData($request->getPost());
if ($form->isValid()) {
$data = $form->getData();
// Configure the instance with constructor parameters...
$sm = $this->getServiceLocator();
$dbAdapter = $sm->get('db-adapter');
$authAdapter = new AuthAdapter($dbAdapter, 'users', 'username', 'password');
$authAdapter
->setIdentity($data['username'])
->setCredential(sha1($data['password']));
// Use 'users' instead of 'Zend_Auth'
$auth->setStorage(new SessionStorage('users'));
$result = $auth->authenticate($authAdapter);
if ($result->isValid()) {
// store the identity as an object where only the username and
// real_name have been returned
$storage = $auth->getStorage();
// store the identity as an object where the password column has
// been omitted
$storage->write($authAdapter->getResultRowObject(
null,
'password'
));
// Redirect to list of application
return $this->redirect()->toRoute('application');
}
}
}
// processed if form is not valid
return array('form' => $form);
}
}
In this code, when i changed the below line,
$auth->setStorage(new SessionStorage('users'));
like this:
$auth->setStorage(new SessionStorage());
hasIdentity method returned true.
I checked two classes Zend\Authentication\AuthenticationService and Zend\Authentication\Storage\Session, and didn't see a way to access session data which has different session namespace other than default.
What i need to understand is how can i access session data which has a different namespace and if there is no way to do it for now, should we define this as a bug?
I can update the question if any other information needed.
We are kinda missing one part of your code, the one where you try and receive the user identity. im guessing that you have forgotten to pass the the SessionStorage Object with the same namespace.
Also the configuration of the Authentication object should be moved to a factory so these kind of issues to not arrise.
Thats my five cents atleast :)

Resources