How can I control the userid of a remote process, such as a servlet, rmid process, or EJB running on behalf of a particular user?

Developers sometimes need to write logic to be run in remote processes
that must assume the permissions of a particular user on the remote
machine. For example, you might want to write JSP or servlet pages that
allow a user to manage his Linux account or access her home directory.

Background

This is a difficult problem for several reasons:

Unix/Linux userids are not a portable concept across all
platforms that support Java.

Unix/Linux userids are not generally portable across a network, even
a homogeneous network populated by just one platform.

Java provides almost no support for such non-portable features
as Unix/Linux user authentication and authorization.

Native mechanisms for managing user identification, such as the
Linux setuid() call, are not portable and do not work in consistent
ways across different Java implementations or different OSes.

First, some brief (and highly simplified) background about
user authorization. The Unix/Linux user authentication/authorization
model is built on these basic ideas:

Every user has a unique numeric ID. This ID characterizes
all processes run by the user and all files owned by the user.
Processes run by a particular user can access that user's resources
but have very limited access to the resources of other users.

There is one user, called the superuser, that has
full rights and privileges to do anything to any process or any file.
A process run by the superuser can fully access any user's resources
and can impersonate any user.

Applying this information to a network daemon, such as a Web server,
an RMI activation server, or an EJB container: the daemon can be run
as a normal user or as the superuser. Running as superuser has some
advantages - classes run by the daemon can control any user's resources
needed to provide any service. But it's also a huge security hole that
can compromise a system with the introduction of erroneous or malicious
code. A much more common, and safer, solution is to create a unique
userid to be used by a daemon or daemons.

Whatever solution is adopted - running as a normal user or superuser -
it is the system administrator who chooses how to set up the daemon.
The configuration decisions made by the system administrator determine
how much power the Java code will be able to exercise.

The Problem

So back to the question: how can your classes - servlets,
EJBs, RMIs, or whetever - gain the privileges they need to provide
services to users?

In general, the answer is that they cannot: the daemon is usually
running under its own safe userid, and the system will not let you
impersonate other users.

A Solution

Unix and Linux systems provide a few special doors that allow users to
assume the privileges of other users. For example, the su command
allows you to execute commands as another user, if you know that user's
password. The best, safest, and most portable way to assume other user
privileges is to use one of these doors to run a program that acts with
the needed user privileges.

One good choice is the sudo utility, a powerful and highly
configurable way to assign user privileges for running programs. Sudo is not a standard
Linux utility, but it is available in many Linux distributions and can
also be found at rpmfind.
It must be installed by the system administrator, and it must be
configured to assign the needed privileges. The next section describes
a sample configuration.

Example Solution Configuration

To explore a possible solution based on sudo, let's consider
a simple problem: a servlet that allows a remote user to reboot the
system.

Assume the servlet engine is run by a non-privileged user named
"apache". This user cannot normally reboot the system, but a couple of
entries in sudo's configuration file, sudoers, can change
that:

Add a command alias specification for the reboot command:

Cmnd_Alias REBOOT=/sbin/reboot

Add a privilege specification:

apache ALL=(ALL) NOPASSWD: REBOOT

This gives the user "apache" the power to reboot the system - without
having to enter an additional password. Anyone
logged in as this user could reboot by entering this command:

sudo /usr/sbin/reboot

Your servlet can do the same thing - by executing that command
through Runtime.exec():

Runtime.getRuntime().exec("sudo /usr/sbin/reboot");

This is obviously a crude example, but it illustrates the basic
point: sudo can assign specific privileges to specific users
to run specific programs, possibly with specific options.
In this example, it assigned superuser
privileges to perform a reboot, but it can also assign privileges for
other userids and other operations: you can tailor the privileges
assigned by sudo to those your classes need to provide their
services.

Conclusion

Dealing with Linux user authorization and authentication in server
processes is not straightforward in Java. This FAQ has described the
problem and presented one approach - running of privileged external
programs - that can be used by server-based Java classes to get the
privileges they need to provide their services.

Advertiser Disclosure:
Some of the products that appear on this site are from companies from which QuinStreet receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. QuinStreet does not include all companies or all types of products available in the marketplace.