001/*
002 * (C) Copyright 2006-2007 Nuxeo SAS (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 *     Nuxeo - initial API and implementation
016 *
017 * $Id: JOOoConvertPluginImpl.java 18651 2007-05-13 20:28:53Z sfermigier $
018 */
019
020package org.nuxeo.ecm.platform.ui.web.auth.proxy;
021
022import java.io.Serializable;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026import java.util.regex.Matcher;
027import java.util.regex.Pattern;
028
029import javax.servlet.http.HttpServletRequest;
030import javax.servlet.http.HttpServletResponse;
031import javax.servlet.http.HttpSession;
032
033import org.apache.commons.logging.Log;
034import org.apache.commons.logging.LogFactory;
035import org.nuxeo.ecm.core.api.DocumentModelList;
036import org.nuxeo.ecm.directory.DirectoryException;
037import org.nuxeo.ecm.directory.Session;
038import org.nuxeo.ecm.directory.api.DirectoryService;
039import org.nuxeo.ecm.platform.api.login.UserIdentificationInfo;
040import org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants;
041import org.nuxeo.ecm.platform.ui.web.auth.NuxeoAuthenticationFilter;
042import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPlugin;
043import org.nuxeo.ecm.platform.usermanager.UserManager;
044import org.nuxeo.runtime.api.Framework;
045
046public class ProxyAuthenticator implements NuxeoAuthenticationPlugin {
047
048    private static final Log log = LogFactory.getLog(ProxyAuthenticator.class);
049
050    private static final String HEADER_NAME_KEY = "ssoHeaderName";
051
052    private static final String HEADER_NOREDIRECT_KEY = "ssoNeverRedirect";
053
054    public static final String USERNAME_REMOVE_EXPRESSION = "usernameUnwantedPartExpression";
055
056    protected String userIdHeaderName = "remote_user";
057
058    protected String regexp = null;
059
060    protected boolean noRedirect;
061
062    public static final String HTTP_CREDENTIAL_DIRECTORY_FIELD_PROPERTY_NAME = "org.nuxeo.ecm.platform.login.mod_sso.credentialDirectoryField";
063
064    private Pattern usernamePartRemovalPattern;
065
066    public List<String> getUnAuthenticatedURLPrefix() {
067        return null;
068    }
069
070    public Boolean handleLoginPrompt(HttpServletRequest httpRequest, HttpServletResponse httpResponse, String baseURL) {
071        return false;
072    }
073
074    public UserIdentificationInfo handleRetrieveIdentity(HttpServletRequest httpRequest,
075            HttpServletResponse httpResponse) {
076        String userName = httpRequest.getHeader(userIdHeaderName);
077        if (userName == null) {
078            return null;
079        }
080        if (regexp != null && usernamePartRemovalPattern != null) {
081            String tmpUsername = userName;
082            Matcher matcher = usernamePartRemovalPattern.matcher(userName);
083            // Remove all instance of regexp from username string
084            userName = matcher.replaceAll("");
085            log.debug(String.format("userName changed from '%s' to '%s'", tmpUsername, userName));
086        }
087
088        String credentialFieldName = Framework.getRuntime().getProperty(HTTP_CREDENTIAL_DIRECTORY_FIELD_PROPERTY_NAME);
089        if (credentialFieldName != null) {
090            // use custom directory field to find the user with the ID given in
091            // the HTTP header
092            String directoryName = Framework.getService(UserManager.class).getUserDirectoryName();
093            try (Session userDir = Framework.getService(DirectoryService.class).open(directoryName)) {
094                Map<String, Serializable> queryFilters = new HashMap<String, Serializable>();
095                queryFilters.put(credentialFieldName, userName);
096                DocumentModelList result = userDir.query(queryFilters);
097                if (result.isEmpty()) {
098                    log.error(String.format("could not find any user with %s='%s' in directory %s",
099                            credentialFieldName, userName, directoryName));
100                    return null;
101                }
102                if (result.size() > 1) {
103                    log.error(String.format("found more than one entry for  %s='%s' in directory %s",
104                            credentialFieldName, userName, directoryName));
105                    return null;
106                }
107                // use the ID of the found user entry as new identification for
108                // the principal
109                userName = result.get(0).getId();
110            } catch (DirectoryException e) {
111                log.error(String.format("could not retrieve user entry with %s='%s':  %s", credentialFieldName,
112                        userName, e.getMessage()), e);
113                return null;
114            }
115        }
116
117        if (!noRedirect) {
118            handleRedirectToValidStartPage(httpRequest, httpResponse);
119        }
120        return new UserIdentificationInfo(userName, userName);
121    }
122
123    /**
124     * Handle redirection so that context is rebuilt correctly see NXP-2060 + NXP-2064
125     */
126    protected void handleRedirectToValidStartPage(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
127        boolean isStartPageValid = false;
128        if (httpRequest.getMethod().equals("GET") || httpRequest.getMethod().equals("POST")) {
129            // try to keep valid start page
130            NuxeoAuthenticationFilter filter = new NuxeoAuthenticationFilter();
131            isStartPageValid = filter.saveRequestedURLBeforeRedirect(httpRequest, httpResponse);
132        }
133        HttpSession session;
134        if (httpResponse.isCommitted()) {
135            session = httpRequest.getSession(false);
136        } else {
137            session = httpRequest.getSession(true);
138        }
139        if (session != null && !isStartPageValid) {
140            session.setAttribute(NXAuthConstants.START_PAGE_SAVE_KEY, NuxeoAuthenticationFilter.DEFAULT_START_PAGE
141                    + "?loginRedirection=true");
142        }
143    }
144
145    public void initPlugin(Map<String, String> parameters) {
146        if (parameters.containsKey(HEADER_NAME_KEY)) {
147            userIdHeaderName = parameters.get(HEADER_NAME_KEY);
148        }
149        if (parameters.containsKey(HEADER_NOREDIRECT_KEY)) {
150            noRedirect = Boolean.parseBoolean(parameters.get(HEADER_NOREDIRECT_KEY));
151        }
152        if (parameters.containsKey(USERNAME_REMOVE_EXPRESSION)) {
153            regexp = parameters.get(USERNAME_REMOVE_EXPRESSION);
154            log.debug(String.format("Will remove all instances of '%s' from userName string.", regexp));
155            usernamePartRemovalPattern = Pattern.compile(regexp);
156        }
157    }
158
159    public Boolean needLoginPrompt(HttpServletRequest httpRequest) {
160        return false;
161    }
162
163}