Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Security] Add a JSON authentication listener #18952

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

Closed
wants to merge 4 commits into from

Conversation

dunglas
Copy link
Member

@dunglas dunglas commented Jun 2, 2016

Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets n/a
License MIT
Doc PR symfony/symfony-docs#7081

Add a new authentication listener allowing to login by sending a JSON document like:

{"_username": "dunglas", "_password": "foo"}.

It is similar to the traditional form login (but take a JSON document as entry) and is convenient for APIs, especially used in combination with JWT.

See api-platform/core#563 and lexik/LexikJWTAuthenticationBundle#123 (comment) for previous discussions.

  • Add functional tests in security bundle

@chalasr
Copy link
Member

chalasr commented Jun 2, 2016

👍 A great help for JSON APis!

@GromNaN
Copy link
Member

GromNaN commented Jun 2, 2016

Unless you have to pass the JWT and the login/password in the same request, the standard way for password authentication is HTTP Basic. This is supported out of the box in Symfony and easy to do with jQuery.ajax.
Then a simple controller that return a new JWT can be created as an entry point.

@chalasr
Copy link
Member

chalasr commented Jun 2, 2016

@GromNaN I agree about that HTTP Basic and form-data stay the standard way for getting a JWT (& simpler for most cases).
But that's not an absolute rule and, depending on the client's platform/language/framework or simply out of preference, JSON can be the way to go.
Also I think that this could be helpful for a large number of use cases therefore good to have in Symfony

@teohhanhui
Copy link
Contributor

Does this make https://github.com/gfreeau/GfreeauGetJWTBundle obsolete?

@dunglas
Copy link
Member Author

dunglas commented Jun 3, 2016

@teohhanhui AFAIK, GfreeauGetJWTBundle is for x-www-formencoded data, not for JSON documents.
@GromNaN it's more common to send JSON documents (or form data) than using HTTP Basic auth to get a JWT token. Most client-side and server-side libs work that way.

@teohhanhui
Copy link
Contributor

teohhanhui commented Jun 3, 2016

@dunglas:

GfreeauGetJWTBundle is for x-www-formencoded data, not for JSON documents

But the usual intention is to avoid form_login, which uses cookies. The fact that it uses x-www-form-urlencoded seems to me simply due to ease of implementation (the code seems to be adapted from Symfony's UsernamePasswordFormAuthenticationListener).

@jorge07
Copy link

jorge07 commented Jun 3, 2016

Why not a Request body listener like FOSRestBundle has? But that way you can use also XML for example... I'm already using exactly this way to login with Json on 3.0.6 with FOSRestBundle 2

throw new BadCredentialsException(sprintf('Missing key "%s".', $this->options['password_parameter']));
}

$username = $data[$this->options['username_parameter']];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about using property paths here? One might not always have the required information on the top level, but may want to wrap it in some other structure.

@dunglas
Copy link
Member Author

dunglas commented Jun 8, 2016

I've done some changes to this PR:

  • The provider is now stateless (it doesn't use the session)
  • It uses the PropertyAccess component to access the username and the password as brilliantly suggested by @xabbuh
  • Functional tests added

It is ready for review.

{
public function loginCheckAction()
{
throw new \RuntimeException('loginAction() should never be called.');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be loginCheckAction() should never be called..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could make use of __FUNCTION__ actually

@Simperfit
Copy link
Contributor

LGTM

@xabbuh
Copy link
Member

xabbuh commented Jul 4, 2016

The min version in the composer.json file of the SecurityBundle needs to be updated.

@dunglas Can you rebase here to hopefully let Travis run the job on PHP 7 again.

@dunglas dunglas force-pushed the json_authentication_listener branch from 8475884 to cd86c9e Compare July 10, 2016 08:33
@dunglas
Copy link
Member Author

dunglas commented Jul 10, 2016

Rebased against master and comments fixed.

@dunglas dunglas force-pushed the json_authentication_listener branch from 163a36a to 653bebb Compare July 17, 2016 10:02
@dunglas
Copy link
Member Author

dunglas commented Jul 17, 2016

ping @symfony/deciders (HHVM error not related)

@xabbuh
Copy link
Member

xabbuh commented Jul 18, 2016

Imo you should also add a functional test case covering a config where the username_path and password_path are actually used.

@dunglas
Copy link
Member Author

dunglas commented Aug 16, 2016

@xabbuh test updated.

@dunglas dunglas force-pushed the json_authentication_listener branch from 5c085a6 to ee40718 Compare October 25, 2016 11:05
public function handle(GetResponseEvent $event)
{
$request = $event->getRequest();
$data = json_decode($request->getContent());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we protect here ourselves by checking the max. length of the request content in the same way that we check the max username (Security::MAX_USERNAME_LENGTH) and password a bit later?

Copy link
Member Author

@dunglas dunglas Oct 25, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@javiereguiluz but what is the max length of the request? The login and password can be stored in any JSON document. It would be similar to checking the length of the form in the traditional login form and AFAIK we don't do it currently.

Copy link
Member

@javiereguiluz javiereguiluz Oct 25, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not an expert about this topic. I just saw this json_decode() that accepts the raw user's input and I was thinking about sending a 100MB request to make the application explode ;)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a security expert either, but it's the same for all endpoints in this case :) There are some configurations in PHP to avoid such problems (like post_max_size, max_execution_time and memory_limit). The check on the username length isn't related to DDOS attacks.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #18733

@dunglas
Copy link
Member Author

dunglas commented Oct 25, 2016

Docs added symfony/symfony-docs#7081

}

if (!is_string($username)) {
throw new BadCredentialsException(sprintf('The key "%s" must contain a string.', $this->options['username_path']));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The key "%s" must be a string.?

}

if (!is_string($password)) {
throw new BadCredentialsException(sprintf('The key "%s" must contain a string.', $this->options['password_path']));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The key "%s" must be a string.?

try {
$username = $this->propertyAccessor->getValue($data, $this->options['username_path']);
} catch (AccessException $e) {
throw new BadCredentialsException(sprintf('Missing key "%s".', $this->options['username_path']));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "%s" key must be provided.?

try {
$password = $this->propertyAccessor->getValue($data, $this->options['password_path']);
} catch (AccessException $e) {
throw new BadCredentialsException(sprintf('Missing key "%s".', $this->options['password_path']));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "%s" key must be provided.?

@dunglas dunglas force-pushed the json_authentication_listener branch from ee40718 to 8fd5666 Compare November 2, 2016 14:54
@fabpot
Copy link
Member

fabpot commented Nov 6, 2016

👍 for 3.3

@javiereguiluz javiereguiluz added this to the 3.3 milestone Nov 6, 2016
@dunglas dunglas force-pushed the json_authentication_listener branch from 8fd5666 to e0bb4e4 Compare December 2, 2016 08:22
@dunglas dunglas force-pushed the json_authentication_listener branch from e0bb4e4 to 10ecbe1 Compare December 2, 2016 08:27
@fabpot
Copy link
Member

fabpot commented Dec 3, 2016

Thank you @dunglas.

@fabpot fabpot closed this Dec 3, 2016
fabpot added a commit that referenced this pull request Dec 3, 2016
This PR was squashed before being merged into the 3.3-dev branch (closes #18952).

Discussion
----------

[Security] Add a JSON authentication listener

| Q | A |
| --- | --- |
| Branch? | master |
| Bug fix? | no |
| New feature? | yes |
| BC breaks? | no |
| Deprecations? | no |
| Tests pass? | yes |
| Fixed tickets | n/a |
| License | MIT |
| Doc PR | symfony/symfony-docs#7081 |

Add a new authentication listener allowing to login by sending a JSON document like:

 `{"_username": "dunglas", "_password": "foo"}`.

It is similar to the traditional form login (but take a JSON document as entry) and is convenient for APIs, especially used in combination with JWT.

See api-platform/core#563 and lexik/LexikJWTAuthenticationBundle#123 (comment) for previous discussions.
- [x] Add functional tests in security bundle

Commits
-------

02178bc [Security] Add a JSON authentication listener
@dunglas dunglas deleted the json_authentication_listener branch December 3, 2016 14:23
xabbuh added a commit to symfony/symfony-docs that referenced this pull request Dec 14, 2016
This PR was merged into the master branch.

Discussion
----------

JSON authentication listener docs

Docs for symfony/symfony#18952.

Commits
-------

b192ab3 Fixed a syntax issue
16ae3f6 Reworded and simplified the article
820f28e Fixed the name of the "username" property
6d018f6 Fixed a syntax error
ab5259b Removed a tip which is not too relevant for the article
d2dd895 Fixed the JSON format (this time for real)
6ff24da Fixed the JSON format
0961128 Show the simple example first and then explain the complex use case
68bd9a5 JSON authentication listener docs
@nicolas-grekas nicolas-grekas modified the milestones: 3.x, 3.3 Mar 24, 2017
@fabpot fabpot mentioned this pull request May 1, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.