Weird laravel authorization issue - laravel

Can someone help me and explain why this issue occurs? I was working with posts and after I finished all regarding CRUD and policies. Then I added logic for tags and this issue occurred. I can't delete (soft) posts, recover or forceDelete them anymore.
This is the code related to posts:
public function delete(User $user, Post $post)
{
return true;
// if($user->isAdmin) {
// return true;
// }
//
// return false;
}
/**
* Determine whether the user can restore the model.
*
* #param User $user
* #param Post $post
* #return Response|bool
*/
public function restore(User $user, Post $post)
{
if($user->isAdmin || $user->id == $post->user_id) {
return true;
}
return false;
}
/**
* Determine whether the user can permanently delete the model.
*
* #param User $user
* #param Post $post
* #return Response|bool
*/
public function forceDelete(User $user, Post $post)
{
if($user->isAdmin || $user->id == $post->user_id) {
return true;
}
return false;
}
/**
* Determine whether the user can check the list of archived users.
*
* #param User $user
* #return bool
*/
public function archived(User $user) {
if($user->isAdmin) {
return true;
}
return false;
}
As you can see for DELETE method I removed all checks and just want to return true, but it still returns an unauthorized action error.
Here is the delete method from the post controller:
/**
* Remove the specified resource from storage.
*
* #param Post $post
* #return void
* #throws AuthorizationException
*/
public function destroy(Post $post)
{
$currentUser = auth()->user();
$this->authorize('delete', $currentUser);
$post->delete();
return redirect()->route('dashboard.post.index')->with('warning', 'Archived');
}
AuthServiceProvider
protected $policies = [
User::class => UserPolicy::class,
Post::class => PostPolicy::class,
Tag::class => TagPolicy::class
];
ROUTES
Route::resource('/tag', TagController::class)->except(['create', 'show']);

SOLVED:
The issue in my case was the second parameter in the authorization. I have sent $currentUser and I should've sent $post. Then if I want to give this ability only to admins it is totally fine not to use $post in policies. Something like: `public
function delete(User $user, Post $post)
{
if($user->isAdmin) {
return true;
}
return false;
}

Related

Returning to route after middleware triggered in Laravel

I am working in Laravel 7 and have a middleware that checks if the user has a current user agreement, if not it redirects to a form that offers the current agreement. When the offer is accepted I need to redirect back to where they were originally going. I think I need to put something in the session so that when my controller stores their acceptance it can redirect back to the original route.
class VerifyAgreement
{
public function handle($request, Closure $next, $agreement)
{
if(UserAgreement::outOfDate($agreement)){
return redirect()->route('agreement.offer', $agreement);
}
return $next($request);
}
}
I think I need to get the current request and pass it to the redirect so the User Agreement controller can capture it somehow and then redirect once the agreement is stored... I am not sure.
class AgreementController extends Controller
{
public function offer(Agreement $agreement)
{
return view('agreement.offer',['agreement' => $agreement]);
}
public function agree(Request $request)
{
$agreement_uuid = App\Agreement::findOrFail($request->agreement)->uuid;
UserAgreement::create(['user_uuid'=>auth()->user()->uuid, 'agreement_uuid'=>$agreement_uuid]);
//redirect something something something
}
}
As mentioned in the comments by #Ruben Danielyan, the Illuminate\Routing\Redirector has some methods that you may find useful
Redirector.php
/**
* Create a new redirect response to the previously intended location.
*
* #param string $default
* #param int $status
* #param array $headers
* #param bool|null $secure
* #return \Illuminate\Http\RedirectResponse
*/
public function intended($default = '/', $status = 302, $headers = [], $secure = null)
{
$path = $this->session->pull('url.intended', $default);
return $this->to($path, $status, $headers, $secure);
}
/**
* Set the intended url.
*
* #param string $url
* #return void
*/
public function setIntendedUrl($url)
{
$this->session->put('url.intended', $url);
}

Block the access to a page students.index()

In my navbar I have 2 pages which are Student Add and Student Index.
When I click on Student Add, I have an error message Access Denied.
Great, no problem...
Now, I would like to make the even thing with the page Students Index and display the items, I have a problem.
I have access to the content...
In my Controller Student I have this:
class StudentController extends Controller
{
public function __construct()
{
$this->middleware(['auth', 'clearance'])
->except('index', 'show');
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$students = Student::orderby('id', 'desc')->paginate(5);
return view('students.index', compact('students'));
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
return view('students.create');
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$this->validate($request, [
'name'=>'required',
'firstname' =>'required',
]);
$name = $request['name'];
$firstname = $request['firstname'];
$student = Student::create($request->only('name', 'firstname'));
return redirect()->route('students.index')
->with('flash_message', 'Article,
'. $student->name.' created');
}
Then, in my Class ClearanceMiddleware I have this:
public function handle($request, Closure $next) {
if (Auth::user()->hasPermissionTo('Administer roles & permissions')) {
return $next($request);
}
if ($request->is('students/create')) {
if (!Auth::user()->hasPermissionTo('Create Student')) {
abort('401');
} else {
return $next($request);
}
}
if ($request->is('students/index')) {
if (!Auth::user()->hasPermissionTo('Index Student')) {
abort('401');
} else {
return $next($request);
}
}
I don't see the missed step. I have to block the access please.
2 things:
1) You need to adjust the middleware call in your controller's constructor. The except() method means the middleware will not run on those methods, so if you want the middleware to run on the index method, you will need to remove it from except().
This will call the middleware on every route method except show():
$this->middleware(['auth', 'clearance'])
->except('show');
2) Inside your middleware, you are using $request->is() to match on the path, but the url for index is not 'students/index'.
// The url path for the index route is '/students'
if ($request->is('students')) {
if (!Auth::user()->hasPermissionTo('Index Student')) {
abort('401');
} else {
return $next($request);
}
}
$this->middleware(['auth', 'clearance'])
->except('show');
Remove index from the except method. As it is you are exempting the index method from the middleware check.

Unable to overwrite authorized method in policy

I want to respond with a custom message when authorization fails.
I've overwritten the method in the Policy class but it does not return the custom message.
Policy:
class PostPolicy
{
use HandlesAuthorization;
/**
* Determine if user can view post
* #param User $user
* #param Post $post
* #return bool
*/
public function view(User $user, Post $post)
{
return $user
->posts()
->where('post_id', $post->id)
->exists();
}
/**
* [deny description]
* #return [type] [description]
*/
protected function deny()
{
return response()->json([
'message' => 'My custom unauthorized message'
], 401);
}
}
Implementing in PostController:
...
public function show(Post $post)
{
$this->authorize('view', $post);
...
}
The response still returns whats defined in the HandlesAuthorization trait, i.e.:
protected function deny($message = 'This action is unauthorized.')
{
throw new AuthorizationException($message);
}
You can simply add this code inside the AuthorizationException.php
/**
* Render the exception into an HTTP response.
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function render(Request $request)
{
if ($request->is('api/*')) {
$response = [
'message' => $this->message,
'status' => 403,
];
return response()->json($response, 403);
}
}

Trying to get property of non-object. Error in laravel

I'm kinda new at laravel and need your help.
I have this IR model :
class IR extends Model
{
//
protected $fillable=['irnum','date','subject','cause','facts','as','at','rec','user_id'];
protected $casts=['user_id'=>'int'];
public function user()
{
return $this->belongsTo(user::class);
}
public static $rules =array (
'date'=>'required',
'status'=>'required|min:10',
'cause' => 'required|min:10',
'facts' => 'required|min:10',
'ir-as' => 'required|min:10',
'rec' => 'required|min:10',
'ir-at' => 'required|min:10',
);
}
and route:
Route::group(['middleware' => ['web']], function () {
Route::get('/', function () {
return view('welcome');
})->middleware('guest');
Route::resource('tasks','TaskController');
Route::get('ir',function ()
{
return View::make('tasks/ir');
});
Route::resource('irs','IRController');
Route::auth();
});
and this is my controller :
class IRController extends Controller
{
/**
* The task repository instance.
*
* #var TaskRepository
*/
protected $irs;
/**
* Create a new controller instance.
*
* #param TaskRepository $tasks
* #return void
*/
public function __construct(IRRepository $irs)
{
$this->middleware('auth');
$this->irs = $irs;
}
/**
* Display a list of all of the user's task.
*
* #param Request $request
* #return Response
*/
public function index(Request $request)
{
return view('tasks.ir',[
'irs' => $this->irs->forUser($request->user()),
]);
}
/**
* Create a new task.
*
* #param Request $request
* #return Response
*/
public function create()
{
return View::make('irs.create');
}
public function store(Request $request)
{
$request->user_id=Auth::user()->id;
$input =$request->all();
$validation=Validator::make($input, IR::$rules);
if($validation->passes())
{
IR::create($input);
return Redirect::route('tasks.ir');
}
return Redirect::route('tasks.ir')
->withInput()
->withErrors($validation)
->with('message','There were validation errors.');
}
/**
* Destroy the given task.
*
* #param Request $request
* #param Task $task
* #return Response
*/
public function destroy(Request $request, IR $irs)
{
}
}
I really dont know what causes to throw this error.
Error throws when i add Incident report.
Pls help.
New at laravel
You're saying you get an error when you're trying to add an incident report or IR, so I assume problem is in a store() action.
I can see only one potential candidate for this error in a store() action:
Auth::user()->id;
Add dd(Auth::user()); before this clause and if it will output null, use check() method, which checks if any user is authenticated:
if (Auth::check()) {
Auth::user->id;
}

Laravel 5 authentication weird behaviour

Before explaining the problem. Let me explain, things i have tried out.I ran the command
php artisan make:auth
it created files like HomeController, a directory auth which had register & login pages. in my application i have a directory Pages. i opened up AuthenticatesUsers trait and changed
return view('auth.login'); to my view return view('Pages.login');
After that: i changed view of showRegistrationForm methods view return view('auth.register'); to return view('Pages.register'); from RegistersUsers.php
Here is UserController
lass UserController extends Controller {
//constructor
public function __construct() {
}
//Admin: return view
public function showCommunity() {
$Community = Community::latest()->get();
$Ideas = Idea::latest()->get();
return view('privatePages.communities', compact(array('Community', 'Ideas')));
}
Routes that were generated by php artisan make:auth
Route::auth();
//Auth Controller
Route::controllers([
'auth' => 'Auth\AuthController',
'password' => 'Auth\PasswordController',
]);
Now coming back to the problem. yesterday morning. When i opened up localhost/auth/register. Registration process was working fine and data was storing in DB. But there was an issue with login view. Neither it was throwing an error on wrong credentials nor logged the user in on correct credentials. Later in the evening. Login view was working and throwing an error even upon entering correct credentials it said Credentials does not match record. But registration process was not working and data was not storing in DB. It really confusing.
Here is AutheticatesUsers File
<?php
namespace Illuminate\Foundation\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Lang;
//use App\Http\Requests\UserRequest;
trait AuthenticatesUsers
{
use RedirectsUsers;
/**
* Show the application login form.
*
* #return \Illuminate\Http\Response
*/
public function getLogin()
{
return $this->showLoginForm();
}
/**
* Show the application login form.
*
* #return \Illuminate\Http\Response
*/
public function showLoginForm()
{
$view = property_exists($this, 'loginView')
? $this->loginView : 'auth.authenticate';
if (view()->exists($view)) {
return view($view);
}
return view('Pages.login');
}
/**
* Handle a login request to the application.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function postLogin(Request $request)
{
return $this->login($request);
}
/**
* Handle a login request to the application.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
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.
$throttles = $this->isUsingThrottlesLoginsTrait();
if ($throttles && $lockedOut = $this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
$credentials = $this->getCredentials($request);
if (Auth::guard($this->getGuard())->attempt($credentials, $request->has('remember'))) {
return $this->handleUserWasAuthenticated($request, $throttles);
}
// 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.
if ($throttles && ! $lockedOut) {
$this->incrementLoginAttempts($request);
}
return $this->sendFailedLoginResponse($request);
}
/**
* Validate the user login request.
*
* #param \Illuminate\Http\Request $request
* #return void
*/
protected function validateLogin(Request $request)
{
$this->validate($request, [
$this->loginUsername() => 'required', 'password' => 'required',
]);
}
/**
* Send the response after the user was authenticated.
*
* #param \Illuminate\Http\Request $request
* #param bool $throttles
* #return \Illuminate\Http\Response
*/
protected function handleUserWasAuthenticated(Request $request, $throttles)
{
if ($throttles) {
$this->clearLoginAttempts($request);
}
if (method_exists($this, 'authenticated')) {
return $this->authenticated($request, Auth::guard($this->getGuard())->user());
}
return redirect()->intended($this->redirectPath());
}
/**
* Get the failed login response instance.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
protected function sendFailedLoginResponse(Request $request)
{
return redirect()->back()
->withInput($request->only($this->loginUsername(), 'remember'))
->withErrors([
$this->loginUsername() => $this->getFailedLoginMessage(),
]);
}
/**
* Get the failed login message.
*
* #return string
*/
protected function getFailedLoginMessage()
{
return Lang::has('auth.failed')
? Lang::get('auth.failed')
: 'These credentials do not match our records.';
}
/**
* Get the needed authorization credentials from the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
protected function getCredentials(Request $request)
{
return $request->only($this->loginUsername(), 'password');
}
/**
* Log the user out of the application.
*
* #return \Illuminate\Http\Response
*/
public function getLogout()
{
return $this->logout();
}
/**
* Log the user out of the application.
*
* #return \Illuminate\Http\Response
*/
public function logout()
{
Auth::guard($this->getGuard())->logout();
return redirect(property_exists($this, 'redirectAfterLogout') ? $this->redirectAfterLogout : '/');
}
/**
* Get the guest middleware for the application.
*/
public function guestMiddleware()
{
$guard = $this->getGuard();
return $guard ? 'guest:'.$guard : 'guest';
}
/**
* Get the login username to be used by the controller.
*
* #return string
*/
public function loginUsername()
{
return property_exists($this, 'username') ? $this->username : 'email';
}
/**
* Determine if the class is using the ThrottlesLogins trait.
*
* #return bool
*/
protected function isUsingThrottlesLoginsTrait()
{
return in_array(
ThrottlesLogins::class, class_uses_recursive(static::class)
);
}
/**
* Get the guard to be used during authentication.
*
* #return string|null
*/
protected function getGuard()
{
return property_exists($this, 'guard') ? $this->guard : null;
}
}
One more thing for registration process. I am not using laravel's Request rather my own created 'UserRequest`. If any other information is needed. i would provide that. Any help would be appreciated.

Resources