How to specify where flask should store cookies (flask Session) - python

I use Flask to host my python-based web application, through Apache2 on a linux server.
By default, flask session stores its cookies on the root directory under /flask_session/.
I want to instead store the cookies within the application folder, i.e. /var/www/webApp/webApp/cookies/ .
After reading the flask documentation , I thought that doing
app.config["SESSION_COOKIE_PATH"] = "/var/www/webApp/webApp/cookies/"
should achieve this, but it does not work, and
app.config["APPLICATION_ROOT"] = "/var/www/webApp/webApp/"
does not affect anything either: the cookies are still put in /flask_session/
In both cases I pass Session the app only after the config:
Session(app)

Firstly, we should clarify that flask does not store 'cookies' locally. Cookies are a client-side mechanism (typically a browser), and all storage is expected to happen on the client side - not in flask.
Another point: by default, flask will store all session data within the cookie. Which means that session data will also be stored by the client. There are plugins available to change this behavior and have the session data stored on the server - and not in the cookie. Flask-Session is one such library, and it appears that is what you are using (please correct me if that isn't the case).
With that out the way, we can get to your actual question which is: "How can we get Flask to store the session data in a custom directory instead of the default (/flask_session/)?"
Per the documentation, the SESSION_FILE_DIR config is where this would be set:
SESSION_FILE_DIR | The directory where session files are stored. Default to use flask_session directory under current working directory.
So this code should do what you are looking for:
app.config["SESSION_FILE_DIR"] = "/var/www/webApp/webApp/"

Related

Global state in a WSGI hosted Flask application

Assume a Flask application that allows to build an object (server-side) through a number of steps (wizard-like ; client-side).
I would like to create an initial object server-side an build it up step by step given the client-side input, keeping the object 'alive' throughout the whole build-process. A unique id will be associated with the creation of each new object / wizard.
Serving the Flask application with the use of WSGI on Apache, requests can go through multiple instance of the Flask application / multiple threads.
How do I keep this object alive server-side, or in other words how to keep some kind of global state?
I like to keep the object in memory, not serialize/deserialize it to/from disk. No cookies either.
Edit:
I'm aware of the Flask.g object but since this is on per request basis this is not a valid solution.
Perhaps it is possible to use some kind of cache layer, e.g.:
from werkzeug.contrib.cache import SimpleCache
cache = SimpleCache()
Is this a valid solution? Does this layer live across multiple app instances?
You're looking for sessions.
You said you don't want to use cookies, but did you mean you didn't want to store the data as a cookie or are you avoiding cookies entirely? For the former case, take a look at server side sessions, e.g. Flask-KVSession
Instead of storing data on the client, only a securely generated ID is stored on the client, while the actual session data resides on the server.

Python Django session returns "None"

tl;dr: Python newbie, Django's session not propagated correctly while using HTTPS
I'm building a basic web service which rely on session/cookies to authentication an user.
During the first authentication, I configure a specific session like this:
request.session['userSecureId'] = "blabla"
return HttpResponseRedirect('http://localhost/secure',context)
At this point, a new session key has been added to django_session table. A basic b64 decode on the session_data field confirm the presence of 'userSecureId'
On my view, I check if this session exist like this:
if request.session.get('userSecureId'):
# do something
If I try this on my local system (plain HTTP), it works great. So my next step was to run it on my remote server with SSL enabled. I've configured
SESSION_COOKIE_SECURE = True on my settings.py but now, the value returned by 'userSecureId' is always None.
This is probably a newbie question, so any pointer will be appreciated =)
Additionally, If I print request.session.session_key I'm able to successfully retrieve the session key, meaning Django correctly detect my sessionid cookie, but can't decode the content of session_value
EDIT: I just tried accessing Django on my remote system (same configuration) and I'm facing the same issue. I have no idea why I can't run the session value. Code works using 127.0.0.1 w/o problem though
According to here and here
To share a session between HTTP and HTTPS (and cross domain also), you should set SESSION_COOKIE_DOMAIN in your settings.
SESSION_COOKIE_DOMAIN = '.example.com'

Flask: share sessions between domain.com and username.domain.com

I have a flask running at domain.com
I also have another flask instance on another server running at username.domain.com
Normally user logs in through domain.com
However, for paying users they are suppose to login at username.domain.com
Using flask, how can I make sure that sessions are shared between domain.com and username.domain.com while ensuring that they will only have access to the specifically matching username.domain.com ?
I am concerned about security here.
EDIT:
Later, after reading your full question I noticed the original answer is not what you're looking for.
I've left the original at the bottom of this answer for Googlers, but the revised version is below.
Cookies are automatically sent to subdomains on a domain (in most modern browsers the domain name must contain a period (indicating a TLD) for this behavior to occur). The authentication will need to happen as a pre-processor, and your session will need to be managed from a centralised source. Let's walk through it.
To confirm, I'll proceed assuming (from what you've told me) your setup is as follows:
SERVER 1:
Flask app for domain.com
SERVER 2:
Flask app for user profiles at username.domain.com
A problem that first must be overcome is storing the sessions in a location that is accessible to both servers. Since by default sessions are stored on disk (and both servers obviously don't share the same hard drive), we'll need to do some modifications to both the existing setup and the new Flask app for user profiles.
Step one is to choose where to store your sessions, a database powered by a DBMS such as MySQL, Postgres, etc. is a common choice, but people also often choose to put them somewhere more ephemeral such as Memcachd or Redis for example.
The short version for choosing between these two starkly different systems breaks down to the following:
Database
Databases are readily available
It's likely you already have a database implemented
Developers usually have a pre-existing knowledge of their chosen database
Memory (Redis/Memchachd/etc.)
Considerably faster
Systems often offer basic self-management of data
Doesn't incur extra load on existing database
You can find some examples database sessions in flask here and here.
While Redis would be more difficult to setup depending on each users level of experience, it would be the option I recommend. You can see an example of doing this here.
The rest I think is covered in the original answer, part of which demonstrates the matching of username to database record (the larger code block).
Old solution for a single Flask app
Firstly, you'll have to setup Flask to handle subdomains, this is as easy as specifying a new variable name in your config file. For example, if your domain was example.com you would append the following to your Flask configuration.
SERVER_NAME = "example.com"
You can read more about this option here.
Something quick here to note is that this will be extremely difficult (if not impossible) to test if you're just working off of localhost. As mentioned above, browsers often won't bother to send cookies to subdomains of a domain without dots in the name (a TLD). Localhost also isn't set up to allow subdomains by default in many operating systems. There are ways to do this like defining your own DNS entries that you can look into (/etc/hosts on *UNIX, %system32%/etc/hosts on Windows).
Once you've got your config ready, you'll need to define a Blueprint for a subdomain wildard.
This is done pretty easily:
from flask import Blueprint
from flask.ext.login import current_user
# Create our Blueprint
deep_blue = Blueprint("subdomain_routes", __name__, subdomain="<username>")
# Define our route
#deep_blue.route('/')
def user_index(username):
if not current_user.is_authenticated():
# The user needs to log in
return "Please log in"
elif username != current_user.username:
# This is not the correct user.
return "Unauthorized"
# It's the right user!
return "Welcome back!"
The trick here is to make sure the __repr__ for your user object includes a username key. For eg...
class User(db.Model):
username = db.Column(db.String)
def __repr__(self):
return "<User {self.id}, username={self.username}>".format(self=self)
Something to note though is the problem that arises when a username contains special characters (a space, #, ?, etc.) that don't work in a URL. For this you'll need to either enforce restrictions on the username, or properly escape the name first and unescape it when validating it.
If you've got any questions or requests, please ask. Did this during my coffee break so it was a bit rushed.
You can do this with the builtin Flask sessions, which are cookie-based client-side sessions. To allow users to login to multiple subdomains in '.domain.com', you need only to specify
app.config['SESSION_COOKIE_DOMAIN'] = '.domain.com'
and the client's browser will have a session cookie that allows him to login to every Flask instance that is at 'domain.com'.
This only works if every instance of Flask has the same app.secret_key
For more information, also see
Same Flask login session across two applications

Google+ login - Server side flow - Storing credentials - Python examples

I am building an app on Google App Engine using Flask. I am implementing Google+ login from the server-side flow described in the Python examples: https://developers.google.com/+/web/signin/server-side-flow and https://github.com/googleplus/gplus-quickstart-python/blob/master/signin.py.
Both of the examples have:
credentials = oauth_flow.step2_exchange(code)
and
session['credentials'] = credentials
storing the credentials object to the Flask session. When I run this code on my Google App Engine project, I get the error:
TypeError: <oauth2client.client.OAuth2Credentials object at 0x7f6c3c953610> is not JSON serializable
As discussed in this issue (marked WontFix), the OAuth2Credentials is not designed to by JSON serializable. It has methods to_json and from_json, which could be used to store it, e.g:
session['credentials'] = credentials.to_json()
However, in the same issue:
Never store a Credentials object in a cookie, it contains the applications
client id and client secret.
Perhaps I misunderstand how a Flask session object works, but from the doc:
... A session basically makes it possible to remember information from one request to another. The way Flask does this is by using a signed cookie. So the user can look at the session contents, but not modify it unless they know the secret key...
And therefore, we should not be storing a credentials object in the session, even if it is a signed cookie.
In my case, I currently only need to re-use the access token for disconnect purposes, so I can just store that.
What is the correct way to deal with this situation? Should the credentials not be stored in the session at all? Should at this point in the examples there be a comment "Securely save credentials here"?
Flask used to use pickle instead of JSON to store values in the session, and the Google example code was written with that in mind. Flask switched to a JSON-based format to reduce the impact of the server-side secret being disclosed (a hacker can hijack your process with pickle, not with JSON).
Store just the access token in your session:
session['credentials'] = credentials.access_token
You can recreate the credentials object with that token, using the AccessTokenCredentials class at a later time, should you need it again:
credentials = AccessTokenCredentials(session['credentials'], 'user-agent-value')
The AccessTokenCredentials object stores just the credentials; because it lacks the client id and client secret it cannot be used to refresh the token, however.
The user agent value is something you get to make up; it can help diagnose problems if you have access to the OAuth server logs; with Google I would not count on that so just make something up here.
"Flask by default uses the Werkzeug provided 'secure cookie' as session system. It works by pickling the session data, compressing it and base64 encoding it." - http://flask.pocoo.org/snippets/51/
In other words, flask is really weird. Anything you put in the session, it gets ciphered with the server key, sent to the client and stored in the client. The server then receives it on each subsequent request and decodes it with the same key. It also means session data will survive server reboots because it's sitting in the client.
To improve this for my app I've used the flask SessionInterface with Couchdb - and now the client only knows a sessionID that is checked against my database where the actual data is stored. Hurray.
Check this out, it has a few approaches to server side sessions depending what db you may be using - http://flask.pocoo.org/snippets/category/sessions/

testing session variables and db storage in cherrypy app

I'm looking to write some unit tests for some cherrypy code.
Most of the unit test examples I have seen depend on os.environ and generally only test for the final response (html output) from the cherrypy apps.
I'm looking for:
testing that session variables have been set/unset for a given request (e.g., user logs in, I want to verify that his 'user' session variable is correct as well as his login time, etc...
checking values in a datastore (mysql/mongodb)
running tests in parallel. By default you access session and other information from cherrypy.cookie/cherrypy.session, etc... These are basically global. Is it possible to access this information another way?
Any other recommendations would be greatly appreciated.
You could write a small python http client and (assuming you run your server) unittest the responses.
Some libs that might be useful:
urllib
urllib2
http.client
Also you might want to check out selenium (allows you to script your browser in python for test cases).

Categories

Resources