In google app engine i have created my own user API appropriately called user so it doesn't interfere with the google app engine API users. Like most multiuser websites, two "versions" of the site are available to the user depending on whether or not they are logged in. Thus is created a file called router.py with the following code
import webapp2
from lib import user
import guest
import authorized
if user.isLoggedIn():
app = webapp2.WSGIApplication(authorized.WSGIHandler,debug=True)
else:
app = webapp2.WSGIApplication(guest.WSGIHandler,debug=True)
the guest and authorized modules are formated like your conventional application script for example:
import webapp2
import os
class MainPage(webapp2.RequestHandler):
def get(self,_random):
self.response.out.write('authorized: '+_random)
WSGIHandler = [('/(.*)', MainPage)]
Thus the router file easily selects which WSGIApplication url director to use by grabbing the WSGIHandler variable from either the guest or authorized module. However the user must close all tabs for the router to detect a change in the isLoggedIn() function. If you log in it does not recognize that you have done so until every tab is closed. I have two possible reasons for this:
isLoggedIn() uses os.environ['HTTP_COOKIE'] to retrieve cookies and see if a user is logged in, it then checks the cookie data against the database to make sure they are valid cookie. Possibly this could have an error where the cookies on the server's end aren't being refreshed when the page is? Maybe because i'm not getting the cookies from self.request.
Is it possible that in order to conserve frontend hours or something that google app engine caches the scripts from the server with in the server's memcache? i Doubt it but i am at a loss for the reason for this behavior.
Thanks in advance for the help
Edit
Upon more testing i found that as suspected the router.py file responded correctly and directed the user based in logged in when a comment was added to it. This seems to indicate caching.
Edit 2
I have uncovered some more information on the WSHI Application:
The Python runtime environment caches imported modules between requests on a single web server, similar to how a standalone Python application loads a module only once even if the module is imported by multiple files. Since WSGI handlers are modules, they are cached between requests. CGI handler scripts are only cached if they provide a main() routine; otherwise, the CGI handler script is loaded for every request.
I wonder how efficient to refresh the WSGI module somehow. This would undoubtably task the server, but solve my problem. Again, this seems to be a partial solution.
Edit 3
Again, any attempt to randomize a comment in the router.py file is ineffective. The id statement looking for user login is completely overlooked and the WSGIApplication is set to its original state. I'm not yet sure if this is due to the module cache in the webapp2 module or thanks to the module cache on the user API. I suspect the latter.
The problem is not "caching", it is just how WSGI applications work. A WSGI process stays alive for a reasonably long period of time, and serves multiple requests during that period. The app is defined when that process is started up, and does not change until the process is renewed. You should not try to do anything dynamic or request-dependent at that point.
replace router.py with:
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from lib import user
import guest
import authorized
def main():
if user.isLoggedIn():
run_wsgi_app(authorized.application)
else:
run_wsgi_app(guest.application)
if __name__ == "__main__":
main()
downgrading to the old webapp allows you to change dynamically the wsgi application. it's tested and works perfectly! The CGI adaptor run_wsgi_app allows for the webapp to change it's directory list without caching.
Related
Background:
I need to run a program on a remote server without logging into the server. The server would only allow people to contact it, not to see what files are on it or login.
The server has in it a .py and an installation of Python. That file has the hardcoded login credentials to a database that I do not want users of the local machine program to see.
I would like to contact the server, pass it arguments and request it to run the program with them.
The reason is I don't want my program on the local machine to store the login credentials for the server, so I dont want to ssh because that would again require some form of localized credentialing which leaves the credentials exposed to the users at some point (and I never want them to see them).
Traditionally when I am making remote machine calls, its to an exposed API through the requests or http.client libraries; from what I can find, this may require the socket library, and that is a library I am not very familiar with and couldn't seem to find examples of what I am trying to do.
Server code:
import sys
from pymongo import MongoClient
usr = 'user_login'
pwd = 'user_pass'
client = MongoClient('mongodb://' + usr + ':' + pwd +'#host:port')
db = client['some_db']
db.add_user(sys.argv[1], sys.argv[2])
Question(s):
How can I do a one way request to a server containing a script file and pass it arguments?
Is this the appropriate way to handle ensuring users cannot see admin credentials?
Question 2 is somewhat out of scope here, because the underlying problem is that the program needs to create a new user account on a database, but you must be logged in with an authorized account to do so. If I hardcoded or stored credentials in a file that the local machine could see, then a savvy user could debug the program and see what they are.
I figured putting them on a server where nobody can see the files, just ask the server to run them, would be a safe bet and ensure security.
What you need seems to be a typical HTTP endpoint. Things to read and consider:
A simplest web framework, like web.py. Or you can run your program as a CGI script, no matter the language.
A config file that would keep the credentials of the mongodb admin user. Read it every time your program runs.
The hardest part: a proper authorization layer on top of your script. Else anyone will be able to run it. At the very least, basic http auth, or token bearer auth.
Unless it's inside your tiny private trusted VPN with built-in encryption, serve your endpoint over HTTPS. Since it will be fronted by a web server anyway (either as a pass-through, or via uwsgi), just use the fact that your web server already does HTTPS (and it does, right?).
a simple example
from flask import Flask, request
app = Flask(__name__)
#app.route("/adduser")
def hello():
user = request.args.get("user")
pwd = request.args.get("pwd")
client = MongoClient('mongodb://' + usr + ':' + pwd +'#host:port')
db = client['some_db']
db.add_user(user, pwd)
return "user inserted"
if __name__ == '__main__':
app.run()
and making the following request http://localhost:5000/adduser?user=root&pwd=1234
on top of that you can use POST over SSL (HTTPS) so the data will be encrypted and transmitted in the request body instead the url (like GET) this suppose to be sufficient, security wise
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.
Using the Google App Engine Python API is there a way to access the name of the currently running application--i.e., the app name specified in your app.yaml file with application: foobar?
import os
appname = os.environ['APPLICATION_ID']
EDIT: I just noticed this because I got a new upvote on it today (shame on you, upvoter!), but this is no longer correct.
from google.appengine.api.app_identity import get_application_id
appname = get_application_id()
should be used. The value in os.environ will include a "s~" prefix for applications using the HR datastore and, by default, "dev~" on the development server. (os.environ should also be avoided entirely on App Engine anyway, since when concurrency support is added with the Python 2.7 runtime, use of os.environ won't be threadsafe and will allow data to leak from one request to another, although obviously the application ID itself would be the same for multiple requests to the same application at the same time...)
I have a Pylons app where I would like to move some of the logic to a separate batch process. I've been running it under the main app for testing, but it is going to be doing a lot of work in the database, and I'd like it to be a separate process that will be running in the background constantly. The main pylons app will submit jobs into the database, and the new process will do the work requested in each job.
How can I launch a controller as a stand alone script?
I currently have:
from warehouse2.controllers import importServer
importServer.runServer(60)
and in the controller file, but not part of the controller class:
def runServer(sleep_secs):
try:
imp = ImportserverController()
while(True):
imp.runImport()
sleepFor(sleep_secs)
except Exception, e:
log.info("Unexpected error: %s" % sys.exc_info()[0])
log.info(e)
But starting ImportServer.py on the command line results in:
2008-09-25 12:31:12.687000 Could not locate a bind configured on mapper Mapper|I
mportJob|n_imports, SQL expression or this Session
If you want to load parts of a Pylons app, such as the models from outside Pylons, load the Pylons app in the script first:
from paste.deploy import appconfig
from pylons import config
from YOURPROJ.config.environment import load_environment
conf = appconfig('config:development.ini', relative_to='.')
load_environment(conf.global_conf, conf.local_conf)
That will load the Pylons app, which sets up most of the state so that you can proceed to use the SQLAlchemy models and Session to work with the database.
Note that if your code is using the pylons globals such as request/response/etc then that won't work since they require a request to be in progress to exist.
I'm redacting my response and upvoting the other answer by Ben Bangert, as it's the correct one. I answered and have since learned the correct way (mentioned below). If you really want to, check out the history of this answer to see the wrong (but working) solution I originally proposed.