I'm trying to adapt another StackOverflow answer on conditionally applying a decorator to only require login for a specific environment (eventually a staging environment, but development until I get this working). Toward that end, I started with the following
auth = HTTPDigestAuth()
def login_required(dec, condition):
def decorator(func):
if not condition:
return func
return dec(func)
return decorator
#bp.route('/auth')
#login_required(auth.login_required, current_app.config['ENV'] != 'development')
def auth_route():
return current_app.config['ENV']
When I launch the server, I get a RuntimeError: Working outside of application context error. After trying a few suggestions from an earlier version of this question, I got the RuntimeError to disappear, but the decorator still isn't being correctly applied when I want. Here's the current version:
def login_required(dec):
def decorator(func):
if not os.environ.get('ENV') != 'development':
return func
return dec(func)
return decorator
#bp.route('/auth')
#login_required(auth.login_required)
def auth_route():
return current_app.config['ENV']
This never returns the auth.login_reqired function. It always lets the browser in without authentication.
So, I tried changing the condition to
if not os.environ.get('ENV') is not None:
and then the authentication shows up.
Yes, I've done an export ENV=development in the shell and confirmed it with the env command. But even then it's not reading the environment variable as I would expect.
Perhaps this is simply the wrong way to go about it? My final goal is to require authentication on one particular environment. Is this possible with the path I'm on? Is it possible at all?
current_app is a context local proxy that only has meaning during a request. This means you can't use it before a request, i.e. as part of a decorator.
Using current_app is generally good practice because Flask allows multiple apps to be configured. In your specific case however, it isn't actually necessary. For instance, the following would work, because it uses the app object directly instead of the current_app proxy:
from yourpackage import app
#bp.route('/auth')
#login_required(auth.login_required, app.config['ENV'] != 'development')
def auth():
return current_app.config['ENV']
Let me paste something from documentation of Flask
Lifetime of the Context
The application context is created and destroyed as necessary. When a Flask application begins handling a request, it pushes an application context and a request context. When the request ends it pops the request context then the application context. Typically, an application context will have the same lifetime as a request.
Now let’s consider how decorators work. It is just a syntactic sugar see this answer.
So the login_required decorator is called while the module is loaded and the current app is not available yet because it’s not handling request.
I would do this way, move condition to the decorator function (relating to your example). It will be called while the request will be handled so you should have access to current_app.
Related
I'm a newbie to google app engine. I want the security restriction for url of cron so that it shouldn't be accessible by url directly. For this I've already read the docs and some of Q&As ([Google app engine: security of cron jobs).
I implemented the login : admin solution suggested in this link. But I failed to implement security as self.request.headers.get('X-AppEngine-Cron') is always None, whether it is cron or accessed via url directly.
So I don't know from where is the request coming (from cron or direct access)
def cron_method(BaseRestHandler):
def check_if_cron(self, *args, **kwargs):
if self.request.headers.get('X-AppEngine-Cron') is None:
logging.info("error-- not cron")
self.UNAUTH = "cron"
self.raise_exception()
else:
return BaseRestHandler(self, *args, **kwargs)
return check_if_cron
I used customized handler BaseRestHandler for other authentications.
#cron_method
def put(self):
logging.info("inside put--")
This is called via taskqueue from the get method of the class.
The problem is I didn't get header X-AppEngine-Cron
Any other logic or method will be appreciated.
Thanks In Advance.
It seems you attempted to make the check a decorator.
But your code shows the decorator applied to a put() method, not a get() method - the cron executes only on a get().
Also your decorator doesn't look quite right to me. Shouldn't a decorator take as argument a function and return some locally defined function which executes (not returns) the function received as argument?
I'd suggest you go back to basics - try to make the header check in the get method of the handler itself and only after you get that working consider further, more complex changes like the pulling the check in a decorator.
It is more likely that your decorator is not working than GAE's documented infra to not be working. Keeping things simple (at first) would at least help your investigation effort be pointed in a better direction.
Try this:
def cron_method(handler_method):
def check_if_cron(self, *args, **kwargs):
if self.request.headers.get('X-AppEngine-Cron') is None:
logging.info("error-- not cron")
self.UNAUTH = "cron"
self.raise_exception()
else:
handler_method(self, *args, **kwargs)
return check_if_cron
As for the invocations from the task queue - those requests are no longer cron requests, even if the tasks are created and enqueued by a cron request.
From Securing task handler URLs:
If a task performs sensitive operations (such as modifying data), you
might want to secure its worker URL to prevent a malicious external
user from calling it directly. You can prevent users from accessing
task URLs by restricting access to App Engine administrators.
Task requests themselves are issued by App Engine and can always
target restricted URL.
You can restrict a URL by adding the login: admin element to the
handler configuration in your app.yaml file.
If you want to also prevent manual access to those URLs (i.e. restrict it only to task queue requests) you can perform header checks similar to the cron one. The header values are listed in Reading request headers. Personally I picked X-AppEngine-TaskName.
I've created a Django-rest-framework app. It exposes some API which does some get/set operations in the MySQL DB.
I have a requirement of making an HTTP request to another server and piggyback this response along with the usual response. I'm trying to use a self-made HTTP connection pool to make HTTP requests instead of making new connections on each request.
What is the most appropriate place to keep this app level HTTP connection pool object?
I've looked around for it & there are multiple solutions each with some cons. Here are some:
To make a singleton class of the pool in a diff file, but this is not a good pythonic way to do things. There are various discussions over why not to use singleton design pattern.
Also, I don't know how intelligent it would be to pool a pooler? (:P)
To keep it in init.py of the app dir. The issue with that are as follows:
It should only contain imports & things related to that.
It will be difficult to unit test the code because the import would happen before mocking and it would actually try to hit the API.
To use sessions, but I guess that makes more sense if it was something user session specific, like a user specific number, etc
Also, the object needs to be serializable. I don't know how HTTP Connection pool can be serialized.
To keep it global in views.py but that also is discouraged.
What is the best place to store such app/global level variables?
This thread is a bit old but still could be googled. generally, if you want a component to be accessible among several apps in your Django project you can put it in a general or core app as a Util or whatever.
in terms of reusability and app-specific you can use a Factory with a cache mechanism something like:
class ConnectionPool:
pass
#dataclass
class ConnectionPoolFactory:
connection_pool_cache: dict[str: ConnectionPool] = field(default_factory=dict)
def get_connection(self, app_name: str) -> ConnectionPool:
if self.connection_pool_cache.get(app_name, None) is None:
self.connection_pool_cache[app_name] = ConnectionPool()
return self.connection_pool_cache[app_name]
A possible solution is to implement a custom Django middleware, as described in https://docs.djangoproject.com/ja/1.9/topics/http/middleware/.
You could initialize the HTTP connection pool in the middleware's __init__ method, which is only called once at the first request. Then, start the HTTP request during process_request and on process_response check it has finished (or wait for it) and append that response to the internal one.
I have some code I want to run for every request that comes into Flask-- specifically adding some analytics information. I know I could do this with a decorator, but I'd rather not waste the extra lines of code for each of my views. Is there a way to just write this code in a catch all that will be applied before or after each view?
Flask has dedicated hooks called before and after requests. Surprisingly, they are called:
Flask.before_request()
Flask.after_request()
Both are decorators:
#app.before_request
def do_something_whenever_a_request_comes_in():
# request is available
#app.after_request
def do_something_whenever_a_request_has_been_handled(response):
# we have a response to manipulate, always return one
return response
I am new to flask, but moderately proficient in python - I have a flask app that uses flask-security for user authentication. I would like to add some additional functionality to the user login process. Specifically, I need to save the user's auth_token (which I have set up to be a one-time-use token) to the db when they login, and remove it when they log out. The issue comes because flask-security does not (to my knowledge) expose the machinery of logging in directly to the developer. As far as I can tell from the code, it imports flask-login, which uses a login_user function.
I started out by trying to override this function by importing flask.ext.login (which normally, I would not need to do) and redefining the function as follows:
import flask.ext.login as a
def new_login_user():
...copy of existing function goes here...
...Plus new stuff with current_user.get_auth_token()...
a.login_user = new_login_user
however, I got hit with all sorts of namespace issues, and it seems like a really ugly way to do it.
I was thinking there might be a way to do it with a decorator, but I am new to flask, and have not used decorators much regardless.
Any ideas on what the best way to approach this might be? for context, I want the auth_token in the db, because I need to pass off the website authentication to another process, which also accesses the db. The other process is an API server using websockets. I don't want to combine the processes.
I think using a signal decorator seems to be the easiest-- in the following example on_user_logged_in should be called when a user logs into your app. More info in the docs.
from flask.ext.login import user_logged_in
#user_logged_in.connect_via(app)
def on_user_logged_in(sender, user):
log_auth_token(user.get_auth_token()) # or whatever.
Best keep it clean, write your own new_login_user function and use that whenever you would otherwise use flask.ext.login.login_user. You could put your new_login_user into its own file and import it from there.
You could even call it login_user, and never import flask.ext.login.login_user directly.
The web app I am working on needs to perform a first-time setup or initialization,
where is a good place to put that logic? I dont want to perform the check if a configuration/setup exists on each request to / or before any request as thats kind of not performant.
I was thinking of performing a check if there is a sane configuration when the app starts up, then change the default route of / to a settings/setup page, and change it back. But thats like self-changing code a bit.
This is required since the web app needs settings and then to index stuff based on those settings which take a bit of time. So after the settings have been made, I still need to wait a while until the indexing is done. So even after the settings/setup has been made, any requests following, will need to see a "wait indexing" message.
Im using flask, but this is relevant for django as well I think.
EDIT: Im thinking like this now;
When starting up, check the appconfig.py for MY_SETTINGS, if it is not there
add a default from config.py and put a status=firstrun object on the app.config, also
change the / route to setup view function.
The setup view function will then check for the app.config.status object and perform
The setup of settings as necessary after user input, when the settings are okay,
remove app.config.status or change it to "indexing", then I can have a before_request function to check for the app.config.status just to flash a message of it.
Or I could use the flask.g instead of app.config to store the status?
The proper way is creating a CLI script, preferably via Flask-Script if you use Flask (in Django it would be the default manage.py where you can easily add custom commands, too) and defining a function such as init or install:
from flaskext.script import Manager
from ... import app
manager = Manager(app)
#manager.command
def init():
"""Initialize the application"""
# your code here
Then you mention it in your documentation and can easily assume that it has been run when the web application itself is accessed.