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
This commit is contained in:
Dave Ward
2009-10-14 09:24:13 +00:00
parent 8b6b0c5720
commit 8f882c680c
10 changed files with 474 additions and 712 deletions

View File

@@ -17,6 +17,7 @@ else if (args["user"] != null)
var userId = args["user"]; var userId = args["user"];
object = people.getPerson(userId); object = people.getPerson(userId);
model.isAdmin = people.isAdmin(object); model.isAdmin = people.isAdmin(object);
model.isGuest = people.isGuest(object);
model.isUser = true; model.isUser = true;
model.includeChildren = false; model.includeChildren = false;
} }

View File

@@ -35,8 +35,8 @@ import javax.servlet.http.HttpServletResponse;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.SessionUser;
import org.alfresco.repo.webdav.auth.AuthenticationFilter; 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.LockService;
import org.alfresco.service.cmr.lock.LockStatus; import org.alfresco.service.cmr.lock.LockStatus;
import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileFolderService;
@@ -604,7 +604,7 @@ public class PropFindMethod extends WebDAVMethod
{ {
// Get the users authentication ticket // 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); xml.startElement(WebDAV.DAV_NS, WebDAV.XML_ALF_AUTHTICKET, WebDAV.XML_NS_ALF_AUTHTICKET, nullAttr);
if ( davUser != null) if ( davUser != null)
@@ -808,7 +808,7 @@ public class PropFindMethod extends WebDAVMethod
// Print out all the custom properties // 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); xml.startElement(WebDAV.DAV_NS, WebDAV.XML_ALF_AUTHTICKET, WebDAV.XML_NS_ALF_AUTHTICKET, nullAttr);
if ( davUser != null) if ( davUser != null)

View File

@@ -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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * 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.ServletResponse;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; 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.security.authentication.AuthenticationException;
import org.alfresco.repo.web.filter.beans.DependencyInjectedFilter; 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.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.codec.binary.Base64;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@@ -55,62 +48,18 @@ import org.apache.commons.logging.LogFactory;
* *
* @author GKSpencer * @author GKSpencer
*/ */
public class AuthenticationFilter implements DependencyInjectedFilter public class AuthenticationFilter extends BaseAuthenticationFilter implements DependencyInjectedFilter
{ {
// Debug logging // Debug logging
private static Log logger = LogFactory.getLog(NTLMAuthenticationFilter.class); private static Log logger = LogFactory.getLog(AuthenticationFilter.class);
// Authenticated user session object name // 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 PPT_EXTN = ".ppt";
private static final String VTI_IGNORE = "&vtiIgnore";
// Various services required by NTLM authenticator // 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 * Run the authentication filter
* *
@@ -130,8 +79,7 @@ public class AuthenticationFilter implements DependencyInjectedFilter
HttpServletResponse httpResp = (HttpServletResponse) resp; HttpServletResponse httpResp = (HttpServletResponse) resp;
// Get the user details object from the session // Get the user details object from the session
SessionUser user = getSessionUser(context, httpReq, httpResp, false);
WebDAVUser user = (WebDAVUser) httpReq.getSession().getAttribute(AUTHENTICATION_USER);
if (user == null) if (user == null)
{ {
@@ -166,21 +114,9 @@ public class AuthenticationFilter implements DependencyInjectedFilter
{ {
// Authenticate the user // Authenticate the user
authService.authenticate(username, password.toCharArray()); authenticationService.authenticate(username, password.toCharArray());
// Set the user name as stored by the back end user = createUserEnvironment(httpReq.getSession(), authenticationService.getCurrentUserName(), authenticationService.getCurrentTicket(), false);
username = authService.getCurrentUserName();
// Get the user node and home folder
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);
} }
catch ( AuthenticationException ex) catch ( AuthenticationException ex)
{ {
@@ -193,85 +129,34 @@ public class AuthenticationFilter implements DependencyInjectedFilter
} }
else else
{ {
// Check if the request includes an authentication ticket // Check if the request includes an authentication ticket
String ticket = req.getParameter( ARG_TICKET); String ticket = req.getParameter(ARG_TICKET);
if ( ticket != null && ticket.length() > 0) if (ticket != null && ticket.length() > 0)
{ {
// PowerPoint bug fix // PowerPoint bug fix
if (ticket.endsWith(PPT_EXTN)) if (ticket.endsWith(PPT_EXTN))
{ {
ticket = ticket.substring(0, ticket.length() - PPT_EXTN.length()); ticket = ticket.substring(0, ticket.length() - PPT_EXTN.length());
} }
// Debug // Debug
if ( logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("Logon via ticket from " + req.getRemoteHost() + " (" + logger.debug("Logon via ticket from " + req.getRemoteHost() + " (" + req.getRemoteAddr() + ":"
req.getRemoteAddr() + ":" + req.getRemotePort() + ")" + " ticket=" + ticket); + req.getRemotePort() + ")" + " ticket=" + ticket);
UserTransaction tx = null; // Validate the ticket
try
{
// Validate the ticket
authService.validate(ticket); authenticationService.validate(ticket);
// Need to create the User instance if not already available // Need to create the User instance if not already available
String currentUsername = authService.getCurrentUserName(); String currentUsername = authenticationService.getCurrentUserName();
// Start a transaction user = createUserEnvironment(httpReq.getSession(), currentUsername, ticket, false);
}
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)
{
}
}
}
} }
// Check if the user is authenticated, if not then prompt again // Check if the user is authenticated, if not then prompt again
@@ -287,28 +172,6 @@ public class AuthenticationFilter implements DependencyInjectedFilter
return; 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 // Chain other filters
@@ -322,4 +185,12 @@ public class AuthenticationFilter implements DependencyInjectedFilter
{ {
// Nothing to do // Nothing to do
} }
/* (non-Javadoc)
* @see org.alfresco.repo.webdav.auth.BaseAuthenticationFilter#getLogger()
*/
protected Log getLogger()
{
return logger;
}
} }

View File

@@ -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> T doInSystemTransaction(final RetryingTransactionHelper.RetryingTransactionCallback<T> callback)
{
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<T>()
{
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<SessionUser>()
{
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();
}

View File

@@ -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.OID;
import org.alfresco.jlan.server.auth.spnego.SPNEGO; import org.alfresco.jlan.server.auth.spnego.SPNEGO;
import org.alfresco.repo.SessionUser; import org.alfresco.repo.SessionUser;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.ietf.jgss.Oid; import org.ietf.jgss.Oid;
@@ -255,8 +254,6 @@ public abstract class BaseKerberosAuthenticationFilter extends BaseSSOAuthentica
HttpServletRequest req = (HttpServletRequest) sreq; HttpServletRequest req = (HttpServletRequest) sreq;
HttpServletResponse resp = (HttpServletResponse) sresp; 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 a filter up the chain has marked the request as not requiring auth then respect it
if (req.getAttribute( NO_AUTH_REQUIRED) != null) if (req.getAttribute( NO_AUTH_REQUIRED) != null)
@@ -287,7 +284,7 @@ public abstract class BaseKerberosAuthenticationFilter extends BaseSSOAuthentica
// Restart the authentication // Restart the authentication
restartLoginChallenge(resp, httpSess); restartLoginChallenge(resp, req.getSession());
chain.doFilter(sreq, sresp); chain.doFilter(sreq, sresp);
return; return;
@@ -295,42 +292,16 @@ public abstract class BaseKerberosAuthenticationFilter extends BaseSSOAuthentica
} }
// Check if the user is already authenticated // Check if the user is already authenticated
SessionUser user = getSessionUser(context, req, resp, true);
SessionUser user = getSessionUser( httpSess); HttpSession httpSess = req.getSession(true);
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 // If the user has been validated and we do not require re-authentication then continue to
// the next filter // the next filter
if ( user != null && reqAuth == false)
if ( reqAuth == false && user != null)
{ {
// Filter validate hook
onValidate( context, req, resp);
// Debug // Debug
if ( getLogger().isDebugEnabled()) if ( getLogger().isDebugEnabled())
@@ -352,7 +323,7 @@ public abstract class BaseKerberosAuthenticationFilter extends BaseSSOAuthentica
{ {
// Check if a ticket parameter has been specified in the reuqest // 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 // Chain to the next filter
@@ -542,14 +513,10 @@ public abstract class BaseKerberosAuthenticationFilter extends BaseSSOAuthentica
if ( negTokenTarg != null) if ( negTokenTarg != null)
{ {
// Create the user authentication context // Create and store the user authentication context
SessionUser user = createUserEnvironment( httpSess, krbDetails.getUserName()); SessionUser user = createUserEnvironment( httpSess, krbDetails.getUserName());
// Store the user
httpSess.setAttribute(AUTHENTICATION_USER, user);
// Debug // Debug
if ( getLogger().isDebugEnabled()) if ( getLogger().isDebugEnabled())

View File

@@ -188,7 +188,6 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication
// Get the HTTP request/response/session // Get the HTTP request/response/session
HttpServletRequest req = (HttpServletRequest) sreq; HttpServletRequest req = (HttpServletRequest) sreq;
HttpServletResponse resp = (HttpServletResponse) sresp; 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 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 // Restart the authentication
restartLoginChallenge(resp, httpSess); restartLoginChallenge(resp, req.getSession());
return; return;
} }
} }
// Check if the user is already authenticated // Check if the user is already authenticated
SessionUser user = getSessionUser( httpSess); SessionUser user = getSessionUser(context, req, resp, true);
if (user != null && reqAuth == false) HttpSession httpSess = req.getSession(true);
{
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;
}
}
// If the user has been validated and we do not require re-authentication then continue to // If the user has been validated and we do not require re-authentication then continue to
// the next filter // the next filter
if (reqAuth == false && user != null) if (user != null && reqAuth == false)
{ {
// Filter validate hook
onValidate( context, req, resp);
if (getLogger().isDebugEnabled()) if (getLogger().isDebugEnabled())
getLogger().debug("Authentication not required (user), chaining ..."); 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 // Check if the request includes an authentication ticket
if ( checkForTicketParameter(req, httpSess)) { if (checkForTicketParameter(context, req, resp))
{
// Authentication was bypassed using a ticket parameter // Authentication was bypassed using a ticket parameter
@@ -330,13 +310,13 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication
{ {
// Process the type 1 NTLM message // Process the type 1 NTLM message
Type1NTLMMessage type1Msg = new Type1NTLMMessage(ntlmByts); Type1NTLMMessage type1Msg = new Type1NTLMMessage(ntlmByts);
processType1(type1Msg, req, resp, httpSess); processType1(type1Msg, req, resp);
} }
else if (ntlmTyp == NTLM.Type3) else if (ntlmTyp == NTLM.Type3)
{ {
// Process the type 3 NTLM message // Process the type 3 NTLM message
Type3NTLMMessage type3Msg = new Type3NTLMMessage(ntlmByts); Type3NTLMMessage type3Msg = new Type3NTLMMessage(ntlmByts);
processType3(type3Msg, context, req, resp, httpSess, chain); processType3(type3Msg, context, req, resp, chain);
} }
else else
{ {
@@ -358,18 +338,15 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication
* @exception IOException * @exception IOException
*/ */
protected void processType1(Type1NTLMMessage type1Msg, HttpServletRequest req, protected void processType1(Type1NTLMMessage type1Msg, HttpServletRequest req,
HttpServletResponse res, HttpSession session) throws IOException HttpServletResponse res) throws IOException
{ {
if (getLogger().isDebugEnabled()) if (getLogger().isDebugEnabled())
getLogger().debug("Received type1 " + type1Msg); getLogger().debug("Received type1 " + type1Msg);
// Get the existing NTLM details // Get the existing NTLM details
NTLMLogonDetails ntlmDetails = null; NTLMLogonDetails ntlmDetails = null;
HttpSession session = req.getSession();
if (session != null) ntlmDetails = (NTLMLogonDetails)session.getAttribute(NTLM_AUTH_DETAILS);
{
ntlmDetails = (NTLMLogonDetails)session.getAttribute(NTLM_AUTH_DETAILS);
}
// Check if cached logon details are available // Check if cached logon details are available
if (ntlmDetails != null && ntlmDetails.hasType2Message() && if (ntlmDetails != null && ntlmDetails.hasType2Message() &&
@@ -473,8 +450,7 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication
* @exception IOException * @exception IOException
* @exception ServletException * @exception ServletException
*/ */
protected void processType3(Type3NTLMMessage type3Msg, ServletContext context, HttpServletRequest req, HttpServletResponse res, protected void processType3(Type3NTLMMessage type3Msg, ServletContext context, HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException
HttpSession session, FilterChain chain) throws IOException, ServletException
{ {
Log logger = getLogger(); Log logger = getLogger();
@@ -485,11 +461,9 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication
NTLMLogonDetails ntlmDetails = null; NTLMLogonDetails ntlmDetails = null;
SessionUser user = null; SessionUser user = null;
if (session != null) user = getSessionUser(context, req, res, true);
{ HttpSession session = req.getSession();
ntlmDetails = (NTLMLogonDetails)session.getAttribute(NTLM_AUTH_DETAILS); ntlmDetails = (NTLMLogonDetails)session.getAttribute(NTLM_AUTH_DETAILS);
user = getSessionUser(session);
}
// Get the NTLM logon details // Get the NTLM logon details
String userName = type3Msg.getUserName(); String userName = type3Msg.getUserName();
@@ -513,26 +487,7 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("Using cached NTLM hash, authenticated = " + authenticated); logger.debug("Using cached NTLM hash, authenticated = " + authenticated);
try onValidate(context, req, res);
{
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;
}
// Allow the user to access the requested page // Allow the user to access the requested page
chain.doFilter(req, res); chain.doFilter(req, res);
@@ -639,21 +594,14 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication
{ {
if (user == null) if (user == null)
{ {
user = createUserEnvironment(session, userName);
}
else
{
// user already exists - revalidate ticket to authenticate the current user thread
try try
{ {
authenticationService.validate(user.getTicket()); user = createUserEnvironment(session, userName);
} }
catch (AuthenticationException ex) catch (AuthenticationException ex)
{ {
if (logger.isErrorEnabled()) if (logger.isDebugEnabled())
logger.error("Failed to validate user " + user.getUserName(), ex); logger.debug("Failed to validate user " + user.getUserName(), ex);
removeSessionUser(session);
onValidateFailed(req, res, session); onValidateFailed(req, res, session);
return; return;

View File

@@ -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.auth.passthru.DomainMapping;
import org.alfresco.jlan.server.config.SecurityConfigSection; import org.alfresco.jlan.server.config.SecurityConfigSection;
import org.alfresco.jlan.util.IPAddress; import org.alfresco.jlan.util.IPAddress;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.SessionUser; import org.alfresco.repo.SessionUser;
import org.alfresco.repo.management.subsystems.ActivateableBean; import org.alfresco.repo.management.subsystems.ActivateableBean;
import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationException; import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.web.filter.beans.DependencyInjectedFilter; 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; import org.springframework.beans.factory.InitializingBean;
/** /**
@@ -63,7 +55,7 @@ import org.springframework.beans.factory.InitializingBean;
* @author gkspencer * @author gkspencer
* @author kroast * @author kroast
*/ */
public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedFilter, ActivateableBean, InitializingBean public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilter implements DependencyInjectedFilter, ActivateableBean, InitializingBean
{ {
// Constants // 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 // 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"; 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 // Allow an authentication ticket to be passed as part of a request to bypass authentication
private static final String ARG_TICKET = "ticket"; private ExtendedServerConfigurationAccessor serverConfiguration;
// File server configuration
private ExtendedServerConfigurationAccessor serverConfiguration;
// Various services required by NTLM authenticator // Various services required by NTLM authenticator
protected AuthenticationService authenticationService; protected AuthenticationComponent authenticationComponent;
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
private String m_loginPage; private String m_loginPage;
// Indicate whether ticket based logons are supported // Indicate whether ticket based logons are supported
@@ -110,8 +80,6 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF
// User object attribute name // User object attribute name
private String m_userAttributeName = AUTHENTICATION_USER;
private String m_lastConfiguredServerName; private String m_lastConfiguredServerName;
private String m_lastResolvedServerName; private String m_lastResolvedServerName;
@@ -125,14 +93,6 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF
this.serverConfiguration = serverConfiguration; this.serverConfiguration = serverConfiguration;
} }
/**
* @param authenticationService the authenticationService to set
*/
public void setAuthenticationService(AuthenticationService authenticationService)
{
this.authenticationService = authenticationService;
}
/** /**
* @param authenticationComponent the authenticationComponent to set * @param authenticationComponent the authenticationComponent to set
*/ */
@@ -141,30 +101,6 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF
this.authenticationComponent = authenticationComponent; 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 * 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 * Callback to create the User environment as appropriate for a filter impl
* *
* @param session HttpSession * @param session
* @param userName String * HttpSession
* @param userName
* String
* @return SessionUser * @return SessionUser
* @throws IOException * @throws IOException
* @throws ServletException * @throws ServletException
*/ */
protected SessionUser createUserEnvironment(HttpSession session, String userName) protected SessionUser createUserEnvironment(final HttpSession session, final String userName) throws IOException,
throws IOException, ServletException ServletException
{ {
SessionUser user = null; return this.transactionService.getRetryingTransactionHelper().doInTransaction(
new RetryingTransactionHelper.RetryingTransactionCallback<SessionUser>()
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<String> getUserNameRunAsWork = new RunAsWork<String>()
{
public String doWork() throws Exception
{ {
return (String) nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME);
}
};
userName = AuthenticationUtil.runAs(getUserNameRunAsWork, AuthenticationUtil.SYSTEM_USER_NAME);
authenticationComponent.setCurrentUser(userName); public SessionUser execute() throws Throwable
String currentTicket = authenticationService.getCurrentTicket(); {
authenticationComponent.setCurrentUser(userName);
NodeRef homeSpaceRef = (NodeRef) nodeService.getProperty(personNodeRef, ContentModel.PROP_HOMEFOLDER); return createUserEnvironment(session, userName, authenticationService.getCurrentTicket(), true);
}
// 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;
} }
/** /**
* Callback executed on successful ticket validation during Type3 Message processing. * 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 servletContext
* @param sess HttpSession * the servlet context
* @param req
* the request
* @param resp
* the response
* @return boolean * @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 // Check if the request includes an authentication ticket
@@ -438,32 +275,21 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF
UserTransaction tx = null; UserTransaction tx = null;
try try
{ {
// Validate the ticket // Get a cached user with a valid ticket
SessionUser user = getSessionUser(servletContext, req, resp, true);
authenticationService.validate(ticket); // If this isn't the same ticket, invalidate the session
if (!ticket.equals(user.getTicket()))
{
invalidateSession(req);
user = null;
}
SessionUser user = getSessionUser( sess); // If we don't yet have a valid cached user, validate the ticket and create one
if ( user == null )
if ( user == null)
{ {
// Start a transaction authenticationService.validate(ticket);
user = createUserEnvironment(req.getSession(), authenticationService.getCurrentUserName(), authenticationService.getCurrentTicket(), true);
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);
} }
// Indicate the ticket parameter was specified, and valid // Indicate the ticket parameter was specified, and valid
@@ -514,13 +340,6 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF
res.sendRedirect(req.getContextPath() + "/faces" + getLoginPage()); res.sendRedirect(req.getContextPath() + "/faces" + getLoginPage());
} }
/**
* Return the logger
*
* @return Log
*/
protected abstract Log getLogger();
/** /**
* Determine if the login page is available * Determine if the login page is available
* *

View File

@@ -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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * 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 * 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 * the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's * 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: * 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; package org.alfresco.repo.webdav.auth;
@@ -39,19 +39,13 @@ import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; 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.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationException; import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.ServiceRegistry; 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.cmr.security.PersonService;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.WebApplicationContext; 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 * WebDAV Authentication Filter Class for SSO linke SiteMinder and IChains
*/ */
public class HTTPRequestAuthenticationFilter implements Filter public class HTTPRequestAuthenticationFilter extends BaseAuthenticationFilter implements Filter
{ {
// Debug logging // Debug logging
private static Log logger = LogFactory.getLog(HTTPRequestAuthenticationFilter.class); 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 // Servlet context
private ServletContext m_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 String httpServletRequestAuthHeaderName;
private AuthenticationComponent m_authComponent; private AuthenticationComponent m_authComponent;
@@ -115,10 +91,10 @@ public class HTTPRequestAuthenticationFilter implements Filter
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(m_context); WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(m_context);
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
m_nodeService = serviceRegistry.getNodeService(); setNodeService(serviceRegistry.getNodeService());
m_authService = serviceRegistry.getAuthenticationService(); setAuthenticationService(serviceRegistry.getAuthenticationService());
m_transactionService = serviceRegistry.getTransactionService(); setTransactionService(serviceRegistry.getTransactionService());
m_personService = (PersonService) ctx.getBean("PersonService"); // transactional and permission-checked setPersonService((PersonService) ctx.getBean("PersonService")); // transactional and permission-checked
m_authComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent"); m_authComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
httpServletRequestAuthHeaderName = config.getInitParameter("httpServletRequestAuthHeaderName"); httpServletRequestAuthHeaderName = config.getInitParameter("httpServletRequestAuthHeaderName");
@@ -159,12 +135,12 @@ public class HTTPRequestAuthenticationFilter implements Filter
{ {
// Assume it's an HTTP request // Assume it's an HTTP request
HttpServletRequest httpReq = (HttpServletRequest) req; final HttpServletRequest httpReq = (HttpServletRequest) req;
HttpServletResponse httpResp = (HttpServletResponse) resp; HttpServletResponse httpResp = (HttpServletResponse) resp;
// Get the user details object from the session // 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) if (user == null)
{ {
@@ -185,12 +161,12 @@ public class HTTPRequestAuthenticationFilter implements Filter
// Throw an error if we have an unknown authentication // Throw an error if we have an unknown authentication
if ((authHdr != null) || (authHdr.length() > 0)) if ((authHdr != null) && (authHdr.length() > 0))
{ {
// Get the user // Get the user
String userName = ""; final String userName;
if (m_authPattern != null) if (m_authPattern != null)
{ {
Matcher matcher = m_authPattern.matcher(authHdr); Matcher matcher = m_authPattern.matcher(authHdr);
@@ -201,8 +177,8 @@ public class HTTPRequestAuthenticationFilter implements Filter
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Extracted null or empty user name from pattern " logger.debug("Extracted null or empty user name from pattern " + m_authPatternString
+ m_authPatternString + " against " + authHdr); + " against " + authHdr);
} }
reject(httpReq, httpResp); reject(httpReq, httpResp);
return; return;
@@ -230,71 +206,34 @@ public class HTTPRequestAuthenticationFilter implements Filter
// Get the authorization header // Get the authorization header
UserTransaction tx = null; user = transactionService.getRetryingTransactionHelper().doInTransaction(
try new RetryingTransactionHelper.RetryingTransactionCallback<SessionUser>()
{
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)
{ {
tx.rollback();
} public SessionUser execute() throws Throwable
} {
catch (Exception tex) 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 else
{ {
@@ -307,76 +246,27 @@ public class HTTPRequestAuthenticationFilter implements Filter
// Debug // Debug
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("Logon via ticket from " logger.debug("Logon via ticket from " + req.getRemoteHost() + " (" + req.getRemoteAddr() + ":"
+ req.getRemoteHost() + " (" + req.getRemoteAddr() + ":" + req.getRemotePort() + ")" + req.getRemotePort() + ")" + " ticket=" + ticket);
+ " ticket=" + ticket);
UserTransaction tx = null;
try try
{ {
// Validate the ticket // Validate the ticket
authenticationService.validate(ticket);
m_authService.validate(ticket);
// Need to create the User instance if not already available // Need to create the User instance if not already available
user = createUserEnvironment(httpReq.getSession(), authenticationService.getCurrentUserName(),
String currentUsername = m_authService.getCurrentUserName(); ticket, true);
// 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);
} }
catch (AuthenticationException authErr) catch (AuthenticationException authErr)
{ {
// Clear the user object to signal authentication failure // Clear the user object to signal authentication failure
if(logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Failed", authErr); logger.debug("Failed", authErr);
} }
user = null; 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; return;
} }
} }
else
{
// Setup the authentication context
m_authService.validate(user.getTicket());
}
// Chain other filters // Chain other filters
@@ -416,4 +300,13 @@ public class HTTPRequestAuthenticationFilter implements Filter
{ {
// Nothing to do // Nothing to do
} }
/* (non-Javadoc)
* @see org.alfresco.repo.webdav.auth.BaseAuthenticationFilter#getLogger()
*/
@Override
protected Log getLogger()
{
return logger;
}
} }

View File

@@ -61,24 +61,9 @@ public class KerberosAuthenticationFilter extends BaseKerberosAuthenticationFilt
// Enable ticket based logons // Enable ticket based logons
setTicketLogons( true); setTicketLogons(true);
// Use the WebDAV specific attribute to store the user details
setUserAttributeName( WEBDAV_AUTH_USER);
} }
/* (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) /* (non-Javadoc)
* @see org.alfresco.repo.webdav.auth.BaseNTLMAuthenticationFilter#onValidateFailed(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.http.HttpSession) * @see org.alfresco.repo.webdav.auth.BaseNTLMAuthenticationFilter#onValidateFailed(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.http.HttpSession)
*/ */

View File

@@ -31,8 +31,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; 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.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@@ -59,23 +57,8 @@ public class NTLMAuthenticationFilter extends BaseNTLMAuthenticationFilter
// Enable ticket based logons // Enable ticket based logons
setTicketLogons( true); setTicketLogons( true);
// Use the WebDAV specific attribute to store the user details
setUserAttributeName( WEBDAV_AUTH_USER);
} }
/* (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) /* (non-Javadoc)
* @see org.alfresco.repo.webdav.auth.BaseNTLMAuthenticationFilter#onValidateFailed(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.http.HttpSession) * @see org.alfresco.repo.webdav.auth.BaseNTLMAuthenticationFilter#onValidateFailed(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.http.HttpSession)
*/ */