jazzband / djangorestframework-simplejwt

A JSON Web Token authentication plugin for the Django REST Framework.
https://django-rest-framework-simplejwt.readthedocs.io/
MIT License
3.99k stars 660 forks source link

Creating tokens manually from admin interface #258

Closed eshaan7 closed 4 years ago

eshaan7 commented 4 years ago

It would be great if the administrator user could create tokens for user from the django admin interface.

I have tried to implement this by overriding the default OutstandingTokenAdmin like this:

class OutstandingTokenForm(forms.Form):
    user = forms.ModelChoiceField(queryset=User.objects.all(), required=True, initial=1)

    def form_action(self, obj, user):
        sliding = SlidingToken.for_user(user)
        return sliding

class CustomOutstandingTokenAdmin(OutstandingTokenAdmin):
    form = OutstandingTokenForm

    def get_readonly_fields(self, *args, **kwargs):
        fields = [f.name for f in self.model._meta.fields]
        fields.remove('user')
        return fields

    def has_add_permission(self, *args, **kwargs):
        return True

admin.site.unregister(OutstandingToken)
admin.site.register(OutstandingToken, CustomOutstandingTokenAdmin)

But this does not work. I just want a simple select input to select a user and then a create button that adds a new token to OutstandingTokens.

Any help regarding this would be greatly appreciated.

Andrew-Chen-Wang commented 4 years ago

Is there a reason for this? Yes, it's possible. You can find code here: https://github.com/SimpleJWT/django-rest-framework-simplejwt/blob/ce80c2d31f0d9aff6a246d30d9aaa27f1e57a364/rest_framework_simplejwt/tokens.py#L214

Actually returning the tokens in the interface is more of a Django issue. Imo, there is not good usage example for this (maybe for developing... but in that case just use curl)

eshaan7 commented 4 years ago

I need this because our project (https://github.com/intelowlproject/) has a CLI client and only the administrator should issue tokens to the user; since for added security, we have removed any endpoint for obtaining sliding token via basic auth. We are using the refresh-access token pair everywhere else.

PS: I was able to implement it. I have made a gist with the required code:

https://gist.github.com/Eshaan7/4485a089c4f51420067d3bcf0b5fa6ab

Hope it helps others too.

PS: Thankyou for this great library.

Andrew-Chen-Wang commented 4 years ago

@Eshaan7 Ah I see! Consider OAuth (django-oauth-toolkit). Generally greater security if you know which endpoints certain users can be picking out. Although I'm slightly concerned that you're thinking about JWT incorrectly. Based on what you're saying, are you saying you're only using the regular access-refresh token pairs? Are you using this package for cross-domain usage? Is this for browser (if so, don't ref #71) or (mobile) client (which is ok)? What is the expiration period of those tokens?

If you need any help in your project regarding security or this package, just ping me! I'm happy to help.

Note: I'm not sure what a sliding token technically is. I'm aware that it came from a different JWT package, but Dave was considering removal in the future as this functionality was only meant to port users from one package to this one. Just a heads up.

eshaan7 commented 4 years ago

@Andrew-Chen-Wang Thanks for your interest. Our project is not a Saas, it's a threat intelligence gathering tool that companies would integrate with their current set of security/incident response toolkit so ease-of-use is a big priority.

We have a web app in angular 9 that uses access-refresh token pair with rotation and blacklisting of old refresh tokens, and It works perfectly. In production, the angular and django both are served from same origin with nginx. For the command line tool/ library that interacts with the server, we are considering using sliding tokens with values SLIDING_TOKEN_LIFETIME=30 minutes and SLIDING_TOKEN_REFRESH_LIFETIME=7days.... because:

PS: IMO, django-oauth-toolkit is too advanced and heavy for our current usage.

eshaan7 commented 4 years ago

Just saw https://github.com/SimpleJWT/django-rest-framework-simplejwt/issues/154. This is a deal breaker, seems like we'd have to use access-refresh in the CLI tool as well. Is there a way to specify the lifetime of a token at creation without copying and modifying code from the library ?

Andrew-Chen-Wang commented 4 years ago

tl;dr Shouldn't there be a library already for how to render your Angular code into HTML and then insert your Django templates with jinja2 very easily?

I don't believe so. When I was creating a websockets security guideline for Django, I couldn't use this library. However, you can use a bit of this library's code for similar purposes (i.e. low-level coding with the JWT package itself).

Otherwise, no. SimpleJWT is just that: simple. Extension of the library is fairly easy imo, but I dislike flexibility regarding security (which is one of the reasons there are new frameworks besides OAuth now for authorization... and Auth0 keeps getting ganged up on).

I've never seen a good third-party frontend framework be able to do a proper example of integrating with SimpleJWT without getting into JS, leaking a portion of code for XSS, simply storing in a local storage, etc. I'm no frontend coder, but when I was browsing some of those articles, someone mentioned Axios. There's someone who created a library for AWS deployment w/ vue; I believe when I was looking through his source code, he was using Axios. Didn't get the time to properly digest it, but hope that gives some sort of inspiration.

I'm curious how it'll work for you guys. I'll take a look at your source code and see if I can tap into wherever you store the tokens.

Shouldn't there be a library already for how to render your Angular code into HTML and then insert your Django templates with jinja2 very easily? I mean that's all frontend frameworks are right? Is it just hard to map out where these values are supposed to go?

Edit: ah It seems like you found Dave's comment too in 154 about not wanting to keep the sliding token feature. I'm just most worried about frontend devs with these JS frameworks continuously using this library...

Andrew-Chen-Wang commented 4 years ago

@Eshaan7 This may be of interest to you: https://www.valentinog.com/blog/drf/ I haven't gone through it all, but perhaps this is the way of going about JS? It takes advantage of session authentication, which is exactly what you need for a browser based app.

eshaan7 commented 4 years ago

SimpleJWT is just that: simple. Extension of the library is fairly easy

Yes, I was able to understand the codebase and extend it as per our requirements. Now, we are using access-refresh token pair in the web with a shorter lifetime whereas a longer lifetime for Refresh Tokens created from the admin interface (to be used with the CLI).

You are very welcome to look at the code. Here's the final PR: https://github.com/intelowlproject/IntelOwl/pull/94

Shouldn't there be a library already for how to render your Angular code into HTML and then insert your Django templates with jinja2 very easily?

I don't think this can work because angular bundles your large application into smaller incomprehensible bundles of different .js files/modules. Also, the entire point of using a framework such as Angular 9 is so we don't have to write any templates in django or jinja2. Our django app therefore is a pure REST API that has no templates besides the default django's admin interface.

I've never seen a good third-party frontend framework be able to do a proper example of integrating with SimpleJWT without getting into JS, leaking a portion of code for XSS, simply storing in a local storage, etc.

Angular 2+ provides really good DOM sanitization for any kind of inputs/user content. Using best practices, XSS is something we don't need to worry about. You can look at the final angular code here as well. Briefly, we are using localStorage and not sessionStorage because we want sessions to persist. Plus, since we are rotating both tokens momentarily + blacklisting old token immediately + good protection against XSS, I'd say it's quite secure especially for an internal application.

Andrew-Chen-Wang commented 4 years ago

I see.

Should be fine then. SimpleJWT should be a secure package as itself; I just worry about a leaked package which could lead to a leaked SECRET_KEY with leaked OAuth credentials. Good luck!