Java tutorial
/* * ConcourseConnect * Copyright 2009 Concursive Corporation * http://www.concursive.com * * This file is part of ConcourseConnect, an open source social business * software and community platform. * * Concursive ConcourseConnect is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, version 3 of the License. * * Under the terms of the GNU Affero General Public License you must release the * complete source code for any application that uses any part of ConcourseConnect * (system header files and libraries used by the operating system are excluded). * These terms must be included in any work that has ConcourseConnect components. * If you are developing and distributing open source applications under the * GNU Affero General Public License, then you are free to use ConcourseConnect * under the GNU Affero General Public License. * * If you are deploying a web site in which users interact with any portion of * ConcourseConnect over a network, the complete source code changes must be made * available. For example, include a link to the source archive directly from * your web site. * * For OEMs, ISVs, SIs and VARs who distribute ConcourseConnect with their * products, and do not license and distribute their source code under the GNU * Affero General Public License, Concursive provides a flexible commercial * license. * * To anyone in doubt, we recommend the commercial license. Our commercial license * is competitively priced and will eliminate any confusion about how * ConcourseConnect can be used and distributed. * * ConcourseConnect 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 Affero General Public License for more * details. * * You should have received a copy of the GNU Affero General Public License * along with ConcourseConnect. If not, see <http://www.gnu.org/licenses/>. * * Attribution Notice: ConcourseConnect is an Original Work of software created * by Concursive Corporation */ package com.concursive.connect.web.controller.hooks; import com.concursive.commons.db.ConnectionElement; import com.concursive.commons.db.ConnectionPool; import com.concursive.commons.http.CookieUtils; import com.concursive.commons.http.RequestUtils; import com.concursive.commons.web.URLFactory; import com.concursive.commons.web.mvc.servlets.ControllerHook; import com.concursive.connect.Constants; import com.concursive.connect.cms.portal.beans.PortalBean; import com.concursive.connect.config.ApplicationPrefs; import com.concursive.connect.config.ApplicationVersion; import com.concursive.connect.web.modules.login.auth.session.ISessionValidator; import com.concursive.connect.web.modules.login.auth.session.SessionValidatorFactory; import com.concursive.connect.web.modules.login.beans.LoginBean; import com.concursive.connect.web.modules.login.dao.User; import com.concursive.connect.web.modules.login.utils.UserUtils; import com.concursive.connect.web.modules.members.dao.InvitationList; import com.concursive.connect.web.modules.messages.dao.PrivateMessageList; import com.concursive.connect.web.modules.profile.dao.Project; import com.concursive.connect.web.modules.profile.dao.ProjectCategory; import com.concursive.connect.web.modules.profile.dao.ProjectCategoryList; import com.concursive.connect.web.modules.profile.dao.ProjectList; import com.concursive.connect.web.modules.profile.utils.ProjectUtils; import com.concursive.connect.web.modules.search.beans.SearchBean; import com.concursive.connect.web.modules.translation.dao.WebSiteLanguageList; import com.concursive.connect.web.utils.ClientType; import com.concursive.connect.web.utils.HtmlSelect; import com.concursive.connect.web.utils.PagedListInfo; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.Iterator; /** * Executed on every request to verify user is logged in, and that system * resources are ready, also prepares portlets * * @author matt rajkowski * @version $Id$ * @created May 7, 2003 */ public class SecurityHook implements ControllerHook { private static Log LOG = LogFactory.getLog(SecurityHook.class); public final static String fs = System.getProperty("file.separator"); private ISessionValidator sessionValidator = null; /** * Checks to see if a User session object exists, if not then the security * check fails. * * @param servlet Description of the Parameter * @param request Description of the Parameter * @param response Description of the Parameter * @return Description of the Return Value */ public String beginRequest(Servlet servlet, HttpServletRequest request, HttpServletResponse response) { LOG.debug("Security request made"); ServletConfig config = servlet.getServletConfig(); ServletContext context = config.getServletContext(); // Application wide preferences ApplicationPrefs prefs = (ApplicationPrefs) context.getAttribute(Constants.APPLICATION_PREFS); // Get the intended action, if going to the login module, then let it proceed String s = request.getServletPath(); int slash = s.lastIndexOf("/"); s = s.substring(slash + 1); // If not setup then go to setup if (!s.startsWith("Setup") && !prefs.isConfigured()) { return "NotSetupError"; } // External calls if (s.startsWith("Service")) { return null; } // Set the layout relevant to this request if ("text".equals(request.getParameter("out")) || "text".equals(request.getAttribute("out"))) { // do not use a layout, send the raw output } else if ("true".equals(request.getParameter(Constants.REQUEST_PARAM_POPUP))) { request.setAttribute(Constants.REQUEST_PAGE_LAYOUT, "/layout1.jsp"); } else if ("true".equals(request.getParameter(Constants.REQUEST_PARAM_STYLE))) { request.setAttribute(Constants.REQUEST_PAGE_LAYOUT, "/layout1.jsp"); } else { request.setAttribute(Constants.REQUEST_PAGE_LAYOUT, context.getAttribute(Constants.REQUEST_TEMPLATE)); } // If going to Setup then allow if (s.startsWith("Setup")) { request.setAttribute(Constants.REQUEST_PAGE_LAYOUT, "/layout1.jsp"); return null; } // If going to Upgrade then allow if (s.startsWith("Upgrade")) { request.setAttribute(Constants.REQUEST_PAGE_LAYOUT, "/layout1.jsp"); return null; } // Detect mobile users and mobile formatting // ClientType clientType = (ClientType) request.getSession().getAttribute(Constants.SESSION_CLIENT_TYPE); // @todo introduce when mobile is implemented // if (clientType.getMobile()) { // request.setAttribute(Constants.REQUEST_PAGE_LAYOUT, "/layoutMobile.jsp"); // } // URL forwarding for MVC requests (*.do, etc.) String requestedPath = (String) request.getAttribute("requestedURL"); if (requestedPath == null && "GET".equals(request.getMethod()) && request.getParameter("redirectTo") == null) { // Save the requestURI to be used downstream String contextPath = request.getContextPath(); String uri = request.getRequestURI(); String queryString = request.getQueryString(); requestedPath = uri.substring(contextPath.length()) + (queryString == null ? "" : "?" + queryString); LOG.debug("Requested path: " + requestedPath); request.setAttribute("requestedURL", requestedPath); // It's important the user is using the correct URL for accessing content; // The portal has it's own redirect scheme, this is a general catch all if (!s.startsWith("Portal") && !uri.contains(".shtml") && prefs.has(ApplicationPrefs.WEB_DOMAIN_NAME)) { // Check to see if an old domain name is used PortalBean bean = new PortalBean(request); String expectedDomainName = prefs.get(ApplicationPrefs.WEB_DOMAIN_NAME); if (expectedDomainName != null && requestedPath != null && !"127.0.0.1".equals(bean.getServerName()) && !"127.0.0.1".equals(expectedDomainName) && !"localhost".equals(bean.getServerName()) && !"localhost".equals(expectedDomainName) && !bean.getServerName().equals(expectedDomainName) && !bean.getServerName().startsWith("10.") && !bean.getServerName().startsWith("172.") && !bean.getServerName().startsWith("192.")) { if (uri != null && !uri.substring(1).equals(prefs.get("PORTAL.INDEX"))) { String newUrl = URLFactory.createURL(prefs.getPrefs()) + requestedPath; request.setAttribute("redirectTo", newUrl); LOG.debug("redirectTo: " + newUrl); request.removeAttribute(Constants.REQUEST_PAGE_LAYOUT); return "Redirect301"; } } } } // Version check if (!s.startsWith("Login") && ApplicationVersion.isOutOfDate(prefs)) { return "UpgradeCheck"; } // Get the user object from the Session Validation... if (sessionValidator == null) { sessionValidator = SessionValidatorFactory.getInstance() .getSessionValidator(servlet.getServletConfig().getServletContext(), request); LOG.debug("Found sessionValidator? " + (sessionValidator != null)); } // Check cookie for user's previous location info SearchBean searchBean = (SearchBean) request.getSession().getAttribute(Constants.SESSION_SEARCH_BEAN); if (searchBean == null) { String searchLocation = CookieUtils.getCookieValue(request, Constants.COOKIE_USER_SEARCH_LOCATION); if (searchLocation != null) { LOG.debug("Setting search location from cookie: " + searchLocation); searchBean = new SearchBean(); searchBean.setLocation(searchLocation); request.getSession().setAttribute(Constants.SESSION_SEARCH_BEAN, searchBean); } } // Continue with session creation... User userSession = sessionValidator.validateSession(context, request, response); ConnectionElement ceSession = (ConnectionElement) request.getSession() .getAttribute(Constants.SESSION_CONNECTION_ELEMENT); // The user is going to the portal so get them guest credentials if they need them if ("true".equals(prefs.get("PORTAL")) || s.startsWith("Register") || s.startsWith("ResetPassword") || s.startsWith("LoginAccept") || s.startsWith("LoginReject") || s.startsWith("Search") || s.startsWith("ContactUs")) { if (userSession == null || ceSession == null) { // Allow portal mode to create a default session with guest capabilities userSession = UserUtils.createGuestUser(); request.getSession().setAttribute(Constants.SESSION_USER, userSession); // Give them a connection element ceSession = new ConnectionElement(); ceSession.setDriver(prefs.get("SITE.DRIVER")); ceSession.setUrl(prefs.get("SITE.URL")); ceSession.setUsername(prefs.get("SITE.USER")); ceSession.setPassword(prefs.get("SITE.PASSWORD")); request.getSession().setAttribute(Constants.SESSION_CONNECTION_ELEMENT, ceSession); } // Make sure SSL is being used for this connection if (userSession.getId() > 0 && "true".equals(prefs.get("SSL")) && !"https".equals(request.getScheme())) { LOG.info("Redirecting to..." + requestedPath); request.setAttribute("redirectTo", "https://" + request.getServerName() + request.getContextPath() + requestedPath); request.removeAttribute(Constants.REQUEST_PAGE_LAYOUT); return "Redirect301"; } // Generate global items Connection db = null; try { db = getConnection(context, request); // TODO: Implement cache since every hit needs this list if (db != null) { // Load the project languages WebSiteLanguageList webSiteLanguageList = new WebSiteLanguageList(); webSiteLanguageList.setEnabled(Constants.TRUE); webSiteLanguageList.buildList(db); // If an admin of a language, enable it... webSiteLanguageList.add(userSession.getWebSiteLanguageList()); request.setAttribute("webSiteLanguageList", webSiteLanguageList); // Load the menu list ProjectList menu = new ProjectList(); PagedListInfo menuListInfo = new PagedListInfo(); menuListInfo.setColumnToSortBy("p.portal_default desc, p.level asc, p.title asc"); menuListInfo.setItemsPerPage(-1); menu.setPagedListInfo(menuListInfo); menu.setIncludeGuestProjects(false); menu.setPortalState(Constants.TRUE); menu.setOpenProjectsOnly(true); menu.setApprovedOnly(true); menu.setBuildLink(true); menu.setLanguageId(webSiteLanguageList.getLanguageId(request)); menu.buildList(db); request.setAttribute("menuList", menu); // Load the main profile to use throughout Project mainProfile = ProjectUtils.loadProject(prefs.get("MAIN_PROFILE")); request.setAttribute(Constants.REQUEST_MAIN_PROFILE, mainProfile); // Load the project categories for search and tab menus ProjectCategoryList categoryList = new ProjectCategoryList(); categoryList.setEnabled(Constants.TRUE); categoryList.setTopLevelOnly(true); categoryList.buildList(db); request.setAttribute(Constants.REQUEST_TAB_CATEGORY_LIST, categoryList); // Determine the tab that needs to be highlighted int chosenTabId = -1; if (requestedPath != null) { String chosenCategory = null; String chosenTab = null; if (requestedPath.length() > 0) { chosenTab = requestedPath.substring(1); } LOG.debug("chosenTab? " + chosenTab); if (chosenTab == null || "".equals(chosenTab)) { LOG.debug("Setting tab to Home"); chosenTab = "home.shtml"; } else { boolean foundChosenTab = false; for (ProjectCategory projectCategory : categoryList) { String categoryName = projectCategory.getDescription(); String normalizedCategoryTab = projectCategory.getNormalizedCategoryName() .concat(".shtml"); if (chosenTab.startsWith(normalizedCategoryTab)) { foundChosenTab = true; chosenCategory = categoryName; chosenTabId = projectCategory.getId(); LOG.debug("found: " + chosenCategory); } } if (!foundChosenTab) { LOG.debug("No tab to highlight"); chosenTab = "none"; } } request.setAttribute("chosenTab", chosenTab); request.setAttribute("chosenCategory", chosenCategory); } // Go through the tabs and remove the ones the user shouldn't see, also check permission if (!userSession.isLoggedIn()) { boolean allowed = true; Iterator i = categoryList.iterator(); while (i.hasNext()) { ProjectCategory projectCategory = (ProjectCategory) i.next(); if (projectCategory.getSensitive()) { if (chosenTabId == projectCategory.getId()) { allowed = false; } i.remove(); } } if (!allowed) { // Redirect to the login, perhaps the page would exist then String newUrl = URLFactory.createURL(prefs.getPrefs()) + "/login?redirectTo=" + requestedPath; request.setAttribute("redirectTo", newUrl); LOG.debug("redirectTo: " + newUrl); request.removeAttribute(Constants.REQUEST_PAGE_LAYOUT); return "Redirect301"; } } // Category drop-down for search HtmlSelect thisSelect = categoryList.getHtmlSelect(); thisSelect.addItem(-1, prefs.get("TITLE"), 0); request.setAttribute(Constants.REQUEST_MENU_CATEGORY_LIST, thisSelect); } } catch (Exception e) { LOG.error("Global items error", e); } finally { this.freeConnection(context, db); } } // The user is not going to login, so verify login if (!s.startsWith("Login")) { if (userSession == null || ceSession == null) { // boot them off now LOG.debug("Security failed."); LoginBean failedSession = new LoginBean(); failedSession.addError("actionError", "* Please login, your session has expired"); failedSession.checkURL(request); request.setAttribute("LoginBean", failedSession); request.removeAttribute(Constants.REQUEST_PAGE_LAYOUT); return "SecurityCheck"; } else { // The user should have a valid login now, so let them proceed LOG.debug("Security passed: " + userSession.getId() + " (" + userSession.getUsername() + ")"); } } // Generate user's global items if (userSession != null && userSession.getId() > 0) { Connection db = null; try { db = getConnection(context, request); // TODO: Implement cache since every hit needs this list if (db != null) { // A map for global alerts ArrayList<String> alerts = new ArrayList<String>(); request.setAttribute(Constants.REQUEST_GLOBAL_ALERTS, alerts); // Check to see if the application is configured... if (userSession.getAccessAdmin()) { String url = URLFactory.createURL(prefs.getPrefs()); if (url == null) { alerts.add( "The application configuration requires that the URL properties are updated. Store <strong>" + RequestUtils.getAbsoluteServerUrl(request) + "</strong>? <a href=\"" + RequestUtils.getAbsoluteServerUrl(request) + "/AdminUsage.do?command=StoreURL\">Save Changes</a>"); } else if (!url.equals(RequestUtils.getAbsoluteServerUrl(request))) { alerts.add("There is a configuration mismatch -- expected: <strong>" + RequestUtils.getAbsoluteServerUrl(request) + "</strong> but the configuration has <strong><a href=\"" + url + "\">" + url + "</a></strong> <a href=\"" + RequestUtils.getAbsoluteServerUrl(request) + "/AdminUsage.do?command=StoreURL\">Save Changes</a>"); } } // Check the # of invitations int invitationCount = InvitationList.queryCount(db, userSession.getId(), userSession.getProfileProjectId()); request.setAttribute(Constants.REQUEST_INVITATION_COUNT, String.valueOf(invitationCount)); // Check the # of private messages int newMailCount = PrivateMessageList.queryUnreadCountForUser(db, userSession.getId()); request.setAttribute(Constants.REQUEST_PRIVATE_MESSAGE_COUNT, String.valueOf(newMailCount)); // NOTE: removed because not currently used // Check the number of what's new // int whatsNewCount = ProjectUtils.queryWhatsNewCount(db, userSession.getId()); // request.setAttribute(Constants.REQUEST_WHATS_NEW_COUNT, String.valueOf(whatsNewCount)); // Check the number of assignments // int whatsAssignedCount = ProjectUtils.queryWhatsAssignedCount(db, userSession.getId()); // request.setAttribute(Constants.REQUEST_WHATS_ASSIGNED_COUNT, String.valueOf(whatsAssignedCount)); // int projectCount = ProjectUtils.queryMyProjectCount(db, userSession.getId()); // request.setAttribute(Constants.REQUEST_MY_PROJECT_COUNT, String.valueOf(projectCount)); } } catch (Exception e) { LOG.error("User's global items error", e); } finally { this.freeConnection(context, db); } } return null; } /** * Description of the Method * * @param servlet Description of the Parameter * @param request Description of the Parameter * @param response Description of the Parameter * @return Description of the Return Value */ public String endRequest(Servlet servlet, HttpServletRequest request, HttpServletResponse response) { return null; } /** * Gets the connection attribute of the SecurityHook object * * @param context Description of the Parameter * @param request Description of the Parameter * @return The connection value * @throws SQLException Description of the Exception */ protected Connection getConnection(ServletContext context, HttpServletRequest request) throws SQLException { ConnectionPool sqlDriver = (ConnectionPool) context.getAttribute("ConnectionPool"); ConnectionElement ce = (ConnectionElement) request.getSession().getAttribute("ConnectionElement"); if (sqlDriver == null || ce == null) { return null; } return sqlDriver.getConnection(ce); } /** * Description of the Method * * @param context Description of the Parameter * @param db Description of the Parameter */ protected void freeConnection(ServletContext context, Connection db) { if (db != null) { ConnectionPool sqlDriver = (ConnectionPool) context.getAttribute("ConnectionPool"); sqlDriver.free(db); } db = null; } }