I would like to create a REST service with authentication for mobile devices. This is the first time I will be doing something like this, so I would like to receive some advise on how I would implement things.
For this I would need to create a signup form which let's the user signup for the services.
I see no issue here I can just post the form data to the server and let it return a response.
If the form is valid a new user object will be created and immediately be logged in. Also a API KEY will be generated using:
from django.contrib.auth.models import User
from django.db import models
from tastypie.models import create_api_key
models.signals.post_save.connect(create_api_key, sender=User)
The request, will return a 301 HTTP status and contain a redirect URI to fetch the API KEY.
After this step the app will request another URI (the URI received in the 301 response of the signup request) to access the API KEY (I will be using Tastypie's ApiKeyAuthentication scheme). The request will contain the session cookie received in the previous request response, this way to view will be secured and I will be able to user the login_required decorator.
The response will be plain JSON with username and api key.
These values will be stored somewhere in the app.
Any requests now made will add the username and API KEY stored in the app so further requests will be more secure.
Does this look like a good scheme to follow ? Are there holes in the design ?
Related
My current Android application requires users to login with Username and Password.
The Android application calls a REST web service for user login and I do not want to transmit the password as cleartext.
How do I go about securing my users passwords so that the server side can Identify/authenticate each user?
I am currently trying to employ the Jasypt library as follows:-
ConfigurablePasswordEncryptor passwordEncryptor = new ConfigurablePasswordEncryptor();
passwordEncryptor.setAlgorithm("SHA-1");
passwordEncryptor.setPlainDigest(true);
String encryptedPassword = passwordEncryptor.encryptPassword(userPassword);
...
if (passwordEncryptor.checkPassword(inputPassword, encryptedPassword)) {
// correct!
} else {
// bad login!
}
however my server side is written in .NET and as far as I understand the Jasypt documentation the password encryptors employ a random salt.
How can I have my server side code match the hashed users password I am sending it?
All my webservices have HTTPS endpoints, does this guarantee that no one can "see" my users passwords "in flight" when exchanging for an access token?
If you use Https(TLS) then your password is inaccessible to anyone intercepting the network.
You should hash the password string in your server side code not in the client
Also you can use OkHttp CertificatePinner to pin Https(TLS) certificate to your connection for avoiding man in the middle attacks.
A good solution would be to avoid using the traditional Email/Password approach to authentication and go with what another answer here suggested of OTP or One-Time-Password.
Consider the user experience: typing an email and password on a mobile device is cumbersome and annoying and awkward. Then they have to remember their password as well? The average person in the Western world probably uses 10 to 15 apps per day and we want to tax their human memory banks for another password to awkwardly type onto their phone while they are on a packed subway train?
Although it's deceptively challenging to put together, consider One Time Password. With it, a user enters in a phone number as an identifying token.
In theory, every single user has their own unique phone number and thats easy for a user to remember. Since your user is on their Android device, makes sense so far, right? And no awkward typing of email and password.
After they enter their phone number, we then text them a code to the mobile device, which is a 4 to 6 digit number. The user enters that code in the application, thereby proving they are the owner of the device that the phone number is tied into.
The benefit of OTP over Email/Password is that it requires very little memory on the users part. And yes, it's even better than OAuth because what if the user never signed in to a Gmail account or Github account via their mobile browser? Then they are back to Email/Password awkward style authentication for mobile device.
One-Time password is user friendly.
But you say okay, but is it secure and more importantly to the question: How can I have my server side code match the hashed users password I am sending it?
Right, so One Time Password technology is always an ambitious project to undertake IMO.
So we need to persist the code that the user should be entering into the device so we can compare it at some point in the future. When you generate a code, save it to Firebase so at some point in the future you can reach back out to Firebase and say the user with phone number 212-555-1212 just sent you the code 1234, is that the correct code?
So, the way Firebase works with OTP is you can store the code in Firebase. The challenge though is actually texting the user a code. This is an actual SMS message. To handle that, you can't use Firebase alone, you can integrate the extremely popular Twilio. Twilio is all about interacting with users via phone SMS messages and so we can make use of Twilio to text the user a code.
You can also take care of authentication or user system inside of Firebase. Once the user enters an OTP, we generate the JSON Web Token through Firebase.
So all the JSON storage and all the info that reflects who the user is, all that can be saved on Firebase.
But there is another part to that question I have not answered:
How do I go about securing my users passwords so that the server side
can Identify/authenticate each user?
Okay, so you need to compare the code on some server. It can't be Firebase because Firebase is simply a datastore, it is a place to store JSON data, it does not give us ability to run custom code.
So do you write a server for the comparison of codes? We do NOT want to do this comparison on the user's device.
So what do we do? Also, how do we generate a code? Don't use the user's device for that either.
So where do we generate the code? We know to use Firebase data storage to store the code, but how do we generate it?
That's a good job for Google Cloud Functions.
So Google Cloud Functions are code snippets that run one time on demand on Google servers. GCF have tight inter-operability and integration with Firebase data stores.
We can add some logic or processing to the data sitting inside of Firebase. GCF will allow you some custom logic to generate your codes and save them to Firebase and GCF can also compare the code once the user sends it in.
AWS Lambda and GCF are nearly identical in functionality so that could be an option as well.
You have to be careful about what you do. Consider implementing a common two-factor key-sharing algorithm, such as TOTP.
A pretty uncommon, but really good practice, is the client-side hashing. This of course doesn't stop the hacker from logging in to the user's account, but it stops them from obtaining the potentially reused plain-text password.
I recommend that changing E-mail and password are done under the reset password formula, such that E-mail/SMS confirmation is required. And finally, as you do it is extremely important that the connection, where the login happens is secure, for example, https/tls.
There are couple of things you need to consider while implementing authentication and authorization between client(Mobile app) and server.
Firstly, what authentication and authorization mechanism does your server have to request api endpoints? (Is it Two-Factor Auth? Is it bearer token (grant-type username and password) based? Is it bearer token (grant-type access-token) based?
Secondly, as you have mentioned server programming is .Net based but can you be more specific whether your service layer (Api ) written in WebApi 2 or OData ?
Finally, does your server allow to communicate with or without SSH i.e. HTTP vs HTTPS? If it's with SSH then its okay to transfer user credentials i.e. username and password over othewise it will be never secured to transer credentials over HTTP.
Then only it comes at your end i.e. in Android Mobile App to impelement the authentication and authorization mechanism as per server requirement to communicate with api endpoints.
For example, my server requires to implement token-based authentication (bearer token and grant-type password) to make every server request (GET, POST, DELETE, PUT) and I have implemented using retrofit client as like :
public Retrofit getRetrofitClient() {
// first add the authorization header
OkHttpClient mOkClient = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder()
.addHeader("Authorization", "XXXXXXXXXXXX")
.build();
return chain.proceed(newRequest);
}
}).build();
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.client(mOkClient)
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
.build();
}
return retrofit;
}
and my service is
public interface LoginService {
#POST("/api/token")
#FormUrlEncoded
Call<TokenModel> getToken(#Field("username") String username,
#Field("password") String password,
#Field("grant_type") String grantType);
}
Now I can use this token in every request to commuicate with server. I don't need to transfer username and password over public internet rather I use just token and it has 24 hours expiration ( as server has implemented this token expiration date).
Hope it helps you to understand the authenticaiton and authorization mechanism between cleint(Android Mobile App) and server.
I'm using LoginActivity template and I'm trying to login to a website with email and password using a standard http request. The site doesn't provide an API so I'm thinking of somehow mirroring the site login to fill the email and password boxes on the page then sending the login request.
Think of logging in to stackoverflow for example by taking the input of an email and password TextView (s) and sending a standard http request to the authentication server with those credentials exactly how it would happen in the browser (same requests and addresses).
I haven't done anything like this before and I have no idea if it's even possible so please forgive any ignorance on my part.
This is done in Android in a similar fashion as in the web browser. Namely, you will send a POST request with proper parameters, let's say a JSON Object for the sake of explaining which contains something like:
{
username: 'myUsername'
password: 'mypass'
}
This will get processed and if your credentials are correct, you will get a response which may contain a variety of data, among which the accessToken (it may be called a slight variation of this).
You are supposed to remember this access token and use it to fetch any other data from the site, because that token is used from there on to authenticate you. I have an API I personally made, and I send the accessToken as a parameter in every request for a resource that is unavailable to the unregistered user.
As for the technical side, I'm using a nifty library called OkHttp for sending the Http requests, and it's quite rewarding and easy to use. Here's a code snippet to see what I'm talking about:
//JSON is a media type for parsing json
//json is a json string containing payload e.g. username and pass like in the example
OkHttpClient httpClient = new OkHttpClient();
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Response response = httpClient.newCall(request).execute();
The only thing left to to for you is to properly parse the response. You can find various solutions on this topic, but I personally use 2 approaches, BufferedReader for huge responses using response.body().byteStream(), and plain old String for not-so-large responses using response.body().string().
This is not a short, but very thorough explanation, so feel free to ask for clarification if you do not get some part.
Assuming that you need to log in to sites like StackOverflow from your app with standard http request. That is simply impossible. Because no organizations will allow third party sites/apps handling their users' credentials. If they intend to share their resource with third party most organizations follow this procedure:
First they provide api for you to use.
With that api only you can make users to login i.e you can't handle those credentials
Then they give a token to you corresponding to the user.
With that token you can perform subsequent requests.
If the organization doesn't provide api then they most probably are in situation of not allowing third party sites/apps to access their users' resource.
I've set up a REST API on my site in order to return information from my database.
I'm implementing login and registration on my app right now. However, I'm not sure how to handle verifying user credentials (checking if an email is already registered, if a password meets its requirements, etc).
Since my REST API is not open to the public, would it be safe to pass the data like this:
/users/verify/email/{email_address}
/users/verify/password/{password}
Or is there a better (safer) way to do this? In other words, how can I authenticate and validate users when the login/register?
In REST you're talking about resources. A resource will have some state expressed through their properties.
With your example I would ask myself: "why verify an email", "why verify a password". Because you want to verify if a user can be registered.
So your resource will not be an email or a password but a user.
Verification is an action. Something which does not go well with a REST architecture.
What do you want to verify? You want to register a new user but also verify if he's allowed to register. So you'll try with some conditions to add a user to your collection of users. In REST with HTTP this can be done with a POST which acts like an add(User). The logic behind the request can then implement the verification rules on the user.
To post data just use the content body and use the headers for additional info. So I'd change my API to:
HTTP method: POST
Path: /users
Content-Type: application/json
Body:
{"email_address":"qsdfg#sdfgh.com", "password":"qlmkdjfmqlsk"}
Which simplifies your API to a single entrypoint for adding a user. Allowing or refusing to register the user can be communicated through the use of HTTP status codes and messages.
Of course sending passwords in plaintext is not a good practice but you can setup a secure connection with SSL or TLS to communicate.
Sending sensitive data in a URL is not a good practice btw. Servers can log the url which will show everyone with access to the log the password of the user.
The login is a bit different but not that much.
You'd need a resource which uniquely links a user to his conversation with your system.
HTTP method: POST
Path: /authentication
Content-Type: application/json
Body:
{"email_address":"qsdfg#sdfgh.com", "password":"qlmkdjfmqlsk"}
Response
Status-Code: 200
Content:
unique-id-to-my-user
The authentication could call your user api to enforce the rules and then generate the id.
You could use an OAuth2 implementation to handle this.
If your web service is Asp.Net WebAPI which will return an access token for the valid user, you can use Http POST request with username and password as body content.
For sample code, please take a look at my answer in the following question
Implementing Oauth2 with login credentials from native login page
For better security, use Https instead of Http.
Hope this helps!
You can use POST method.
/register with name, email, password for User registration
/login with email, password for User login.
Just make sure that you do not pass the password in clear. Perform some kind of encryption on it.
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.
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.