Laravel SAML - user automatically logged out after log in - laravel

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);
}
});
}

Related

Create session on consuming login with api on laravel

I have an api that has a method to start and I am calling it from a frontend project.
In the front end project I use Guzzle to make the call via post to the api and login, from which I get back a json with the user data and a jwt token.
But when I receive the token as I manage the session, I must create a session and save the token, since the laravel to authenticate I need a model user and have a database, which of course I do not have in this backend because I call the api to log in, which brings a token and user data, then as I manage it from the backend, I'm a little lost there.
$api = new Api();
$response = $api->loginapi(['user'=>'wings#test.com','password'=>'123']);
Because here I could not do Auth::login($user) to generate the session.
Because I don't have here the database because the login is done from the api.
There I call the api, of which the answer is the token, but how do I manage it from here, creating a session? saving the token?
thanks for your help.
With api, you don't usually manage a session. usually, you'd call something like
Auth::attempt([
'email' => 'me#example.com',
'password' => 'myPassword'
]);
If the credentials are correct, laravel will include a Set-Cookie header in response, and, that is how you authenticate with api. Via an auth cookie. You don't need to do anything else.
Let's show you how:
//AuthController.php
public function login(Request $request) {
$validatedData = $request->validate([
'email' => 'required|email',
'password' => 'required'
]);
if(Auth::attempt($validatedData)){
return ['success' => 'true'];
}
else{
return ['success' => false, 'message' => 'Email or password Invalid'];
}
}
public function currentUser (){
return Auth::user();
}
Now, the APi file
Route::post('/login', ['App\Http\Controllers\AuthController', 'login']);
Route::get('/current_user', ['App\Http\Controllers\AuthController', 'currentUser']);
Now if you make a call to /api/current_user initially, you'll get null response since you're not currently logged in. But once you make request to /api/login and you get a successful response, you are now logged in. Now if you go to /api/current_user, you should see that you're already logged in.
Important ::
If you are using fetch, you need to include credentials if you're using something other than fetch, check out how to use credentials with that library or api
You want to use the API to authenticate and then use the SessionGuard to create session including the remember_me handling.
This is the default login controller endpoint for logging in. You don't want to change this, as it makes sure that user's do not have endless login attempts (protects for brut-force attacks) and redirects to your current location.
public function login(Request $request)
{
$this->validateLogin($request);
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if (method_exists($this, 'hasTooManyLoginAttempts') &&
$this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if ($this->attemptLogin($request)) {
if ($request->hasSession()) {
$request->session()->put('auth.password_confirmed_at', time());
}
return $this->sendLoginResponse($request);
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
The core happens when we try to "attemptLogin" at
protected function attemptLogin(Request $request)
{
return $this->guard()->attempt(
$this->credentials($request), $request->boolean('remember')
);
}
When using the SessioGurad (which is default) the method attemptLogin fires a couple of events, checks if the user has valid credentials (by hashing the password and matching it with db) and then logs the user in, including the remember me functionality.
Now, if you don't care about events, you can just check from your API if the credentials match and then use the login method from the guard. This will also handle the remember me functionality. Something like this:
protected function attemptLogin(Request $request)
{
$username = $request->input($this->username());
$password = $request->input('password');
$result = \Illuminate\Support\Facades\Http::post(env('YOUR_API_DOMAIN') . '/api/v0/login' , [
'username' => $username,
'password' => $password
])->json();
if(empty($result['success'])){
return false;
}
// Maybe you need to create the user here if the login is for the first time?
$user = User::where('username', '=', $username)->first();
$this->guard()->login(
$user, $request->boolean('remember')
);
return true;
}

Ask User's Password When Logging with Social Account - Laravel Socialite

I have fully functional Socialite social login with Google and Facebook but i want to add another step that is "ask a password before logging in".
This function logs the user immediately after successfully logging in with the provider:
public function callback(Request $request, $provider, SocialAccountsService $service)
{
if ($request->has("error")) {
return redirect()->route("website.index");
}
try {
$user = $service->createOrGetUser(
Socialite::driver($provider)->user(),
$provider
);
auth()->login($user);
} catch (InvalidStateException $e) {
Log::error($e->getMessage());
return redirect()->route("auth.register.index");
}
return redirect()->route("dashboard.profile.index");
}
What should i do so when they login with the provider they must insert a password before logging to my website?
Okey, you want to create user but do not want to log it. Than:
Delete auth()->login($user);
Add something like session()->put('created_social_user_id', $user->id);
Create PasswordCreation controller and view and redirect user from callback to it
In this controller - use session, get user_id, find before created model and ask user about password.
After password creation - add auth()->login($user); and redirect to dashboard

Laravel retrieve deleted users multiple times

In my application, I have a button for deleting the account.
This is the function code:
public function deleteAccount()
{
$user = auth()->user();
auth()->logout();
request()->session()->invalidate();
request()->session()->regenerateToken();
$user->delete();
return redirect(route('login'))->with([
'status' => __('Your account has been deleted')
]);
}
I signed in with the same account with the "Remember" option on both Edge and Firefox browsers. When I click "Delete Account" on Edge, Laravel also dismisses me on Firefox because it deleted my account.
The problem is: On Firefox, Laravel is still trying to retrieve my account with Session and Cookies info because it hasn't been updated. And it runs again and again everywhere I use the auth() function.
How to avoid this? Or how do other sessions know that their information is out of date?
(I think it should only check once, like when it finds a user)
Demo code: https://github.com/tungwoodboi/demo-laravel-deleted-user
I found this in the SessionGuard class:
public function user()
{
if ($this->loggedOut) {
return;
}
// If we've already retrieved the user for the current request we can just
// return it back immediately. We do not want to fetch the user data on
// every call to this method because that would be tremendously slow.
if (! is_null($this->user)) {
return $this->user;
}
$id = $this->session->get($this->getName());
// First we will try to load the user using the identifier in the session if
// one exists. Otherwise we will check for a "remember me" cookie in this
// request, and if one exists, attempt to retrieve the user using that.
if (! is_null($id) && $this->user = $this->provider->retrieveById($id)) {
$this->fireAuthenticatedEvent($this->user);
}
// If the user is null, but we decrypt a "recaller" cookie we can attempt to
// pull the user data on that cookie which serves as a remember cookie on
// the application. Once we have a user we can return it to the caller.
if (is_null($this->user) && ! is_null($recaller = $this->recaller())) {
$this->user = $this->userFromRecaller($recaller);
if ($this->user) {
$this->updateSession($this->user->getAuthIdentifier());
$this->fireLoginEvent($this->user, true);
}
}
return $this->user;
}

JWT laravel: check auth. Cannot check if user is authenticated even i have set the token

I'm trying make a mobile application with vue and i'm using jwt in laravel.
On first login, I can access the auth()->check() then I get false after the app is cancelled. I'm saving the token. I'm saving the token in local storage. How can I get the authenticated user.
controller:
public function JwtAuth(){
if($this->getAuthenticatedUser()){
return $this->JwtUser = $this->getAuthenticatedUser();
}
return [];
}
I want to acheive something like:
if(auth()->user()){
$user = "something";
}else{
$user = '';
}
return $user;
So sometime I will have token and sometime i dont .. how to check?

laravel login with google account

I am making an application and I want users to login with their google account. I have user oauth-4-laravel and I have this:
UserController.php
// get data from input
$code = Input::get('code');
// get google service
$googleService = Artdarek\OAuth\Facade\OAuth::consumer("Google");
if (!empty($code)) {
// This was a callback request from google, get the token
$token = $googleService->requestAccessToken($code);
// Send a request with it
$result = json_decode($googleService->request('https://www.googleapis.com/oauth2/v1/userinfo'), true);
$user = DB::select('select id from users where email = ?', array($result['email']));
if (empty($user)) {
$data = new User;
$data->Username = $result['name'];
$data->email = $result['email'];
$data->first_name = $result['given_name'];
$data->last_name = $result['family_name'];
$data->save();
}
if (Auth::attempt(array('email' => $result['email']))) {
return Redirect::to('/');
} else {
echo 'error';
}
}
// if not ask for permission first
else {
// get googleService authorization
$url = $googleService->getAuthorizationUri();
// return to facebook login url
return Redirect::to((string) $url);
}
}
After this i get successfully user info and can save user name, in my database. The problem is that after this I want to redirect user to home page and can't do this because with normal login i chec authentication:
if (Auth::attempt(array('email' => Input::get('email'), 'password' => Input::get('password')))) {
return Response::json(["redirect_to" => "/"]);
and with google login i get onlu username , user id and email. How to login directly the user after google login?
If you need to log an existing user instance into your application, you may simply call the login method with the instance:
$user = User::find(1);
Auth::login($user);
This is equivalent to logging in a user via credentials using the attempt method.
For further info see: http://laravel.com/docs/security#manually

Resources