Java tutorial
/* * (C) Copyright 2006-2009 Nuxeo SA (http://nuxeo.com/) and contributors. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser General Public License * (LGPL) version 2.1 which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl.html * * This library 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 * Lesser General Public License for more details. * * Contributors: * Nuxeo - initial API and implementation * Academie de Rennes - proxy CAS support * * $Id: JOOoConvertPluginImpl.java 18651 2007-05-13 20:28:53Z sfermigier $ */ package fr.univlille2.ecm.platform.ui.web.auth.cas2; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuxeo.common.utils.URIUtils; import org.nuxeo.ecm.core.api.ClientException; import org.nuxeo.ecm.core.api.CoreSession; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.DocumentModelList; import org.nuxeo.ecm.core.api.DocumentRef; import org.nuxeo.ecm.core.api.IdRef; import org.nuxeo.ecm.core.api.repository.Repository; import org.nuxeo.ecm.core.api.repository.RepositoryManager; import org.nuxeo.ecm.platform.api.login.UserIdentificationInfo; import org.nuxeo.ecm.platform.ui.web.auth.interfaces.LoginResponseHandler; import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPlugin; import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPluginLogoutExtension; import org.nuxeo.ecm.platform.ui.web.auth.service.PluggableAuthenticationService; import org.nuxeo.ecm.platform.ui.web.util.BaseURL; import org.nuxeo.ecm.platform.usermanager.UserManager; import org.nuxeo.ecm.platform.web.common.vh.VirtualHostHelper; import org.nuxeo.runtime.api.Framework; import org.xml.sax.SAXException; import edu.yale.its.tp.cas.client.ProxyTicketValidator; import edu.yale.its.tp.cas.client.ServiceTicketValidator; /** * @author Thierry Delprat * @author Olivier Adam * @author M.-A. Darche * @author Benjamin Jalon * @author Thierry Martins * @author acordier */ public class Cas2Authenticator implements NuxeoAuthenticationPlugin, NuxeoAuthenticationPluginLogoutExtension, LoginResponseHandler { protected static final String CAS_SERVER_HEADER_KEY = "CasServer"; protected static final String CAS_SERVER_PATTERN_KEY = "$CASSERVER"; protected static final String NUXEO_SERVER_PATTERN_KEY = "$NUXEO"; protected static final String LOGIN_ACTION = "Login"; protected static final String LOGOUT_ACTION = "Logout"; protected static final String VALIDATE_ACTION = "Valid"; protected static final String PROXY_VALIDATE_ACTION = "ProxyValid"; protected static final Log log = LogFactory.getLog(Cas2Authenticator.class); protected static final String EXCLUDE_PROMPT_KEY = "excludePromptURL"; protected String ticketKey = "ticket"; protected String proxyKey = "proxy"; protected String appURL = "http://127.0.0.1:8080/nuxeo/"; protected String serviceLoginURL = "http://127.0.0.1:8080/cas/login"; protected String serviceValidateURL = "http://127.0.0.1:8080/cas/serviceValidate"; /** * We tell the CAS server whether we want a plain text (CAS 1.0) or XML (CAS * 2.0) response by making the request either to the '.../validate' or * '.../serviceValidate' URL. The older protocol supports only the CAS 1.0 * functionality, which is left around as the legacy '.../validate' URL. */ protected String proxyValidateURL = "http://127.0.0.1:8080/cas/proxyValidate"; protected String serviceKey = "service"; protected String logoutURL = ""; protected String defaultCasServer = ""; protected String ticketValidatorClassName = "edu.yale.its.tp.cas.client.ServiceTicketValidator"; protected String proxyValidatorClassName = "edu.yale.its.tp.cas.client.ProxyTicketValidator"; protected boolean promptLogin = true; protected List<String> excludePromptURLs; protected String errorPage; private boolean guestIsGranted; public List<String> getUnAuthenticatedURLPrefix() { // CAS login screen is not part of Nuxeo5 Web App return null; } protected String getServiceURL(HttpServletRequest httpRequest, String action) { String url = ""; if (action.equals(LOGIN_ACTION)) { url = serviceLoginURL; } else if (action.equals(LOGOUT_ACTION)) { url = logoutURL; } else if (action.equals(VALIDATE_ACTION)) { url = serviceValidateURL; } else if (action.equals(PROXY_VALIDATE_ACTION)) { url = proxyValidateURL; } if (url.contains(CAS_SERVER_PATTERN_KEY)) { String serverURL = httpRequest.getHeader(CAS_SERVER_HEADER_KEY); if (serverURL != null) { url = url.replace(CAS_SERVER_PATTERN_KEY, serverURL); } else { if (url.contains(CAS_SERVER_PATTERN_KEY)) { url = url.replace(CAS_SERVER_PATTERN_KEY, defaultCasServer); } } } log.debug("serviceUrl: " + url); return url; } public Boolean handleLoginPrompt(HttpServletRequest httpRequest, HttpServletResponse httpResponse, String baseURL) { // Redirect to CAS Login screen // passing our application URL as service name String location = null; try { Map<String, String> urlParameters = new HashMap<String, String>(); urlParameters.put("service", getAppURL(httpRequest)); location = URIUtils.addParametersToURIQuery(getServiceURL(httpRequest, LOGIN_ACTION), urlParameters); httpResponse.sendRedirect(location); } catch (IOException e) { log.error("Unable to redirect to CAS login screen to " + location, e); return false; } return true; } protected String getAppURL(HttpServletRequest httpRequest) { log.debug("getAppURL"); if (isValidStartupPage(httpRequest)) { StringBuffer sb = new StringBuffer(VirtualHostHelper.getServerURL(httpRequest)); if (VirtualHostHelper.getServerURL(httpRequest).endsWith("/")) { sb.deleteCharAt(sb.length() - 1); } sb.append(httpRequest.getRequestURI()); if (httpRequest.getQueryString() != null) { sb.append("?"); sb.append(httpRequest.getQueryString()); // remove ticket parameter from URL to correctly validate the // service int indexTicketKey = sb.lastIndexOf(ticketKey + "="); if (indexTicketKey != -1) { sb.delete(indexTicketKey - 1, sb.length()); } } log.debug(sb.toString()); return sb.toString(); } if (appURL == null || appURL.equals("")) { log.debug("null app url"); appURL = NUXEO_SERVER_PATTERN_KEY; } if (appURL.contains(NUXEO_SERVER_PATTERN_KEY)) { String nxurl = BaseURL.getBaseURL(httpRequest); log.debug(String.format("nxurl app url : %s", appURL.replace(NUXEO_SERVER_PATTERN_KEY, nxurl))); return appURL.replace(NUXEO_SERVER_PATTERN_KEY, nxurl); } else { log.debug(String.format("appurl: %s", appURL)); return appURL; } } private boolean isValidStartupPage(HttpServletRequest httpRequest) { if (httpRequest.getRequestURI() == null) { return false; } PluggableAuthenticationService service = (PluggableAuthenticationService) Framework.getRuntime() .getComponent(PluggableAuthenticationService.NAME); if (service == null) { return false; } String startPage = httpRequest.getRequestURI().replace(VirtualHostHelper.getContextPath(httpRequest) + "/", ""); for (String prefix : service.getStartURLPatterns()) { if (startPage.startsWith(prefix)) { return true; } } return false; } public UserIdentificationInfo handleRetrieveIdentity(HttpServletRequest httpRequest, HttpServletResponse httpResponse) { /* This is output object*/ UserIdentificationInfo userIdentificationInfo = null; String casTicket = httpRequest.getParameter(ticketKey); /*beginning of custom * */ String url = httpRequest.getRequestURL().toString(); log.debug(String.format("handleRetrieveIdentity %s", url)); String esupDocId; if (url.contains("/esupversions/") || url.contains("/nxdoc/")) { int from = url.indexOf("nuxeo") + "nuxeo".length() + 1; String[] urlNodes = (url.substring(from)).split("/"); esupDocId = urlNodes[2]; log.debug(String.format("Doc id : %s", esupDocId)); LoginContext loginContext = null; try { loginContext = Framework.login(); RepositoryManager repoManager = Framework.getService(RepositoryManager.class); Repository repository = repoManager.getDefaultRepository(); CoreSession session; if (repository != null) { session = repository.open(); DocumentRef docRef = new IdRef(esupDocId); DocumentModelList proxies = session.getProxies(docRef, null); DocumentModel doc = null; if (proxies.size() > 0) { doc = proxies.get(0); } else { doc = session.getDocument(docRef); } UserManager userManager = Framework.getService(UserManager.class); String anonymousId = userManager.getAnonymousUserId(); log.debug(String.format("Anonymous id is %s", anonymousId)); guestIsGranted = doc.getACP().getAccess(userManager.getAnonymousUserId(), "Read").toBoolean(); if (guestIsGranted) { log.debug("Guest is granted"); userIdentificationInfo = new UserIdentificationInfo(anonymousId, anonymousId); guestIsGranted = false; return userIdentificationInfo; } else { log.debug("Guest is not granted"); } loginContext.logout(); } } catch (LoginException e) { log.error("login as system failed"); } catch (ClientException e) { log.error(String.format("Document %s not found", esupDocId)); } catch (Exception e) { log.error(String.format("Error getting service: %s", e.getMessage())); } } /*end of custom */ String proxy = httpRequest.getParameter(proxyKey); if (casTicket == null) { log.debug("No ticket found"); return null; } String userName; if (proxy == null) { userName = checkCasTicket(casTicket, httpRequest); } else { userName = checkProxyCasTicket(casTicket, httpRequest); } if (userName == null) { return null; } userIdentificationInfo = new UserIdentificationInfo(userName, casTicket); userIdentificationInfo.setToken(casTicket); return userIdentificationInfo; } public void initPlugin(Map<String, String> parameters) { if (parameters.containsKey(CAS2Parameters.TICKET_NAME_KEY)) { ticketKey = parameters.get(CAS2Parameters.TICKET_NAME_KEY); } if (parameters.containsKey(CAS2Parameters.PROXY_NAME_KEY)) { proxyKey = parameters.get(CAS2Parameters.PROXY_NAME_KEY); } if (parameters.containsKey(CAS2Parameters.NUXEO_APP_URL_KEY)) { appURL = parameters.get(CAS2Parameters.NUXEO_APP_URL_KEY); } if (parameters.containsKey(CAS2Parameters.SERVICE_LOGIN_URL_KEY)) { serviceLoginURL = parameters.get(CAS2Parameters.SERVICE_LOGIN_URL_KEY); } if (parameters.containsKey(CAS2Parameters.SERVICE_VALIDATE_URL_KEY)) { serviceValidateURL = parameters.get(CAS2Parameters.SERVICE_VALIDATE_URL_KEY); } if (parameters.containsKey(CAS2Parameters.PROXY_VALIDATE_URL_KEY)) { proxyValidateURL = parameters.get(CAS2Parameters.PROXY_VALIDATE_URL_KEY); } if (parameters.containsKey(CAS2Parameters.SERVICE_NAME_KEY)) { serviceKey = parameters.get(CAS2Parameters.SERVICE_NAME_KEY); } if (parameters.containsKey(CAS2Parameters.LOGOUT_URL_KEY)) { logoutURL = parameters.get(CAS2Parameters.LOGOUT_URL_KEY); } if (parameters.containsKey(CAS2Parameters.DEFAULT_CAS_SERVER_KEY)) { defaultCasServer = parameters.get(CAS2Parameters.DEFAULT_CAS_SERVER_KEY); } if (parameters.containsKey(CAS2Parameters.SERVICE_VALIDATOR_CLASS)) { ticketValidatorClassName = parameters.get(CAS2Parameters.SERVICE_VALIDATOR_CLASS); } if (parameters.containsKey(CAS2Parameters.PROXY_VALIDATOR_CLASS)) { proxyValidatorClassName = parameters.get(CAS2Parameters.PROXY_VALIDATOR_CLASS); } if (parameters.containsKey(CAS2Parameters.PROMPT_LOGIN)) { promptLogin = Boolean.parseBoolean(parameters.get(CAS2Parameters.PROMPT_LOGIN)); } excludePromptURLs = new ArrayList<String>(); for (String key : parameters.keySet()) { if (key.startsWith(EXCLUDE_PROMPT_KEY)) { excludePromptURLs.add(parameters.get(key)); } } if (parameters.containsKey(CAS2Parameters.ERROR_PAGE)) { errorPage = parameters.get(CAS2Parameters.ERROR_PAGE); } } public Boolean needLoginPrompt(HttpServletRequest httpRequest) { log.debug(String.format("needLoginPrompt %s", httpRequest.getRequestURL().toString())); String requestedURI = httpRequest.getRequestURI(); String context = httpRequest.getContextPath() + '/'; requestedURI = requestedURI.substring(context.length()); for (String prefixURL : excludePromptURLs) { if (requestedURI.startsWith(prefixURL)) { return false; } } return promptLogin; } public Boolean handleLogout(HttpServletRequest httpRequest, HttpServletResponse httpResponse) { log.debug(String.format("handleLogout %s", httpRequest.getRequestURL().toString())); if (logoutURL == null || logoutURL.equals("")) { log.debug("No CAS logout params, skipping CAS2Logout"); return false; } try { httpResponse.sendRedirect(getServiceURL(httpRequest, LOGOUT_ACTION)); } catch (IOException e) { log.error("Unable to redirect to CAS logout screen:", e); return false; } return true; } protected String checkProxyCasTicket(String ticket, HttpServletRequest httpRequest) { log.debug(String.format("checkProxyCasTicket %s", httpRequest.getRequestURL().toString())); String service = httpRequest.getParameter(serviceKey); if (service == null) { // added ESUP => does not work otherwise. service = getAppURL(httpRequest); } ProxyTicketValidator proxyValidator; try { proxyValidator = (ProxyTicketValidator) Framework.getRuntime().getContext() .loadClass(proxyValidatorClassName).newInstance(); } catch (InstantiationException e) { log.error( "checkProxyCasTicket during the ProxyTicketValidator initialization with InstantiationException:", e); return null; } catch (IllegalAccessException e) { log.error( "checkProxyCasTicket during the ProxyTicketValidator initialization with IllegalAccessException:", e); return null; } catch (ClassNotFoundException e) { log.error( "checkProxyCasTicket during the ProxyTicketValidator initialization with ClassNotFoundException:", e); return null; } proxyValidator.setCasValidateUrl(getServiceURL(httpRequest, PROXY_VALIDATE_ACTION)); proxyValidator.setService(service); proxyValidator.setServiceTicket(ticket); try { proxyValidator.validate(); } catch (IOException e) { log.error("checkProxyCasTicket failed with IOException:", e); return null; } catch (SAXException e) { log.error("checkProxyCasTicket failed with SAXException:", e); return null; } catch (ParserConfigurationException e) { log.error("checkProxyCasTicket failed with ParserConfigurationException:", e); return null; } log.debug("checkProxyCasTicket: validation executed without error"); String username = proxyValidator.getUser(); log.debug("checkProxyCasTicket: validation returned username = " + username); return username; } // Cas2 Ticket management protected String checkCasTicket(String ticket, HttpServletRequest httpRequest) { log.debug(String.format("checkCasTicket %s", httpRequest.getRequestURL().toString())); ServiceTicketValidator ticketValidator; try { ticketValidator = (ServiceTicketValidator) Framework.getRuntime().getContext() .loadClass(ticketValidatorClassName).newInstance(); } catch (InstantiationException e) { log.error( "checkCasTicket during the ServiceTicketValidator initialization with InstantiationException:", e); return null; } catch (IllegalAccessException e) { log.error( "checkCasTicket during the ServiceTicketValidator initialization with IllegalAccessException:", e); return null; } catch (ClassNotFoundException e) { log.error( "checkCasTicket during the ServiceTicketValidator initialization with ClassNotFoundException:", e); return null; } ticketValidator.setCasValidateUrl(getServiceURL(httpRequest, VALIDATE_ACTION)); ticketValidator.setService(getAppURL(httpRequest)); ticketValidator.setServiceTicket(ticket); try { ticketValidator.validate(); } catch (IOException e) { log.error("checkCasTicket failed with IOException:", e); return null; } catch (SAXException e) { log.error("checkCasTicket failed with SAXException:", e); return null; } catch (ParserConfigurationException e) { log.error("checkCasTicket failed with ParserConfigurationException:", e); return null; } log.debug("checkCasTicket : validation executed without error"); String username = ticketValidator.getUser(); log.debug("checkCasTicket: validation returned username = " + username); return username; } @Override public boolean onError(HttpServletRequest request, HttpServletResponse response) { try { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); if (errorPage != null) { response.sendRedirect(errorPage); } } catch (Exception e) { log.error(e); return false; } return true; } @Override public boolean onSuccess(HttpServletRequest arg0, HttpServletResponse arg1) { log.debug(String.format("checkCasTicket %s", arg0.getRequestURL().toString())); return false; } }