001/* 002 * (C) Copyright 2006-2012 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 * Antoine Taillefer 018 */ 019package org.nuxeo.ecm.platform.ui.web.auth.token; 020 021import java.util.List; 022import java.util.Map; 023 024import javax.security.auth.spi.LoginModule; 025import javax.servlet.http.Cookie; 026import javax.servlet.http.HttpServletRequest; 027import javax.servlet.http.HttpServletResponse; 028 029import org.apache.commons.logging.Log; 030import org.apache.commons.logging.LogFactory; 031import org.nuxeo.ecm.platform.api.login.UserIdentificationInfo; 032import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPlugin; 033import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPluginLogoutExtension; 034import org.nuxeo.ecm.platform.usermanager.UserManager; 035import org.nuxeo.ecm.platform.web.common.CookieHelper; 036import org.nuxeo.ecm.tokenauth.service.TokenAuthenticationService; 037import org.nuxeo.runtime.api.Framework; 038 039/** 040 * Handles authentication with a token sent as a request header. 041 * <p> 042 * The user is retrieved with the {@link TokenAuthenticationService}. 043 * <p> 044 * This Authentication Plugin is configured to be used with the Trusting_LM {@link LoginModule} plugin => no password 045 * check will be done, a principal will be created from the userName if the user exists in the user directory. 046 * 047 * @author Antoine Taillefer (ataillefer@nuxeo.com) 048 * @since 5.7 049 */ 050public class TokenAuthenticator implements NuxeoAuthenticationPlugin, NuxeoAuthenticationPluginLogoutExtension { 051 052 public static final String ALLOW_ANONYMOUS_KEY = "allowAnonymous"; 053 054 private static final String HTTPS = "https"; 055 056 private static final String LOCALHOST = "localhost"; 057 058 private static final Log log = LogFactory.getLog(TokenAuthenticator.class); 059 060 protected static final String TOKEN_HEADER = "X-Authentication-Token"; 061 062 protected static final String TOKEN_PARAM = "token"; 063 064 protected boolean allowAnonymous = false; 065 066 @Override 067 public Boolean handleLoginPrompt(HttpServletRequest httpRequest, HttpServletResponse httpResponse, String baseURL) { 068 return false; 069 } 070 071 @Override 072 public UserIdentificationInfo handleRetrieveIdentity(HttpServletRequest httpRequest, 073 HttpServletResponse httpResponse) { 074 075 String token = getTokenFromRequest(httpRequest); 076 077 if (token == null) { 078 log.debug(String.format("Found no '%s' header in the request.", TOKEN_HEADER)); 079 return null; 080 } 081 082 String userName = getUserByToken(token); 083 if (userName == null) { 084 log.debug(String.format("No user bound to the token '%s' (maybe it has been revoked), returning null.", 085 token)); 086 return null; 087 } 088 // Don't retrieve identity for anonymous user unless 'allowAnonymous' parameter is explicitly set to true in 089 // the authentication plugin configuration 090 UserManager userManager = Framework.getService(UserManager.class); 091 if (userManager != null && userName.equals(userManager.getAnonymousUserId()) && !allowAnonymous) { 092 log.debug("Anonymous user is not allowed to get authenticated by token, returning null."); 093 return null; 094 } 095 096 Cookie cookie = CookieHelper.createCookie(httpRequest, TOKEN_HEADER, token); 097 httpResponse.addCookie(cookie); 098 099 return new UserIdentificationInfo(userName, userName); 100 } 101 102 /** 103 * Gets the token from the request if present else null. 104 * 105 * @since 5.9.2 106 */ 107 private String getTokenFromRequest(HttpServletRequest httpRequest) { 108 String token = httpRequest.getHeader(TOKEN_HEADER); 109 110 if (token == null) { 111 token = httpRequest.getParameter(TOKEN_PARAM); 112 } 113 114 // If we don't find the token in request header, let's check in cookies 115 if (token == null && httpRequest.getCookies() != null) { 116 Cookie cookie = getTokenCookie(httpRequest); 117 if (cookie != null) { 118 return cookie.getValue(); 119 } 120 } 121 return token; 122 } 123 124 /** 125 * Returns the token from the cookies if found else null. 126 * 127 * @since 5.9.2 128 */ 129 private Cookie getTokenCookie(HttpServletRequest httpRequest) { 130 Cookie[] cookies = httpRequest.getCookies(); 131 if (cookies != null) { 132 for (Cookie cookie : cookies) { 133 if (cookie.getName().equals(TOKEN_HEADER)) { 134 return cookie; 135 } 136 } 137 } 138 return null; 139 } 140 141 @Override 142 public Boolean needLoginPrompt(HttpServletRequest httpRequest) { 143 return false; 144 } 145 146 @Override 147 public void initPlugin(Map<String, String> parameters) { 148 if (parameters.containsKey(ALLOW_ANONYMOUS_KEY)) { 149 allowAnonymous = Boolean.valueOf(parameters.get(ALLOW_ANONYMOUS_KEY)); 150 } 151 } 152 153 @Override 154 public List<String> getUnAuthenticatedURLPrefix() { 155 return null; 156 } 157 158 protected String getUserByToken(String token) { 159 160 TokenAuthenticationService tokenAuthService = Framework.getService(TokenAuthenticationService.class); 161 return tokenAuthService.getUserName(token); 162 } 163 164 @Override 165 public Boolean handleLogout(HttpServletRequest httpRequest, HttpServletResponse httpResponse) { 166 Cookie cookie = getTokenCookie(httpRequest); 167 if (cookie != null) { 168 cookie.setValue(""); 169 httpResponse.addCookie(cookie); 170 } 171 return false; 172 } 173}