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