Reputation: 1835
Aim: to create user friendly web interface to linux program without any ssh (console) terrible stuff. I have chosen Python + Django + Apache. Problem: user should login through the browser to linux user and then all user`s requests should be served on behalf of this linux user. By now, server is run as root and when user login through a browser, server root can switch to required user using django user name:
uid = pwd.getpwnam(userName)[2]
os.setuid(uid)
and it can execute all django stuff on behalf of appropriate user.
The problem is that server must be run as root! How could I provide possibility to normally run server with usual apache user rights with providing login to linux user through a browser? (Just get user Name and PWD from the Http POST request and login to appropriate user using Python)?
Update: I need to map any user via web to specific linux user to give him his home directory to execute specific linux program only as this specific user! I guess something like this is realized in webmin?
Possible solution: I could execute su userName
but it doesn't work without terminal:
p = subprocess.Popen(["su", "test"], stdout = subprocess.PIPE, stdin = subprocess.PIPE, stderr = subprocess.STDOUT)
suOUT = p.communicate(input="test")[0]
print suOUT
I just got:
su: must be run from a terminal
Upvotes: 0
Views: 2756
Reputation: 45244
I'm not sure what "standard" approaches are for dealing with this problem. However, this is a simple technique for environments with a small number of users that doesn't involve sudo
, nor changing UID inside the web server (this is likely to be very problematic for concurrent access by multiple users).
Launch a daemon process for each user having access to this application. This process should itself serve web requests for that user over FastCGI (substitute for protocol of your choice). Your web server should have some user to port number mapping. Then, redirect your gateway's requests to the proper FastCGI process based on the logon used by the Django user.
Example (using internal
redirects by NGINX, assuming setup with FastCGI):
foo
logs on to Django web application/.../
/.../
by user foo
X-Accel-Redirect
to indicate internal redirect to /delegate/foo/.../
./delegate/foo/
associated to a FastCGI handler on port 9000foo
and grants access to stuff in home directory.You can substitute the web server and communication protocol to combinations of your choice. I used FastCGI here because it allows to write both the gateway and the handler as Django applications. I chose NGINX because of the internal
redirect feature. This prevents impersonation by direct use of /delegate/foo/.../
URLs by users other than foo
.
Example:
Assuming you have the flup
module, you can start a FastCGI server directly using Django. To start a Django application over FastCGI under a specific user account, you can use:
sudo -u $user python /absolute/path/to/manage.py runfcgi host=127.0.0.1 port=$port
Substitute the $user
for the user name and $port
for a unique port for that user (no two users can share the same port).
Assuming an NGINX configuration, you can set this up like:
location /user/$user {
internal;
fastcgi_pass 127.0.0.1:$port;
# additional FastCGI configuration...
}
Make sure to add one such directive for each $user
and $port
combination above.
Then, from your front-end Django application, you can check permissions and stuff using:
@login_required
def central_dispatch_view ( request ):
response = HttpResponse()
response['X-Accel-Redirect'] = '/user/'+request.user.username
return response
Disclaimer: This is totally untested, and almost a year after the original answer, I'm not sure this is possible, mainly because the documentation on XSendFile in NGINX specifies that this should work with static files. I haven't inquired any further to know if you can actually perform an internal NGINX redirect from a FastCGI application.
Alternate solution:
A better approach might not involve internal redirects, but instead to use a FastCGI authorizer. Basically, a FastCGI is a program that your webserver runs before serving a request. Then, you can bypass the shady internal redirect thing and just have a FastCGI authorizer that check if the request accessing /user/foo/
actually can from a Django user logged in as foo
. This authorizer program won't be able to run as a Django application (since this is not an HTTP request/response cycle), but you can write it using flup
and access your Django settings.
Upvotes: 1
Reputation: 77321
You can include the wsgi user in the sudoers file, and limit the commands and arguments it can run. Why can't you use sudo?
for example:
Cmnd_Alias TRUSTED_CMDS = /bin/su johndoe /some/command, \
/bin/su janedoe /some/command
my_wsgi_user ALL = NOPASSWD: TRUSTED_CMDS
From the security perspective, you should assume the users have shell access - I think its ok for a coorporate intranet but not for a public site.
From python/django you will be able to call ['sudo', '/bin/su', 'johndoe', '/some/command']
.
Another solution if you really can't use sudo (with NOPASSWD) is connect via ssh using the user credentials (user, password) with paramiko.
Upvotes: 1