/*
* (C) Copyright 2006-2012 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Antoine Taillefer
*/
package org.nuxeo.ecm.platform.ui.web.auth.token;
import java.util.List;
import java.util.Map;
import javax.security.auth.spi.LoginModule;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuxeo.ecm.platform.api.login.UserIdentificationInfo;
import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPlugin;
import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPluginLogoutExtension;
import org.nuxeo.ecm.platform.usermanager.UserManager;
import org.nuxeo.ecm.platform.web.common.CookieHelper;
import org.nuxeo.ecm.tokenauth.service.TokenAuthenticationService;
import org.nuxeo.runtime.api.Framework;
/**
* Handles authentication with a token sent as a request header.
* <p>
* The user is retrieved with the {@link TokenAuthenticationService}.
* <p>
* This Authentication Plugin is configured to be used with the Trusting_LM {@link LoginModule} plugin => no password
* check will be done, a principal will be created from the userName if the user exists in the user directory.
*
* @author Antoine Taillefer (ataillefer@nuxeo.com)
* @since 5.7
*/
public class TokenAuthenticator implements NuxeoAuthenticationPlugin, NuxeoAuthenticationPluginLogoutExtension {
public static final String ALLOW_ANONYMOUS_KEY = "allowAnonymous";
private static final String HTTPS = "https";
private static final String LOCALHOST = "localhost";
private static final Log log = LogFactory.getLog(TokenAuthenticator.class);
protected static final String TOKEN_HEADER = "X-Authentication-Token";
protected static final String TOKEN_PARAM = "token";
protected boolean allowAnonymous = false;
@Override
public Boolean handleLoginPrompt(HttpServletRequest httpRequest, HttpServletResponse httpResponse, String baseURL) {
return false;
}
@Override
public UserIdentificationInfo handleRetrieveIdentity(HttpServletRequest httpRequest,
HttpServletResponse httpResponse) {
String token = getTokenFromRequest(httpRequest);
if (token == null) {
log.debug(String.format("Found no '%s' header in the request.", TOKEN_HEADER));
return null;
}
String userName = getUserByToken(token);
if (userName == null) {
log.debug(String.format("No user bound to the token '%s' (maybe it has been revoked), returning null.",
token));
return null;
}
// Don't retrieve identity for anonymous user unless 'allowAnonymous' parameter is explicitly set to true in
// the authentication plugin configuration
UserManager userManager = Framework.getService(UserManager.class);
if (userManager != null && userName.equals(userManager.getAnonymousUserId()) && !allowAnonymous) {
log.debug("Anonymous user is not allowed to get authenticated by token, returning null.");
return null;
}
Cookie cookie = CookieHelper.createCookie(httpRequest, TOKEN_HEADER, token);
httpResponse.addCookie(cookie);
return new UserIdentificationInfo(userName, userName);
}
/**
* Gets the token from the request if present else null.
*
* @since 5.9.2
*/
private String getTokenFromRequest(HttpServletRequest httpRequest) {
String token = httpRequest.getHeader(TOKEN_HEADER);
if (token == null) {
token = httpRequest.getParameter(TOKEN_PARAM);
}
// If we don't find the token in request header, let's check in cookies
if (token == null && httpRequest.getCookies() != null) {
Cookie cookie = getTokenCookie(httpRequest);
if (cookie != null) {
return cookie.getValue();
}
}
return token;
}
/**
* Returns the token from the cookies if found else null.
*
* @since 5.9.2
*/
private Cookie getTokenCookie(HttpServletRequest httpRequest) {
Cookie[] cookies = httpRequest.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(TOKEN_HEADER)) {
return cookie;
}
}
}
return null;
}
@Override
public Boolean needLoginPrompt(HttpServletRequest httpRequest) {
return false;
}
@Override
public void initPlugin(Map<String, String> parameters) {
if (parameters.containsKey(ALLOW_ANONYMOUS_KEY)) {
allowAnonymous = Boolean.valueOf(parameters.get(ALLOW_ANONYMOUS_KEY));
}
}
@Override
public List<String> getUnAuthenticatedURLPrefix() {
return null;
}
protected String getUserByToken(String token) {
TokenAuthenticationService tokenAuthService = Framework.getLocalService(TokenAuthenticationService.class);
return tokenAuthService.getUserName(token);
}
@Override
public Boolean handleLogout(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
Cookie cookie = getTokenCookie(httpRequest);
if (cookie != null) {
cookie.setMaxAge(0);
cookie.setValue("");
httpResponse.addCookie(cookie);
}
return false;
}
}