# Run 'some' code as a different user? NET::SSH?

**URL:** <https://www.ruby-forum.com/t/run-some-code-as-a-different-user-net-ssh/103019>\
**Category:** Ruby\
**Created:** [April 30, 2007, 9:48pm UTC](https://www.ruby-forum.com/t/run-some-code-as-a-different-user-net-ssh/103019 "2007-04-30T21:48:29Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![amin1426](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/4da419/32.png) [@amin1426](https://www.ruby-forum.com/u/amin1426)\
**Post date:** [April 30, 2007, 9:48pm UTC](https://www.ruby-forum.com/t/run-some-code-as-a-different-user-net-ssh/103019/1 "2007-04-30T21:48:29Z")

</div>

Hello,

I’m working on a ROR app that allows users to track batch computing jobs  
submitted to our high performance computing clusters. Anyway, a piece of  
functionality to that application is an online file browser to the  
server.

Net, I have a need to authenticate users to the Server’s OS (I was  
thinking using Net:SSH). Then, once authenticated, I’d like to run some  
ruby commands as that user vs. the 'non-priviledged user the webserver  
is running under.

Is this possible? Any ideas?

Thanks  
KF

---

<div class="post-metadata">

**Author:** ![amin1426](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/4da419/32.png) [@amin1426](https://www.ruby-forum.com/u/amin1426)\
**Post date:** [April 30, 2007, 10:24pm UTC](https://www.ruby-forum.com/t/run-some-code-as-a-different-user-net-ssh/103019/2 "2007-04-30T22:24:51Z")

</div>

On Tue, May 01, 2007 at 04:48:37AM +0900, John C. wrote:

> is running under.
> 
> Is this possible? Any ideas?

The user will authenticate by providing their OS username and password?

Perhaps you could use PTY.spawn and run ‘su - username’

---

<div class="post-metadata">

**Author:** ![amin1426](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/4da419/32.png) [@amin1426](https://www.ruby-forum.com/u/amin1426)\
**Post date:** [April 30, 2007, 10:34pm UTC](https://www.ruby-forum.com/t/run-some-code-as-a-different-user-net-ssh/103019/3 "2007-04-30T22:34:39Z")

</div>

Brian C. wrote:

> On Tue, May 01, 2007 at 04:48:37AM +0900, John C. wrote:
> 
> > is running under.
> > 
> > Is this possible? Any ideas?
> 
> The user will authenticate by providing their OS username and password?
> 
> Perhaps you could use PTY.spawn and run ‘su - username’

Yes, I will authenticate useing their OS username and password. I  
haven’t used PTY.spawn before. Does it just spawn off a new psuedo  
terminal? After doing a ‘su -username’ and authenicating; I want to  
execute a block of ruby code as that user. Ideally that block would  
return a ruby object that I could then manipulate in the broader app.  
(ie since this is a Rails app, I would execute controller code as the  
authenticated user (ie to get job files); and use one set of views for  
all users.

Am I making sense or over thinking this? Basically, I’m trying to avoid  
calling everything in shell’s and reading in stdout. I’m trying to stay  
completely in Ruby here.

THanks!  
KF

---

<div class="post-metadata">

**Author:** ![amin1426](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/4da419/32.png) [@amin1426](https://www.ruby-forum.com/u/amin1426)\
**Post date:** [April 30, 2007, 11:03pm UTC](https://www.ruby-forum.com/t/run-some-code-as-a-different-user-net-ssh/103019/4 "2007-04-30T23:03:54Z")

</div>

On 4/30/07, John C. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> calling everything in shell’s and reading in stdout. I’m trying to stay  
> completely in Ruby here.
> 
> THanks!  
> KF

Ruby is one process to the OS - so most probably it cannot have  
credentials of more users. What you can do is have ‘session’ have  
another process running with respective user’s credentials and  
communicate with it with drb or similar. You would need to keep a pool  
of these and kill/stop them when the session is done or timeouted.

You probably won’t be able to avoid more processes though, but you may  
avoid communicating through stdout.

Or, maybe you can avoid all of this if the user under which the the  
webserver is running has rights to users’ files (i.e. they all belong  
to the same group and have the rights set appropriately).

Finally, you will want to double-check your code for security issues…

HTH.  
J.

---

<div class="post-metadata">

**Author:** ![amin1426](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/4da419/32.png) [@amin1426](https://www.ruby-forum.com/u/amin1426)\
**Post date:** [April 30, 2007, 11:16pm UTC](https://www.ruby-forum.com/t/run-some-code-as-a-different-user-net-ssh/103019/5 "2007-04-30T23:16:39Z")

</div>

Jano S. wrote:

> On 4/30/07, John C. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:
> 
> > calling everything in shell’s and reading in stdout. I’m trying to stay  
> > completely in Ruby here.
> > 
> > THanks!  
> > KF
> 
> Ruby is one process to the OS - so most probably it cannot have  
> credentials of more users. What you can do is have ‘session’ have  
> another process running with respective user’s credentials and  
> communicate with it with drb or similar. You would need to keep a pool  
> of these and kill/stop them when the session is done or timeouted.
> 
> You probably won’t be able to avoid more processes though, but you may  
> avoid communicating through stdout.
> 
> Or, maybe you can avoid all of this if the user under which the the  
> webserver is running has rights to users’ files (i.e. they all belong  
> to the same group and have the rights set appropriately).
> 
> Finally, you will want to double-check your code for security issues…
> 
> HTH.  
> J.

J.

Very helpful thanks! Ironically, I was just starting to look into this  
method. Looks like my ‘little’ app just got much more complex!

Thanks!  
John

---

<div class="post-metadata">

**Author:** ![amin1426](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/4da419/32.png) [@amin1426](https://www.ruby-forum.com/u/amin1426)\
**Post date:** [May 1, 2007, 9:48am UTC](https://www.ruby-forum.com/t/run-some-code-as-a-different-user-net-ssh/103019/6 "2007-05-01T09:48:36Z")

</div>

On Tue, May 01, 2007 at 05:34:40AM +0900, John C. wrote:

> Yes, I will authenticate useing their OS username and password. I  
> haven’t used PTY.spawn before. Does it just spawn off a new psuedo  
> terminal? After doing a ‘su -username’ and authenicating; I want to  
> execute a block of ruby code as that user.

I was thinking of something like this (untested):

username = “foo”  
password = “bar”

require ‘pty’  
require ‘expect’  
inp, out = PTY.spawn(“su - #{username}”)  
inp.expect /assword: /  
out.puts password  
inp.expect /$ /  
out.puts “ruby /path/to/foo.rb”

> Ideally that block would  
> return a ruby object that I could then manipulate in the broader app.

That’s more difficult, because your web server is running as one uid and  
the  
other part is running as a completely different uid, and therefore by  
definition must be in a separate process.

You can run a DRb server in the child process, and have a DRb client  
(proxy)  
object in the web service. This will work fine, but DRb doesn’t run over  
stdin/stdout, so you would have to bind each child process to a  
different  
port number.

This isn’t unsurmountable though. I think you can let DRb in the child  
pick  
a port number dynamically, and then send that number back over stdout  
(which  
you then pick up by reading the PTY)

There’s a DRb tutorial at  
[http://wiki.rubygarden.org/Ruby/page/show/DrbTutorial](http://wiki.rubygarden.org/Ruby/page/show/DrbTutorial)  
which you may find useful. (Personal interest disclaimer: I wrote it 🙂

> (ie since this is a Rails app, I would execute controller code as the  
> authenticated user (ie to get job files); and use one set of views for  
> all users.

It seems you have hit against the brick wall which many PHP hosting  
providers come across: namely, they want to run Apache with mod\_php for  
efficiency, but they don’t want one user’s PHP scripts to be able to  
access  
or modify another user’s files. Since Apache runs as a single user, and  
mod\_php runs as that user, this turns out to be tricky.

One solution is to run each user’s applications as fastcgi scripts,  
where  
the users’ code runs as a pool of separate processes running under their  
own  
uid. A similar solution is to give each user their own completely  
separate  
webserver instance (e.g. httpd), either bound to a separate IP, or bound  
to  
a separate port with a proxy in front which routes the incoming HTTP  
requests to the right webserver instance.

In your case, this would effectively mean running multiple copies of  
your  
entire Rails app, one under each user ID. If the number of users you  
have is  
not large, this is probably a reasonable approach.

You could do this statically, e.g. with webrick or mongrel (run a  
separate  
application instance for each user, bound to a separate port, running as  
their userid). Or, although I’ve not tried it myself, it should also be  
possible to run Rails under fastcgi with suexec or cgiwrap. The  
advantage of  
this approach is that when a user is no longer active, the webserver can  
completely kill off their Rails application instance.

In both cases, the app would then take on responsibility for  
authenticating  
the user. Once they had authenticated, the controller would have rights  
to  
do whatever that user could do.

Regards,

Brian.

---

<div class="post-metadata">

**Author:** ![amin1426](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/4da419/32.png) [@amin1426](https://www.ruby-forum.com/u/amin1426)\
**Post date:** [May 1, 2007, 2:00pm UTC](https://www.ruby-forum.com/t/run-some-code-as-a-different-user-net-ssh/103019/7 "2007-05-01T14:00:38Z")

</div>

Brian,

WOW!!! Thank you very much for taking so much of your time to help! 🙂  
Pretty amazing.

Anyway, I think I may try your first approach of initiating a separate  
Rails process per user. We’re only realistically talking about 10  
concurrent users at any given time. The webserver is relatively beefy  
so it should be able to handle it with ease (4 X86\_64 cpu’s; 8GB RAM).

I’m also going to dive a bit further into Option 2. The setuid wrapper  
seems like a good plan. Unfortunately, I’m no security expert; but our  
HPC Systems Admins are very strong. Net, I can work the solution  
through them…

Thanks!  
John

---

<div class="post-metadata">

**Author:** ![amin1426](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/4da419/32.png) [@amin1426](https://www.ruby-forum.com/u/amin1426)\
**Post date:** [May 1, 2007, 10:08am UTC](https://www.ruby-forum.com/t/run-some-code-as-a-different-user-net-ssh/103019/8 "2007-05-01T10:08:38Z")

</div>

On Tue, May 01, 2007 at 04:46:48PM +0900, Brian C. wrote:

> One solution is to run each user’s applications as fastcgi scripts, where  
> the users’ code runs as a pool of separate processes running under their own  
> uid. A similar solution is to give each user their own completely separate  
> webserver instance (e.g. httpd), either bound to a separate IP, or bound to  
> a separate port with a proxy in front which routes the incoming HTTP  
> requests to the right webserver instance.
> 
> In your case, this would effectively mean running multiple copies of your  
> entire Rails app, one under each user ID. If the number of users you have is  
> not large, this is probably a reasonable approach.

Another approach to consider, if the number of types of different  
requests  
your users need to implement is small, is to have a small C setuid  
wrapper  
program which in turn performs an action after validating the  
parameters.

You’d then invoke it as, say,

```
system("/path/to/rubywrap",username,command,arg)

```

rubywrap.c would be a small C program which checks command and arg are  
“safe”, changes userid to username, and then does whatever command  
implies.  
It would then be installed setuid root, and possibly also made only  
executable by the webserver user or group.

However, I wouldn’t recommend going this way unless you fully understand  
the  
security implications of this. Find someone else’s implementation of  
something similar (e.g. Apache suexec) and understand all the subtleties  
of  
its implementation, before trying it yourself.

Regards,

Brian.
