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

Skip to content

PR for #585, client_id behavior with prepare_request_body #593

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

Merged
merged 9 commits into from
Sep 21, 2018

Conversation

jvanasco
Copy link
Contributor

This PR addresses #585

I had to make the new test a little bit 'dumb' to keep it simple while maintaining support under Python2 & Python3

  1. The order of arguments inserted into the request body is deterministic and can shift on different platforms (or even the same platform on different computers). Instead of sorting the result in the test, or generating a sorted Response body, I just test against 2 possible permutations.

  2. The test checks for a ValueError Exception and a DeprecationWarning. I couldn't manage to support a check for the expected error message on both platforms while maintaining a clear and concise test -- so I just omitted that check.

* `prepare_request_body` client_id is deprecated in favor of include_client_id
* a new unit test `test_prepare_request_body` is added to ensure conformity of several use cases
* the docstrings for the `body` param have been consolidated and standardized across multiple functions linked to `prepare_request_body` for clarity
integrated against requests_oauthlib idea
* added LegacyApplicationClient tests to ensure the grant supports a variety of allowed methods
@jvanasco
Copy link
Contributor Author

Cross reference to paired requests-oauthlib PR - requests/requests-oauthlib#331

Copy link
Member

@JonathanHuot JonathanHuot left a comment

Choose a reason for hiding this comment

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

Hi @jvanasco, I tried to review your changes, those are great. It is the in the right direction, the RFC's one ! While preserving ability to work with broken implem', that's great.

However, the include_client_id stuff should be moved to parameters.prepare_token_request instead. Why ? Because this auth stuff is not tied to a specific grant type, but to all: it is eligible to password (LegacyApplicationClient), refresh_token (base Client), client_credentials (BackendApplicationClient) and authorization_code (WebApplicationClient).

The good thing, is that all those Clients have a thing in common: they call parameters.prepare_token_request(.., **kwargs). Once that's done, I think you can also extend the tests for the other Clients, if possible.

Let me know your thoughts!

PS: don't hesitate to join in Gitter#oauthlib to discuss!

@jvanasco
Copy link
Contributor Author

However, the include_client_id stuff should be moved to parameters.prepare_token_request instead.

Agreed. I'll make the change and circle back here. I was just updating the tests, and they were starting to lead me to this same conclusion.

@jvanasco
Copy link
Contributor Author

My latest commit has the following:

prepare_token_request

This now accepts include_client_id and has the logic for popping the client_id out of the kwargs. ** The default is True, thought it might be better as None. **

I updated the docstring to note some fields with an asterisk * are not explicit kwargs but have special meanings or are expected. I did the same with the ServiceApplication as the same confusing phenomena happened there -- i.e. a docstring for a kwarg that isn't an enumerated kwarg.

Client.prepare_request_body

These were all extended to have an include_client_id argument as well. This is a pass-through to prepare_token_request; only the WebApplicationClient defaults to True. Others all default to None for backwards compatibility. This might not be the correct default for the other classes.

They all implement this code before invoking prepare_token_request.

kwargs['client_id'] = self.client_id
kwargs['include_client_id'] = include_client_id

Only WebApplicationClient has some logic to compare an explicit client_id to self.client_id and the deprecation warning, because this is the only class I know of which has some docs/examples supporting/old-code using client_id as a keyword argument.

Copy link
Member

@JonathanHuot JonathanHuot left a comment

Choose a reason for hiding this comment

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

LGTM! Would be great to have feedback from someone else.. poke @skion ?

# pull the `client_id` out of the kwargs.
client_id = kwargs.pop('client_id', None)
if include_client_id:
if client_id is not None:
Copy link
Member

Choose a reason for hiding this comment

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

It seems that client_id isn't used in this function except in this line... I'm not sure if I understand why we'd need include_client_id in this function's signature in that case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There was a request by @JonathanHuot (above) to migrate the include_client_id functionality into this function, as it is shared by a few endpoints/clients.

The section of code you cited pulls client_id out of the kwargs and conditionally appends it to params (line 144, not included above) - if it is None, it will not appear in the params, but an empty string will. This allows an empty string to be sent for client_id if the oAuth server requires/prefers that to omitting the argument (the RFC supports both, and we should expect some servers to be broken and support only one or the other). By pulling client_id out of the kwargs, the logic operating on the kwargs does not affect it -- that logic requires a true-ish value (so no empty string is possible).

include_client_id was put in the function's signature because it is defaulting to True. client_id was left out of the signature and documented as an explicitly supported kwarg because of it's significance in here.

an alternate approach would be removing include_client_id here, but then we'd have to implement the logic to include or exclude the client_id in each subclass method which invokes this method.

Copy link
Member

Choose a reason for hiding this comment

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

It feels a bit fiddly with the None, False, True options and I'd be inclined to put the logic in the individual client classes, but am happy with this too.

Copy link
Member

@skion skion left a comment

Choose a reason for hiding this comment

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

Excellent work on this @jvanasco and @JonathanHuot! Good to have in 3.0.

# pull the `client_id` out of the kwargs.
client_id = kwargs.pop('client_id', None)
if include_client_id:
if client_id is not None:
Copy link
Member

Choose a reason for hiding this comment

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

It feels a bit fiddly with the None, False, True options and I'd be inclined to put the logic in the individual client classes, but am happy with this too.

if kwargs[k]:
params.append((unicode_type(k), kwargs[k]))

if ('client_secret' in kwargs) and ('client_secret' not in params):
Copy link
Member

Choose a reason for hiding this comment

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

This might deserve a comment...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good idea.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

wow, thanks for this comment. i actually found a weird issue from this and am rewriting the function a bit!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed, and with a comment.

the outdated code will never find "client_secret" in params, because params is a list of tuples.

('client_secret' not in params)

the search should have been something like this:

('client_secret' not in [p[0] for p in params])

but that's ugly and inefficient.

in the fix, I just popped client_secret from the kwargs and compared it to None.

@@ -10,19 +10,26 @@

from ....unittest import TestCase

# this is the same import method used in oauthlib/oauth2/rfc6749/parameters.py
Copy link
Member

Choose a reason for hiding this comment

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

Feels superfluous as a comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Catching an ImportError for a fallback library has caused a bunch of problems for me in the past. Eventually someone changes the import strategy in one place, and you end up with tests (or functions) breaking because two functions/packages with the same name aren't actually the same. I wanted a callout in the tests that would point people in the right direction when a test breaks, to ensure it gets updated without a headache.

…ings

* fixed some formatting issues in `prepare_token_request` docstring
* slightly altered `prepare_token_request` in handling nontruthy values for `client_secret`.
@jvanasco
Copy link
Contributor Author

@JonathanHuot when you have time, please take a look at the last commit and review the 'outdated' comment regarding client_secret above. i found/fixed a small issue after the changes were approved.

@JonathanHuot
Copy link
Member

@jvanasco, I have no objections about the docstring changes. I bet we should do something better than playing with kwargs however that's not the purpose of this PR and what you did is great.

For client_secret, it is odd that unittest didn't caught this ? maybe we could add this test. However that's the right change 👍

@jvanasco
Copy link
Contributor Author

Existing tests didn't catch an error, because the block always generates the right output - it just generates the right output in the wrong way. The block correctly only acted on the client_secret if it was an empty string, but ran the comparison on every client_secret submission -- missing the shortcircuit exit that ensured it wasn't already in the kwargs.

# this line will always evaluate to True if `client_secret` is in the kwargs, it should have exited if already present
if ('client_secret' in kwargs) and ('client_secret' not in params):	
    # this comparison still worked correctly. 
    if kwargs['client_secret'] == '':

I'm not a fan of playing with the kwargs either, unfortunately it's just done a lot in this library. I did upgrade the docs whenever there is some kwarg action going on to make things more apparent.

@JonathanHuot JonathanHuot merged commit fabcf86 into oauthlib:master Sep 21, 2018
@JonathanHuot
Copy link
Member

That's merged! Thanks for this great contribution.

@JonathanHuot JonathanHuot added this to the 3.0.0 milestone Dec 3, 2018
@JonathanHuot JonathanHuot added the OAuth2-Client This impact the client part of OAuth2. label Dec 3, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
OAuth2-Client This impact the client part of OAuth2.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants