Authenticated / Authorized HTML (JSP method)


Scope:  Define the process and methods used to Authenticate and Authorize web pages using  JSP, PKI, LDAP and Sun web servers.  Include 2 methods of Authentication with and without Authorization. Explain the process used in the Iplanet server for authorization and handling of X.509 certificates.  Extrapolate into the Apache Server model a similar development.

Methods:


Web Server functions:
The Sun One (formerly Netscape/Iplanet) web servers have always maintained support for X.509 certificate authentication.  Apache has provided similar support using Mod SSL.  The heart of the process is done using the web servers ability to protect a document or portion of the web tree by requiring authentication.  Each of the server platforms can provide such a function and provide information from the certificate of a successful authentication.  The web servers can validate the certificate, parse the certificate internals for explicitly defined values which can be used to populate session variables to be passed to other applications such as jsp back end applications for additional processing.  Once the user's presented certificate is verified, values in the certificate can be used to query a directory for additional information such as group membership which can be used for authorization purposes. 

UTHSC-Houston JSP authentication:
    Any web page can be made to require authentication using this process. Web server X.509 configuration, certificate authority installation and support for Java Server Pages are required but once correctly configured are not modified.  JSPs must be stored in a directory that has been configured to support them.  Once a web page is located in a JSP directory, a simple 3 line modification at the top of the pages provides authentication and if required authorization.  Add the following lines to the top of the page you wish to protect.

<% request.setAttribute("authenticationMethod","certificate"); %>
<% request.setAttribute("authorizationGroup","oac_staff"); %>
<%@ include file="/jsp/auth/authentication.jsp" %>

    The first line sets the type of authentication that will be required to access the page.  The second line defines an LDAP group that whose membership is authorized to access the page (not required).  The third line sends the attribute set to the authentication application that will provide that logic required for access. 
    If the authentication method is certificate, the application is directed to run check_certificate.jsp under a certificate protected directory where the user is asked to present his/her X.509 certificate for AuthN, the web server verifies the certificate and if successful, returns the user's uid found in LDAP via a search by the users email address from the certificate.  The user's information is queried from LDAP by the web server and stored in a session variable by check_cert.jsp.
    If the authentication method is login, the application is directed to run login.jsp under an LDAP authentication protected directory. The web server presents a standardized LDAP login page where the user presents login credentials.  The remote users attribute is populated in the session variable and returned to authentication.jsp for additional processing.
    The JSPs return this information to Authentication.jsp where it can be used to test if the user's DN value is a unique member of the specified Authorization group if the second line defines an LDAP authorization group.





Authentication.jsp
<%@ page import="edu.tmc.uth.oac.ldap.*"%> //for ldap connections
<%@ page import="edu.tmc.uth.oac.util.*"%> //may not be required
<%@ page import="java.net.URLEncoder"%>    //may not be required
<%@ page import="netscape.ldap.LDAPException"%> //error handling in ldap

<%
  //    ldap_connection_monitor.jsp contains a class that implements HttpSessionBindingListener
  //    This class is used to make sure that the LDAP directory connection is closed no matter
  //    how the user navigates away from the page.
%>
<%@ include file="/jsp/auth/ldap_connection_monitor.jsp" %>

<% 
  // Save the requested URL ( the calling page )
  String setpage = request.getScheme() + "://" + request.getServerName() + request.getServletPath();
  session.setAttribute("setpage", setpage);
   
if(request.getQueryString()!=null) {
    session.setAttribute("theRequestQueryString",request.getQueryString());
}

  // Get LDAP directory
  String authDirectory = (String)request.getAttribute("authDirectory");
  if(authDirectory==null) authDirectory = (String)session.getAttribute("authDirectory");
  if(authDirectory==null) authDirectory = "ProdLDAP_SSL";
 
  // Get Authentication Method: from the calling jsp, sets the method to cert or ldap password
  String authenticationMethod = (String)request.getAttribute("authenticationMethod");
  if(authenticationMethod==null) authenticationMethod = (String)session.getAttribute("authenticationMethod");
  if(authenticationMethod==null) authenticationMethod = "password";
 
  // Set Authentication Page: if the authentication is cert, redirect to cert protected directory else ldap protected directory
  String authenticationPage;
  String authError = null;
  if(authenticationMethod.equals("certificate")) authenticationPage = "/jspcert/auth/check_certificate.jsp";
  else authenticationPage = "/jsp/auth/login.jsp";
 
  // Get Authorization Method:  If an authorization group is required, it is sent as a parameter to this app from the calling jsp
  String authorizationGroup = (String)request.getAttribute("authorizationGroup");
  String authorizationGroupOwner = (String)request.getAttribute("authorizationGroupOwner");
  if(authorizationGroup!=null) request.setAttribute("authorizationGroup", authorizationGroup);
  if(authorizationGroupOwner!=null) request.setAttribute("authorizationGroupOwner", authorizationGroupOwner);

  // Authenticate and Authorize
  if(request.getParameter("uid")!=null || session.getAttribute("certUid")!=null) { //CHANGED
    String uid = request.getParameter("uid");
    if (uid==null) { uid = (String)session.getAttribute("certUid");} //ADDED
    String password = request.getParameter("userPassword");
    if(password==null && session.getAttribute("certUid")==null) {
        response.sendRedirect(authenticationPage);
        return;
    }

    UTHLdap uthLdap = null;
    LDAPUser ldapUser;

    try {
        // Bind to LDAP using credentials provided by user
        if(authDirectory == "ProdLDAP") {
            if(password != null) uthLdap = new ProdLDAP(uid,password);
            // or open anonymous LDAP connection
            else {
                uid = (String)session.getAttribute("certUid");
                session.removeAttribute("certUid");
                if (uid==null) {
                    authError = URLEncoder.encode("Invalid Page Navigation");
                    response.sendRedirect(authenticationPage + "?uid=" + uid + "&error=" + authError);
                    return;
                }
                uthLdap = new ProdLDAP(ProdLDAP.PROXY,uid);
            }
        }
        else if(authDirectory == "ProdLDAP_SSL") {
           
            if(password != null) uthLdap = new ProdLDAP(uid,password,true);
            else {
                uid = (String)session.getAttribute("certUid");
                if (uid==null) { uid = (String)session.getAttribute("certUid");} //ADDED
           
                session.removeAttribute("certUid");
           
                if (uid==null) {
                    authError = URLEncoder.encode("Invalid Page Navigation");
                    response.sendRedirect(authenticationPage + "?uid=" + uid + "&error=" + authError);
                    return;
                }
                uthLdap = new ProdLDAP(ProdLDAP.PROXY_SSL,uid);
            }
        }
        else if(authDirectory == "ProdDcLDAP") {
            if(password != null) uthLdap = new ProdDcLDAP(uid,password);
            // or open anonymous LDAP connection
            else {
                uid = (String)session.getAttribute("certUid");
                session.removeAttribute("certUid");
                if (uid==null) {
                    authError = URLEncoder.encode("Invalid Page Navigation");
                    response.sendRedirect(authenticationPage + "?uid=" + uid + "&error=" + authError);
                    return;
                }
                uthLdap = new ProdDcLDAP(ProdDcLDAP.PROXY,uid);
            }
        }
        else if(authDirectory == "VLDAP") {
            if(password != null) uthLdap = new VLDAP(uid,password);
            // or open anonymous LDAP connection
            else {
                uid = (String)session.getAttribute("certUid");
                session.removeAttribute("certUid");
                if (uid==null) {
                    authError = URLEncoder.encode("Invalid Page Navigation");
                    response.sendRedirect(authenticationPage + "?uid=" + uid + "&error=" + authError);
                    return;
                }
                uthLdap = new ProdLDAP(ProdLDAP.PROXY,uid);
            }
        }
        else if(authDirectory == "TestLDAP") {
            if(password != null) uthLdap = new TestLDAP(uid,password);
            // or open anonymous LDAP connection
            else {
                uid = (String)session.getAttribute("certUid");
                session.removeAttribute("certUid");
                if (uid==null) {
                    authError = URLEncoder.encode("Invalid Page Navigation");
                    response.sendRedirect(authenticationPage + "?uid=" + uid + "&error=" + authError);
                    return;
                }
                uthLdap = new TestLDAP(TestLDAP.PROXY,uid);
            }
        }
        else if(authDirectory == "TestDcLDAP") {
            if(password != null) uthLdap = new TestDcLDAP(uid,password);
            // or open anonymous LDAP connection
            else {
                uid = (String)session.getAttribute("certUid");
                session.removeAttribute("certUid");
                if (uid==null) {
                    authError = URLEncoder.encode("Invalid Page Navigation");
                    response.sendRedirect(authenticationPage + "?uid=" + uid + "&error=" + authError);
                    return;
                }
                uthLdap = new TestDcLDAP(TestDcLDAP.PROXY,uid);
            }
        }
    } catch (LDAPException le) {
        // If authentication fails return error message to authentication page
        authError = URLEncoder.encode("Invalid UID or password");
        response.sendRedirect(authenticationPage + "?uid=" + uid + "&error=" + authError);
        return;
    } catch (Exception e) {
        // If authentication fails return error message to authentication page
        authError = URLEncoder.encode(e.toString());
        response.sendRedirect(authenticationPage + "?uid=" + uid + "&error=" + authError);
        return;
    }

    // Check for successful bind to LDAP or assume certificate authentication method is being used
    if (uthLdap.isAuthenticated() || authenticationMethod.equals("certificate")) {
        ldapUser = new LDAPUser(uid,uthLdap);

        // Perform Group membership authorization if required
        if(authorizationGroup != null) {
            if(!ldapUser.isMemberOf(authorizationGroup)) {
                uthLdap.close();
                authError = URLEncoder.encode("Group Authorization failure");
                response.sendRedirect(authenticationPage + "?uid=" + uid + "&error=" + authError);
                return;
            }
        }
       
        // Perform Group ownership authorization if required
        if(authorizationGroupOwner != null) {
            if(!ldapUser.isOwnerOf(authorizationGroupOwner)) {
                uthLdap.close();
                authError = URLEncoder.encode("Owner Authorization failure");
                response.sendRedirect(authenticationPage + "?uid=" + uid + "&error=" + authError);
                return;
            }
        }
       
        session.setMaxInactiveInterval(300); // set default session timeout - 5 minutes
       
        // Set authorization method indicators
        if(authorizationGroup==null) session.removeAttribute("authorizationGroup");
        else session.setAttribute("authorizationGroup", authorizationGroup);
        if(authorizationGroupOwner==null) session.removeAttribute("authorizationGroupOwner");
        else session.setAttribute("authorizationGroupOwner", authorizationGroupOwner);
   
        // Save user information in the session
        session.setAttribute("uid",uid);
        if (password != null) session.setAttribute("userPassword",password);
        if (ldapUser != null) {
            session.setAttribute("thisUser",ldapUser);
            session.setAttribute("lastName",ldapUser.sn);
            session.setAttribute("firstName",ldapUser.givenname);
            session.setAttribute("middleName",ldapUser.middlename);
            session.setAttribute("cn",ldapUser.cn);
            session.setAttribute("mail",ldapUser.mail);
        }
        session.setAttribute("remoteHost",request.getRemoteHost());    // Users IP Address
        session.setAttribute("authenticationMethod", authenticationMethod);    // Method used to authenticate
        session.setAttribute("authDirectory", authDirectory);    // Directory used to authenticate

        // Save LDAP connection and create HttpSessionBindingListener to make sure the connection gets closed
        session.setAttribute("uthLdap",uthLdap);
        LdapConnectionMonitor lcm = new LdapConnectionMonitor();
        lcm.setLogFileName("ldapconnection.log");
        lcm.setSessionId(session.getId());
        lcm.setLdapConnection(uthLdap);
        session.setAttribute("lcm",lcm);
    }
    else {
        uthLdap.close();
        // If authentication fails return error message to authentication page
        authError = URLEncoder.encode("Invalid UID or password");
        response.sendRedirect(authenticationPage + "?uid=" + uid + "&error=" + authError);
        return;
    }
  }

  // If the session uid equals null the user has not been authenticated
 
  if(session.getAttribute("uid")==null) {
    response.sendRedirect(authenticationPage);
    return;
  }

  // If the session authentication method is null the user has not been authenticated
  if(session.getAttribute("authenticationMethod")==null) {
    response.sendRedirect(authenticationPage);
    return;
  }
  // If the session authentication method is different than the request authentication method
  // reauthentication is required
  if(!((String)session.getAttribute("authenticationMethod")).equals(authenticationMethod)) {
    response.sendRedirect(authenticationPage);
    return;
  }
 
  // If the session authentication directory is different than the request authentication directory
  // reauthentication is required
  if(!((String)session.getAttribute("authDirectory")).equals(authDirectory)) {
    response.sendRedirect(authenticationPage);
    return;
  }
 
  // The request authorization group must match the session authorization group
  // If Group Membership authorizaion is requested
  if(authorizationGroup!=null) if(session.getAttribute("authorizationGroup") == null) {
    response.sendRedirect(authenticationPage);
    return;
  }
  if(authorizationGroup!=null) if(!((String)session.getAttribute("authorizationGroup")).equals(authorizationGroup)) {
    response.sendRedirect(authenticationPage);
    return;
  }
 
  // The request authorization group must match the session authorization group
  // If Group ownership authorizaion is requested
  if(authorizationGroupOwner!=null) if(session.getAttribute("authorizationGroupOwner") == null) {
    response.sendRedirect(authenticationPage);
    return;
  }
  if(authorizationGroupOwner!=null) if(!((String)session.getAttribute("authorizationGroupOwner")).equals(authorizationGroupOwner)) {
    response.sendRedirect(authenticationPage);
    return;
  }

%>

Check_cert.jsp

<%
    // Get users uid from web server.
    // This server value is set once the user presents a valid certificate.
    String uid = request.getRemoteUser();
   
    // Get error message if one exists
    String error = (String) request.getParameter("error");
   
    // Set return page
    String setpage = (String) session.getAttribute("setpage");

    // Set 'certUid' attribute to indicate that certificate authentication was successful
    session.setAttribute("certUid",uid);

    String temp = (String)session.getAttribute("theRequestQueryString");
    if(temp!=null) {
        session.removeAttribute("theRequestQueryString");
    }

    // If authentication is successful, return to calling page and set 'uid' parameter
    if(error == null) {
        if(temp!=null) {
            response.sendRedirect(setpage + "?"+temp);
        }else {
            response.sendRedirect(setpage);   
        }
    } else {
        // Display error message below.
%>
            <html><head><title>UT-Houston Directory Service Login</title></head>
            <body BGCOLOR="#ffffff" LINK="#003366" ALINK="#669999" VLINK="#003366">
            <center><H2>Authentication/Authorization Failure in Check Certificate Page!</H2></center>
            <center>
              <table border=1>
                <tr>
                  <td>
                    The following error occurred:
                  </td>
                </tr>
                <tr>
                  <td>
                    <%=error%>
                  </td>
                </tr>
                <tr>
                  <td>
                    <% if(setpage!=null) { %><a href="<%=setpage%>"><%=setpage%></a><%}%>
                  </td>
                </tr>
              </table>
            </center>
            </body>
            </html>
<%
    }
%>


Office of Academic Computing 1/25/04