001/* 002 * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * bjalon 016 */ 017package org.nuxeo.ecm.mobile.filter; 018 019import java.io.IOException; 020import java.io.UnsupportedEncodingException; 021import java.util.List; 022import java.util.Map; 023 024import javax.servlet.http.HttpServletRequest; 025import javax.servlet.http.HttpServletResponse; 026 027import org.apache.commons.logging.Log; 028import org.apache.commons.logging.LogFactory; 029import org.nuxeo.common.utils.URIUtils; 030import org.nuxeo.ecm.mobile.ApplicationDefinitionService; 031import org.nuxeo.ecm.platform.api.login.UserIdentificationInfo; 032import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPlugin; 033import org.nuxeo.runtime.api.Framework; 034 035import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.ERROR_USERNAME_MISSING; 036import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.FORM_SUBMITTED_MARKER; 037import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.LOGIN_ERROR; 038 039/** 040 * Authenticator that redirects user to dedicated application authentication form if user has selected this application 041 * or if this application matched the request context. Can't extends Form Authentication as login form is static and 042 * here is dynamic. 043 * 044 * @author <a href="mailto:bjalon@nuxeo.com">Benjamin JALON</a> 045 * @since 5.5 046 */ 047public class ApplicationFormAuthenticator implements NuxeoAuthenticationPlugin { 048 049 protected static final Log log = LogFactory.getLog(ApplicationFormAuthenticator.class); 050 051 private ApplicationDefinitionService service; 052 053 private String usernameKey = "user_name"; 054 055 private String passwordKey = "user_password"; 056 057 public ApplicationDefinitionService getService() { 058 if (service == null) { 059 service = Framework.getLocalService(ApplicationDefinitionService.class); 060 } 061 return service; 062 } 063 064 @Override 065 public void initPlugin(Map<String, String> parameters) { 066 if (parameters.get("UsernameKey") != null) { 067 usernameKey = parameters.get("UsernameKey"); 068 } 069 if (parameters.get("PasswordKey") != null) { 070 passwordKey = parameters.get("PasswordKey"); 071 } 072 } 073 074 @Override 075 public Boolean needLoginPrompt(HttpServletRequest httpRequest) { 076 if (getService().getApplicationBaseURL(httpRequest) != null) { 077 return true; 078 } 079 log.debug("No Application match this request, next authenticator to expose login prompt"); 080 return false; 081 } 082 083 @Override 084 public Boolean handleLoginPrompt(HttpServletRequest httpRequest, HttpServletResponse httpResponse, String baseURL) { 085 log.debug("Login Prompt - URL :" + httpRequest.getRequestURL() + "?" + httpRequest.getQueryString()); 086 087 String loginPage = getService().getLoginURL(httpRequest); 088 if (loginPage == null) { 089 log.debug("No Application matched for this request context, so next Authenticator in Chain will be used"); 090 return Boolean.FALSE; 091 } 092 093 log.debug("Application matched for this request context so login page " 094 + "used will be the target application detected: " + loginPage); 095 096 Map<String, String> parameters; 097 try { 098 RequestAdapter adapter = new RequestAdapter(httpRequest); 099 parameters = adapter.getParametersAndAddTargetURLIfNotSet(); 100 // avoid resending the password in clear !!! 101 parameters.remove(passwordKey); 102 } catch (UnsupportedEncodingException e) { 103 log.error(e, e); 104 return Boolean.FALSE; 105 } 106 String redirectUrl = URIUtils.addParametersToURIQuery(loginPage, parameters); 107 try { 108 httpResponse.sendRedirect(redirectUrl); 109 return Boolean.TRUE; 110 } catch (IOException e) { 111 log.error(e, e); 112 } 113 return Boolean.FALSE; 114 } 115 116 @Override 117 public List<String> getUnAuthenticatedURLPrefix() { 118 List<String> result = getService().getUnAuthenticatedURLPrefix(); 119 log.debug("List of skipped URL:" + result); 120 return result; 121 } 122 123 @Override 124 public UserIdentificationInfo handleRetrieveIdentity(HttpServletRequest httpRequest, 125 HttpServletResponse httpResponse) { 126 127 if (getService().getApplicationBaseURL(httpRequest) == null) { 128 log.debug("No Application match this request, use next Authenticator " + "in chain to retrieve identity"); 129 return null; 130 } 131 132 Map<String, String> parameters; 133 try { 134 RequestAdapter adapter = new RequestAdapter(httpRequest); 135 parameters = adapter.getParametersAndAddTargetURLIfNotSet(); 136 // avoid resending the password in clear !!! 137 } catch (UnsupportedEncodingException e) { 138 log.error(e, e); 139 return null; 140 } 141 142 String userName = parameters.get(usernameKey); 143 String password = parameters.get(passwordKey); 144 145 if (parameters.get(FORM_SUBMITTED_MARKER) != null && (userName == null || userName.length() == 0)) { 146 parameters.put(LOGIN_ERROR, ERROR_USERNAME_MISSING); 147 } 148 if (userName == null || userName.length() == 0) { 149 return null; 150 } 151 152 return new UserIdentificationInfo(userName, password); 153 } 154 155}