Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DX] The built-in security listeners should support stateless authentication #11451

Closed
gfreeau opened this issue Jul 23, 2014 · 5 comments
Closed
Labels
DX DX = Developer eXperience (anything that improves the experience of using Symfony) Security

Comments

@gfreeau
Copy link

gfreeau commented Jul 23, 2014

The built-in security listeners such as "form_login" are designed to only work well when using cookies. There is a stateless parameter that can be set to true, however even when it is true and sessions are disabled, a cookie will be set. (The basic auth listener will work with stateless authentication)

This is mentioned briefly in the docs at http://symfony.com/doc/current/book/security.html#stateless-authentication:

If you use a form login, Symfony2 will create a cookie even if you set stateless to true.

And I confirmed it by reading the source for the security listeners.

If you check https://github.com/symfony/SecurityBundle/tree/master/DependencyInjection/Security/Factory, the basic auth listeners just implement the SecurityFactoryInterface, most of them inherit the AbstractFactory. Here are the built-in listeners: https://github.com/symfony/Security/tree/master/Http/Firewall. This is the one the 'form_login' uses: https://github.com/symfony/Security/blob/master/Http/Firewall/UsernamePasswordFormAuthenticationListener.php. In attemptAuthentication() a session variable is set.

In my projects, more and more I am not using symfony2 as a traditional framework, I have been disabling sessions and twig in the production environment and instead making heavy use of FOSRestBundle, JMSSerializerBundle, NelmioApiDocBundle etc. Instead I've been building my frontends with AngularJS and authenticating using Json Web Tokens. The frontend and backend are completely separated code bases.

I've been working on and contributing to the LexikJWTAuthenticationBundle and I created an additional side project at https://github.com/gfreeau/GfreeauGetJWTBundle.

This implements a basic security listener that accepts input via post and returns a Json Web Token without creating sessions or cookies.

I think something like this should be in the symfony core and I'd go a step further and suggest we need to make a "Symfony Rest Edition", to go alongside the Symfony Standard Edition.

More and more developers are needing to write APIs for their mobile apps and single page applications, I think symfony2 should treat this use case as a first class experience.

@jakzal jakzal added the DX label Jul 25, 2014
@wheelsandcogs
Copy link

This sounds like something @lsmith77 and @willdurand might be interested in.

@xabbuh
Copy link
Member

xabbuh commented Jul 29, 2014

@gfreeau For the Symfony Rest Edition, did you notice https://github.com/gimler/symfony-rest-edition?

@fabpot
Copy link
Member

fabpot commented Jul 31, 2014

To summarize, Symfony does support stateless authentication except for the login form. If not, that's a bug somewhere.

Now, for the login form, it does make sense that a cookie is needed as I don't see how you would make it work otherwise (and passing the cookie as a query string does not qualify as a stateless auth method).

So, I'm not sure what this ticket is about.

@gfreeau
Copy link
Author

gfreeau commented Jul 31, 2014

@fabpot

The idea is for a security factory that is more advanced than http_basic but simpler than form_login.

For example form_login is cookie based, has other features such as remember me and doesn't support stateless authentication.

When building a rest api, you may use a token based authentication such as json web tokens. This means you might post a username/password and get a token back. This token is then sent in a HTTP Authorization header on every request to authenticate.

The security listener is easily implemented with the existing features of the security component, it is easy to create a new listener. In the case of json web tokens, this is done by https://github.com/lexik/LexikJWTAuthenticationBundle

However, to get the initial json web token, if you used a built in symfony security listener, it would set a cookie if you used form_login, even though it is not needed.

I tried to implement something simple for my project at https://github.com/gfreeau/GfreeauGetJWTBundle. It is a simple factory that takes a username/password and returns a json web token.

If there was a generic listener that could take a username/password and fire your custom success/failure handler, it would make implementing this simpler.

https://github.com/gfreeau/GfreeauGetJWTBundle is an example of this, it can be configured to take a username/password and then it fires success/error handlers. This bundle is configured to only work with the json web tokens bundle, but it could be generic and put into symfony core.

The proposal is a generic listener that takes a username/password and fires success/error handlers. It is simplier than form_login and doesn't assume you are using cookies, but is more advanced than basic auth.

fabpot added a commit that referenced this issue Sep 24, 2015
…back into security) (weaverryan)

This PR was merged into the 2.8 branch.

Discussion
----------

New Guard Authentication System (e.g. putting the joy back into security)

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | at least partially: #14300, #11158, #11451, #10035, #10463, #8606, probably more
| License       | MIT
| Doc PR        | symfony/symfony-docs#5265

Hi guys!

Though it got much easier in 2.4 with `pre_auth`, authentication is a pain in Symfony. This introduces a new authentication provider called guard, with one goal in mind: put everything you need for *any* authentication system into one spot.

### How it works

With guard, you can perform custom authentication just by implementing the [GuardAuthenticatorInterface](https://github.com/weaverryan/symfony/blob/guard/src/Symfony/Component/Security/Guard/GuardAuthenticatorInterface.php) and registering it as a service. It has methods for every part of a custom authentication flow I can think of.

For a working example, see https://github.com/weaverryan/symfony-demo/tree/guard-auth. This uses 2 authenticators simultaneously, creating a system that handles [form login](https://github.com/weaverryan/symfony-demo/blob/guard-auth/src/AppBundle/Security/FormLoginAuthenticator.php) and [api token auth](https://github.com/weaverryan/symfony-demo/blob/guard-auth/src/AppBundle/Security/TokenAuthenticator.php) with a respectable amount of code. The [security.yml](https://github.com/weaverryan/symfony-demo/blob/guard-auth/app/config/security.yml) is also quite simple.

This also supports "manual login" without jumping through hoops: https://github.com/weaverryan/symfony-demo/blob/guard-auth/src/AppBundle/Controller/SecurityController.php#L45

I've also tested with "remember me" and "switch user" - no problems with either.

I hope you like it :).

### What's Needed

1) **Other Use-Cases?**: Please think about the code and try it. What use-cases are we *not* covering? I want Guard to be simple, but cover the 99.9% use-cases.

2) **Remember me** functionality cannot be triggered via manual login. That's true now, and it's not fixed, and it's tricky.

### Deprecations?

This is a new feature, so no deprecations. But, creating a login form with a guard authenticator is a whole heck of a lot easier to understand than `form_login` or even `simple_form`. In a perfect world, we'd either deprecate those or make them use "guard" internally so that we have just **one** way of performing authentication.

Thanks!

Commits
-------

a01ed35 Adding the necessary files so that Guard can be its own installable component
d763134 Removing unnecessary override
e353833 fabbot
dd485f4 Adding a new exception and throwing it when the User changes
302235e Fixing a bug where having an authentication failure would log you out.
396a162 Tweaks thanks to Wouter
c9d9430 Adding logging  on this step and switching the order - not for any huge reason
31f9cae Adding a base class to assist with form login authentication
0501761 Allowing for other authenticators to be checked
293c8a1 meaningless author and license changes
81432f9 Adding missing factory registration
7a94994 Thanks again fabbot!
7de05be A few more changes thanks to @iltar
ffdbc66 Splitting the getting of the user and checking credentials into two steps
6edb9e1 Tweaking docblock on interface thanks to @iltar
d693721 Adding periods at the end of exceptions, and changing one class name to LogicException thanks to @iltar
eb158cb Updating interface method per suggestion - makes sense to me, Request is redundant
c73c32e Thanks fabbot!
6c180c7 Adding an edge case - this should not happen anyways
180e2c7 Properly handles "post auth" tokens that have become not authenticated
873ed28 Renaming the tokens to be clear they are "post" and "pre" auth - also adding an interface
a0bceb4 adding Guard tests
05af97c Initial commit (but after some polished work) of the new Guard authentication system
330aa7f Improving phpdoc on AuthenticationEntryPointInterface so people that implement this understand it
@fabpot
Copy link
Member

fabpot commented Oct 5, 2015

Closing as the new Guard layer should simplify the implementation of such a system.

@fabpot fabpot closed this as completed Oct 5, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
DX DX = Developer eXperience (anything that improves the experience of using Symfony) Security
Projects
None yet
Development

No branches or pull requests

5 participants