Laravel Protecting Routes from other System Request - php

We have this system that our students access to get access to other platforms that we provide, such as Office 365 with student license and other programs...
We have access to create this access links, create an route and add some availables TAGS that they provide, such as student email, student unique code, student cellphone...
This links work as a bridge to our Laravel 6.0 application, that link should send the student to an internal page that they can create their office 365 account (if they dont already have) and redefine their passwords, but the problem is, I cannot garantee that this logged user will not change manually (from dev inspector) the data that is passed from the route parameter, and access other student data and change their Office password.
The point is, I can control that this page can be only accessed from this previous URL (this system that the student is logged), and It works, but I cannot do a Middleware from my application that check's if the user is logged in other application, and we don't have any API to check authentication from this system..
Is there any way to protect our routes from this other system?
Controller method that receive this parameters coming from the other system and verify the previous URL:
public function index($ra, $email){
if(url()->previous() != "https://other.system/" ){
return view('errors.503');
}
$usuario = UsuariosMicrosoft::where('login', '=', $ra)->get();
return view('portaloffice.pagina', compact('ra', 'email', 'usuario'));
}
This is my route:
Route::get('office365/{ra}/{email}', 'PortalOffice\PortalOfficeController#index')->name('portaloffice.usuario');

It's generally a pretty bad idea to secure things by keeping URLs secret. They're fairly easily sniffed or guessed.
The way projects usually protect from unauthorised access is to use the Auth guard, and with a relationship between the model you're trying to protect and the User model.
After setting up the models, relationships and guards you end up with something like this in your controller:
$user = Auth::user();
$user->UsuariosMicrosoft->get()
return $user;

Related

How to avoid multiple user sessions in symfony 4?

How can I prevent a register user from accessing the site from multiple devices?
I create a function onSecurityInteractiveLogin in a EventListener
<?php
namespace App\EventListener;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
class LoginListener
{
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
$user = $event->getAuthenticationToken()->getUser();
$session = $event->getRequest()->getSession();
//TODO validate if that user is logged in
}
}
But I can't get if the user is logged in other device and close that session, I found a solution but in Symfony 2.3 in here.
Can anybody explain me a solution in Symfony 4?
The short answer is that you can't.
The longer answer is more complex: there's no way for your site to know which devices belong to an anonymous user; from the point of view of the server, all the requests look like they are coming from random places (which they are).
However, once the user has logged in, you can enforce more restrictions. The trick lies in how you issue authentication tokens and how to associate them with a user record in your application. There are a lot of ways to skin that cat, but they all involve keeping track of how many authentications have been granted to a user's account. Usually authentication requests get tracked with the user's IP and the user agent string from their browser to help distinguish one of the user's logins from another. E.g. when you log into GMail, you can view all the logins that have accessed the account -- that could help you identify a fraudulent login, but it also shows you how many devices (or browsers) have been used to log in.

Using Laravel Passport to only access own account on a few Routes

My whole application has a lot of api routes that serve my frontend with ajax responses. I use Laravel Passport xsrf token protection to protect my routes and manage authentication. However, we are planning to serve an api that a specific type of user can consume. To go in more detail, here is a (fictional) example of what we want to achieve:
A company can have a lot vacancies.
My api routes are a lot, now I want to give the company owner the ability to get all his vacancies over our sdk and place them on his website. The Problem I am facing: As far as I understand passport correctly, personal access tokens are the thing I need. I don’t want a „log in with my application“ functionality (jet), how do I disable this? I want only the user to access his own informations, not from other users. And I probably want in the future to let the user register for different apis. So that he has multiple access tokens for different routes, but the routes are all together in one api.php routes file. I think I would need to use scopes for this, but how do I safely assign the scopes to the tokens, since this only does a single route?
Can someone help me to understand the concept of passport correctly?
I do not use passport, however it seems this issue could be solved with scopes (not needing to be tied to an access token). If you are struggling with getting the authenticated user, you could follow this post:
Get authenticated user with Laravel Passport and grant password
If you are struggling with how to write your scope, here is what I am thinking
You have a table containing companies called companies
You have a table containing employees called employees
You have a table containing vacancies called vacancies
You have a join table called company_employee
Now you can create a scope on your Vacancy model
class User {
public function companies()
{
return $this->hasMany(App\CompanyEmployee::class)
}
}
class Employee {
}
class Company {
}
class CompanyEmployee {
}
class Vacancy {
public function scopeMine($query)
{
$my_companies = auth()
->user()
->companies()
->select('company_id')
->pluck('company_id')
->get()
->toArray();
return $query->whereIn('company_id', $my_companies);
}
}
Then no matter how you are querying the vacancies (through an API or front end GUI), you can simply add the scope to your query presumably in your controller.
class VacancyController {
public function index()
{
return App\Vacancy::mine()->get();
}
}

Laravel 5.0 multiauth

I have an application which has two parts back-end, and front-end. In the back-end admin can log in, and in the front-end the client can log in. Now it has been implemented. All application's query is done by logged in user id in both admin and client end.
Now my app needs a functionality where admin can view client data as same as client see their profile.There are a lot of things in client end. I can you use Auth::loginUsingId($client_id). Here client profile is showing perfectly but admin loggin session is lost as expected.
How to achieve this while admin login remain and admin can see client full data?
Let me introduce the simpliest way to have login as client functionality. First, define asuser and returnback routes.
Routes and actions
Route::get('/asuser/{user}', 'AdminController#asuser')
->where('user', '[0-9]+')
->name('asuser');
Route::get('/returnback', 'ClientController#returnback')
->name('returnback');
In admin's controller:
public function asuser(User $client, Request $request) {
/* insert checking if user has right either here with some field
* like $user->is_admin or using middleware settings and Policy
*/
# who user is
$fromId = Auth::user()->getId();
# logging as a client
Auth::login($client, true);
# but keeping admin in a session
$request->session()->put('adm_id', $fromId);
return redirect()->route('some-client-route')
->with('status', 'You are logged in as a client');
}
And for returning back ClientController
public function returnback(Request $request) {
$fromId = Auth::user()->getId();
# getting admin id
$admId = $request->session()->pull('adm_id');
$adminUser = User::find($admId);
if (!$adminUser) {
return redirect()->back()
->with('status', 'Not allowed');
}
# logging out as a client and logging in as admin
Auth::logout();
Auth::login($adminUser, true);
return redirect()->route('some-admin-route')
->with('status', 'Welcome back!');
}
Is it ready for production
No, it's not. That's not a great solution, it's just a glimpse how to use it. Sessions have lifetime, so if admin doesn't return back in its lifetime, session variables are lost and he becomes a client (if remember me=true, as in the code above). You can store value not in a session but in a database column.
In addition as t1gor mentioned, you must pay attention to the fact that you can't log client's actions and send events when admin is a client. That's the most serious problem of logging as a client. Anyway, I suppose, it is easier to solve that, than to move all the auth logic out of the views.
Well, hope it is helpful.
I think a good way to manage client/user profiles is to implement an user management section at your backend, display and edit your users and their profiles there.
Laravel does not provide mixed sessions. You can only be authenticated as one user at a time. If you really need this kind functionality in Laravel 5.0 you could solve this by hackish user ping-pong (e.g. login temporarily as client and switching back to admin right after).
But it seems like your problem is more Authorization-related (in contrast to Authentication). Laravel implemented an authorization layer in v5.1.11. Since v5.0 is not supported anymore you should update regardless of this feature.
You can find more information about authorization in the official documentation: https://laravel.com/docs/5.1/authorization
I would rather suggest you separate the view logic e.g. business logic into some common layer rather then doing a "login-as-client" functionality. Even though it looks like a short-cut, you'll have a whole lot of things to think about.
For instance, how do you log application events now? Add a check everwhere that the session has a adm_id and log it instead of userId? This is just one example.
What I would have done:
Separate the view (e.g. user profiles, user content, etc.) from the session so that it is accessed by the ID in the URL or whatever else method, not by currently logged in user id.
Implement a propper role-based ACL. There are plenty of packages already. In your example, you wouold have an admin role and a client role, both havin permission object view-client-profile, for instance.
In the end, this might take a lot more time for development, but would defenitely save you some time debugging/troubleshooting with the angry client on the phone. Hope that helps.
I think middleware is the best possible option to filter the content between the admin and the normal user,because the code in the middleware run before any function call.
You just only need to set the usertype in the session and filter accordingly.
Visit:https://laravel.com/docs/5.4/middleware

Laravel dual authentication types

I am developing an application using Laravel 4, where I need to have 2 authentication types.
Type 1: Users - which are administators / back-office workers of the system.
Type 2: Customers - which are the visitors of the website who can do certain things (like purchase services) if they are authenticated.
The Type 1 Users are authenticated using username/password, so that fits nicely within the Laravel authentication model.
The Type 2 Customers will be authenticated either using OAuth style (with Google / Facebook) or manual authentication if the customer prefers. I do not want to mix the two together, so if you are authenticated as a customer I don't want the authentication filter to think you can access the admin pages, and vice-versa.
The two types will have their own tables (Users and Customers respectively). Is there a way to have a different Auth model running concurrently in some way? Or do I have to write my own thing for customers? What is the recommended approach in this scenario?
If I understand your question correctly this should set you on the right path.
You can simply set an account_level indicator in each table and wrap your admin routes in a filter that checks that the user's account_level is correct. For example:
in routes.php
Route::group(array('before' => 'admin_only'), function() {
Route::get('my-admin-route', 'AdminController#adminAction');
});
in filters.php
Route::filter('admin_only', function() {
if (!Auth::check() || Auth::user()->account_level !== Config::get('constants.ADMIN_ACCOUNT_LEVEL') {
return App::abort(404);
}
});
In order to log a user in that does not have a username and password in your system you would need to handle the OAuth connection separately and once you have a valid user you may use the Auth::login($user) method to get the user back into your usual application flow.
http://laravel.com/docs/4.2/security#manually

Zend Auth and ACL

I am hoping some can help me a little bit, I am currently developing my first site using a PHP framework, part of the site is spilt into a members area, this is where my confusion begins to surface, withing the members area I want normal members to be able to add new comments and edit there own comments, simple enough that I can just check the posters name against the username that is stored in the session, my confusion comes with differentiating between the 'normal' users and the higher level users who have the ability to delete and modify any ones comments etc, they should also be able to access the admin section of the site.
My question is should all user login through the same Zend_Auth controller, or should there be seperate controllers using Zend_Auth for each type of user or can all that be dealt with using Zend_Acl? Any help, advice, article, or tutorials would be greatfully appreciated. Personally I think the Zend documentation is a little raw on some classes.
Thanks in advance
sico87
I recommend the book "Zend Framework in Action" from Manning Publications as a great, up-to-date, introduction to this. It's available as PDF download, so you can have it now :)
But to answer this particular question:
Let's start by defining two key terms.
The "Auth" in Zend_Auth refers to Authentication, which proves someone is who they say they are (i.e. login).
The "A" in Zend_Acl refers to Authorization, which proves someone has the right to do what they're trying to do (i.e. access control).
Assuming the user has a single role...
Store the user's roles in the "identity" you get as part of Zend_Auth.
At login:
$auth = Zend_Auth::getInstance();
$identity = new stdClass();
$identity->user_pk = $user->getPrimaryKey();
$identity->user_name = $user->getName();
$identity->role = $user->getRole(); // select * from user_role where user_pk=xxx
$auth->getStorage()->write($identity);
In Controller:
$acl->add(new Zend_Acl_Resource('news'))
->allow('defaultRole', 'news');
Everything is denied by default, so you don't really need to specify:
->deny('defaultRole', 'news', 'add');
Further on in the Controller's code:
$identity = Zend_Auth::getInstance()->getIdentity();
if(!$acl->isAllowed($identity->role, 'news', 'add'))
{
header('Location: http://www.yoursite.com/error/unauthorized');
}
If the user's identity is not allowed to do "news->add", it will redirect them to the unauthorized page (assuming you've made such a page).
If the user had >1 role, you'd store an array of roles in their identity.
Then your check would go something like this:
$identity = Zend_Auth::getInstance()->getIdentity();
$isAllowed = false;
foreach($identity->role as $role)
{
if($acl->isAllowed($role, 'news', 'add'))
{
$isAllowed = true;
}
}
if(!$isAllowed)
{ // if NO ROLES have access, redirect to unauthorized page
header('Location: http://www.yoursite.com/error/unauthorized');
}
Hope that helps.
Yes, in most cases all of your authentication should go through the same controller. However, Zend Auth is not a controller type. Zend Auth is an API for utilizing common authentication methods like a database or http. Its job is really just to be a wrapper around the grunt work of writing authentication code.
Zend Acl is what you are looking for to distinguish between normal and privileged users. You only involve Zend Acl after the users have authenticated and logged in.
Most of what you need is in the ZF documentation. I read almost all of the documentation for Auth and Acl before it made great sense to me. Even though ZF's Auth, ACL, Storage_* and other classes are used very closely together, they all serve very distinct purposes. With a little time you will see that they build on each other nicely.
A couple of links to get you started:
Pádraic Brady's ZF Tutorial
Zend's DevZone article on ACL and MVC
I can understand why you are getting confused. I was/am still a bit confused. So, unfortunately I cannot answer your question directly. But, one thing i am doing in order to clarify all this stuff in my head is to think in terms of 'domain objects' as opposed to database records.
My tactic to deal with this issue is to create my own Auth Adaptor that is passed a 'User Base Object' along with the user credentials. My 'User Base' is kind of like a repository of users.
So the Zend Auth is left being 'an interface' to other Zend Components whilst i still have a bit more control over my system for storing and accessing 'Users'.
My User_Base class could be a wrapper around a Zend Db tbl or even just have some hard code in it that i can use for testing.
So in general-
design your own model of a 'user'
design your own Auth Adaptor - starting with the minimum interface required as outlined here: http://framework.zend.com/manual/en/zend.auth.html
and just keep it all simple and go slowly as you learn more about it.
well that's what i am gonna do anyway.
I aint even gonna bother with Zend ACL just yet til i have Auth clear in my head.
I'm revamping a legacy site and converting it to Zend MVC
These are some things (perhaps unconventional) that I have had to get to grips with for my 'model' to work. :
an app may be used by users from multiple 'user bases' - openID, legacy users table, new users table, fleeting guests, etc
a guest's identity might just be a hash created when they first arrive
whereas, a legacy user's identity might be represented by an id in the legacy users table
users and user_accounts are separate things. don't try to mix them into one concept cos it could get complicated.
there may be many different types of accounts in the system. I.e. Buyers Accounts versus Sellers accounts. Readers_Account versus Writers_Account
accounts 'have' users - 'primary account holder', 'admin super user', etc
the relationship between the users and an account are represented by, say, 'account_users' (a local subset of all users in all user bases)
roles arew attached to account_users (the users of that particular account).(As opposed to roles floating around )
don't be afraid to have more than one Zend application on a server to represent a website - e.g admin app, members app, front end app.
don't be afraid to let these apps use model objects stored in say 'shared models' folder, with the only model code that directly relates to the individual app sitting in the /application/models/foomodel folders.
each app might have its own custom Auth adaptor
an admin auth adaptor may only allow users from the 'admin users table' whereas a front end app's Auth adaptor might be able to authenticate users from the guest userbase, staff, or members user base.
might be a speical case where front-end apps session is cleared and replced by member session upon elevation when member logs in.
one user object per app per webclient at anyone time (as opposed to trying to reference a person with a guest user AND a member user - that's too complicated)
one session per user per app (namespaced to avoid conflicts with other apps that they may be logged into on that domain) - (as opposed to trying to simultaneously refer to 'the person using it' with a guest session AND a member session. again, that's too complicated)
ok i am starting to ramble....but you get the idea. Don't let the Zend_Auth+Zend Db tutorials that you see sway your own model. they are just simplified examples.
nuff said
I have a few questions about this piece of code
$auth = Zend_Auth::getInstance();
$identity = new stdClass();
$identity->user_pk = $user->getPrimaryKey();
$identity->user_name = $user->getName();
$identity->role = $user->getRole(); // select * from user_role where user_pk=xxx
$auth->getStorage()->write($identity);
$identity = Zend_Auth::getInstance()->getIdentity();
Are user_pk, user_name and role stored as cookies? Will someone that makes a cookie with the role-name able to access the secured parts of the websites? Shouldn't a password (with md5-encryption) be part of the identy as well so when can verify username and password with each request?

Categories