From 8f882c680c08dc60dc3b8d5d73c9679642c47e90 Mon Sep 17 00:00:00 2001 From: Dave Ward Date: Wed, 14 Oct 2009 09:24:13 +0000 Subject: [PATCH] Merged V3.2 to HEAD 16662: LDAP sync: improved group association filtering, referential integrity checking, deletion strategy and performance tuning of batch sizes 16648: ETHREEOH-2752: Improved ticket validation fix - Invalidate user's tickets during person deletion rather than validation or it can mess up chained validation 16647: ETHREEOH-2534: Fixed Sharepoint NTLM authentication - user details were never getting cached in the session 16579: Small improvement to LDAP error reporting - Committed errors counted before successes in a logging interval 16515: LDAP sync performance - Improved full sync strategy - run differential queries to work out required updates/additions and full queries to work out required deletions. Saves updating unchanged nodes. - Use a TreeSet rather than a HashSet to gather group associations in an attempt to avoid blowing the heap size 16498: More LDAP performance improvements - Uses thread pool with 4 worker threads and blocking queue to process returned results. The number of worker threads can be controlled by the synchronization.workerThreads property. - Switched LDAP connection pooling back on again - Group Associations processsed individually so that errors are collated and we get a better idea of their throughput - Fixed potential bug. Group membership resolution done with isolated LDAP context to avoid cookies from paging creeping in. 16424: Try switching off LDAP connection pooling to see if it works better with our flaky server. 16414: Further LDAP fault tolerance - Log causes of group member resolution failures where possible 16413: More fault tolerance for LDAP sync - Always commit last sync times before overall sync is complete to avoid the 'forgetting' of differential sync information - DN comparisons should be case insensitive to avoid issues resolving DNs to user and group IDs 16398: Improved monitoring and fault tolerance for LDAP sync - When the batch is complete a summary of the number of errors and the last error stack trace will be logged at ERROR level - Each individual error is logged at WARN level and progress information (including % complete) is collated and logged at INFO level after a configurable interval - In the Enterprise Edition all metrics can be monitored in real time through JMX - Sanity testing to be performed by Mike! 16319: Merged HEAD to V3.2 16316: ALFCOM-3397: JBoss 5 compatibility fix - Relative paths used by LDAP subsystem configuration weren't being resolved correctly - See also https://jira.jboss.org/jira/browse/JBAS-6548 and https://jira.springsource.org/browse/SPR-5120 16272: ETHREEOH-2752: Once more with feeling! 16261: ETHREEOH-2752: Correct exception propagation. 16260: ETHREEOH-2752: Fix ticket validation - Current ticket was getting forgotten by previous fix - Person validation in CHECK mode now done AFTER the current user is set, so that the current ticket is remembered 16243: ETHREEOH-2752: Improve ticket validation used by all authentication filters - Now takes into account whether person actually exists or not - Tickets for non-nonexistent persons are now considered invalid and cached session information is invalidated - New BaseAuthenticationFilter superclass for all authentication filters - Improved fix to ETHREEOH-2839: WebDAV user is cached consistently using a different session attribute from the Web Client 16233: ETHREEOH-2754: Correction to previous checkin. - relogin for SSO authentication, logout for normal login page - logout is default 16232: ETHREEOH-2754: Log Out Action outcome passed as a parameter - relogin for SSO authentication, login for normal login page - Means the log out link always leads to the correct place, even when the session has expired - Also lowered ticket validation error logging to DEBUG level to avoid unnecessary noise in the logs from expired sessions 16220: ETHREEOH-2839: Fixed potential ClassCastExceptions when Alfresco accessed via WebDAV and Web Client links in same browser - WebDAV side no longer directly casts session user to a WebDAVUser - ContextListener no longer casts session user to web client user - Web client side will 'promote' session user to a web client User if necessary via AuthenticationHelper - All authentication filters made to use appropriate AuthenticationHelper methods 16211: ETHREEOH-2835: LDAP sync batches user and group deletions as well as creations - Also improved logging of sync failures 16197: ETHREEOH-2782: LDAP subsystems now support search-based user DN resolution - When ldap.authentication.userNameFormat isn't set (now the default) converts a user ID to a DN by running ldap.synchronization.personQuery with an extra condition tacked on the end to find the user by ID - Structured directories and authentication by attributes not in the DN such as email address now supported 16189: ALFCOM-3283: Prevent errors when user accepts an invite when not logged in - new isGuest attribute propagated to user object - header component (used by accept-invite page) needs to avoid calling prefs and site webscripts for guest user - Conditional stuff in header template changed to use user.isGuest git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@16896 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../org/alfresco/webframework/metadata.get.js | 1 + .../alfresco/repo/webdav/PropFindMethod.java | 6 +- .../webdav/auth/AuthenticationFilter.java | 211 +++---------- .../webdav/auth/BaseAuthenticationFilter.java | 295 ++++++++++++++++++ .../BaseKerberosAuthenticationFilter.java | 53 +--- .../auth/BaseNTLMAuthenticationFilter.java | 98 ++---- .../auth/BaseSSOAuthenticationFilter.java | 263 +++------------- .../auth/HTTPRequestAuthenticationFilter.java | 223 ++++--------- .../auth/KerberosAuthenticationFilter.java | 17 +- .../webdav/auth/NTLMAuthenticationFilter.java | 19 +- 10 files changed, 474 insertions(+), 712 deletions(-) create mode 100644 source/java/org/alfresco/repo/webdav/auth/BaseAuthenticationFilter.java diff --git a/config/alfresco/templates/webscripts/org/alfresco/webframework/metadata.get.js b/config/alfresco/templates/webscripts/org/alfresco/webframework/metadata.get.js index 1fdb69674d..a2f76d36b3 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/webframework/metadata.get.js +++ b/config/alfresco/templates/webscripts/org/alfresco/webframework/metadata.get.js @@ -17,6 +17,7 @@ else if (args["user"] != null) var userId = args["user"]; object = people.getPerson(userId); model.isAdmin = people.isAdmin(object); + model.isGuest = people.isGuest(object); model.isUser = true; model.includeChildren = false; } diff --git a/source/java/org/alfresco/repo/webdav/PropFindMethod.java b/source/java/org/alfresco/repo/webdav/PropFindMethod.java index 8b30ade538..a24b2e287f 100644 --- a/source/java/org/alfresco/repo/webdav/PropFindMethod.java +++ b/source/java/org/alfresco/repo/webdav/PropFindMethod.java @@ -35,8 +35,8 @@ import javax.servlet.http.HttpServletResponse; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; +import org.alfresco.repo.SessionUser; import org.alfresco.repo.webdav.auth.AuthenticationFilter; -import org.alfresco.repo.webdav.auth.WebDAVUser; import org.alfresco.service.cmr.lock.LockService; import org.alfresco.service.cmr.lock.LockStatus; import org.alfresco.service.cmr.model.FileFolderService; @@ -604,7 +604,7 @@ public class PropFindMethod extends WebDAVMethod { // Get the users authentication ticket - WebDAVUser davUser = (WebDAVUser) m_request.getSession().getAttribute( AuthenticationFilter.AUTHENTICATION_USER); + SessionUser davUser = (SessionUser) m_request.getSession().getAttribute( AuthenticationFilter.AUTHENTICATION_USER); xml.startElement(WebDAV.DAV_NS, WebDAV.XML_ALF_AUTHTICKET, WebDAV.XML_NS_ALF_AUTHTICKET, nullAttr); if ( davUser != null) @@ -808,7 +808,7 @@ public class PropFindMethod extends WebDAVMethod // Print out all the custom properties - WebDAVUser davUser = (WebDAVUser) m_request.getSession().getAttribute( AuthenticationFilter.AUTHENTICATION_USER); + SessionUser davUser = (SessionUser) m_request.getSession().getAttribute( AuthenticationFilter.AUTHENTICATION_USER); xml.startElement(WebDAV.DAV_NS, WebDAV.XML_ALF_AUTHTICKET, WebDAV.XML_NS_ALF_AUTHTICKET, nullAttr); if ( davUser != null) diff --git a/source/java/org/alfresco/repo/webdav/auth/AuthenticationFilter.java b/source/java/org/alfresco/repo/webdav/auth/AuthenticationFilter.java index d856970bbc..f79fb3aa83 100644 --- a/source/java/org/alfresco/repo/webdav/auth/AuthenticationFilter.java +++ b/source/java/org/alfresco/repo/webdav/auth/AuthenticationFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -34,18 +34,11 @@ import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.transaction.UserTransaction; -import org.alfresco.model.ContentModel; +import org.alfresco.repo.SessionUser; import org.alfresco.repo.security.authentication.AuthenticationException; import org.alfresco.repo.web.filter.beans.DependencyInjectedFilter; -import org.alfresco.service.cmr.repository.InvalidNodeRefException; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.NoSuchPersonException; -import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.service.transaction.TransactionService; import org.apache.commons.codec.binary.Base64; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -55,62 +48,18 @@ import org.apache.commons.logging.LogFactory; * * @author GKSpencer */ -public class AuthenticationFilter implements DependencyInjectedFilter +public class AuthenticationFilter extends BaseAuthenticationFilter implements DependencyInjectedFilter { // Debug logging - private static Log logger = LogFactory.getLog(NTLMAuthenticationFilter.class); + private static Log logger = LogFactory.getLog(AuthenticationFilter.class); // Authenticated user session object name - public final static String AUTHENTICATION_USER = "_alfDAVAuthTicket"; - - // Allow an authentication ticket to be passed as part of a request to bypass authentication - - private static final String ARG_TICKET = "ticket"; private static final String PPT_EXTN = ".ppt"; - private static final String VTI_IGNORE = "&vtiIgnore"; // Various services required by NTLM authenticator - private AuthenticationService authService; - private PersonService personService; - private NodeService nodeService; - private TransactionService transactionService; - - - /** - * @param authService the authService to set - */ - public void setAuthenticationService(AuthenticationService authService) - { - this.authService = authService; - } - - /** - * @param personService the personService to set - */ - public void setPersonService(PersonService personService) - { - this.personService = personService; - } - - /** - * @param nodeService the nodeService to set - */ - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - - /** - * @param transactionService the transactionService to set - */ - public void setTransactionService(TransactionService transactionService) - { - this.transactionService = transactionService; - } - /** * Run the authentication filter * @@ -130,8 +79,7 @@ public class AuthenticationFilter implements DependencyInjectedFilter HttpServletResponse httpResp = (HttpServletResponse) resp; // Get the user details object from the session - - WebDAVUser user = (WebDAVUser) httpReq.getSession().getAttribute(AUTHENTICATION_USER); + SessionUser user = getSessionUser(context, httpReq, httpResp, false); if (user == null) { @@ -166,21 +114,9 @@ public class AuthenticationFilter implements DependencyInjectedFilter { // Authenticate the user - authService.authenticate(username, password.toCharArray()); - - // Set the user name as stored by the back end - username = authService.getCurrentUserName(); - - // Get the user node and home folder + authenticationService.authenticate(username, password.toCharArray()); - NodeRef personNodeRef = personService.getPerson(username); - NodeRef homeSpaceRef = (NodeRef) nodeService.getProperty(personNodeRef, ContentModel.PROP_HOMEFOLDER); - - // Setup User object and Home space ID etc. - - user = new WebDAVUser(username, authService.getCurrentTicket(), homeSpaceRef); - - httpReq.getSession().setAttribute(AUTHENTICATION_USER, user); + user = createUserEnvironment(httpReq.getSession(), authenticationService.getCurrentUserName(), authenticationService.getCurrentTicket(), false); } catch ( AuthenticationException ex) { @@ -193,87 +129,36 @@ public class AuthenticationFilter implements DependencyInjectedFilter } else { - // Check if the request includes an authentication ticket - - String ticket = req.getParameter( ARG_TICKET); - - if ( ticket != null && ticket.length() > 0) - { - // PowerPoint bug fix - if (ticket.endsWith(PPT_EXTN)) - { - ticket = ticket.substring(0, ticket.length() - PPT_EXTN.length()); - } + // Check if the request includes an authentication ticket - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("Logon via ticket from " + req.getRemoteHost() + " (" + - req.getRemoteAddr() + ":" + req.getRemotePort() + ")" + " ticket=" + ticket); - - UserTransaction tx = null; - try - { - // Validate the ticket - - authService.validate(ticket); + String ticket = req.getParameter(ARG_TICKET); - // Need to create the User instance if not already available - - String currentUsername = authService.getCurrentUserName(); + if (ticket != null && ticket.length() > 0) + { + // PowerPoint bug fix + if (ticket.endsWith(PPT_EXTN)) + { + ticket = ticket.substring(0, ticket.length() - PPT_EXTN.length()); + } - // Start a transaction - - tx = transactionService.getUserTransaction(); - tx.begin(); - - NodeRef personRef = personService.getPerson(currentUsername); - user = new WebDAVUser( currentUsername, authService.getCurrentTicket(), personRef); - NodeRef homeRef = (NodeRef) nodeService.getProperty(personRef, ContentModel.PROP_HOMEFOLDER); - - // Check that the home space node exists - else Login cannot proceed - - if (nodeService.exists(homeRef) == false) - { - throw new InvalidNodeRefException(homeRef); - } - user.setHomeNode(homeRef); - - tx.commit(); - tx = null; - - // Store the User object in the Session - the authentication servlet will then proceed - - httpReq.getSession().setAttribute( AUTHENTICATION_USER, user); - } - catch (AuthenticationException authErr) - { - // Clear the user object to signal authentication failure - - user = null; - } - catch (Throwable e) - { - // Clear the user object to signal authentication failure - - user = null; - } - finally - { - try - { - if (tx != null) - { - tx.rollback(); - } - } - catch (Exception tex) - { - } - } - } + // Debug + + if (logger.isDebugEnabled()) + logger.debug("Logon via ticket from " + req.getRemoteHost() + " (" + req.getRemoteAddr() + ":" + + req.getRemotePort() + ")" + " ticket=" + ticket); + + // Validate the ticket + + authenticationService.validate(ticket); + + // Need to create the User instance if not already available + + String currentUsername = authenticationService.getCurrentUserName(); + + user = createUserEnvironment(httpReq.getSession(), currentUsername, ticket, false); + } } - + // Check if the user is authenticated, if not then prompt again if ( user == null) @@ -287,28 +172,6 @@ public class AuthenticationFilter implements DependencyInjectedFilter return; } } - else - { - try - { - // Setup the authentication context - authService.validate(user.getTicket()); - - // Set the current locale - - // I18NUtil.setLocale(Application.getLanguage(httpRequest.getSession())); - } - catch (Exception ex) - { - // No user/ticket, force the client to prompt for logon details - - httpResp.setHeader("WWW-Authenticate", "BASIC realm=\"Alfresco DAV Server\""); - httpResp.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - - httpResp.flushBuffer(); - return; - } - } // Chain other filters @@ -322,4 +185,12 @@ public class AuthenticationFilter implements DependencyInjectedFilter { // Nothing to do } + + /* (non-Javadoc) + * @see org.alfresco.repo.webdav.auth.BaseAuthenticationFilter#getLogger() + */ + protected Log getLogger() + { + return logger; + } } diff --git a/source/java/org/alfresco/repo/webdav/auth/BaseAuthenticationFilter.java b/source/java/org/alfresco/repo/webdav/auth/BaseAuthenticationFilter.java new file mode 100644 index 0000000000..98b63061e2 --- /dev/null +++ b/source/java/org/alfresco/repo/webdav/auth/BaseAuthenticationFilter.java @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2005-2009 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have received a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.webdav.auth; + +import java.io.IOException; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.SessionUser; +import org.alfresco.repo.security.authentication.AuthenticationException; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.transaction.TransactionService; +import org.apache.commons.logging.Log; + +/** + * A base class for authentication filters. Handles management of the session user. + * + * @author dward + */ +public abstract class BaseAuthenticationFilter +{ + /** The default session attribute used to cache the user. Subclasses may override this with {@link #setUserAttributeName(String)}. */ + public static final String AUTHENTICATION_USER = "_alfDAVAuthTicket"; + + /** The session attribute that indicates external authentication. */ + private static final String LOGIN_EXTERNAL_AUTH = "_alfExternalAuth"; + + /** The name of the ticket argument. */ + protected static final String ARG_TICKET = "ticket"; + + /** The authentication service. */ + protected AuthenticationService authenticationService; + + /** The person service. */ + protected PersonService personService; + + /** The node service. */ + protected NodeService nodeService; + + /** The transaction service. */ + protected TransactionService transactionService; + + /** The configured user attribute name. */ + private String userAttributeName = AUTHENTICATION_USER; + + /** + * Sets the authentication service. + * + * @param authenticationService + * the authService to set + */ + public void setAuthenticationService(AuthenticationService authenticationService) + { + this.authenticationService = authenticationService; + } + + /** + * Sets the person service. + * + * @param personService + * the personService to set + */ + public void setPersonService(PersonService personService) + { + this.personService = personService; + } + + /** + * Sets the node service. + * + * @param nodeService + * the nodeService to set + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * Sets the transaction service. + * + * @param transactionService + * the transactionService to set + */ + public void setTransactionService(TransactionService transactionService) + { + this.transactionService = transactionService; + } + + /** + * Create the user object that will be stored in the session. + * + * @param userName + * String + * @param ticket + * String + * @param personNode + * NodeRef + * @param homeSpaceRef + * NodeRef + * @return SessionUser + */ + protected SessionUser createUserObject(String userName, String ticket, NodeRef personNode, NodeRef homeSpaceRef) + { + return new WebDAVUser(userName, ticket, homeSpaceRef); + } + + /** + * Callback to get the specific impl of the Session User for a filter. + * + * @param servletContext + * the servlet context + * @param httpServletRequest + * the http servlet request + * @param httpServletResponse + * the http servlet response + * @param externalAuth + * has the user been authenticated by SSO? + * @return User from the session + */ + protected SessionUser getSessionUser(ServletContext servletContext, final HttpServletRequest httpServletRequest, + HttpServletResponse httpServletResponse, final boolean externalAuth) + { + String sessionAttrib = getUserAttributeName(); + HttpSession session = httpServletRequest.getSession(); + SessionUser sessionUser = (SessionUser) session.getAttribute(sessionAttrib); + if (sessionUser != null) + { + try + { + authenticationService.validate(sessionUser.getTicket()); + setExternalAuth(session, externalAuth); + } + catch (AuthenticationException e) + { + // The ticket may have expired or the person could have been removed + invalidateSession(httpServletRequest); + sessionUser = null; + } + } + return sessionUser; + } + + /** + * Remove the user from the session and expire the session - after failed ticket auth. + * + * @param session + * the session + */ + protected void invalidateSession(HttpServletRequest req) + { + HttpSession session = req.getSession(false); + if (session != null) + { + setExternalAuth(session, false); + session.removeAttribute(getUserAttributeName()); + session.invalidate(); + } + } + + /** + * Executes a callback in a transaction as the system user + * + * @param callback + * the callback + * @return the return value from the callback + */ + protected T doInSystemTransaction(final RetryingTransactionHelper.RetryingTransactionCallback callback) + { + return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + { + public T doWork() throws Exception + { + return transactionService.getRetryingTransactionHelper().doInTransaction(callback); + } + }, AuthenticationUtil.SYSTEM_USER_NAME); + } + + /** + * Return the user object session attribute name. + * + * @return the user object session attribute name + */ + protected final String getUserAttributeName() + { + return userAttributeName; + } + + /** + * Set the user object attribute name. + * + * @param userAttr + * the user object session attribute name + */ + protected final void setUserAttributeName(String userAttr) + { + userAttributeName = userAttr; + } + + /** + * Callback to create the User environment as appropriate for a filter impl. + * + * @param session + * HttpSession + * @param userName + * String + * @param ticket + * the ticket + * @param externalAuth + * has the user been authenticated by SSO? + * @return SessionUser + * @throws IOException + * Signals that an I/O exception has occurred. + * @throws ServletException + * the servlet exception + */ + protected SessionUser createUserEnvironment(HttpSession session, final String userName, final String ticket, boolean externalAuth) + throws IOException, ServletException + { + SessionUser user = doInSystemTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + + public SessionUser execute() throws Throwable + { + // Setup User object and Home space ID etc. + + final NodeRef personNodeRef = personService.getPerson(userName); + + String name = (String) nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME); + + NodeRef homeSpaceRef = (NodeRef) nodeService.getProperty(personNodeRef, ContentModel.PROP_HOMEFOLDER); + + return createUserObject(name, ticket, personNodeRef, homeSpaceRef); + } + }); + + // Store the user on the session + + session.setAttribute(getUserAttributeName(), user); + setExternalAuth(session, externalAuth); + return user; + } + + private void setExternalAuth(HttpSession session, boolean externalAuth) + { + if (externalAuth) + { + session.setAttribute(LOGIN_EXTERNAL_AUTH, Boolean.TRUE); + } + else + { + session.removeAttribute(LOGIN_EXTERNAL_AUTH); + } + } + + /** + * Return the logger. + * + * @return Log + */ + protected abstract Log getLogger(); + +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/webdav/auth/BaseKerberosAuthenticationFilter.java b/source/java/org/alfresco/repo/webdav/auth/BaseKerberosAuthenticationFilter.java index b798a908c5..beca7887dd 100644 --- a/source/java/org/alfresco/repo/webdav/auth/BaseKerberosAuthenticationFilter.java +++ b/source/java/org/alfresco/repo/webdav/auth/BaseKerberosAuthenticationFilter.java @@ -56,7 +56,6 @@ import org.alfresco.jlan.server.auth.spnego.NegTokenTarg; import org.alfresco.jlan.server.auth.spnego.OID; import org.alfresco.jlan.server.auth.spnego.SPNEGO; import org.alfresco.repo.SessionUser; -import org.alfresco.repo.security.authentication.AuthenticationException; import org.apache.commons.codec.binary.Base64; import org.ietf.jgss.Oid; @@ -255,8 +254,6 @@ public abstract class BaseKerberosAuthenticationFilter extends BaseSSOAuthentica HttpServletRequest req = (HttpServletRequest) sreq; HttpServletResponse resp = (HttpServletResponse) sresp; - HttpSession httpSess = req.getSession(true); - // If a filter up the chain has marked the request as not requiring auth then respect it if (req.getAttribute( NO_AUTH_REQUIRED) != null) @@ -287,50 +284,24 @@ public abstract class BaseKerberosAuthenticationFilter extends BaseSSOAuthentica // Restart the authentication - restartLoginChallenge(resp, httpSess); + restartLoginChallenge(resp, req.getSession()); chain.doFilter(sreq, sresp); return; } } - // Check if the user is already authenticated + // Check if the user is already authenticated + SessionUser user = getSessionUser(context, req, resp, true); + HttpSession httpSess = req.getSession(true); - SessionUser user = getSessionUser( httpSess); - - if ( user != null && reqAuth == false) - { - try - { - // Debug - - if ( getLogger().isDebugEnabled()) - getLogger().debug("User " + user.getUserName() + " validate ticket"); - - // Validate the user ticket - - authenticationService.validate( user.getTicket()); - reqAuth = false; - - // Filter validate hook - onValidate( context, req, resp); - } - catch (AuthenticationException ex) - { - if ( getLogger().isErrorEnabled()) - getLogger().error("Failed to validate user " + user.getUserName(), ex); - - removeSessionUser( httpSess); - - reqAuth = true; - } - } - // If the user has been validated and we do not require re-authentication then continue to // the next filter - - if ( reqAuth == false && user != null) + if ( user != null && reqAuth == false) { + // Filter validate hook + onValidate( context, req, resp); + // Debug if ( getLogger().isDebugEnabled()) @@ -352,7 +323,7 @@ public abstract class BaseKerberosAuthenticationFilter extends BaseSSOAuthentica { // Check if a ticket parameter has been specified in the reuqest - if ( checkForTicketParameter( req, httpSess)) + if (checkForTicketParameter(context, req, resp)) { // Chain to the next filter @@ -542,14 +513,10 @@ public abstract class BaseKerberosAuthenticationFilter extends BaseSSOAuthentica if ( negTokenTarg != null) { - // Create the user authentication context + // Create and store the user authentication context SessionUser user = createUserEnvironment( httpSess, krbDetails.getUserName()); - // Store the user - - httpSess.setAttribute(AUTHENTICATION_USER, user); - // Debug if ( getLogger().isDebugEnabled()) diff --git a/source/java/org/alfresco/repo/webdav/auth/BaseNTLMAuthenticationFilter.java b/source/java/org/alfresco/repo/webdav/auth/BaseNTLMAuthenticationFilter.java index 6a73d53c34..22ca9e432f 100644 --- a/source/java/org/alfresco/repo/webdav/auth/BaseNTLMAuthenticationFilter.java +++ b/source/java/org/alfresco/repo/webdav/auth/BaseNTLMAuthenticationFilter.java @@ -188,7 +188,6 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication // Get the HTTP request/response/session HttpServletRequest req = (HttpServletRequest) sreq; HttpServletResponse resp = (HttpServletResponse) sresp; - HttpSession httpSess = req.getSession(true); // If a filter up the chain has marked the request as not requiring auth then respect it @@ -221,43 +220,23 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication // Restart the authentication - restartLoginChallenge(resp, httpSess); + restartLoginChallenge(resp, req.getSession()); return; } } // Check if the user is already authenticated - SessionUser user = getSessionUser( httpSess); + SessionUser user = getSessionUser(context, req, resp, true); - if (user != null && reqAuth == false) - { - try - { - if (getLogger().isDebugEnabled()) - getLogger().debug("User " + user.getUserName() + " validate ticket"); - - // Validate the user ticket - authenticationService.validate(user.getTicket()); - reqAuth = false; - - // Filter validate hook - onValidate( context, req, resp); - } - catch (AuthenticationException ex) - { - if (getLogger().isErrorEnabled()) - getLogger().error("Failed to validate user " + user.getUserName(), ex); - - removeSessionUser( httpSess); - - reqAuth = true; - } - } + HttpSession httpSess = req.getSession(true); // If the user has been validated and we do not require re-authentication then continue to // the next filter - if (reqAuth == false && user != null) + if (user != null && reqAuth == false) { + // Filter validate hook + onValidate( context, req, resp); + if (getLogger().isDebugEnabled()) getLogger().debug("Authentication not required (user), chaining ..."); @@ -303,7 +282,8 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication { // Check if the request includes an authentication ticket - if ( checkForTicketParameter(req, httpSess)) { + if (checkForTicketParameter(context, req, resp)) + { // Authentication was bypassed using a ticket parameter @@ -330,13 +310,13 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication { // Process the type 1 NTLM message Type1NTLMMessage type1Msg = new Type1NTLMMessage(ntlmByts); - processType1(type1Msg, req, resp, httpSess); + processType1(type1Msg, req, resp); } else if (ntlmTyp == NTLM.Type3) { // Process the type 3 NTLM message Type3NTLMMessage type3Msg = new Type3NTLMMessage(ntlmByts); - processType3(type3Msg, context, req, resp, httpSess, chain); + processType3(type3Msg, context, req, resp, chain); } else { @@ -358,18 +338,15 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication * @exception IOException */ protected void processType1(Type1NTLMMessage type1Msg, HttpServletRequest req, - HttpServletResponse res, HttpSession session) throws IOException + HttpServletResponse res) throws IOException { if (getLogger().isDebugEnabled()) getLogger().debug("Received type1 " + type1Msg); // Get the existing NTLM details NTLMLogonDetails ntlmDetails = null; - - if (session != null) - { - ntlmDetails = (NTLMLogonDetails)session.getAttribute(NTLM_AUTH_DETAILS); - } + HttpSession session = req.getSession(); + ntlmDetails = (NTLMLogonDetails)session.getAttribute(NTLM_AUTH_DETAILS); // Check if cached logon details are available if (ntlmDetails != null && ntlmDetails.hasType2Message() && @@ -473,8 +450,7 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication * @exception IOException * @exception ServletException */ - protected void processType3(Type3NTLMMessage type3Msg, ServletContext context, HttpServletRequest req, HttpServletResponse res, - HttpSession session, FilterChain chain) throws IOException, ServletException + protected void processType3(Type3NTLMMessage type3Msg, ServletContext context, HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException { Log logger = getLogger(); @@ -485,11 +461,9 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication NTLMLogonDetails ntlmDetails = null; SessionUser user = null; - if (session != null) - { - ntlmDetails = (NTLMLogonDetails)session.getAttribute(NTLM_AUTH_DETAILS); - user = getSessionUser(session); - } + user = getSessionUser(context, req, res, true); + HttpSession session = req.getSession(); + ntlmDetails = (NTLMLogonDetails)session.getAttribute(NTLM_AUTH_DETAILS); // Get the NTLM logon details String userName = type3Msg.getUserName(); @@ -513,26 +487,7 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication if (logger.isDebugEnabled()) logger.debug("Using cached NTLM hash, authenticated = " + authenticated); - try - { - if (logger.isDebugEnabled()) - logger.debug("User " + user.getUserName() + " validate ticket"); - - // Validate the user ticket - authenticationService.validate(user.getTicket()); - - onValidate(context, req, res); - } - catch (AuthenticationException ex) - { - if (logger.isErrorEnabled()) - logger.error("Failed to validate user " + user.getUserName(), ex); - - removeSessionUser(session); - - onValidateFailed(req, res, session); - return; - } + onValidate(context, req, res); // Allow the user to access the requested page chain.doFilter(req, res); @@ -639,22 +594,15 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication { if (user == null) { - user = createUserEnvironment(session, userName); - } - else - { - // user already exists - revalidate ticket to authenticate the current user thread try { - authenticationService.validate(user.getTicket()); + user = createUserEnvironment(session, userName); } catch (AuthenticationException ex) { - if (logger.isErrorEnabled()) - logger.error("Failed to validate user " + user.getUserName(), ex); - - removeSessionUser(session); - + if (logger.isDebugEnabled()) + logger.debug("Failed to validate user " + user.getUserName(), ex); + onValidateFailed(req, res, session); return; } diff --git a/source/java/org/alfresco/repo/webdav/auth/BaseSSOAuthenticationFilter.java b/source/java/org/alfresco/repo/webdav/auth/BaseSSOAuthenticationFilter.java index 662e25265d..d04fe9ac8d 100644 --- a/source/java/org/alfresco/repo/webdav/auth/BaseSSOAuthenticationFilter.java +++ b/source/java/org/alfresco/repo/webdav/auth/BaseSSOAuthenticationFilter.java @@ -41,20 +41,12 @@ import org.alfresco.jlan.server.auth.ntlm.NTLM; import org.alfresco.jlan.server.auth.passthru.DomainMapping; import org.alfresco.jlan.server.config.SecurityConfigSection; import org.alfresco.jlan.util.IPAddress; -import org.alfresco.model.ContentModel; import org.alfresco.repo.SessionUser; import org.alfresco.repo.management.subsystems.ActivateableBean; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationException; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.web.filter.beans.DependencyInjectedFilter; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.security.AuthenticationService; -import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.service.transaction.TransactionService; -import org.apache.commons.logging.Log; import org.springframework.beans.factory.InitializingBean; /** @@ -63,7 +55,7 @@ import org.springframework.beans.factory.InitializingBean; * @author gkspencer * @author kroast */ -public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedFilter, ActivateableBean, InitializingBean +public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilter implements DependencyInjectedFilter, ActivateableBean, InitializingBean { // Constants // @@ -71,37 +63,15 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF // // Note: These values are copied from the AuthenticationHelper and LoginBean classes to avoid project dependencies - protected static final String AUTHENTICATION_USER = "_alfAuthTicket"; - protected static final String LOGIN_EXTERNAL_AUTH = "_alfExternalAuth"; - - // Request level marker to indicate that authentication should not be processed - // - // Note: copied from the AbstractAuthenticationFilter to avoid project dependencies - protected static final String NO_AUTH_REQUIRED = "alfNoAuthRequired"; - - // Attribute used by WebDAV filters for storing the WebDAV user details - - protected static final String WEBDAV_AUTH_USER = "_alfDAVAuthTicket"; // Allow an authentication ticket to be passed as part of a request to bypass authentication - private static final String ARG_TICKET = "ticket"; - - // File server configuration - - private ExtendedServerConfigurationAccessor serverConfiguration; + private ExtendedServerConfigurationAccessor serverConfiguration; // Various services required by NTLM authenticator - protected AuthenticationService authenticationService; - protected AuthenticationComponent authenticationComponent; - protected PersonService personService; - protected NodeService nodeService; - protected TransactionService transactionService; - - // Login page relative address, if null then login will loop until a valid login is received - + protected AuthenticationComponent authenticationComponent; private String m_loginPage; // Indicate whether ticket based logons are supported @@ -110,8 +80,6 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF // User object attribute name - private String m_userAttributeName = AUTHENTICATION_USER; - private String m_lastConfiguredServerName; private String m_lastResolvedServerName; @@ -125,14 +93,6 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF this.serverConfiguration = serverConfiguration; } - /** - * @param authenticationService the authenticationService to set - */ - public void setAuthenticationService(AuthenticationService authenticationService) - { - this.authenticationService = authenticationService; - } - /** * @param authenticationComponent the authenticationComponent to set */ @@ -141,30 +101,6 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF this.authenticationComponent = authenticationComponent; } - /** - * @param personService the personService to set - */ - public void setPersonService(PersonService personService) - { - this.personService = personService; - } - - /** - * @param nodeService the nodeService to set - */ - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - - /** - * @param transactionService the transactionService to set - */ - public void setTransactionService(TransactionService transactionService) - { - this.transactionService = transactionService; - } - /** * Activates or deactivates the bean * @@ -206,136 +142,33 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF { } - /** - * Create the user object that will be stored in the session - * - * @param userName String - * @param ticket String - * @param personNode NodeRef - * @param homeSpace String - * @return SessionUser - */ - protected abstract SessionUser createUserObject( String userName, String ticket, NodeRef personNode, String homeSpace); - - /** - * Callback to get the specific impl of the Session User for a filter - * - * @return User from the session - */ - protected SessionUser getSessionUser(HttpSession session) - { - return (SessionUser)session.getAttribute( getUserAttributeName()); - } - - /** - * Remove the user from the session - after failed ticket auth - */ - protected void removeSessionUser(HttpSession session) - { - session.removeAttribute( getUserAttributeName()); - } - - /** - * Return the user object session attribute name - * - * @return String - */ - protected final String getUserAttributeName() - { - return m_userAttributeName; - } - - /** - * Set the user object attribute name - * - * @param userAttr String - */ - protected final void setUserAttributeName( String userAttr) - { - m_userAttributeName = userAttr; - } - /** * Callback to create the User environment as appropriate for a filter impl * - * @param session HttpSession - * @param userName String + * @param session + * HttpSession + * @param userName + * String * @return SessionUser * @throws IOException * @throws ServletException */ - protected SessionUser createUserEnvironment(HttpSession session, String userName) - throws IOException, ServletException + protected SessionUser createUserEnvironment(final HttpSession session, final String userName) throws IOException, + ServletException { - SessionUser user = null; - - UserTransaction tx = transactionService.getUserTransaction(); - - try - { - tx.begin(); - - // Setup User object and Home space ID etc. - - final NodeRef personNodeRef = personService.getPerson(userName); - - // Use the system user context to do the user lookup - RunAsWork getUserNameRunAsWork = new RunAsWork() - { - public String doWork() throws Exception + return this.transactionService.getRetryingTransactionHelper().doInTransaction( + new RetryingTransactionHelper.RetryingTransactionCallback() { - return (String) nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME); - } - }; - userName = AuthenticationUtil.runAs(getUserNameRunAsWork, AuthenticationUtil.SYSTEM_USER_NAME); - - authenticationComponent.setCurrentUser(userName); - String currentTicket = authenticationService.getCurrentTicket(); - - NodeRef homeSpaceRef = (NodeRef) nodeService.getProperty(personNodeRef, ContentModel.PROP_HOMEFOLDER); - - // Create the user object to be stored in the session - - user = createUserObject( userName, currentTicket, personNodeRef, homeSpaceRef.getId()); - - tx.commit(); - } - catch (Throwable ex) - { - try - { - tx.rollback(); - } - catch (Exception err) - { - getLogger().error("Failed to rollback transaction", err); - } - if (ex instanceof RuntimeException) - { - throw (RuntimeException)ex; - } - else if (ex instanceof IOException) - { - throw (IOException)ex; - } - else if (ex instanceof ServletException) - { - throw (ServletException)ex; - } - else - { - throw new RuntimeException("Authentication setup failed", ex); - } - } - - // Store the user on the session - - session.setAttribute( getUserAttributeName(), user); - session.setAttribute( LOGIN_EXTERNAL_AUTH, Boolean.TRUE); - - return user; + + public SessionUser execute() throws Throwable + { + authenticationComponent.setCurrentUser(userName); + return createUserEnvironment(session, userName, authenticationService.getCurrentTicket(), true); + } + }); } + /** * Callback executed on successful ticket validation during Type3 Message processing. * @@ -416,13 +249,17 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF } /** - * Check if the request has specified a ticket parameter to bypass the standard authentication + * Check if the request has specified a ticket parameter to bypass the standard authentication. * - * @param req HttpServletRequest - * @param sess HttpSession + * @param servletContext + * the servlet context + * @param req + * the request + * @param resp + * the response * @return boolean */ - protected boolean checkForTicketParameter( HttpServletRequest req, HttpSession sess) + protected boolean checkForTicketParameter(ServletContext servletContext, HttpServletRequest req, HttpServletResponse resp) { // Check if the request includes an authentication ticket @@ -438,32 +275,21 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF UserTransaction tx = null; try { - // Validate the ticket - - authenticationService.validate(ticket); - - SessionUser user = getSessionUser( sess); + // Get a cached user with a valid ticket + SessionUser user = getSessionUser(servletContext, req, resp, true); + + // If this isn't the same ticket, invalidate the session + if (!ticket.equals(user.getTicket())) + { + invalidateSession(req); + user = null; + } - if ( user == null) + // If we don't yet have a valid cached user, validate the ticket and create one + if ( user == null ) { - // Start a transaction - - tx = transactionService.getUserTransaction(); - tx.begin(); - - // Need to create the User instance if not already available - - String currentUsername = authenticationService.getCurrentUserName(); - - NodeRef personRef = personService.getPerson(currentUsername); - user = createUserObject( currentUsername, authenticationService.getCurrentTicket(), personRef, null); - - tx.commit(); - tx = null; - - // Store the User object in the Session - the authentication servlet will then proceed - - req.getSession().setAttribute( getUserAttributeName(), user); + authenticationService.validate(ticket); + user = createUserEnvironment(req.getSession(), authenticationService.getCurrentUserName(), authenticationService.getCurrentTicket(), true); } // Indicate the ticket parameter was specified, and valid @@ -514,13 +340,6 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF res.sendRedirect(req.getContextPath() + "/faces" + getLoginPage()); } - /** - * Return the logger - * - * @return Log - */ - protected abstract Log getLogger(); - /** * Determine if the login page is available * diff --git a/source/java/org/alfresco/repo/webdav/auth/HTTPRequestAuthenticationFilter.java b/source/java/org/alfresco/repo/webdav/auth/HTTPRequestAuthenticationFilter.java index 70aebbd6a7..08d6d80362 100644 --- a/source/java/org/alfresco/repo/webdav/auth/HTTPRequestAuthenticationFilter.java +++ b/source/java/org/alfresco/repo/webdav/auth/HTTPRequestAuthenticationFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -18,9 +18,9 @@ * As a special exception to the terms and conditions of version 2.0 of * the GPL, you may redistribute this Program in connection with Free/Libre * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing + * FLOSS exception. You should have received a copy of the text describing * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing + * http://www.alfresco.com/legal/licensing" */ package org.alfresco.repo.webdav.auth; @@ -39,19 +39,13 @@ import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.transaction.UserTransaction; -import org.alfresco.model.ContentModel; +import org.alfresco.repo.SessionUser; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationException; +import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.service.ServiceRegistry; -import org.alfresco.service.cmr.repository.InvalidNodeRefException; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.security.AuthenticationService; -import org.alfresco.service.cmr.security.NoSuchPersonException; import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.service.transaction.TransactionService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.web.context.WebApplicationContext; @@ -60,34 +54,16 @@ import org.springframework.web.context.support.WebApplicationContextUtils; /** * WebDAV Authentication Filter Class for SSO linke SiteMinder and IChains */ -public class HTTPRequestAuthenticationFilter implements Filter +public class HTTPRequestAuthenticationFilter extends BaseAuthenticationFilter implements Filter { // Debug logging private static Log logger = LogFactory.getLog(HTTPRequestAuthenticationFilter.class); - // Authenticated user session object name - - public final static String AUTHENTICATION_USER = "_alfDAVAuthTicket"; - - // Allow an authenitcation ticket to be passed as part of a request to bypass authentication - - private static final String ARG_TICKET = "ticket"; - // Servlet context private ServletContext m_context; - // Various services required by NTLM authenticator - - private AuthenticationService m_authService; - - private PersonService m_personService; - - private NodeService m_nodeService; - - private TransactionService m_transactionService; - private String httpServletRequestAuthHeaderName; private AuthenticationComponent m_authComponent; @@ -115,10 +91,10 @@ public class HTTPRequestAuthenticationFilter implements Filter WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(m_context); ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); - m_nodeService = serviceRegistry.getNodeService(); - m_authService = serviceRegistry.getAuthenticationService(); - m_transactionService = serviceRegistry.getTransactionService(); - m_personService = (PersonService) ctx.getBean("PersonService"); // transactional and permission-checked + setNodeService(serviceRegistry.getNodeService()); + setAuthenticationService(serviceRegistry.getAuthenticationService()); + setTransactionService(serviceRegistry.getTransactionService()); + setPersonService((PersonService) ctx.getBean("PersonService")); // transactional and permission-checked m_authComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent"); httpServletRequestAuthHeaderName = config.getInitParameter("httpServletRequestAuthHeaderName"); @@ -159,12 +135,12 @@ public class HTTPRequestAuthenticationFilter implements Filter { // Assume it's an HTTP request - HttpServletRequest httpReq = (HttpServletRequest) req; + final HttpServletRequest httpReq = (HttpServletRequest) req; HttpServletResponse httpResp = (HttpServletResponse) resp; // Get the user details object from the session - WebDAVUser user = (WebDAVUser) httpReq.getSession().getAttribute(AUTHENTICATION_USER); + SessionUser user = (SessionUser) httpReq.getSession().getAttribute(AUTHENTICATION_USER); if (user == null) { @@ -185,12 +161,12 @@ public class HTTPRequestAuthenticationFilter implements Filter // Throw an error if we have an unknown authentication - if ((authHdr != null) || (authHdr.length() > 0)) + if ((authHdr != null) && (authHdr.length() > 0)) { // Get the user - String userName = ""; + final String userName; if (m_authPattern != null) { Matcher matcher = m_authPattern.matcher(authHdr); @@ -201,8 +177,8 @@ public class HTTPRequestAuthenticationFilter implements Filter { if (logger.isDebugEnabled()) { - logger.debug("Extracted null or empty user name from pattern " - + m_authPatternString + " against " + authHdr); + logger.debug("Extracted null or empty user name from pattern " + m_authPatternString + + " against " + authHdr); } reject(httpReq, httpResp); return; @@ -230,71 +206,34 @@ public class HTTPRequestAuthenticationFilter implements Filter // Get the authorization header - UserTransaction tx = null; - try - { - tx = m_transactionService.getUserTransaction(); - tx.begin(); - // Authenticate the user - - m_authComponent.clearCurrentSecurityContext(); - m_authComponent.setCurrentUser(userName); - - // Get the user node and home folder - - NodeRef personNodeRef = m_personService.getPerson(userName); - NodeRef homeSpaceRef = (NodeRef) m_nodeService.getProperty(personNodeRef, - ContentModel.PROP_HOMEFOLDER); - - // Setup User object and Home space ID etc. - - user = new WebDAVUser(userName, m_authService.getCurrentTicket(), homeSpaceRef); - - tx.commit(); - tx = null; - - httpReq.getSession().setAttribute(AUTHENTICATION_USER, user); - } - catch (AuthenticationException ex) - { - if(logger.isDebugEnabled()) - { - logger.debug("Failed", ex); - } - user = null; - // Do nothing, user object will be null - } - catch (NoSuchPersonException e) - { - // Do nothing, user object will be null - if(logger.isDebugEnabled()) - { - logger.debug("Failed", e); - } - user = null; - } - catch (Exception e) - { - // Do nothing, user object will be null - if(logger.isDebugEnabled()) - { - logger.debug("Failed", e); - } - user = null; - } - finally - { - try - { - if (tx != null) + user = transactionService.getRetryingTransactionHelper().doInTransaction( + new RetryingTransactionHelper.RetryingTransactionCallback() { - tx.rollback(); - } - } - catch (Exception tex) - { - } - } + + public SessionUser execute() throws Throwable + { + try + { + // Authenticate the user + + m_authComponent.clearCurrentSecurityContext(); + m_authComponent.setCurrentUser(userName); + + return createUserEnvironment(httpReq.getSession(), userName, authenticationService + .getCurrentTicket(), true); + } + catch (AuthenticationException ex) + { + if (logger.isDebugEnabled()) + { + logger.debug("Failed", ex); + } + return null; + // Perhaps auto-creation/import is disabled + } + } + }); + } else { @@ -307,76 +246,27 @@ public class HTTPRequestAuthenticationFilter implements Filter // Debug if (logger.isDebugEnabled()) - logger.debug("Logon via ticket from " - + req.getRemoteHost() + " (" + req.getRemoteAddr() + ":" + req.getRemotePort() + ")" - + " ticket=" + ticket); + logger.debug("Logon via ticket from " + req.getRemoteHost() + " (" + req.getRemoteAddr() + ":" + + req.getRemotePort() + ")" + " ticket=" + ticket); - UserTransaction tx = null; try { // Validate the ticket - - m_authService.validate(ticket); + authenticationService.validate(ticket); // Need to create the User instance if not already available - - String currentUsername = m_authService.getCurrentUserName(); - - // Start a transaction - - tx = m_transactionService.getUserTransaction(); - tx.begin(); - - NodeRef personRef = m_personService.getPerson(currentUsername); - user = new WebDAVUser(currentUsername, m_authService.getCurrentTicket(), personRef); - NodeRef homeRef = (NodeRef) m_nodeService.getProperty(personRef, ContentModel.PROP_HOMEFOLDER); - - // Check that the home space node exists - else Login cannot proceed - - if (m_nodeService.exists(homeRef) == false) - { - throw new InvalidNodeRefException(homeRef); - } - user.setHomeNode(homeRef); - - tx.commit(); - tx = null; - - // Store the User object in the Session - the authentication servlet will then proceed - - httpReq.getSession().setAttribute(AUTHENTICATION_USER, user); + user = createUserEnvironment(httpReq.getSession(), authenticationService.getCurrentUserName(), + ticket, true); } catch (AuthenticationException authErr) { // Clear the user object to signal authentication failure - if(logger.isDebugEnabled()) + if (logger.isDebugEnabled()) { logger.debug("Failed", authErr); } user = null; } - catch (Throwable e) - { - // Clear the user object to signal authentication failure - if(logger.isDebugEnabled()) - { - logger.debug("Failed", e); - } - user = null; - } - finally - { - try - { - if (tx != null) - { - tx.rollback(); - } - } - catch (Exception tex) - { - } - } } } @@ -389,12 +279,6 @@ public class HTTPRequestAuthenticationFilter implements Filter return; } } - else - { - // Setup the authentication context - - m_authService.validate(user.getTicket()); - } // Chain other filters @@ -416,4 +300,13 @@ public class HTTPRequestAuthenticationFilter implements Filter { // Nothing to do } + + /* (non-Javadoc) + * @see org.alfresco.repo.webdav.auth.BaseAuthenticationFilter#getLogger() + */ + @Override + protected Log getLogger() + { + return logger; + } } diff --git a/source/java/org/alfresco/repo/webdav/auth/KerberosAuthenticationFilter.java b/source/java/org/alfresco/repo/webdav/auth/KerberosAuthenticationFilter.java index a8bd987dc5..efbc64887e 100644 --- a/source/java/org/alfresco/repo/webdav/auth/KerberosAuthenticationFilter.java +++ b/source/java/org/alfresco/repo/webdav/auth/KerberosAuthenticationFilter.java @@ -61,24 +61,9 @@ public class KerberosAuthenticationFilter extends BaseKerberosAuthenticationFilt // Enable ticket based logons - setTicketLogons( true); - - // Use the WebDAV specific attribute to store the user details - - setUserAttributeName( WEBDAV_AUTH_USER); + setTicketLogons(true); } - /* (non-Javadoc) - * @see org.alfresco.repo.webdav.auth.BaseSSOAuthenticationFilter#createUserObject(java.lang.String, java.lang.String, org.alfresco.service.cmr.repository.NodeRef, java.lang.String) - */ - @Override - protected SessionUser createUserObject(String userName, String ticket, NodeRef personNode, String homeSpace) { - - // Create a WebDAV user object - - return new WebDAVUser( userName, ticket, personNode); - } - /* (non-Javadoc) * @see org.alfresco.repo.webdav.auth.BaseNTLMAuthenticationFilter#onValidateFailed(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.http.HttpSession) */ diff --git a/source/java/org/alfresco/repo/webdav/auth/NTLMAuthenticationFilter.java b/source/java/org/alfresco/repo/webdav/auth/NTLMAuthenticationFilter.java index b09359e0d3..e0dca883ea 100644 --- a/source/java/org/alfresco/repo/webdav/auth/NTLMAuthenticationFilter.java +++ b/source/java/org/alfresco/repo/webdav/auth/NTLMAuthenticationFilter.java @@ -31,8 +31,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.alfresco.repo.SessionUser; -import org.alfresco.service.cmr.repository.NodeRef; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -58,23 +56,8 @@ public class NTLMAuthenticationFilter extends BaseNTLMAuthenticationFilter // Enable ticket based logons - setTicketLogons( true); - - // Use the WebDAV specific attribute to store the user details - - setUserAttributeName( WEBDAV_AUTH_USER); + setTicketLogons( true); } - - /* (non-Javadoc) - * @see org.alfresco.repo.webdav.auth.BaseSSOAuthenticationFilter#createUserObject(java.lang.String, java.lang.String, org.alfresco.service.cmr.repository.NodeRef, java.lang.String) - */ - @Override - protected SessionUser createUserObject(String userName, String ticket, NodeRef personNode, String homeSpace) { - - // Create a WebDAV user object - - return new WebDAVUser( userName, ticket, personNode); - } /* (non-Javadoc) * @see org.alfresco.repo.webdav.auth.BaseNTLMAuthenticationFilter#onValidateFailed(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.http.HttpSession)