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

Suggestion for a REST Debug mode? (integration with flask-restplus) #142

Closed
zedrdave opened this issue Apr 24, 2018 · 13 comments
Closed

Suggestion for a REST Debug mode? (integration with flask-restplus) #142

zedrdave opened this issue Apr 24, 2018 · 13 comments

Comments

@zedrdave
Copy link

Apologies if this is only tangentially a jwt issue:

I am trying to figure out a simple way to enable a "debug mode" (conditional to FLASK_DEBUG) where @jwt_required requests succeed, regardless of the presence of an authorization header. That would be especially useful to be able to test using flask-restplus' automatically generated API docs and request forms.

Ideally, I would simply add a custom jwt.claims_verification_loader when in debug mode, but that callback does not seem to be called at all, if the header is not set altogether.

Is there a (clean) way to intercept the verification process higher up? Any other suggestions on the best way to implement a debug mode that will play nice with flask-restplus?

@vimalloc
Copy link
Owner

Right now I don't think there is an easy way to do this, it would probably involve monkey patching part of the library or importing a mocked version of jwt_required if app.debug was true.

This suggestion seems reasonable to me. I don't have much time to work on implementing that right now though. Would you be interested in putting together a pull request with that functionality? I could help point you in the right direction and what not.

Cheers 👍

@zedrdave
Copy link
Author

zedrdave commented May 1, 2018

Hi and thanks for your reply…
Right now, I seem to be heading in the direction of a larger rule-based authorisation scheme on my api and probably do not need this feature…

But I can probably take a stab at a PR nonetheless…

From what I can see, adding a check for an env variable in verify_token_claims would be the way to do it… Or is there a better place?

@vimalloc
Copy link
Owner

vimalloc commented May 1, 2018

I would make it a flask_jwt_extended option instead so that it is easier to test and more consistent with the rest of the extension. We could provide an example in the docs about how you could check for an env variable at the create_app time to set that option in the extension.

The biggest thing that users would have to keep in mind here is that they probably couldn’t use most of their endpoints by default. Anything that relies on a logged in user (looking current user info from a db for example) would fail hard because there was no current user present. Maybe we could provide a way for them to mock the current user instead? A callback function that allows them to say what data the dummy user should have (so that can make sure that their custom claims are available to them in debug mode). Doesn’t do anything for mocking their underlying data store, but that fallls outside of the scope of this extension.

Cheers.

@zedrdave
Copy link
Author

zedrdave commented May 2, 2018

Indeed, it would be much more useful to have a callback that sends back a fake identifier (I wouldn't load the user itself, as it would make more sense to go through the existing callback for that, no?).

In that case, how about adding a check in _decode_jwt_from_request for a certain callback (fake_token_callback?). If that callback is present, return its value (a decoded token dict) directly. That seems cleaner than doing it inside each jwt_required, jwt_optional etc decorator…

@vimalloc
Copy link
Owner

vimalloc commented May 2, 2018

Seems totally reasonable to me 👍

@vimalloc
Copy link
Owner

vimalloc commented May 2, 2018

For a bit of extra protection from shooting ones self in the foot, maybe there should also be an extra protection where it needs a fake token callback defined and the app needs to be running in debug mode for this to work.

@zedrdave
Copy link
Author

zedrdave commented May 3, 2018

Probably a good idea. Should we just ignore the callback if app.debug != True (maybe with a console output), or throw an exception?

@vimalloc
Copy link
Owner

vimalloc commented May 3, 2018

Ignore or issue a warning https://docs.python.org/3.8/library/warnings.html. I think the warning would probably be better, but a case could be made either way.

@zedrdave
Copy link
Author

zedrdave commented May 3, 2018

OK. Let's go with ignoring with a warning… 😁

I'll try and put together a PR later today.

@zedrdave
Copy link
Author

zedrdave commented May 3, 2018

@vimalloc OK, I finished an update that seems to work as expected. You can check the code first for comments and let me know if you want a PR: https://github.com/zedrdave/flask-jwt-extended

  • I added an entry in the doc, but not sure if you want to mention it somewhere else.
  • Haven't written a test for it yet. But can try, unless you prefer to write it
  • Wondering if there shouldn't be a console output warning dev that fake token is being used

@vimalloc
Copy link
Owner

vimalloc commented May 4, 2018

  • I think that's fine, thanks!
  • If you can write a test for this, that would be very much appreciated. There is an example in test_config.py that you could use to verify the warnings work properly
  • I think that's a great idea.

@vimalloc
Copy link
Owner

Another option is available for this issue with the new 3.9.1 release. You could build your own decorator instead of using the built in jwt_required decorator which checks if an environmental variable (or setting or whatever) is set, and if so don't do any token verification and store some dummy data in the context stack (ex:ctx_stack.top.jwt = jwt_data or ctx_stack.top.jwt_user = sqlalchemy_user). The context stack is important, as it is what various helper functions like like jwt_identity and get_jwt_claims working.

Messing with the context stack internals obviously isn't the most ideal solution, as if there are ever any changes to this library there is no guarantee that those will still work as expected. But this does provide a way to start using this functionality right now. Maybe I could expose a set_jwt_token and set_jwt_user or something to provide a stable API for modifying the context stack with ones own decorators 🤷‍♂️

Some docs on getting started with building your own decorators can been seen here: http://flask-jwt-extended.readthedocs.io/en/latest/custom_decorators.html

@vimalloc
Copy link
Owner

Or heck, perhaps even simpler would be to not use a custom decorator, but add a flask before_request to inject a jwt into the headers of each request.

@vimalloc vimalloc closed this as completed Jun 3, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants