title: Authenticating via curl with Tasty Pie, using Session Authentication
body: <p>So, it seems that I can perform this action just fine from the browser, but I can't seem to replicate it via CURL. Any pointers on how this is supposed to work are greatly, greatly appreciated.</p>
  
  <p>I perform this request to log in a user:</p>
  
  <pre><code>curl -X POST -H "Content-Type: application/json" \ 
  -d '{"username":"tester", "password":"password"}' --verbose \
  http://localhost:8000/api/user/login/
  </code></pre>
  
  <p>And the response seems to indicate that the request was successful:</p>
  
  <pre><code>* About to connect() to localhost port 8000 (#0)
  *   Trying 127.0.0.1... connected
  &gt; POST /api/user/login/ HTTP/1.1
  &gt; User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
  &gt; Host: localhost:8000
  &gt; Accept: */*
  &gt; Content-Type: application/json
  &gt; Content-Length: 44
  &gt; 
  * upload completely sent off: 44out of 44 bytes
  &lt; HTTP/1.1 200 OK
  &lt; Server: nginx/1.1.19
  &lt; Date: Wed, 11 Dec 2013 12:31:34 GMT
  &lt; Content-Type: application/json
  &lt; Transfer-Encoding: chunked
  &lt; Connection: keep-alive
  &lt; Vary: Accept, Cookie
  &lt; Set-Cookie: csrftoken=h4tjM6o3QyelsAvUhdqNJPinZRdJyrBz; Path=/
  &lt; Set-Cookie: sessionid=4tsny8kcl7j9x7icr6vptnq1ims89tzr; expires=Wed, 25-Dec-2013 12:31:34 GMT; httponly; Max-Age=1209600; Path=/
  &lt; 
  * Connection #0 to host localhost left intact
  * Closing connection #0
  {"success": true, "username": "tester"}
  </code></pre>
  
  <p>If I include only the CSRF token in my authenticated request, I get a 401. However, if I include both the CSRF token and the session ID, I get some kind of Python error. For example:</p>
  
  <pre><code>curl -X GET -H "Content-Type: application/json" -H \
  "X-CSRFToken: h4tjM6o3QyelsAvUhdqNJPinZRdJyrBz" --cookie \
  "sessionid=4tsny8kcl7j9x7icr6vptnq1ims89tzr" --verbose \
  http://localhost:8000/api/user/ | python -mjson.tool \
  </code></pre>
  
  <p>I get back from the server:</p>
  
  <pre><code>{
      "error_message": "getattr(): attribute name must be string", 
      "traceback": "Traceback (most recent call last):
  File \"/opt/phaidra/env/local/lib/python2.7/site-packages/tastypie/resources.py\", line 195, in wrapper\n    response = callback(request, *args, **kwargs)\n\n  
  File \"/opt/phaidra/env/local/lib/python2.7/site-packages/tastypie/resources.py\", line 426, in dispatch_list\n    return self.dispatch('list', request, **kwargs)\n\n  
  File \"/opt/phaidra/env/local/lib/python2.7/site-packages/tastypie/resources.py\", line 454, in dispatch\n    self.throttle_check(request)\n\n  
  File \"/opt/phaidra/env/local/lib/python2.7/site-packages/tastypie/resources.py\", line 551, in throttle_check\n    identifier = self._meta.authentication.get_identifier(request)\n\n  
  File \"/opt/phaidra/env/local/lib/python2.7/site-packages/tastypie/authentication.py\", line 515, in get_identifier\n    return request._authentication_backend.get_identifier(request)\n\n  
  File \"/opt/phaidra/env/local/lib/python2.7/site-packages/tastypie/authentication.py\", line 283, in get_identifier\n    return getattr(request.user, username_field)\n\n
  TypeError: getattr(): attribute name must be string\n"
  }
  </code></pre>
  
  <p>Looking at the lines of the errors is not particularly illuminating. Since this error doesn't occur unless --cookie is used, I'm presuming it's trying incorrectly to parse the cookie parameter.</p>
  
  <p>It should also be noted that I am using Neo4django, which I believe precludes me from being able to use API Key Authentication. The code for my user is as such:</p>
  
  <pre><code>class UserResource(ModelResource):
      class Meta:
          queryset = AppUser.objects.all()
          resource_name = 'user'
          fields = ['first_name', 'last_name', 'username', 'email', 'is_staff']
          allowed_methods = ['get', 'post', 'patch']
          always_return_data = True
          authentication = MultiAuthentication(SessionAuthentication(), BasicAuthentication()) 
          authorization = Authorization()
  
      def prepend_urls(self):
          params = (self._meta.resource_name, trailing_slash())
          return [
              url(r"^(?P&lt;resource_name&gt;%s)/login%s$" % params, self.wrap_view('login'), name="api_login"),
              url(r"^(?P&lt;resource_name&gt;%s)/logout%s$" % params, self.wrap_view('logout'), name="api_logout")
      ]
  
      def login(self, request, **kwargs):
          """
          Authenticate a user, create a CSRF token for them, and return the user object as JSON.
          """
          self.method_check(request, allowed=['post'])
  
          data = self.deserialize(request, request.raw_post_data, format=request.META.get('CONTENT_TYPE', 'application/json'))
  
          username = data.get('username', '')
          password = data.get('password', '')
  
          if username == '' or password == '':
              return self.create_response(request, {
                  'success': False,
                  'error_message': 'Missing username or password'
              })
  
          user = authenticate(username=username, password=password)
  
          if user:
              if user.is_active:
                  login(request, user)
                  response = self.create_response(request, {
                      'success': True,
                      'username': user.username
                  })
                  response.set_cookie("csrftoken", get_new_csrf_key())
                  return response
              else:
                  return self.create_response(request, {
                      'success': False,
                      'reason': 'disabled',
                  }, HttpForbidden)
          else:
              return self.create_response(request, {
                  'success': False,
                  'error_message': 'Incorrect username or password'
              })
  
  def read_list(self, object_list, bundle):
          """
          Allow the endpoint for the User Resource to display only the logged in user's information
          """
          self.is_authenticated(request)
          return object_list.filter(pk=bundle.request.user.id)
  </code></pre>
  
  <p>(You can view the entire contents of the file, if you need, at <a href="https://github.com/OpenPhilology/phaidra/blob/master/api/api.py" rel="nofollow">https://github.com/OpenPhilology/phaidra/blob/master/api/api.py</a>)</p>
  
  <p>So, in summary, the main questions/points of confusion for me:</p>
  
  <ol>
  <li>Which data must be sent via the curl request to send an authenticated GET/POST/etc.?</li>
  <li>Is the Authentication value correct for the User Resource?</li>
  <li>Am I supposed to be able to authenticate with only the CSRF token, or is the session ID also necessary?</li>
  </ol>
  
  <p>Thanks in advance for any insight on this!</p>
  
  <p>EDIT:
  Here is the custom user model we have.</p>
  
  <pre><code>from django.contrib.auth import authenticate
  
  from django.db import models as django_models 
  from neo4django.db import models
  from neo4django.graph_auth.models import User, UserManager
  
  
  class AppUser(User):
      objects = UserManager()
  
      USERNAME_FIELD = 'username'
  
      def __unicode__(self):
          return unicode(self.username) or u'' 
  </code></pre>