0

I'm having problems with testing Django rest api with cURL and Postman. I'm using LoginRequiredMixin to restrict access to my ClassView:

class UserList(LoginRequiredMixin, generics.ListCreateAPIView):
    model = User
    queryset = User.objects.all()
    serializer_class = UserSerializer

When an unauthorised user tries to access the page he is redirected to login page. In the URL is a ?next parameter so that user views the desired page right after authorization.

/accounts/login/?next=/users/

Problem is that cURL and Postman probably don't even use provided user name and password for authentication and are immediately redirected to the login page which is returned as a result.

Here is an example or cURL command. Even though user name and password is provided the result is 302 Found. When I add -L parameter for following redirects it returns the response from login page and doesn't redirect back to original page.

curl -i -L -u superadmin:superadmin http://127.0.0.1:8000/users/
HTTP/1.0 302 Found
Date: Fri, 13 Oct 2017 10:16:31 GMT
Server: WSGIServer/0.2 CPython/3.5.2
Vary: Cookie
Content-Length: 0
Content-Type: text/html; charset=utf-8
Location: /accounts/login/?next=/users/
X-Frame-Options: SAMEORIGIN

HTTP/1.0 200 OK
Date: Fri, 13 Oct 2017 10:16:31 GMT
Server: WSGIServer/0.2 CPython/3.5.2
Vary: Cookie
Content-Length: 1128
Content-Type: text/html; charset=utf-8
Cache-Control: max-age=0, no-cache, must-revalidate, no-store
X-Frame-Options: SAMEORIGIN
Expires: Fri, 13 Oct 2017 10:16:31 GMT
Set-Cookie:  csrftoken=cCfAfsSlHOZEQGvPD1RR33r1UXj6JtEscWKFjmVyHmvVasqMx2J0pqyeNbVpY3X9; expires=Fri, 12-Oct-2018 10:16:31 GMT; Max-Age=31449600; Path=/

<html>
    <head>
        <title>Login</title>
    </head>
    <body>
        <h1>Login</h1>

        <form method="post" action="">
            <table>
                <tr>
                    <td><label for="id_username">Username:</label></td>
                    <td><input type="text" name="username" id="id_username" autofocus maxlength="254" required /></td>
                </tr>
                <tr>
                    <td><label for="id_password">Password:</label></td>
                    <td><input type="password" name="password" id="id_password" required /></td>
                </tr>
                <tr>
                    <td colspan="2">
                        <input type="submit" value="Login" />
                        <input type="hidden" name="next" value="/private/meals/" />
                        <input type='hidden' name='csrfmiddlewaretoken' value='Pd3g7jmZ0WAACWihmRxNGvLF2wy5yzP9Pxylbdpc0u6RWIdegSpW2SSSVKaoN98Q' />
                    </td>
                </tr>
            </table>
        </form>

        <p><a href="/accounts/signup/">Sign up</a></p>
    </body>
</html>

I tried saving and loading cookie as suggested here but it doesn't work either. Is there any way to pass the LoginRequiredMixin in cURL and Postman? Or what is the proper way of access restriction in Django Rest Framework that would work with Rest API testers.

Thank you

Petr Hofman
  • 162
  • 1
  • 15

2 Answers2

1

You need to use an appropriate authentication mechanism. You need to check the what AUTHENTICATION_BACKEND you are using. Most likely you will be using session based authentication, which means you need to add a Cookie in Postman that contains an authenticated session.

To get the Cookie, login to your website via Chrome, open Developer Tools -> Storage -> Cookies. Look for your Domain and copy the Name and Value into the Postman app -> Cookies -> Manage Cookies for your domain.

This is not the appropriate REST API way of doing authentication. Postman provides support for varied authentication mechanisms like Basic Auth (which is what you are attempting to do with a username/password), OAuth, Digest Auth and several other techniques. If you intend to build REST APIs for your backend you will be better of using a Django API framework like Django REST Framework or Django Tastypie.

Pratik Mandrekar
  • 9,362
  • 4
  • 45
  • 65
0

Did you try using -e option ?

From curl manpage

-e, --referer <URL>

    (HTTP) Sends the "Referrer Page" information to the HTTP server. This can also be set with the -H, --header flag of course. When used with -L, --location you can append ";auto" to the -e, --referer URL to make curl automatically set the previous URL when it follows a Location: header. The ";auto" string can be used alone, even if you don't set an initial -e, --referer.

    If this option is used several times, the last one will be used.

    See also -A, --user-agent and -H, --header. 
  • Unfortunately it doesn't help either. I'm not using different code for other browsers and do not check from where the user comes. I'm not sure how to use the --header option or how it should help. I start to think that cURL and Postman don't even get to use the provided authentication and are redirected immediately by LoginRequiredMixin in Django. I'm not sure what other good access restriction in Django I have. – Petr Hofman Oct 13 '17 at 12:22
  • did you say that saving cookie didn't work? as in: curl -X POST -d "username=superadmin&password=superadmin" -c login http://localhost:8000/accounts/login; curl -b login http://localhost:8000/users/ –  Oct 13 '17 at 12:40
  • Wow. With a small modification it actually works. After logging by POSTing data to login page I got "403 Forbidden - CSRF verification failed. Request aborted." message. Which is weird because I have set the csrf token in login page properly. Nevertheless I tried setting csrf as parameters to curl command as advised [here](https://stackoverflow.com/questions/10628275/how-to-use-curl-with-django-csrf-tokens-and-post-requests) and it worked.
    Do you have any idea how to do it with Postman. Also could you post it as an answer. I would do it, but don't want to take your credit.
    – Petr Hofman Oct 13 '17 at 13:48
  • Can u post please the solution you ended up using as an answer? Thx. and congratz! –  Oct 13 '17 at 13:51
  • Thank you very much for your help, but I was happy too early :( The get methods work now, but post, put or delete still don't. 403 Forbidden - {"detail":"CSRF Failed: CSRF token missing or incorrect."}. There is probably something wrong or missing in my Class-based views that doesn't cause problems in the application but won't allow proper Rest API testing. – Petr Hofman Oct 13 '17 at 16:20
  • NVM in case of dangerous methods I just had to set --header with X-CSRFToken and --cookie with csrftoken and sessionid parameters in each command – Petr Hofman Oct 13 '17 at 17:38