8.4. Example: Handling All Security Programmatically

Listing 8.4 shows a servlet that generates hot stock recommendations. If it were made freely available on the Web, it would put half the financial advisors out of business. So, it needs to be password protected, available only to people who have paid the very reasonable $2000 access fee.

Furthermore, the servlet needs to be as portable as possible because ISPs keep shutting it down (they claim fraud, but no doubt they are really being pressured by the financial services companies that the servlet outperforms). So, it uses complete programmatic security and is entirely self-contained: absolutely no changes or server-specific customizations are required to move the servlet from system to system.

Finally, requiring an exact match against a static list of usernames and passwords (as is required in container-managed security) is too limiting for this application. So, the servlet uses a custom algorithm (see the areEqualReversed method) for determining if an incoming username and password are legal.

Figure 8-3 shows what happens when the user first tries to access the servlet. Figure 8-4 shows the result of a failed authorization attempt; Figure 8-5 shows what happens if the user gives up at that point. Figure 8-6 shows the result of successful authorization.

Figure 8-3. When the browser first receives the 401 (Unauthorized) status code, it opens a dialog box to collect the username and password.


Figure 8-4. When the browser receives the 401 (Unauthorized) status code on later attempts, it indicates that authorization failed. Netscape 6 and Internet Explorer indicate authorization failure by showing the original dialog box with the previously entered username and an empty password field.


Figure 8-5. Result of cancelled authorization attempt with Tomcat—Tomcat returns an error page along with the 401 (Unauthorized) status code. JRun and ServletExec omit the error page in this case.


Figure 8-6. Result of successful authorization attempt. Invest now!


Listing 8.4. StockTip.java
package stocks; 

import java.io.*; 
import javax.servlet.*; 
import javax.servlet.http.*; 
import sun.misc.BASE64Decoder; 

/** Servlet that gives very hot stock tips. So hot that 
 *  only authorized users (presumably ones who have paid 
 *  the steep financial advisory fee) can access the servlet. 
 */ 

public class StockTip extends HttpServlet {

  /** Denies access to all users except those who know 
   *  the secret username/password combination. 
   */ 
  public void doGet(HttpServletRequest request, 
                    HttpServletResponse response) 
      throws ServletException, IOException {
    String authorization = request.getHeader("Authorization");
						if (authorization == null) {
						askForPassword(response);
						} else { 
      // Authorization headers looks like "Basic blahblah", 
      // where blahblah is the base64 encoded username and 
      // password. We want the part after "Basic ". 
      String userInfo = authorization.substring(6).trim();
						BASE64Decoder decoder = new BASE64Decoder();
						String nameAndPassword =
						new String(decoder.decodeBuffer(userInfo)); 
      // Decoded part looks like "username:password". 
      int index = nameAndPassword.indexOf(":");
						String user = nameAndPassword.substring(0, index);
						String password = nameAndPassword.substring(index+1); 
      // High security: username must be reverse of password. 
      if (areEqualReversed(user, password)) {
						showStock(request, response);
						} else {
						askForPassword(response);
						} 
    } 
  } 

  // Show a Web page giving the symbol of the next hot stock. 
  private void showStock(HttpServletRequest request, 
                         HttpServletResponse response) 
      throws ServletException, IOException {
        response.setContentType("text/html"); 
    PrintWriter out = response.getWriter(); 
    String docType = 
      "<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 " + 
      "Transitional//EN">
"; 
    out.println(docType + 
                "<HTML>
" + 
                "<HEAD><TITLE>Hot Stock Tip!</TITLE></HEAD>
" + 
                "<BODY BGCOLOR="#FDF5E6">
" + 
                "<H1>Today's Hot Stock:"); 
    for(int i=0; i<3; i++) {
      out.print(randomLetter()); 
    } 
    out.println("</H1>
" + 
                "</BODY></HTML>"); 
  } 

  // If no Authorization header was supplied in the request. 

  private void askForPassword(HttpServletResponse response) {
						response.setStatus(response.SC_UNAUTHORIZED); // I.e., 401
						response.setHeader("WWW-Authenticate",
						"BASIC realm="Insider-Trading"");
						} 

  // Returns true if s1 is the reverse of s2. 
  // Empty strings don't count. 

  private boolean areEqualReversed(String s1, String s2) {
    s2 = (new StringBuffer(s2)).reverse().toString(); 
    return((s1.length() > 0) && s1.equals(s2)); 
  } 

  private final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 

  // Returns a random number from 0 to n-1 inclusive. 

  private int randomInt(int n) {
    return((int)(Math.random() * n)); 
  } 

  // A random letter from the alphabet. 

  private char randomLetter() {
    return(ALPHABET.charAt(randomInt(ALPHABET.length()))); 
  } 
} 

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.139.86.18