Oauth2-server-laravel always ask to approve/deny after login - laravel

I am newbie in Oauth2 and laravel. I am trying to implement Authorization Server in laravel with authorization code grant. I followed all implementation instruction mentioned in https://github.com/lucadegasperi/oauth2-server-laravel.
Every thing is working fine except user need to approve/deny on each login to get access code. I want to show authorization-form only once when user first time ask for authorization and not every time, similar to how Oauth2 is implemented in google.
How can I do it, any pointers?

I have implemented a solution for your issue in one of my work, here is the sample code, hope that help:
Route::get('/oauth/authorize', array('before' => 'check-authorization-params|auth', function() {
// get the data from the check-authorization-params filter
$params = Session::get('authorize-params');
// get the user id
$params['user_id'] = Auth::user()->id;
if ($params['approval_prompt'] != 'force')
{
$session = DB::table('oauth_sessions')->where('client_id', '=', $params['client_id'])
->where('owner_type', '=', 'user')
->where('owner_id', '=', $params['user_id'])
->first();
if ($session)
{
$code = AuthorizationServer::newAuthorizeRequest('user', $params['user_id'], $params);
Session::forget('authorize-params');
return Redirect::to(AuthorizationServer::makeRedirectWithCode($code, $params));
}
}
// display the authorization form
return View::make('authorization-form', array('params' => $params));
}));
If the approval_prompt is not set to force, then I will check whether if there are any sessions belong to this user and show the authorization form only if there is no saved sessions.
Notice: This code is for the 1.0 version of the package, if you're using another version, there may be some different things.

This is modification of Hieu Le answer for Laravel 5.1 and lucadegasperi/oauth2-server-laravel with league/oauth2-server 4.1.2
Route::get('/oauth/authorize', ['as' => 'oauth.authorize.get','middleware' => ['check-authorization-params', 'auth'], function() {
// display a form where the user can authorize the client to access it's data
$authParams = Authorizer::getAuthCodeRequestParams();
$authParams['client_id'] = $authParams['client']->getId();
$formParams = array_except($authParams,'client');
$authParams['user_id'] = Auth::user()->id;
if (array_get($authParams, 'approval_prompt', null) != 'force')
{
$session = DB::table('oauth_sessions')->where('client_id', '=', $authParams['client_id'])
->where('owner_type', '=', 'user')
->where('owner_id', '=', $authParams['user_id'])
->first();
if ($session)
{
$redirectUri = Authorizer::issueAuthCode('user', $authParams['user_id'], $authParams);
return Redirect::to($redirectUri);
}
}
return View::make('oauth.authorization-form', ['params'=>$formParams,'client'=>$authParams['client']]);
}]);

Related

ADLDAP openLDAP authentication - Session not stored - returning to login page

My environment is a laravel 5.8 with adldap2 in version 6.0.8 web app and an openLDAP directory.
After hours, I finally could authenticate my user against the openLDAP directory and also the database import into the users table works:
Id name username password remember_token created_at updated_at
King king $2y$10$YF9q7cYqjYnkl.We4Evwv.u/a2sddrfBA3pohgpS2vR... j4AOUHSlkHE3IQW7bsgF7pOIY8EAss6iukfnKhwi2lqXR0eTjE... NULL NULL
When I check the variable user in the function: attemptLogin -> $this->guard()->login($user, true); it is from the DB and seems to be fine. But still after I log in, I also get the message "Redirecting to http://localhost/home.", it returns to the login page and is still not logged in.
For LDAP authentication I followed mostly this example: https://jotaelesalinas.github.io/laravel-simple-ldap-auth/ even if it is a bit obsolete.
My attemptLogin function looks like this:
protected function attemptLogin(Request $request)
{
$username = Adldap::search()->users()->select('mail','uid','displayName')->findBy('cn', request()->get('username'));
$result = 1;
if($username){
if(Adldap::auth()->attempt($username->getdistinguishedName(), request()->get('password'))){
echo("success");
// Check group
$group = Adldap::search()->groups()->findOrFail('cio');
foreach ($group->getMemberNames() as $name) {
if($name === $username->getAccountName()){
echo("The user is a member of the group.");
$result = 0;
}
}
if ($result != 0){
$result = 2;
}
} else {
echo("Password wrong");
$result = 1;
}
} else {
echo(request()->get('username') . " not found");
$result = 1;
}
if($result == 0) {
// the user exists in the LDAP server, with the provided password
echo("Everything ok");
$user = \App\User::where($this->username(), $username->getAccountName())->first();
if (!$user) {
// the user doesn't exist in the local database, so we have to create one
$user = new \App\User();
$user->username = $username;
$user->password = '';
// you can skip this if there are no extra attributes to read from the LDAP server
// or you can move it below this if(!$user) block if you want to keep the user always
// in sync with the LDAP server
//dd($username->getDisplayName());
$sync_attrs = $this->retrieveSyncAttributes($username->getAccountName());
//dd($sync_attrs);
foreach ($sync_attrs as $field => $value) {
$user->$field = $value !== null ? $value : '';
}
}
$this->guard()->login($user, true);
return 0;
}
// the user doesn't exist in the LDAP server or the password is wrong
// log error
return $result;
}
Web.php
Route::get('login', 'Auth\LoginController#showLoginForm')->name('login');
Route::post('login', 'Auth\LoginController#login');
Route::post('logout', 'Auth\LoginController#logout')->name('logout');
Route::get('/home', 'HomeController#index')->name('home');
Has anyone an idea what I am missing? Or if you need more information, please tell me. It seems like the session is not stored.
Thanks in advance
Stephan
A small update after playing around some more hours. It seems like that Auth is after the successful login null. So tried different approaches I could find on the internet like changing the web.php routes or adding the protected $user variable to the LoginController.php but of course without any success.
I figured out that when I change the middleware from auth to web, I will get a session but the Auth::User() is still empty
Route::group(['middleware' => 'auth'], function () {
Route::get('/home', 'HomeController#index')->name('home');
});
After spending more and more hours, I finally found the solution in this thread: Laravel Auth:attempt() will not persist login
My issue was that I was using "echo's".
It cost me probably some days of my life

How to add expiry date condition to login function in laravel 5.2

In laravel 5.2, i want to add the condition so that only users where their expiry date is greater than today's date to login.
protected function getCredentials(Request $request)
{
return ['email' => $request->{$this->loginUsername()}, 'password' => $request->password];
}
The code does not accept adding:
'expires' => gte(Carbon::now())
Any help is appreciated
I don't think this is possible, even in Laravel 5.5. Taking a look at the retrieveByCredentials method in Illuminate\Auth\EloquentUserProvider which is used to get the user from the database, you can see that the query passes simple key/value combinations to the where method on the $query object, which equate to where key = value. This is from 5.5:
public function retrieveByCredentials(array $credentials)
{
if (empty($credentials) ||
(count($credentials) === 1 &&
array_key_exists('password', $credentials))) {
return;
}
// First we will add each credential element to the query as a where clause.
// Then we can execute the query and, if we found a user, return it in a
// Eloquent User "model" that will be utilized by the Guard instances.
$query = $this->createModel()->newQuery();
foreach ($credentials as $key => $value) {
if (! Str::contains($key, 'password')) {
$query->where($key, $value);
}
}
return $query->first();
}
To achieve what you are after I would recommend doing this check after the user has logged in, in your controller for instance:
// Imagine this is the controller method where you're dealing with user logins
public function login(array $credentials)
{
if (! auth()->attempt($credentials)) {
// Handle what happens if the users credentials are incorrect.
}
$user = auth()->user();
if (Carbon::now()->gte($user->expires)) {
// User's account has expired, lets log them out.
auth()->logout();
// Return a redirect with a message or something...
}
// Handle a successful login.
}
I'm not sure if the auth() helper is available in 5.2, but you should be able to use the Auth facade to do the same thing, e.g. Auth::attempt(...).

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 unauthorized page when ajax send request

I'm making web based game. The game need to login first, so I use laravel auth::register and auth::login as usual, and add middleware auth to every pages except login&register page.
Then check the game status using smartupdater if ready or not.
$("section").smartupdater({
url : urlCheckStatus,
data : data,
dataType : 'json',
minTimeout: 2000
}, function(response){
var gameStatus = response.data.status;
if(gameStatus === 'start')
{
gameOn();
}
else if(gameStatus === 'active')
{
pleaseWait();
}
else if(gameStatus === 'stop')
{
backToMenu();
}
});
Register and login function
public function register(Request $request)
{
$name = $request->input('username');
$user = new User;
$user->name = $request->input('username');
$user->email = $name.'#abc.com';
$user->password = bcrypt(Carbon\Carbon::now());
$user->grade = $request->input('grade');
$user->numb = $request->input('numb');
$user->save();
Auth::login($user, true);
return redirect('menu');
}
check game status function
public function checkGameStatus()
{
$game_id = Request::input('game_id');
$data = Game::find($game_id);
return response()->json([
'data' => $data
]);
}
But sometimes I was thrown to login page, because error 401 Unauthorized. Trying to console log like the image above.
Thanks
I see you are using Javascript for authorization with Laravel, as per Laravel documentation for API Authentication with Javascript:
If you are using a different JavaScript framework, you should make
sure it is configured to send the X-CSRF-TOKEN and X-Requested-With
headers with every outgoing request.
Can you ensure X-CSRF-TOKEN and X-Requested-With are always present in your headers.

Laravel, log in user for one request

I am building a REST API with Laravel, and I have a filter that checks for a TOKEN:
Route::filter('api.auth', function() {
$token = Request::header('X-CSRF-Token') ? Request::header('X-CSRF-Token') : '';
if (empty($token)) {
return Response::json(
['message' => 'A valid API key is required!'],
401
);
};
$user = User::where('token', '=', $token);
if ($user->count()) {
$user = $user->first();
Auth::login($user);
} else {
return Response::json(
['message' => 'Your token has expired!'],
401
);
};
});
If everything is ok, the filter will log in the user with uth::login($user);
How can I log him for only 1 request?
Since this filter is going to be checked on every request, I think it would be better to log the user out each time.
I have seen this in Laravel's docs, not sure how to apply it:
if (Auth::once($credentials))
{
//
}
Could I have a callback in my response? where I could log the user out?
/*
Get all products.
*/
public function getProducts() {
$products = Auth::user()->products;
return Response::json($products, 200);
}
Any ideas?
If you haven't user's password use this:
if(Auth::onceUsingId($userId)) {
// do something here
}
If I correctly understand the question then I would say that, just replace following
Auth::login($user);
with this (To log the user in only for current request):
Auth::once(['email' => $user->email, 'password' => $user->password]);
If you log in a user only for once then you don't have to manually logo out the user, the user will be asked again for to log in on next request.

Resources