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.plugins;
021
022import java.io.IOException;
023import java.util.ArrayList;
024import java.util.List;
025import java.util.Map;
026import java.util.Map.Entry;
027
028import javax.servlet.http.Cookie;
029import javax.servlet.http.HttpServletRequest;
030import javax.servlet.http.HttpServletResponse;
031
032import org.apache.commons.lang.StringUtils;
033import org.nuxeo.common.utils.Base64;
034import org.nuxeo.ecm.platform.api.login.UserIdentificationInfo;
035import org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants;
036import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPlugin;
037
038public class BasicAuthenticator implements NuxeoAuthenticationPlugin {
039
040    protected static final String REALM_NAME_KEY = "RealmName";
041
042    protected static final String FORCE_PROMPT_KEY = "ForcePromptURL";
043
044    protected static final String AUTO_PROMPT_KEY = "AutoPrompt";
045
046    protected static final String PROMPT_URL_KEY = "PromptUrl";
047
048    protected static final String DEFAULT_REALMNAME = "Nuxeo 5";
049
050    protected static final String BA_HEADER_NAME = "WWW-Authenticate";
051
052    protected static final String EXCLUDE_URL_KEY = "ExcludeBAHeader";
053
054    protected String realName;
055
056    protected Boolean autoPrompt = false;
057
058    protected List<String> forcePromptURLs;
059
060    private List<String> excludedHeadersForBasicAuth;
061
062    @Override
063    public Boolean handleLoginPrompt(HttpServletRequest httpRequest, HttpServletResponse httpResponse, String baseURL) {
064        try {
065
066            if (needToAddBAHeader(httpRequest)) {
067                String baHeader = "Basic realm=\"" + realName + '\"';
068                httpResponse.addHeader(BA_HEADER_NAME, baHeader);
069            }
070            int statusCode;
071            Integer requestStatusCode = (Integer) httpRequest.getAttribute(NXAuthConstants.LOGIN_STATUS_CODE);
072            if (requestStatusCode != null) {
073                statusCode = requestStatusCode;
074            } else {
075                statusCode = HttpServletResponse.SC_UNAUTHORIZED;
076            }
077            httpResponse.sendError(statusCode);
078            return true;
079        } catch (IOException e) {
080            return false;
081        }
082    }
083
084    /**
085     * Checks if we need to include a basic auth header back to the client.
086     *
087     * @param httpRequest
088     * @return true if we need to include the auth header
089     * @since 5.9.2
090     */
091    private boolean needToAddBAHeader(HttpServletRequest httpRequest) {
092        for (String header : excludedHeadersForBasicAuth) {
093            if (StringUtils.isNotBlank(httpRequest.getHeader(header))) {
094                return false;
095            }
096            if (httpRequest.getCookies() != null) {
097                for (Cookie cookie : httpRequest.getCookies()) {
098                    if (cookie.getName().equals(header)) {
099                        return false;
100                    }
101                }
102            }
103        }
104        return true;
105    }
106
107    @Override
108    public UserIdentificationInfo handleRetrieveIdentity(HttpServletRequest httpRequest,
109            HttpServletResponse httpResponse) {
110
111        String auth = httpRequest.getHeader("authorization");
112
113        if (auth != null && auth.toLowerCase().startsWith("basic")) {
114            int idx = auth.indexOf(' ');
115            String b64userPassword = auth.substring(idx + 1);
116            byte[] clearUp = Base64.decode(b64userPassword);
117            String userCredentials = new String(clearUp);
118            int idxOfColon = userCredentials.indexOf(':');
119            if (idxOfColon > 0 && idxOfColon < userCredentials.length() - 1) {
120                String username = userCredentials.substring(0, idxOfColon);
121                String password = userCredentials.substring(idxOfColon + 1);
122                return new UserIdentificationInfo(username, password);
123            } else {
124                return null;
125            }
126        }
127        return null;
128    }
129
130    @Override
131    public Boolean needLoginPrompt(HttpServletRequest httpRequest) {
132        if (autoPrompt) {
133            return true;
134        } else {
135            String requestedURI = httpRequest.getRequestURI();
136            String context = httpRequest.getContextPath() + '/';
137            requestedURI = requestedURI.substring(context.length());
138            for (String prefixURL : forcePromptURLs) {
139                if (requestedURI.startsWith(prefixURL)) {
140                    return true;
141                }
142            }
143            return false;
144        }
145    }
146
147    @Override
148    public void initPlugin(Map<String, String> parameters) {
149        if (parameters.containsKey(REALM_NAME_KEY)) {
150            realName = parameters.get(REALM_NAME_KEY);
151        } else {
152            realName = DEFAULT_REALMNAME;
153        }
154
155        if (parameters.containsKey(AUTO_PROMPT_KEY)) {
156            autoPrompt = parameters.get(AUTO_PROMPT_KEY).equalsIgnoreCase("true");
157        }
158
159        forcePromptURLs = new ArrayList<String>();
160        for (Entry<String, String> entry : parameters.entrySet()) {
161            if (entry.getKey().startsWith(FORCE_PROMPT_KEY)) {
162                forcePromptURLs.add(entry.getValue());
163            }
164        }
165
166        excludedHeadersForBasicAuth = new ArrayList<>();
167        for (Entry<String, String> entry : parameters.entrySet()) {
168            if (entry.getKey().startsWith(EXCLUDE_URL_KEY)) {
169                excludedHeadersForBasicAuth.add(entry.getValue());
170            }
171        }
172    }
173
174    @Override
175    public List<String> getUnAuthenticatedURLPrefix() {
176        return null;
177    }
178
179}