Java tutorial
/* * Asimba Server * * Copyright (C) 2012 Asimba * Copyright (C) 2007-2009 Alfa & Ariss B.V. * * This program 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, either version 3 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see www.gnu.org/licenses * * Asimba - Serious Open Source SSO - More information on www.asimba.org * */ package com.alfaariss.oa.sso.web; import java.io.IOException; import java.util.Hashtable; import java.util.Map; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.w3c.dom.Element; import com.alfaariss.oa.OAException; import com.alfaariss.oa.SystemErrors; import com.alfaariss.oa.api.IComponent; import com.alfaariss.oa.api.IService; import com.alfaariss.oa.api.configuration.IConfigurationManager; import com.alfaariss.oa.api.sso.ISSOProfile; import com.alfaariss.oa.engine.core.Engine; import com.alfaariss.oa.sso.SSOService; import com.alfaariss.oa.sso.authentication.web.AuthenticationManager; import com.alfaariss.oa.sso.authorization.web.PreAuthorizationManager; import com.alfaariss.oa.sso.web.profile.logout.LogoutProfile; import com.alfaariss.oa.sso.web.profile.user.UserProfile; import com.alfaariss.oa.sso.web.profile.web.WebProfile; /** * Web based Authentication and SSO Component. * * This Web SSO is part of OA. OA is a professionalized A-Select SSO product * targeting existing and new A-Select customers. * <br><br> * The WebSSO is the controller servlet which uses JSP pages as view and * the {@link SSOService} as business service (model in MVC). * * <h4>WebSSO functionality:</h4> * * <dl> * <dt>Display TGT</dt> * <dd>Show the users TGT if available (No session required)</dd> * <dt>Pre authorization</dt> * <dd>{@link PreAuthorizationManager}</dd> * <dt>SSO</dt> * <dd>Check for a valid and sufficient SSO session</dd> * <dt>Authentication selection</dt> * <dd>Select a profile to authenticate with</dd> * <dt>Authentication</dt> * <dd>{@link AuthenticationManager}</dd> * </dl> * <br><br> * * The WebSSO should be called by an authentication profile to perform the * actual authentication process. * * @author MHO * @author EVB * @author Alfa & Ariss * */ public class WebSSOServlet extends HttpServlet implements IComponent { /** The name of the Web SSO TGT cookie. */ public static final String TGT_COOKIE_NAME = "oa_sso_id"; /** serialVersionUID */ private static final long serialVersionUID = -2883420193342476092L; private static Log _logger; private AuthenticationManager _authenticationManager; private ServletContext _context; private Engine _engine; private Map<String, ISSOProfile> _mapSSOProfiles; private WebProfile _defaultSSOProfile; /** * Create a new Web based Authentication and SSO Component. */ public WebSSOServlet() { _logger = LogFactory.getLog(WebSSOServlet.class); _engine = Engine.getInstance(); _authenticationManager = new AuthenticationManager(); _mapSSOProfiles = new Hashtable<String, ISSOProfile>(); } /** * Starts SSO profiles. * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig) */ @Override public void init(ServletConfig oServletConfig) throws ServletException { try { _context = oServletConfig.getServletContext(); //Retrieve configuration manager IConfigurationManager config = _engine.getConfigurationManager(); //Start profiles and helpers start(config, null); //Add as listener _engine.addComponent(this); } catch (OAException e) { _logger.fatal("Error starting WebSSO", e); stop(); //Stop started profiles and helpers throw new ServletException(SystemErrors.toHexString(e.getCode())); } catch (Exception e) { _logger.fatal("Error starting WebSSO", e); stop(); //Stop started profiles and helpers throw new ServletException(SystemErrors.toHexString(SystemErrors.ERROR_INTERNAL)); } } /** * Start the WebSSO. * @see IComponent#start(IConfigurationManager, org.w3c.dom.Element) */ @Override public void start(IConfigurationManager configurationManager, Element config) throws OAException { Element eWebSSO = configurationManager.getSection(null, "websso"); if (eWebSSO == null) { _logger.error("No 'websso' configuration found"); throw new OAException(SystemErrors.ERROR_INIT); } //Authentication configuration Element eAuthentication = configurationManager.getSection(eWebSSO, "authentication"); if (eAuthentication == null) { _logger.error("No authentication configuration found"); throw new OAException(SystemErrors.ERROR_CONFIG_READ); } _authenticationManager.start(configurationManager, eAuthentication); _defaultSSOProfile = new WebProfile(_authenticationManager); _defaultSSOProfile.init(_context, configurationManager, eWebSSO, null); addSSOProfile(_defaultSSOProfile.getID(), _defaultSSOProfile); _logger.info("Started WebSSO Profile: " + _defaultSSOProfile.getID()); UserProfile userProfile = new UserProfile(); userProfile.init(_context, configurationManager, eWebSSO, null); addSSOProfile(userProfile.getID(), userProfile); LogoutProfile logoutProfile = new LogoutProfile(_authenticationManager); logoutProfile.init(_context, configurationManager, eWebSSO, null); addSSOProfile(logoutProfile.getID(), logoutProfile); Element eProfiles = configurationManager.getSection(eWebSSO, "profiles"); if (eProfiles != null) loadProfiles(configurationManager, eWebSSO, eProfiles); _logger.info("Started SSO Profiles"); } /** * Restart the WebSSO. * @see com.alfaariss.oa.api.IComponent#restart(org.w3c.dom.Element) */ @Override public void restart(Element eConfig) throws OAException { synchronized (this) { _logger.info("Restarting WebSSO"); stop(); IConfigurationManager config = _engine.getConfigurationManager(); start(config, eConfig); } } /** * Process the WebSSO HTTP requests. * @throws IOException * * @see javax.servlet.http.HttpServlet#service( * javax.servlet.http.HttpServletRequest, * javax.servlet.http.HttpServletResponse) * */ @Override public void service(HttpServletRequest oRequest, HttpServletResponse oResponse) throws ServletException, IOException { try { if (_defaultSSOProfile == null) oResponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, oRequest.getRequestURI()); String sTarget = resolveTarget(oRequest); if (sTarget == null) _defaultSSOProfile.service(oRequest, oResponse); else { ISSOProfile ssoProfile = _mapSSOProfiles.get(sTarget); if (ssoProfile != null & (ssoProfile instanceof IService)) { ((IService) ssoProfile).service(oRequest, oResponse); } else {//if profile not found by target, then use default profile _defaultSSOProfile.service(oRequest, oResponse); } } //send okay if no response is sent yet if (!oResponse.isCommitted()) oResponse.sendError(HttpServletResponse.SC_OK); } catch (OAException e) { _logger.error("Could not process request", e); if (!oResponse.isCommitted()) oResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } catch (Exception e) { _logger.fatal("Could not process request due to internal error", e); if (!oResponse.isCommitted()) oResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } } /** * Destroys the Servlet. * @see javax.servlet.Servlet#destroy() */ @Override public void destroy() { stop(); _engine.removeComponent(this); _logger.info("Stopped: WebSSO"); } /** * Stop the WebSSO. * @see com.alfaariss.oa.api.IComponent#stop() */ @Override public synchronized void stop() { if (_authenticationManager != null) _authenticationManager.stop(); //Stop profiles for (ISSOProfile profile : _mapSSOProfiles.values()) { profile.destroy(); } //Clear profiles _mapSSOProfiles.clear(); _logger.info("Stopped SSO Profiles"); if (_defaultSSOProfile != null) { _defaultSSOProfile.destroy(); _logger.info("Stopped WebSSO Profile"); } } //Start the profiles private void loadProfiles(IConfigurationManager config, Element eWebSSO, Element eProfiles) throws OAException { try { Element eProfile = config.getSection(eProfiles, "profile"); while (eProfile != null) { String sClass = config.getParam(eProfile, "class"); if (sClass == null) { _logger.error("No 'class' parameter found in 'profile' section"); throw new OAException(SystemErrors.ERROR_CONFIG_READ); } ISSOProfile profile = null; try { Class profileClass = Class.forName(sClass); profile = (ISSOProfile) profileClass.newInstance(); } catch (ClassNotFoundException e) { _logger.error("Configured SSO profile class could not be found: " + sClass, e); throw new OAException(SystemErrors.ERROR_CONFIG_READ); } catch (InstantiationException e) { _logger.error("Configured SSO profile class could not be instantiated: " + sClass, e); throw new OAException(SystemErrors.ERROR_CONFIG_READ); } catch (IllegalAccessException e) { _logger.error("Configured SSO profile class could not be accessed: " + sClass, e); throw new OAException(SystemErrors.ERROR_CONFIG_READ); } catch (ClassCastException e) { _logger.error("Configured SSO profile class isn't of type 'ISSOProfile': " + sClass, e); throw new OAException(SystemErrors.ERROR_CONFIG_READ); } profile.init(_context, config, eWebSSO, eProfile); if (_mapSSOProfiles.containsKey(profile.getID())) { _logger.error("Configured SSO profile id is not unique: " + profile.getID()); throw new OAException(SystemErrors.ERROR_INIT); } addSSOProfile(profile.getID(), profile); _logger.info("Started SSO profile: " + profile.getID()); //Get next eProfile = config.getNextSection(eProfile); } } catch (OAException e) { throw e; } catch (Exception e) { _logger.fatal("Could not load SSO profiles", e); throw new OAException(SystemErrors.ERROR_INTERNAL); } } private String resolveTarget(HttpServletRequest servletRequest) { String sRequestURI = servletRequest.getRequestURI(); if (!sRequestURI.endsWith("/")) sRequestURI = sRequestURI + "/"; sRequestURI = sRequestURI.toLowerCase(); String sContextPath = servletRequest.getContextPath(); String sServletPath = servletRequest.getServletPath(); String target = sRequestURI.substring(sContextPath.length() + sServletPath.length() + 1);// +1 for trailing / if (target != null && target.length() > 1)// >1: target must be larger then '/' { int iIndex = target.indexOf("/"); if (target.length() - 1 > iIndex) {//target must be splitted to first / return target.substring(0, iIndex + 1); } return target; } return null; } private void addSSOProfile(String profileID, ISSOProfile profile) { String id = profileID; if (!profileID.endsWith("/")) id = id + "/"; _mapSSOProfiles.put(id.toLowerCase(), profile); } }