Saturday, May 02, 2009

Using JSP/Servlet/Filter to Implement Login Authorization

login.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<%@ include file="/common/taglibs.jsp"%>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<%@ include file="/common/meta.jsp"%>
<title>Login - <m:message key="webapp.title" /></title>
<link rel="stylesheet" type="text/css" href="<c:url value='/styles/login.css'/>" />
<script type="text/javascript" src="<c:url value='/scripts/login.js'/>"></script>
</head>
<body>
<%@ include file="/common/header.jsp"%>
<div id="login">
<%@ include file="/common/status.jsp"%>
<div id="loginContent">
<form action="<c:url value='/login.do'></c:url>" method="post" onsubmit="return check()">
<div><input type="hidden" name="uri" value="${uri}" /></div>
<div><input type="hidden" name="repos" value="${repos}" /></div>
<div><m:message key="login.username" /><input type="text" class="commonInput" name="username" value="${username}" /></div>
<div><m:message key="login.password" /><input type="password" class="passwordInput" name="password" value="${password}" /></div>
<div id="submit"><input type="submit" class="buttonInput" value="<m:message key="button.login" />" /></div>
</form>
</div>
</div>
<%@ include file="/common/footer.jsp"%>
</body>
</html>



LoginServlet.java

package sa.cdc.svn.web.security;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import sa.cdc.svn.Constant;
import sa.cdc.svn.model.security.Certificate;
import sa.cdc.svn.service.server.ServerManager;
import sa.cdc.svn.web.BaseServlet;

public class LoginServlet extends BaseServlet {
    private static final long serialVersionUID = 8871588625655468698L;

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String loginPage = "/WEB-INF/pages/login.jsp";
        Certificate certificate = null;

        // redirect to this page after login
        String uri = request.getParameter("uri");
        uri = (uri == null) ? "/home.do" : uri;
       
        request.setAttribute("uriClick", uri);
       
        String repos = request.getParameter("repos");
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        String ip = request.getRemoteAddr();

        // first try to use current certificate
        certificate = (Certificate) request.getSession().getAttribute(Constant.SESSION_CERTIFICATE);
        if (certificate == null) {
            if ((repos == null || repos.length() == 0) && isReposOperation(uri)) {
                // repository can't be empty
                request.setAttribute("uri", uri);
                request.setAttribute(Constant.STATUS, Constant.STATUS_ERROR);
                request.setAttribute(Constant.MESSAGE, "Please select a repository to login.");
                request.getRequestDispatcher("/home.do").forward(request, response);
            } else if (username == null || password == null) {
                // username or password can't be null
                request.setAttribute("uri", uri);
                request.setAttribute("repos", repos);
                request.getRequestDispatcher(loginPage).forward(request, response);
            } else if (username.length() == 0 || password.length() == 0) {
                // username or password can't be empty
                request.setAttribute("uri", uri);
                request.setAttribute("repos", repos);
                request.setAttribute(Constant.STATUS, Constant.STATUS_ERROR);
                request.setAttribute(Constant.MESSAGE, "Please input username and password.");
                request.getRequestDispatcher(loginPage).forward(request, response);
            } else {
                // go into authentication
                ServerManager serverManager = new ServerManager(repos);
                certificate = serverManager.validateUser(username, password);
                if (certificate != null) {
                    // succeeded to login
                    request.getSession().setAttribute(Constant.SESSION_CERTIFICATE, certificate);
                    request.setAttribute(Constant.STATUS, Constant.STATUS_OK);
                    response.sendRedirect(request.getContextPath() + uri);
                    logInfo(request, "Login from [" + ip + "]");
                } else {
                    // failed to login
                    request.setAttribute("uri", uri);
                    request.setAttribute("repos", repos);
                    request.setAttribute(Constant.STATUS, Constant.STATUS_WARNING);
                    request.setAttribute(Constant.MESSAGE, "Username or password is invalid.");
                    request.getRequestDispatcher(loginPage).forward(request, response);
                }
            }
        } else {
            ServerManager serverManager = new ServerManager(repos);
            username = certificate.getUsername();
            password = certificate.getPassword();
            certificate = serverManager.validateUser(username, password);
            if (certificate != null) {
                // succeeded to login
                request.getSession().setAttribute(Constant.SESSION_CERTIFICATE, certificate);
                //logInfo(request, "login from [" + ip + "]");
                request.setAttribute(Constant.STATUS, Constant.STATUS_OK);
                response.sendRedirect(request.getContextPath() + uri);
            } else {
                // failed to login
                // remove the current invalid certificate
                request.getSession().removeAttribute(Constant.SESSION_CERTIFICATE);
                request.setAttribute("uri", uri);
                request.setAttribute("repos", repos);
                request.setAttribute(Constant.STATUS, Constant.STATUS_WARNING);
                request.setAttribute(Constant.MESSAGE, "Username or password is invalid.");
                request.getRequestDispatcher(loginPage).forward(request, response);
            }
        }
    }

    private boolean isReposOperation(String uri) {
        return (uri.equals("/authz.do") || uri.equals("/group.do") || uri.equals("/alias.do") || uri
                .equals("/account.do"));
    }

}



LogoutServlet.java

package sa.cdc.svn.web.security;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import sa.cdc.svn.web.BaseServlet;

public class LogoutServlet extends BaseServlet {
    private static final long serialVersionUID = 9069229823236250773L;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String ip = request.getRemoteAddr();
        logInfo(request, "Logout from [" + ip + "]");
        request.getSession().invalidate();
        response.sendRedirect(request.getContextPath() + "/home.do");
       
    }
}



AccessControlFilter.java

package sa.cdc.svn.web.security;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import sa.cdc.svn.Constant;
import sa.cdc.svn.model.security.Certificate;

public class AccessControlFilter implements Filter {

    @Override
    public void destroy() {
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        String uri = httpRequest.getRequestURI();
        uri = uri.substring(uri.indexOf('/', 1));
        request.setAttribute("uriClick", uri);
        // no need to filter login.do
        if (uri.equals("/login.do") || uri.equals("/home.do") || uri.equals("/logout.do")
                || uri.equals("/search.do")) {
           
            chain.doFilter(request, response);
            return;
        }
       
        HttpSession session = httpRequest.getSession();
        Certificate certificate = (Certificate) session.getAttribute(Constant.SESSION_CERTIFICATE);
        if (certificate != null) {
            // validate user if have permission
            boolean permitted = false;
            if (uri.equals("/authz.do"))
                permitted = certificate.hasRole(Constant.ROLE_CONTROLLER);
            else if (uri.equals("/group.do"))
                permitted = certificate.hasRole(Constant.ROLE_CONTROLLER);
            else if (uri.equals("/alias.do"))
                permitted = certificate.hasRole(Constant.ROLE_CONTROLLER);
            else if (uri.equals("/account.do"))
                permitted = certificate.hasRole(Constant.ROLE_CONTROLLER);
            else if (uri.equals("/davsvn.do"))
                permitted = certificate.hasRole(Constant.ROLE_ADMINISTRATOR);
            else if (uri.equals("/admin.do"))
                permitted = certificate.hasRole(Constant.ROLE_ADMINISTRATOR);
            else if (uri.equals("/webclient.do"))
                permitted = certificate.hasRole(Constant.ROLE_ADMINISTRATOR);
            if (permitted) {
                // transfer to next filter
                chain.doFilter(request, response);
            } else {
                // redirect to deny page
                request.setAttribute(Constant.STATUS, Constant.STATUS_WARNING);
                request.setAttribute(Constant.MESSAGE, "Have no permission to access " + uri + ".");
                request.getRequestDispatcher("/WEB-INF/pages/deny.jsp").forward(request, response);
            }
        } else {
            // go to login to get a certificate, forward to this uri after login
            httpResponse.sendRedirect(httpRequest.getContextPath() + "/login.do?uri=" + uri);
        }
    }
}



meta.jsp

<!-- Prevents caching at the Proxy Server -->
<meta http-equiv="Expires" content="0" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Cache-Control" content="no-store" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="icon" href="<c:url value='/images/favicon.ico'/>" type="image/x-icon" />
<link rel="shortcut icon" href="<c:url value='/images/favicon.ico'/>" type="image/x-icon" />
<link rel="stylesheet" type="text/css" href="<c:url value='/styles/global.css'/>" />
<script type="text/javascript" src="<c:url value='/scripts/global.js'/>"></script>



taglib.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="m"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="s"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="n"%>



Status.jsp

<%@ include file="/common/taglibs.jsp"%>
<div id="status">
  <span style="background:url(<c:url value='/images/${status}.gif'/>) no-repeat;">
     <c:out value="${message}" />
  </span>
</div>

No comments: