django, using session in web for the first time - android

Client access the login view,
//user is properly set here
user = auth.authenticate(username=email, password=password)
auth.login(request,user)
The same client which requested the login view, requests another view
// I expect the same user I logged in previously here. But I see anonymous user here.
user = request.user
I don't know how exactly web server recognizes two different http requests (because http is connectionless) are coming from the same user. But I know that session is the concept that makes it possible.
I have MIDDLEWARE_CLASSES = ('django.contrib.sessions.middleware.SessionMiddleware',...) in my settings.py
Is there something else I need to check to make this work?
-edit
I debugged a bit,
django/contrib/auth/init:login does request.session[SESSION_KEY] = user.id
django/contrib/auth/init:get_user tries looking up request.session[SESSION_KEY] on next run and fails.
I need to understand what request.session is.
I thought request is something a client sends per http-request.(so it's not persistent)
** Below is my understanding, please correct me if I'm wrong **
When a user logins, server assigns a unique id for a user and send it to the user.
Server also stores relevant data for the id in somewhere persistent.
The user sends the unique id for every subsequent http-request.(this is cookie)
Django looks up data stored in step 2(or in other cases) with the id given.
Django puts the data in request.session and give to view.
I followed Django, request.user is always Anonymous User
I suspect all this is due to my custom authentication backends copied from http://www.micahcarrick.com/django-email-authentication.html
My First View.
#csrf_exempt
def login(request):
# import pdb
# pdb.set_trace()
email = request.POST['email']
password = request.POST['password']
user = auth.authenticate(username=email, password=password)
# auth.logout(request)
if user is not None and user.is_active:
auth.login(request, user)
profile = user.get_profile()
user_dict = profile.to_dict()
jsonUser = json.dumps(user_dict, ensure_ascii=False, cls=DjangoJSONEncoder)
return HttpResponse(jsonUser)
else:
raise Http404
My second view.
#csrf_exempt
def user_update(request):
import pdb
pdb.set_trace()
user = request.user
=> if not user.is_authenticated():
raise Http404 // always ends up here
print 'in user_update'
.......
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
# Uncomment the next line for simple clickjacking protection:
# 'django.middleware.clickjacking.XFrameOptionsMiddleware', )
my Backends
from django.contrib.auth.models import User, check_password
class EmailAuthBackend(object):
"""
Email Authentication Backend
Allows a user to sign in using an email/password pair rather than
a username/password pair.
"""
supports_inactive_user = False
def authenticate(self, username=None, password=None):
""" Authenticate a user based on email address as the user name. """
try:
user = User.objects.get(email=username)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, user_id):
""" Get a User object from the user_id. """
print 'getting an user for user_id: ', user_id
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None

You are right about http being stateless. However using cookie can help you maintain state of the request. When you call login function Django will save the user ID (encrypted value) in the cookie named sessionid. So the next time you get a request from the user, the browser will also send this cookie in the request header.
If you look at the table named *django_session* you should see an entry where session_key has the same value as cookie sessionid.
AuthenticationMiddleware keeps track of a user authentication and assigns user object to request.user
SessionMiddleware tracks session data for a user
That's how Django will track a user and its session.
If you really want to look into details you could have a look at authentication middleware code (django.contrib.auth.middleware), especially process_request to check how a user is added in request object.
Perhaps this is useful in debugging your issue?
EDIT:
Based on what helped Eugene from the comments.
When it's session related issue (login or session data) it's a good idea to check if the cookie is set properly on the client side. If it's a desktop browser, a tool like Firebug can be helpful by reading the http headers in "Net" tab of Firebug.
In Eugene's case it's an Android client, so one option is to debug Django middleware to check the values for request.COOKIE. If you are not receiving right cookies on Django end then the cookie is not set properly on the client side. One of the reasons for this on a browser is cookies could be disabled.
So it's a good idea to check client side settings to make sure cookies are stored and sent correctly.

Related

Is Captcha good solution for android authentication?

I'm developing an application (as a part of team) for android that interacts with server (asp.net web service) for synchronize and update information in client side.
for preventing attack to server we use SSL connection and also authenticate users with soap header message contains username and password.
here is the scenario for synchronization:
users send web service request with header contains : username , password , time of request , and(for preventing man on the middle attack) hash code of all three parameters(username+password+time) as message signature
web service check that :
is this a new message by checking the signature of message stored in server
if this is a new message (and its not duplicated) then check that signature is true by hashing all three parameters(username+password+time)
then check expiration time : is the message new ( in 5 minute ) for expiring old messages
Authenticate username and password
validate datatype and length of parameters ( in this case only time of device's last sync )
response to request
device get the response as xml file
the question :
because of this scenario we have to give user's devices authentication information so they could interact with server in future and also we don't want to get any information like username and password from users ( for user experience purpose! )
so we build a Web Handler Captcha in server and when users are new, we send them a captcha image generated by their device code(it is uid generated by device something like : https://www.server.com?appid=00000000-0000-0000-0000-000000000000 ) and when if user sends the correct captcha to server we add a new user to our database ( auto username and random password ) and save to the android's account manager for future use
in your opinion is this a good approach for authentication and security?
Thank you for tips
Https and a method to get a sessionId is enough security for most apps, anyhow my opinion:
Unless you include a secret within the hashed variables a "man in the middle" can change the parameters and forge a valid hash.
I would recomend a registration method. It's going to take device information as parameter, and the captcha if you will.
It's going to return a deviceId and a deviceSecret. The deviceSecret must not be transmitted again, just used as part of the hashes.
Also consider using a counter instead of time. It can help against replay attacks and it's easier overall.

ParseUser.getCurrentUser() confusion

I'm using Parse as the backend.
To check if the user is logged in I use ParseUser.getCurrentUser(). What I don't understand is, if the user changes his password from somewhere else (another device, the web-client), will this ParseUser return with some kind of error?
I don't think it does a check on the server, so I think it just returns the last saved user. This mean that I can continue to use this user (with an old password) or will I get a "wrong credential" response on the first request to the servers?
If I don't get it, will I at least get it when setting an ACL with parseObject.setACL(new ParseACL(ParseUser.getCurrentUser()));?
Try same action on yahoo in 2 open browsers of different types and see what you get?
Each client's been handed a token value by the respective servers and until the token expire will not be prompt for a new logon.
Well IMO Parse work very similar except the lease on Parse token never expire.
Response to the original parse logon contain the token value which the SDK may retain. Details are in the docs section on Rest api / user logon...
So, if a diff client change password but the token lease over on some other client never expire, the other client stays logged in.

Rails api and native mobile app authentication

I know there is a lot of information about this topic, but I can't find any that is up to date.
I see topics like this one relating to rails and android authentication but I see that TokenAuthenticatable is now removed from devise.
My question is simple: is there a good way to authenticate users from native Android and iPhone apps using Rails 4? Does anyone know of good tutorials or articles that provide a solution ?
Adam Waite Adding a bounty:
I have just opened a 500 bounty on this question because I can't find the correct practice for authenticating a user from an iOS app to a Rails API anywhere. This is what I was considering doing but have no idea if it's secure or not?!:
Let's assume we have a User record. A user has signed up for an account which has created a User record in the database with an email column and a password_digest column.
When the user signs-in I would like that user to remain authenticated on the mobile app until explicitly signing-out.
I imagine we're going to need a token based authentication. I would perhaps create an ApiKey record when the User is created and have that saved as an association on the User record.
When the user signs in/up, the response will contain an API token (something like SecureRandom.hex) which will be saved in the iOS Keychain and used with all subsequent requests to verify the user by passing it in a header and verifying it using something like:
before_filter :restrict_access
private
def restrict_access
authenticate_or_request_with_http_token do |token, options|
ApiKey.exists?(access_token: token)
end
Is this secure? Should I be refreshing the token with every request and including it in the response?
What other options do I have? What do the likes of Facebook, Twitter and Pinterest do?
I am aware of OAuth2.0, but is that not for granting external applications?
Is there a gem that manages any of this?
Sorry, completely unsure here.
500 to the best answer.
Gist of a solution from my research. Feel free to edit, correct, invalidate, etc.
SessionsController < ApplicationController
skip_before_filter :authenticate_user, :only => [:create]
def create
user = User.where("username = ? OR email = ?", params[:username_or_email], params[:username_or_email]).first
if user && user.authenticate(params[:password])
api_key = user.find_api_key
if !api_key.secret_key || api_key.is_expired?
api_key.set_expiry_date
api_key.generate_secret_key
end
api_key.save
render json: api_key, status: 201
else
status: 401
end
end
Note the ApiAuth.authentic? method and the request object. The request must be signed with an HMAC algorithm on the client.
ApplicationController < ActionController::Base
respond_to :json
force_ssl
protect_from_forgery with: :null_session
before_filter :authenticate_user
private
def authenticate_user
if authenticate_user_from_secret_key
return true
else
head :unauthorized
end
end
def authenticate_user_from_secret_key
userid = ApiAuth.access_id(request)
currentuser = userid && User.find_by_id(userid)
if ApiAuth.authentic?(request, currentuser.find_api_key.secret_key)
return true
else
return false
end
false
end
User creation/registration
UsersController < ApplicationController
skip_before_filter :authenticate_user, :only => [:create]
def create
user = User.create(user_params)
if !user.new_record?
render json: user.find_apit_key, status: 201
else
# error
end
end
Api key model. Similar to api key model in #352 railscast only difference is ApiAuth key generation.
class ApiKey < ActiveRecord::Base
before_create :generate_secret_key, :set_expiry_date
belongs_to :user
def generate_secret_key
begin
self.secret_key = ApiAuth.generate_secret_key
end while self.class.exists?(secret_key: secret_key)
end
User model.
class User < ActiveRecord::Base
has_secure_password
before_save :ensure_api_key
has_many :api_keys
def find_api_key
self.api_keys.active.ios.first_or_create
end
On the client side the HMAC algorithm must be used to sign requests.
The code is from:
[SHA1 HMAC Key generation/authentication] https://github.com/mgomes/api_auth
[Controllers & Models] https://github.com/danahartweg/authenticatable_rest_api
I've had this issue, I'm an API developer. You could do it the hard way with tokens and custom authorization, but I will tell you what we do with our application, which serves users in the six digit figure.
At least for iOS, the device will handle sessions for you, meaning that if a user on an iOS app makes a POST request to /users/sign_in with the parameters
user: {
password: 'mypassword',
email: 'testuser#example.com',
remember_me: true # optional
}
the iOS device will store the session for you, safely and persistently.
Now, if you want to go the OAuth 2 route, I actually maintain a gem for rails 4 called OAuth 2 providable, to which I added a pretty cool feature that allows you to have the user pass through the "authorization" screen, because obviously if you developed the software you don't need the user to confirm that they trust you.
If you do decide to use OAuth 2, you will need to use what is call the implicit access token.
This is the long and very boring OAuth2 spec for that
The rails 4 project can be found on github
https://github.com/bwheeler96/devise-oauth2-provider-rails4
If you're not on rails 4, you can use the original gem
https://github.com/socialcast/devise_oauth2_providable
By the way, the gem needs work so if there's anyone reading this who wants to help make it better, please by all means fork this repository
You are on the right track, but the user's token should only be used to identify which user is making the request. You still need some kind of authentication since, as you speculate with changing the token on each request, a hacker could intercept the data stream, get the token, and then "be" that user in subsequent requests.
By changing the token on each request, you eliminate the interception issue, but once someone has intercepted the token, they can then further exploit the system by continuing to intercept it and even modifying the response. One solution to this is to use HMAC (which is used by Amazon Web Services). It is an algorithm that provides a signature (hash) for your request that is unique for every request, doesn't require a changing key, and cannot be predicted for future requests.
There is a ruby gem for rails that implements HMAC on the server side for signing HMAC requests as well as generating them when doing server-to-server communications. For client-to-server requests as in your case, you need to generate the signature on the iOS or Android side and authenticate them on the server.
Consider the ApiAuth gem to do the work on the server side. On the iOS client side, consider the HBHMAC library for generating the signature. Take a look at the ApiAuth's specific implementation as it adds a timestamp to the data to prevent replay attacks, so you may need to add a field to your data before passing it to HBHMAC.
In summary, using HMAC authentication will avoid man in the middle attacks and replay attacks by utilizing a one-way hashing algorithm that prevents attackers from generating authentic requests even if they are able to intercept valid requests.
If you want to use OAuth2.0 in ruby on rails, you would be use Doorkeeper, you can see an example (not free) here:
http://railscasts.com/episodes/353-oauth-with-doorkeeper
But you can use a token with SecureRandom.hex, a example (not free) for this is here (in level 6):
https://www.codeschool.com/courses/surviving-apis-with-rails
I hope my answer help you!

Handling Sessions on Google App Engine with Android/IPhone

I'm starting to write an app whereby a mobile app (Android/IPhone) will communicate with the GAE backend (Python) through a series of Web API calls using JSON.
I can't use Google Accounts for authentication so I need to implement my own auth. I have an idea of how to do this, but I'm not sure if there is a better way.
Can anyone help with some code examples/suggestions of how to achieve the below please?
Method
Mobile app calls a Login method on the server which authenticates and creates a session key in the store and returns this to the app - not sure how to generate the key/session or where on the request/response it should be.
On every call, the app passes this key for the server to authenticate and allows the action if it passes.
User should not have to login on mobile again unless they explicitly logout or lose the key.
Login Method - without key generation
class Login(webapp.RequestHandler):
def post(self):
args = json.loads(self.request.body)
email = args['e']
pwd = args['p']
ret = {}
user = User.gql('WHERE email = :1', email).get()
if user and helpers.check_password(pwd, user.password):
ret['ret_code'] = 0
ret['dn'] = user.display_name
else:
ret['ret_code'] = 1
self.response.headers['Content-Type'] = 'application/json'
self.response.out.write(json.dumps(ret))
I think you should use features webapp2 providing to implement your custom registration.
from webapp2_extras import auth
from google.appengine.api import users
class RegisterHandler(webapp2.RequestHandler):
def post(self):
email=self.request.POST['email']
password=self.request.POST['password']
#Let webapp2 handle register and manage session
user = auth.get_auth().store.user_model.create_user('own:'+str(email), password_raw=password,email=email)
#user (True, User(key=Key('User', 80001), auth_ids=[u'own:useremail#mail.com'],email='useremail#mail.com',password=u'hashed_password',...))
if not user[0]: #user is a tuple
self.response.write(user[1]) # Error message
else:
#You can extend your User Model e.g UserProfile(User): or have a UserProperty in your profile model as the example.
profile=UserProfile(user=users.User(user[1].email)).put()
self.response.write(str(profile.key()))
class LoginHandler(webapp2.RequestHandler):
def post(self):
email = self.request.POST.get('email')
email = self.request.POST.get('password')
# Try to login user with password
# Raises InvalidAuthIdError if user is not found
# Raises InvalidPasswordError if provided password doesn't match with specified user
try:
auth.get_auth().get_user_by_password('own:'+email, password)
#Return user_session with User id,
except InvalidPasswordError, InvalidAuthIdError:
#Error
You can check user logged in by:
if auth.get_user_by_session():
#Logged in
else:
#Not logged in
On your client application(Android, IOS). You only have to store the response cookie and send it for every sub sequence requests.
Good luck :)
Have a look at webapp2 and webapp2 extras with sessions, auth and JSON
I cannot see why you would need a session?
Sessions on App Engine are persisted in the data store, so if you can keep your requests stateless, I encourage you to do so.
As you will have your own user service which will authenticate the users, I suggest you use Digest authentication, as the secret is never included in the request.
There are libraries implementing Digest for most client and server platforms.
If you dont explicitly want to use Sessions etc. you can simply use the Datastore. Try following this:
Get a unique deviceID/email to identify each unique user.
On request from a specific user, generate a random authentication key, and store it attached to the user's email/deviceID and probably the current timestamp and a loggedIn flag.
SO you have:
User email/id: someone#example.com
password: xxxxxxxxxx
Key : 2131231312313123123213
Timestamp: 20:00 12-02-2013
loggedIn : boolean value
This can be database model. Now whenever the user logs in:
Check email, password combination.
If valid, generate random key, and update the datastore with the new key
update timestamp with current time, and set loggedIn to True
Now return the key back to the client (Android/iPhone) in a JSON object.
Now on every request, Check the received key against the one in your datastore, and if loggedIn flag is set to true. If both OK, process the request.
Also, on Logout:
Just set the loggedIn flag in the datastore to False.
Hope this helps :)
Try gae-sessions for session management. It creates secure cookies for you and allows you to easily associate data with each user. Just provide your own logic for the initial authentication.
It was built specifically for App Engine and is pretty popular and super fast/scalable.
https://github.com/dound/gae-sessions
There are many ways to do this.
1) When you check the users login details if it checks out you can then create a random UUID or string and store the User object in memcache with the random string as the Key and the User Object as the value. Then return the random string along with your response headers. On the mobile when you are parsing the response, get this header and store it in the local cache. On all further requests keep sending this key back in the request header and in your controller get the User object from memcache using this key and proceed. If the object is not in memcache you can send back a response which prompts the user to log in.
2) If you dont want to use memcache you can store the User object in the session and on the client side while parsing the response get the session id from the response. Its usually JSESSIONID. Then store that and resend it with further requests. In the controller you can check if the current session has the user object else force login.
1) Another way to go would be to return the appengine key for the user along with the response and resend it.
Just google get response header from response. Then get the SESSIONID/JSESSIONID header, store and add the field with the same name and value to all further request headers. Thats the easiest way.
My first answer on stackoverflow and no code exapmles, dangit if only i knew python.

Android-Django user authentication-1

I am trying to refer user as foreign key in my django model AddRec(Having android at frontend)
at django side I have this code ,
this is django model,
class AddRec(models.Model):
user=models.ForeignKey(User)
about=models.CharField(User)
created = models.DateTimeField(auto_now_add=True)
class AddRecForm(ModelForm):
class Meta:
model=AddRec
#login_required
def add_record(request):
if request.method=='POST':
if not request.user.is_authenticated(): # if user is not logged in
response_data=[{"success": "0"}]
return HttpResponse(simplejson.dumps(response_data),mimetype='application/json')
current_user=request.User
description=request.POST['about']
new_rec = AddRec(user=current_user,about=description)
new_rec.save()
response_data=[{"success": "1"}]
return HttpResponse(simplejson.dumps(response_data), mimetype='application/json')
else:
response_data=[{"success": "0"}]
return HttpResponse(simplejson.dumps(response_data),mimetype='application/json')
When I execute the code above with Android as backend it gives me error "fatal exception".
The main thing is that I am not able to access the request the user sent from Android in django.
From the Android side I just send data with
nameValuePairs.add(new BasicNameValuePair("about", "123"));
and with httppost I am sending data.
Is it necessary to send user name from the Android side even if the user is logged in?
The authentication you are using stores session key in a cookie on the client side (android). Are you using HttpClient? if so you must use cookies.
Additionally, api's should be stateless. You should not be keeping a user logged in using cookies for an api. http://en.wikipedia.org/wiki/Representational_state_transfer There are a couple popular api authentication schemes that address this.
Are you sending csrf token with the request? If not you can explicitly disable csrf protection for your view using a decorator. https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#django.views.decorators.csrf.csrf_exempt (not recommended)
When posting a question please post error logs, tracebacks, basically everything you see when something doesn't go right.

Categories

Resources