For each request, a servlet has the ability to find out about the client machine and, for pages requiring authentication, about the actual user. This information can be used for logging access data, associating information with individual users, or restricting access to certain clients.
A
servlet can use
getRemoteAddr()
and
getRemoteHost()
to retrieve the IP address and hostname of the client machine,
respectively:
public String ServletRequest.getRemoteAddr() public String ServletRequest.getRemoteHost()
Both values are returned as String
objects. The
information comes from the socket that connects the server to the
client, so the remote address and hostname may be that of a proxy
server. An example remote address might be
"192.26.80.118"
while an example remote host might
be "dist.engr.sgi.com"
.
The IP address or remote hostname can be converted to a
java.net.InetAddress
object using
InetAddress.getByName()
:
InetAddress remoteInetAddress = InetAddress.getByName(req.getRemoteAddr());
Due to the United States government’s policy restricting the export of strong encryption outside the United States and Canada, some web sites must be careful about who they let download certain software. Servlets, with their ability to find out about the client machine, are well suited to enforce this restriction. These servlets can check the client machine and provide links for download only if the client appears to be coming from inside the United States or Canada. Example 4.5 gives an example.
Example 4-5. Can they be trusted?
import java.io.*; import java.net.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class ExportRestriction extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html"); PrintWriter out = res.getWriter(); // ...Some introductory HTML... // Get the client's hostname String remoteHost = req.getRemoteHost(); // See if the client is allowed if (! isHostAllowed(remoteHost)) { out.println("Access <BLINK>denied</BLINK>"); // filter out the blink! } else { out.println("Access granted"); // Display download links, etc... } } // We assume hosts ending with .com, .edu, .net, .org, // .gov, .mil, .us, and .ca are legal even though this is an // over-simplification now that .com, .net, and .org have // become global top-level domains. We also assume // clients without a domain name are local and that // local is allowed. (After all, if local isn't allowed // you would have to be outside the United States and Canada -- so // why would you be using this servlet?) private boolean isHostAllowed(String host) { return (host.endsWith(".com") || host.endsWith(".edu") || host.endsWith(".net") || host.endsWith(".org") || host.endsWith(".gov") || host.endsWith(".mil") || host.endsWith(".us") || host.endsWith(".ca") || (host.indexOf('.') == -1)); // no domain, assume OK } }
This servlet gets the client hostname with a call to
req.getRemoteHost()
and, based on its suffix,
decides if the client came from inside or outside the United States
and Canada. Of course, be sure to get high-priced
legal counsel
before making any cryptographic code available for download.
What do you do when you need to restrict access to some of your web pages but want to have a bit more control over the restriction than this “continent by continent” approach? Say, for example, you publish an online magazine and want only paid subscribers to read the articles. Well (prepare yourself), you don’t need servlets to do this.
Nearly every HTTP server has a built-in capability to restrict access to some or all of its pages to a given set of registered users. How you set up restricted access depends on the server, but here’s how it works mechanically. The first time a browser attempts to access one of these pages, the HTTP server replies that it needs special user authentication. When the browser receives this response, it usually pops open a window asking the user for a name and password appropriate for the page, as shown in Figure 4.1.
Once the user enters his information, the browser again attempts to access the page, this time attaching the user’s name and password along with the request. If the server accepts the name/password pair, it happily handles the request. If, on the other hand, the server doesn’t accept the name/password pair, the browser is again denied and the user swears under his breath about forgetting yet another password.
How does this involves servlets? When access to a servlet has been
restricted by the server, the servlet can get the name of the user
that was accepted by the server, using the getRemoteUser()
method:
public String HttpServletRequest.getRemoteUser()
Note that this information is retrieved from the servlet’s
HttpServletRequest
object, the HTTP-specific subclass of
ServletRequest
. This method returns the name of
the user making the request as a String
or
null
if access to the servlet was not restricted.
There is no comparable method to get the remote user’s password
(although it can be manually determined, as shown in Chapter 8). An example remote user might be
"jhunter"
.
A servlet can also use the
getAuthType()
method to find out what type of
authorization was used:
public String HttpServletRequest.getAuthType()
This method returns the type of authorization used or
null
if access to the servlet was not restricted.
The most common authorization types are "BASIC"
and "DIGEST"
.
By the time the servlet calls
getRemoteUser()
, the server has already determined that the user is authorized to
invoke the servlet, but that doesn’t mean the remote
user’s name is worthless. The servlet could perform a second
authorization check, more restrictive and dynamic than the
server’s. For example, it could return sensitive information
about someone only if that person made the request, or it could
enforce a rule that each user can make only 10 accesses per
day.[21]
Then again, the client’s name can simply tell the servlet who is accessing it. After all, the remote host is not necessarily unique to one user. Unix servers often host hundreds of users, and gateway proxies can act on behalf of thousands. But bear in mind that access to the client’s name comes with a price. Every user must be registered with your server and, before accessing your site, must enter his name and password. Generally speaking, authentication should not be used just so a servlet can know to whom it is talking. Chapter 7, describes some better, lower-maintenance techniques for knowing about users. However, if a servlet is already protected and has the name easily available, the servlet might as well use it.
With the remote user’s name, a servlet can save information about each client. Over the long term, it can remember each individual’s preferences. For the short term, it can remember the series of pages viewed by the client and use them to add a sense of state to a stateless HTTP protocol. The session tracking tricks from Chapter 7 may be unnecessary if the servlet already knows the name of the client user.
A
simple servlet that uses
getRemoteUser()
can greet its clients by name and
remember when each last logged in, as shown in Example 4.6.
Example 4-6. Hey, I remember you!
import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class PersonalizedWelcome extends HttpServlet { Hashtable accesses = new Hashtable(); public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html"); PrintWriter out = res.getWriter(); // ...Some introductory HTML... String remoteUser = req.getRemoteUser(); if (remoteUser == null) { out.println("Welcome!"); } else { out.println("Welcome, " + remoteUser + "!"); Date lastAccess = (Date) accesses.get(remoteUser); if (lastAccess == null) { out.println("This is your first visit!"); } else { out.println("Your last visit was " + accesses.get(remoteUser)); } if (remoteUser.equals("PROFESSOR FALKEN")) { out.println("Shall we play a game?"); } accesses.put(remoteUser, new Date()); } // ...Continue handling the request... } }
This servlet uses a
Hashtable
to save the last access time for each
remote user. The first thing it does for each request is greet the
person by name and tell him the time of his last visit. Then it
records the time of this visit, for use next time. After that, it
continues handling the request.
Get Java Servlet Programming now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.