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