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}