remember me option in GAE python - python

I am working on a project in which i am working on a signup/login module. I have implemented the sessions in webapp2 python successfully. Now i want to implement the remember me feature on login. I am unable to find anything which can help me. I do know that i have to set the age of session. But i do not know how. Here is my session code.
def dispatch(self):
# Get a session store for this request.
self.session_store = sessions.get_store(request=self.request)
try:
# Dispatch the request.
webapp2.RequestHandler.dispatch(self)
finally:
# Save all sessions.
self.session_store.save_sessions(self.response)
#webapp2.cached_property
def session(self):
# Returns a session using the default cookie key.
return self.session_store.get_session()
Config:
config = {}
config['webapp2_extras.sessions'] = {
'secret_key': 'my-super-secret-key',
}
Kindly help me.

First in case you don't know the difference between sessions and cookies
What is a Cookie? A cookie is a small piece of text stored on a
user's computer by their browser. Common uses for cookies are
authentication, storing of site preferences, shopping cart items, and
server session identification.
Each time the users' web browser interacts with a web server it will
pass the cookie information to the web server. Only the cookies stored
by the browser that relate to the domain in the requested URL will be
sent to the server. This means that cookies that relate to
www.example.com will not be sent to www.exampledomain.com.
In essence, a cookie is a great way of linking one page to the next
for a user's interaction with a web site or web application.
.
What is a Session? A session can be defined as a server-side storage of
information that is desired to persist throughout the user's
interaction with the web site or web application.
Instead of storing large and constantly changing information via
cookies in the user's browser, only a unique identifier is stored on
the client side (called a "session id"). This session id is passed to
the web server every time the browser makes an HTTP request (ie a page
link or AJAX request). The web application pairs this session id with
it's internal database and retrieves the stored variables for use by
the requested page.
If you want to implement something like "remember me" you should use cookies because data stored in session isn't persistent.
For setting and getting cookies in webapp2:
response.headers.add_header('Set-Cookie', 'remember_me=%s' % some_hash)
request.cookies.get('remember_me', '')
I strongly recommend you to read this article that has explained this stuff thoroughly.

Related

Python Flask: limit requests sent to API

I'm new to Flask and I'm creating a website with the following functionality: I want to retrieve the user location and store it in a database in order to build some analytics about the website audience (and eventually, also include some degree of personalisation according to the user location).
In order to do so I'm using an external API (https://ipinfo.io) and my goal would be to send a GET request to this API, with the user IP address every time somebody logs in my website.
My current approach is this:
def get_my_ip():
# Get user id
ip_address = request.remote_addr
# Retrieve user location data
location_details = get_ip_location_details(ip_address="80.57.40.203", access_token=ACCESS_TOKEN)
# Store data in the database
webview = WebsiteView(**location_details)
db.session.add(webview)
db.session.commit()
And I'm passing this function to all my routes along with their function for rendering the templates.
# Home route
#app.route("/")
def home():
get_my_ip()
return render_template('home.html')
This actually works but sometimes the website sends multiple requests to the external API when somebody logs in or refresh the page (even though the user interaction with the website is the same and all the requests are successful)
I would like to store this information only once every time somebody logs in the website and in order to do so the only idea I got is putting some constraints in the database to not keep track of the same user in multiple records, but what I would also like to do is sending the least amount of requests to the Ipinfo API.
Is this something possible to tell the website to wait for the response of request before sending new ones?

Flask Blueprint Putting something on session

I was trying to put
session['logged_in'] = True
in the session, but in another blueprint it doesn't persist... Why is that?
Is there any better way to keep something in the session?
Extended:
I have a blueprint giving a form to login. When done and submitted, it will set a session key like above. Then it redirects via
return redirect(url_for('admin.index'))
to admin page where If I call the key via
session.get('logged_in')
I get "None" Instead of the True or False one.
I think I understand your confusion now~
Your flask session won't store anything on the server.
the 'session' dict is filled by the cookies from the client request.
Again. that is:
client make login request to server, and got a [login success] response as well as a [cookies] which contains the !!!sessionINFO!!! you think are stored on the server side.
Next time, you must send the whole cookies to the server again, then your session in the server may have data.
Browser will do this for you.
If you use a local client, say python requests library. Then be sure you are making requests with session (for requests-lib, it's requests.Session())
------------------OLD-------------------------------------
Though not an expert, but the case you described should not have happened.
The session is cookies data encrypted with a secret, if you have gone through the document mentioned by Beqa.
Just set
app.secret = '........'
And use session as a dict.
just FYI,
client request---->server (encrypt your_data 'logged_in' and client_relating_data 'maybe: ip, host or etc.', and put the encrypted info in cookies 'session=....') ------> client (get response with cookies)
client request again -----> server (decrypt the cookie 'session=...' with your secret), find the 'logged_in' data and know you are logged in.)
the cookies is something like below.
So, I'm not sure what's actually your trouble when using session, and put some basic information here. Just hope it helps in case.

Passing token to the client

I'm developing an iOS app and using Django for backend. There are two apps I'm using in Django
Django OAuth Toolkit to support OAuth authentication
Python Social Auth to support social authentication
The social authentication process should be:
GET localhost/login/{application}
Authentication on Application site
Redirect to localhost/complete/{application}
Fetch {application}'s access token
Create a new user with my server's access token, and associate it with {application}'s access token
Redirect to localhost/accounts/profile
Then, I can use my server's access token to communicate with {application}.
But the client will see that the browser start with localhost/login/{application} and end with localhost/accounts/profile, and still don't know what is my server's access token, so my question is how to pass the access token to the client?
One solution is that redirect with access token as localhost/accounts/profile?token=MyServerToken, but how to add parameter when redirecting to profile url?
You likely already have what you need on the Django session for your user in question. That is, provided you are using the session middleware (auth of this type is nearly impossible without it), your identity provider specific tokens will usually be populated in the extra_data dict on the SocialUser model for the specific provider in question.
For example, assuming you have a reference to the Django user model (lets call it user):
access_token = user.social_auth.get(provider='google-oauth2').extra_data['access_token']
Unfortunately the specifics will vary depending on the backend you're working with. Remember that these tools are designed to let users authenticate against your app rather than to let you perform arbitrary actions against the product-specific APIs exposed by the various identity providers.
As for passing these tokens to the client, I'd need to know more about your use case. Chances are the identity provider in question set some session cookies on the client during its authentication flow. For example, if you sign in with Facebook, they set a few cookies which are automatically retrieved by the Facebook client-side javascript API. As such, there's no explicit sharing of tokens necessary between the server and the client.
Otherwise, if you must do it yourself, store them on a secure session cookie as follows:
response.set_cookie(social_auth_tokens,
value=your_data_here,
max_age=None, #cookie will expire at end of user session
expires=None,
path='/',
domain=None, #only readable by this domain
secure=True, #only transmitted over https
httponly=False) #readable by scripts running on the page
You should not pass the access token in the query string like /?token=my_token. Its not a secure way and definitely not recommended.
Some other approaches you can use are:
Approach-1: Setting server_access_token in response headers
You can set the access token in the response headers and send it using HTTPS protocol.
The token will be sent once and consumed by the client. Since the response headers are not passed in the subsequent requests, the token will be passed only once to the client. Client will then use it to make further requests by setting the token in the request headers.
class MySocialApplicationRedirectView(View):
def get(self, request, *args, **kwargs):
# Here, write your code to fetch the {application}'s access token,
# creating a new user with your server's access token, and then
# associating it with {application}'s access token
# assign the response to a variable and set the access token as a header in the response
response = HttpResponseRedirect('/accounts/profile/')
response['X-Auth-Token'] = 'my_server_access_token'
# can also use the below name as 'X-' prefixed headers are deprecated
# response['Auth-Token'] = 'my_server_access_token'
return response
Client can then retrieve the token from the headers and use this token to make further requests. In further requests, he must send the access token in request headers.
Approach-2: Setting server_access_token as a cookie
Another option is to set the server_access_token cookie in your response as #Ben mentioned.
response.set_cookie() would set the server_access_token cookie in the response and then the client can read the cookie and send this in further requests in the request headers.
class MySocialApplicationRedirectView(View):
def get(self, request, *args, **kwargs):
# Here, write your code to fetch the {application}'s access token,
# creating a new user with your server's access token, and then
# associating it with {application}'s access token
# assign the response to a variable and set the access token as a cookie in the response object
response = HttpResponseRedirect('/accounts/profile/')
response.set_cookie(key, value='my_server_access_token', ..other parameters )
return response
Note: For safety and security, all requests (both to obtain and use the tokens) must use HTTPS endpoints.
It does not answer your specific question, but I've solved similar problem using TastyPie. It was very straightforward, didn't have to handle more than one application though, but since it provides an API for any given application, shouldn't be a problem.

Django - sessionid cookie - Is this a security failure?

In order to see this possible error you need to open two browsers and some plug-in to get/set cookies.
If you create a new project in django 1.7 and access to the admin site (/admin), and login succesfuly in the first broser and get the sessionid and csrftoken cookies and set them into the second browser login page and set a random user and password, you obtain a CSRF error and if you go back in the browser you are logged in.
how can avoid this?
I suppose, you can obtain same result just by copying sessionid cookie to another browser and navigating /admin. You don't need csrftoken to reproduce this issue. It's called sessionid stealing and all frameworks I know are vulnerable to this type of attack.
To avoid it, set SESSION_COOKIE_SECURE = True (default False) to protect your sessionid cookie from man-in-the-middle attacks. You will also need to install ssl certificate on your production server. Then configure it to redirect all http:// requests to https://. S in https stands for secure, this means all traffic between client and server is encrypted, and no one between client and server (client's ISP, server's hosting provider, proxies, etc) can read any data is sent. Including session cookie value.
And use SESSION_COOKIE_HTTPONLY = True (default) to protect session cookie from stealing via XSS. HTTPONLY means that this cookie will be sent with each http request, but won't be accessible from client's browser via javascript. So if some malware javascript managed to run in client browser, it will not have access to session cookie anyways.
Good tutorial on configuring secure django server can be found here: https://security.stackexchange.com/a/8970

How to check browser cookies support with Pyramid

I would like to know, when is the right moment and how to check the browser cookies support.
I understand I have to check the next request and for instance, with beaker, looking for the session key _creation_time or request.headers['Cookie']... and raise an exception if not found but I don't want to do that or something similar for every request. Some parts of my application don't require cookies, like the home page or info, faq page...
When a user logs out, the session gets deleted or invalidated and I used to redirect to the home view, if I check the session key at that moment, I'll not find it but it doesn't mean there is this issue.
An example I used at the beginning of login view:
try: request.headers['Cookie']
except KeyError:
return HTTPFound(location=request.route_url('home'))
Please also note that if I try to print an error message using request.session.flash(msg, 'error') or use the snippet again at the beginning of the home view and render a message with the template using a control return variable, after logout it will be erroneous displayed.
I am looking for the most elegant way to resolve issue...maybe subscribe to a event?...write down a function to call in some interested view?
There are a few things that could the cause of your problems.
Before I continue... FYI Pyramid uses WebOb to handle request and response objects
WebOb Overview
WebOb Class Documentation
Scenario 1
If you call set_cookie under Pyramid , and then do a redirect, the set_cookie will not be sent. This is because redirects create a new response object.
There are a few ways around this:
The most straightforward is to just copy response headers into the cookie when you raise/return a redirect
return HTTPfound( "/path/to/redirect", headers=[ (k,v) for (k,v)\
in self.request.response.headers.iteritems() if k == 'Set-Cookie'] )
OR
resp = HTTPFound(location='/path/to/redirect')
return self.request.response.merge_cookies(resp)
I should also note that MOST browsers accept cookies on redirects, however Safari does not.
another way is to use pyramid's hooks to convert cookies behind the scenes. i wrote subscribers that automate this. they're on pypi and github. https://github.com/jvanasco/pyramid_subscribers_cookiexfer
Scenario 2
There are two ways of handling sessions in Pyramid. Pyramid has its own session library, and then there is Beaker, which handled sessions for Pylons and has Pyramid support that many people use. I can't speak of pyramid.session, but Beaker has two modes to kill the session:
delete()
Delete the cookie, and clear the session
invalidate()
Clear the contents and start a new session
If you call invalidate(), the Beaker session cookie stays the same and all the session data is cleared -- so you can start storing new data into an empty session object.
If you call delete(), the cookie gets killed as does the session data. If you put new information into the session, IIRC, it will go into a new sessionid / cookie . However, as I noted in the first part above, set_cookie will get called but then thrown out during the redirect. So if you delete() the session and then don't migrate the set_cookie headers... the client will never receive a session identifier.
Some example behaviors of cookies under pyramid
Behavior of redirect
User visits site and is given cookie: SessionId=1
User clicks login
App saves login status to session "1"
App calls set_cookie with "LoggedIn=1"
App calls redirect to /home
Redirect sent, no cookies
User lands on /home
App only sees cookie for "SessionId=1"
Behavior of delete with redirect:
User clicks logout
App calls 'delete()' on session, killing the datastore and placing a set_cookie in request.response to expire the old cookie. if a new sessionid is created, that is sent as well.
If app renders a response, then client receives cookies
If app redirects, client does not receive headers to expire the cookie or set up a new one
Behavior of invalidate with redirect:
User clicks logout
App calls 'invalidate()' on session, killing the datastore
App sets a custom "loggedout=0" cookie
If app renders a response, then client receives cookies
If app redirects:
Client does not receive "loggedout=0" header
Client still has the old session cookie, but it was invalidated/purged on the backend, so they are effectively locked out.
side note: I personally don't like using the request.headers interface -- which handles all headers -- to get at cookies. I've had better luck with request.cookies -- which returns a dictionary of cookies.

Categories