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