Java tutorial
/* * Adito * * Copyright (C) 2003-2006 3SP LTD. All Rights Reserved * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package com.adito.core.actions; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts.Globals; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage; import org.apache.struts.action.ActionMessages; import com.adito.boot.Branding; import com.adito.boot.Util; import com.adito.core.CoreUtil; import com.adito.core.ServletRequestAdapter; import com.adito.core.ServletResponseAdapter; import com.adito.policyframework.NoPermissionException; import com.adito.policyframework.Permission; import com.adito.policyframework.PolicyDatabaseFactory; import com.adito.policyframework.ResourceType; import com.adito.properties.PropertyProfile; import com.adito.security.Constants; import com.adito.security.LogonController; import com.adito.security.LogonControllerFactory; import com.adito.security.SessionInfo; import com.adito.security.SystemDatabaseFactory; import com.adito.security.User; /** * * Generic action to be used for all authenticated actions by the Adito * project. This checks that the user is logged on and if not directs them to * the logon page. Once logon is complete, the user will be directed to the * request path. * @since 0.1 * @see com.adito.core.actions.AuthenticatedDispatchAction */ public abstract class AuthenticatedAction extends DefaultAction implements CoreAction { static Log log = LogFactory.getLog(AuthenticatedAction.class); // Private instance variables private boolean requiresAdministrator; private ResourceType resourceType; private Permission[] permissions; /** * Use this constructor for actions that do not require any resource * permissions */ public AuthenticatedAction() { } /** * Use this constructor for actions that require a resource permission to * operator * * @param resourceType resource type * @param permissions permission required */ public AuthenticatedAction(ResourceType resourceType, Permission permissions[]) { if (resourceType == null || permissions == null || permissions.length < 1) { throw new IllegalArgumentException("Must provide a resource type and at least 1 permission."); } this.resourceType = resourceType; this.permissions = permissions; } /** * Get the {@link SessionInfo} for this session. This will only be available * after * {@link #execute(ActionMapping, ActionForm, HttpServletRequest, HttpServletResponse)} * has been called. * <p> * There are many places where the session info object is required. The * usual way is to use * {@link LogonController#getSessionInfo(HttpServletRequest)}. Whereever * possible that method should be replaced with a call to this method. * * @param request TODO * * @return session info for request */ public SessionInfo getSessionInfo(HttpServletRequest request) { return LogonControllerFactory.getInstance().getSessionInfo(request); } public final ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { // Setup mode boolean installMode = isInstallMode(); if (installMode) { if ((getNavigationContext(mapping, form, request, response) & SessionInfo.SETUP_CONSOLE_CONTEXT) == 0) { return mapping.findForward("setup"); } else { /* * Make the mapping and form available, this helps with reusing * some JSP pages */ request.setAttribute(Constants.REQ_ATTR_ACTION_MAPPING, mapping); request.setAttribute(Constants.REQ_ATTR_FORM, form); CoreUtil.checkNavigationContext(this, mapping, form, request, response); return onExecute(mapping, form, request, response); } } try { try { if (!SystemDatabaseFactory.getInstance().verifyIPAddress(request.getRemoteAddr())) { String link = null; log.error(request.getRemoteHost() + " is not authorized"); if (log.isInfoEnabled()) log.info("Logging off, IP address verification failed."); if (LogonControllerFactory.getInstance().hasClientLoggedOn(request, response) == LogonController.LOGGED_ON) { LogonControllerFactory.getInstance().logoffSession(request, response); } if (link != null) { return new ActionForward(link, true); } else { // Do not direct to logon page for Ajax requests if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) { response.setStatus(HttpServletResponse.SC_FORBIDDEN); return null; } return mapping.findForward("logon"); } } else { int logonStatus = LogonControllerFactory.getInstance().hasClientLoggedOn(request, response); if (logonStatus == LogonController.INVALID_TICKET) { ActionMessages msgs = new ActionMessages(); msgs.add(Globals.ERROR_KEY, new ActionMessage("login.invalidTicket")); saveErrors(request, msgs); } else if (logonStatus == LogonController.LOGGED_ON) { User currentUser = LogonControllerFactory.getInstance().getUser(request); // Set the logon ticket / domain logon ticket again LogonControllerFactory.getInstance().addCookies(new ServletRequestAdapter(request), new ServletResponseAdapter(response), (String) request.getSession().getAttribute(Constants.LOGON_TICKET), getSessionInfo(request)); if (!LogonControllerFactory.getInstance().isAdministrator(getSessionInfo(request).getUser()) && requiresAdministrator) { response.sendError(403, "You do not have permission to access this area"); return null; } else { /* * Make the mapping and form available, this helps * with reusing some JSP pages */ request.setAttribute(Constants.REQ_ATTR_ACTION_MAPPING, mapping); request.setAttribute(Constants.REQ_ATTR_FORM, form); // Check for intercepts, but don't forward if the // result of an Ajax action ActionForward fwd = checkIntercept(mapping, request, response); if (fwd != null) { return fwd; } /* * Make sure the current navigation context is * correct. If not, then check the user can switch * to the correct and switch it. */ CoreUtil.checkNavigationContext(this, mapping, form, request, response); // Check the user has the permissions to access this // page if (resourceType != null) { if (!PolicyDatabaseFactory.getInstance().isPermitted(resourceType, permissions, currentUser, false)) { throw new NoPermissionException("Action denied for current user"); } } if (request.getSession().getAttribute(Constants.SESSION_LOCKED) == null || isIgnoreSessionLock()) { if (requiresProfile()) { PropertyProfile profile = (PropertyProfile) request.getSession() .getAttribute(Constants.SELECTED_PROFILE); if (profile == null) { request.getSession().setAttribute(Constants.ORIGINAL_REQUEST, Util.getOriginalRequest(request)); return mapping.findForward("selectPropertyProfile"); } } return onExecute(mapping, form, request, response); } } } } } catch (NoPermissionException e) { if (log.isDebugEnabled()) log.debug("User attempted to access page they do have have permission for. Resource type = " + resourceType + ". Now attempting to find the first valid item in the current menu tree to display.", e); response.sendError(HttpServletResponse.SC_FORBIDDEN); return null; } catch (SecurityException ex) { // Not logged in or expired } catch (ServletException ex) { throw ex; } // Do not direct to logon page for Ajax requests if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) { response.setStatus(HttpServletResponse.SC_FORBIDDEN); return null; } return gotoLogon(mapping, form, request, response); } catch (Throwable t) { log.error("Failed to process authenticated request.", t); throw t instanceof Exception ? (Exception) t : new Exception(t); } } /** * Logon is required. By default this will direct to the logon page. * Subclasses may overide this method to go somewhere different. * * @param mapping mapping * @param form form * @param request request * @param response response * @return forward * @throws Exception */ protected ActionForward gotoLogon(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { request.getSession().setAttribute(Constants.ORIGINAL_REQUEST, Util.getOriginalRequest(request)); return mapping.findForward("logon"); } /** * Get the resource type that was passed in on the constructor. The resource * type will be supplied if this particular action implementation deals with * resources controlled by the policy framework. This is used to check * permissions * * @return resource type */ public ResourceType getResourceType() { return resourceType; } /** * Get if this action requires a profile to be selected. Some actions may * not require a profile to be present (the main one being the profile * selection page!). If no profile is found in the session and this method * returned <code>true</code> then the user will be directed to the * 'selectPropertyProfile' page. * * @return requires a profile */ protected boolean requiresProfile() { return true; } /** * Get if this action requires authentication to operator. * * @return authentication */ protected boolean requiresAuthentication() { return true; } /** * Get if this action should ignore any session locks * * @return ignore session locks */ protected boolean isIgnoreSessionLock() { return false; } /* * Send SC_AUTHORIZED to the client browser forcing HTTP authentication with * the realm "Adito". * * @param response response to write authentication request to. */ void sendAuthorizationError(HttpServletResponse response) throws IOException { response.setHeader("WWW-Authenticate", "Basic realm=\"" + Branding.PRODUCT_NAME + "\""); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); } /** * This method is called when all the default checks have take place. * Subclass would do their actual processing here. * * @param mapping mapping * @param form form * @param request request * @param response response * @return forward * @throws Exception on any error */ protected ActionForward onExecute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { return mapping.findForward("success"); } /** * Return the navigation context this action may be used in as a mask. If * the user is not in the appropriate navigation then they will be * automatically redirected to the action that switches contexts. * * @param mapping mapping * @param form form * @param request request * @param response response * @return navigation context * @see SessionInfo#MANAGEMENT_CONSOLE_CONTEXT * @see SessionInfo#USER_CONSOLE_CONTEXT * @see SessionInfo#getNavigationContext() */ public abstract int getNavigationContext(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response); protected void saveError(HttpServletRequest request, String message) { saveMessage(request, message, ""); } protected void saveError(HttpServletRequest request, String message, Object... objects) { ActionMessages actionMessages = new ActionMessages(); actionMessages.add(Globals.ERROR_KEY, new ActionMessage(message, objects)); saveErrors(request, actionMessages); } protected void saveMessage(HttpServletRequest request, String message) { saveMessage(request, message, ""); } protected void saveMessage(HttpServletRequest request, String message, Object... objects) { ActionMessages actionMessages = new ActionMessages(); actionMessages.add(Globals.MESSAGE_KEY, new ActionMessage(message, objects)); saveErrors(request, actionMessages); } }