I'm looking at implementing two-factor authentication for one of my projects. I've seen: https://github.com/bitbeans/Yubikey
https://github.com/antonioribeiro/google2fa
https://github.com/lahaxearnaud/laravel-u2f
And I want to leave the choice up to my users, on which and how many methods of authentication will be required. As such I know I'm looking at coding something special to achieve this but I'm not sure where to start.
My goal is to enable users to not use any additional authentication methods or allow them to use all additional authentication methods available. Ideally the login form would only require username/password; upon entering correct credentials the user would be directed to a new page for every authentication method the user has chosen to use.
laravel-u2f uses middleware; which I'm not against doing, but seems like too much extra logic to process for every request instead of just when logging the user in.
I've thought about replacing the default Auth driver but I'm not sure that's the best thing to do.
My final thought; and what I'm leaning towards is listening for the "auth.attempt" event and using that to check what additional authentication needs to be done. But I'm not sure how the best way to process getting additional authentication information from that.
So the reason I'm posting is looking for input on the best way to achieve what I'm looking for.
You could place a value e.g. full_authenticated
Session::put('full_authenticated', 'false');
and use it in the existing authentication middleware.
This way you cut the logic in the middleware section to one comparison.
If you want to add later more methods for authentication you should implement an interface/contract for a general authentication method.
Then you write a authentication manager class which sets full_authenticated in the session and handles the different methods for the different users.
Related
I'm starting with Symfony 3, and I need some guidance about how to proceed with the process of implementing dynamic authorization and authentication.
First of all, the authentication bit is mostly done, I've done it according to this link from symfony docs: http://symfony.com/doc/current/security/entity_provider.html. What I'm yet to understand is how to implement the interface function getRoles() in order to return a value from the database (I have a table Role related to the User table).
Secondly, the authorization part. My application will require the end user to create his own access mechanism, in other words, I have an interface where the user creates a Role, then defines what pages that Role will be able to access and what privileges it'll have (create, read, update, delete, and so on). Afterwards the roles are attributed to the application users.
All in all it is pretty standard stuff so Symfony must have a clean way to do it. What I figured out so far is that I'll have to use ACLs, so I did as in the docs: http://symfony.com/doc/current/security/acl.html
My honest question here is: What now? What steps do I take to fully implement the authentication mechanism? What should I do now in order to persist and retrieve the access rules? How do I relate them with the user Roles?
P.S.: This question might be sort of a duplicate of some other questions here, but truth being told, those questions did not help me either, nor my scavenging in the docs did.
So, your question is very broad. Anyway it is a good question, so I'm going to try to reply.
THE AUTHENTICATION
Nothing to say here, I simply hope you used FOSUserBundle as suggested by the article itself: is the best way to implement a registration/login system in Symfony and it will give you an idea of how the entire process works. Starting from scratch if you are not a Symfony experienced developer seems to not be the best idea.
Give FOSUserBundle a try!
THE AUTHORIZATION PROCESS
About authorization you have basically two options: the use of Voters and the use of ACL.
In my experience the best option is ever the use of Voters.
In most cases, in fact, you will have a bidirectional reference (see Doctrine's documentation about this) in your entities between the User and the object on which (s)he have rights. In this case the ACL is not required and even discouraged.
In fact, the ACL does nothing more than creating a relationship between two objects (the User and the Article in your use case). To manage this relationship it uses a table in the database and so it has to query it to get the relationship and check for the authorization rights.
But if you already have a bidirectional reference between the User and the Article/Group directly in your entities, then you already have this relationship in place and so you can use Voters and the use of the ACL is superfluous and even, as said, discouraged as it is a useless duplication.
If you don't have this bidirectional relationship in your entities, then create it: it will be certainly useful in the future for other things and, anyway, you will have ever the ability to access your linked entities directly from your entities tree!
More, in your scenario, you cannot use ACL as you will have custom rights/privileges on your objects: the voters, again, are the best option to build this kind of things.
Don't use ACL, but Voters instead
HOW TO PROCEED
The first thing I would do, is to list in an interface all the available privileges: after all, they are strictly related to your application business logic, as it is not possible for a user to make someone able to do something that your app cannot do: if your application doesn't implement an editing flow, then it is not possible for a user to give someone the ability to edit an article. It's obvious.
So, something like this may be good:
interface PrivilegesEnum
{
const CREATE = 1;
const EDIT = 2;
const DELETE = 4;
const READ = 8;
const OTHER = 16;
// ... Other privileges
}
As you can see, I've given a numeric value to each privilege: this will give you the ability to use bitmasks that is a really powerful mechanism to manage this kind of things: it allows you to use only one field in the database to list all the privileges.
You can read more about bitmasks here:
https://www.google.it/search?q=bitmask+php+example
How to implement a bitmask in php?
Why should I use bitwise/bitmask in PHP?
http://alanhollis.com/a-quick-guide-to-using-bitmasks-for-permissions-in-php/
https://codereview.stackexchange.com/questions/1509/php-bitmask-class
https://www.google.it/search?q=php+bitmask+theory
How to implement a bitmask in php?
http://php.net/manual/en/language.operators.bitwise.php
http://php.net/manual/it/language.operators.bitwise.php
https://code.tutsplus.com/articles/understanding-bitwise-operators--active-11301
https://code.tutsplus.com/articles/number-systems-an-introduction-to-binary-hexadecimal-and-more--active-10848
I used this system in the past and those are some useful links I collected. They might help you!
BUILD A FORM TO LIST PRIVILEGES
Another thing you may find useful is a FormType to list your available privileges: you can do this writing a simple custom FormType.
HOW TO MANAGE ROLES
To manage roles read how Roles are managed by the Security Component and in FOSUserBundle (on Stackoverflow)
THE RELATIONSHIP BETWEEN USERS AND GROUPS AND ARTICLES
Once you reached this point you should have some more entities, read more about Doctrine relationship mechanisms knowing it better and you should be able to relate your users with their role, their group and the articles.
Anyway you will have all the required conceptual and practical tools needed to think better at your concrete implementation.
FINAL NOTE
As you can see, implement such type how authorization process isn't so simple.
I suggest you to think very carefully if it is really required in this stage of the development of your app, because if you can defer it in the future, then I suggest you to do it.
If you want to go online as fast as possible, implementing this system will require a lot of time to learn, implement, debug and refact the code (I'm speaking of weeks, not days!).
So, if you have all this time, then, go to implement this system. But if you feel you haven't all this time, then go with a more "static" system, go online, and then make it more "dynamic".
After all, this is the Lean Startup era!
Good luck!
I was looking through the built in auth controllers and I noticed they use something called "Guards". Up until now whenever I made my own logins/register forms I never touched these and would usually just do things like:
Auth::attempt()
without any type of guard. I've tried looking up what exactly it is but I couldn't really find any information on it, could someone explain to me what the purpose of the guards are?
They're the definition of how the system should store and retrieve information about your users.
You can find the configuration in your config/auth.php file. A web guard is the traditional cookie store - so that web guard instructs Laravel to store and retrieve session information the classic way. The API guard, on the other hand, uses tokens. So you would use the API guard if you want to authenticate users and requests using an API token in the header (bearer) or query parameter.
You can also create your own guard if you wish, and there's also this good introductory blog post on the topic by Matt Stauffer.
Since I had the same question and the other answers did not provide me the information I was looking for (they explain perfectly what a guard does, but not why you should ever worry about calling its methods), I will provide another answer.
I was also unsure about the difference between methods provided by the auth() helper and methods provided by the guard itself auth()->guard(), as they seemed to do the same.
A quick dd(auth()) reveals that it returns an instance of AuthManager. So we can look up that class in the source code: On the bottom of AuthManager.php there is a __call() magic method which forwards all undefined calls to its own guard() method.
public function __call($method, $parameters)
{
return $this->guard()->{$method}(...$parameters);
}
This clearly shows us that the methods of auth() and auth()->guard() not only seem to do the same, but are exactly the same. So as long as the default guard should be used, an additional ->guard() can be omitted with peace of mind.
A guard is a way of supplying the logic that is used to identify authenticated users. Laravel provides different guards like sessions and tokens. The session guard maintains the state of the user in each request by cookies, and on the other hand, the token guard authenticates the user by checking a valid token in every request.
Guard role is to authenticate routes
Web guard will authenticate web routes
Api guard will authenticate api routes.
For other user types e.g Admin guard will authenticate admin routes and so on.
In my website, different pages like add new customers, customers list, firm or company panel.
should I call the controller for each panel or I should use the ajax for partial refresh.
Please suggest me what should I use, which is the best way for better application.
Ajax is always a better option, because it keeps the rest of your page intact, which is visually much more desirable. However, there must be enough error checking both on client and server side to ensure the validity and correctness of data.
The best way is to create layered structure like:
UI -> Controller -> Service -> Repository (Database Queries).
You can use Ajax to call functions in your Controllers which in turn invoke Service layer to solve business logic and get or set any data by calling the Repositories.
This approach is helpful especially when you need to create both Public as well as Admin interfaces of your website which appears to be necessary in your case.
I have used this tutorial for creating my user login in Laravel: Laravel Authentication Essentials. So I have a SessionController that contains the methods create, store and destroy, for showing the form, logging in and out respectively.
But there is no model in this tutorial, the validation and Auth::attempt is in the controller. And that doesn't feel right. I can not create a Session model, since the Session class already exists.
Should I put the login/out logic in the User model, or is there another way to do this that complies with the MVC architectural pattern?
First, remember (or know) that you can change everything in Laravel. If you need a Session model using a sessions table, go to app/config/session.php and change the Laravel sessions table to laravel_sessions:
'table' => 'laravel_sessions',
People are doing things differently these days, methods are improving on a daily basis and the way you do your code must be confortable to you. If you feel it is not right the way you are seeing people doing it, change it, Laravel give you the power to change and do things your way. And if you feel you just found a better way of doing it, share it.
This is a 2013 video and today Jeffrey is doing authentication in a completly different way. Sign up for a Laracasts account and take the full Build a Larabook video series to see how he's doing it now.
There's no Session model in this tutorial because he's not storing sessions (successful logins) in a sessions table.
In the tutorial he never touches the User model, so there is no login in the user model. The only thing he's using to do authentication is Auth::attempt(), a Laravel facade method which uses internally the user model (M), to find a user and check if the password matches. He's working with a Session controller (C) and everything related to login (or sign in) and showing login views (V) is done inside that particular controller.
If it is easier to you, you can rename SessionsController to LoginController, I, myself, don't really like the Sessions name for login, but that's a matter of taste not code correctness.
That being said I don't see an MVC (or whatever name people like to call it this week) problem in that video.
EDIT Answering the comment:
The purpose of the model is towards data, no data, no model. In the context of Laravel and a database management system, yes, no table, no model. In the context, for instance, of a client-server API, your server API (Laravel, Rails...) will provide data for your client model (Angular, EmberJS...), so, there will be no table directly related to the client model, but still a model.
But in that particular case you are accessing a model, the user model, via a service, the Authentication service.
I know that this problem was discussed so many times but I had found some solution and I'm not sure if it is the best and the most efficient approach.
My problem: I'm using fosuserbundle to handle user authentication and I would also like to prevent displaying of login, password resetting, etc. form for logged in users. Below I put some approaches:
The first one (which has been already implemented) based on the kernel events, there is a code
https://gist.github.com/walmen/871c13014b80c6a3d05d
The second approach which was mentioned by my colleague based on the method overloading (removing listeners and duplicate code in the each method which has some logic which shouldn't be displayed for logged in users)
Write custom annotation, i.e. #RequireAnonymous
As I mentioned before, I've already implemented the first approach but I'm not sure if it is the best and the most efficient solution (this listener would be called for each request - it is not too heavy load for application? How listeners affect the application, if they?).
The second approach is the easiest one of course but...code duplication doesn't sound really nice.
The last one might be the best but If we take a look on this example https://gist.github.com/cystbear/1391850 we will see that there is also problem with calling event during any controller call.
Any advice or other ideas with good arguments and explanation?
If I'm understanding you correctly, you can use the third approach with the JMSSecurityExtraBundle which is included with Symfony Standard.
On the action's you want to exclude from authenticated users you can do like so:
/**
* #Secure(roles="IS_AUTHENTICATED_ANONYMOUSLY")
*/
public function fooAction()
{
// stuff...
}
This ensures that the user requesting the specific path is not authenticated.
#Ramon not really because every user has the role IS_AUTHENTICATED_ANONYMOUSLY, even the authenticated ones.
What is more we don't want to throw an exception like "Access denied" or something but we want to 'hide' those pages thanks to the redirection.
What do you think about this https://github.com/FriendsOfSymfony/FOSUserBundle/issues/996#issuecomment-14812806 ?