mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
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:
@@ -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;
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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());
|
||||
authenticationService.authenticate(username, password.toCharArray());
|
||||
|
||||
// Set the user name as stored by the back end
|
||||
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);
|
||||
user = createUserEnvironment(httpReq.getSession(), authenticationService.getCurrentUserName(), authenticationService.getCurrentTicket(), false);
|
||||
}
|
||||
catch ( AuthenticationException ex)
|
||||
{
|
||||
@@ -195,9 +131,9 @@ public class AuthenticationFilter implements DependencyInjectedFilter
|
||||
{
|
||||
// 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
|
||||
if (ticket.endsWith(PPT_EXTN))
|
||||
@@ -207,70 +143,19 @@ public class AuthenticationFilter implements DependencyInjectedFilter
|
||||
|
||||
// Debug
|
||||
|
||||
if ( logger.isDebugEnabled())
|
||||
logger.debug("Logon via ticket from " + req.getRemoteHost() + " (" +
|
||||
req.getRemoteAddr() + ":" + req.getRemotePort() + ")" + " ticket=" + ticket);
|
||||
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);
|
||||
authenticationService.validate(ticket);
|
||||
|
||||
// Need to create the User instance if not already available
|
||||
|
||||
String currentUsername = authService.getCurrentUserName();
|
||||
String currentUsername = authenticationService.getCurrentUserName();
|
||||
|
||||
// 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
user = createUserEnvironment(httpReq.getSession(), currentUsername, ticket, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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();
|
||||
|
||||
}
|
@@ -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,7 +284,7 @@ public abstract class BaseKerberosAuthenticationFilter extends BaseSSOAuthentica
|
||||
|
||||
// Restart the authentication
|
||||
|
||||
restartLoginChallenge(resp, httpSess);
|
||||
restartLoginChallenge(resp, req.getSession());
|
||||
|
||||
chain.doFilter(sreq, sresp);
|
||||
return;
|
||||
@@ -295,42 +292,16 @@ public abstract class BaseKerberosAuthenticationFilter extends BaseSSOAuthentica
|
||||
}
|
||||
|
||||
// Check if the user is already authenticated
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
SessionUser user = getSessionUser(context, req, resp, 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);
|
||||
|
||||
// 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())
|
||||
|
@@ -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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
user = getSessionUser(context, req, res, true);
|
||||
HttpSession session = req.getSession();
|
||||
ntlmDetails = (NTLMLogonDetails)session.getAttribute(NTLM_AUTH_DETAILS);
|
||||
user = getSessionUser(session);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Allow the user to access the requested page
|
||||
chain.doFilter(req, res);
|
||||
@@ -639,21 +594,14 @@ 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;
|
||||
|
@@ -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;
|
||||
|
||||
// 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
|
||||
|
||||
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,135 +142,32 @@ 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
|
||||
return this.transactionService.getRetryingTransactionHelper().doInTransaction(
|
||||
new RetryingTransactionHelper.RetryingTransactionCallback<SessionUser>()
|
||||
{
|
||||
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 SessionUser execute() throws Throwable
|
||||
{
|
||||
public String doWork() throws Exception
|
||||
{
|
||||
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);
|
||||
return createUserEnvironment(session, userName, authenticationService.getCurrentTicket(), true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 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.
|
||||
@@ -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
|
||||
// Get a cached user with a valid ticket
|
||||
SessionUser user = getSessionUser(servletContext, req, resp, true);
|
||||
|
||||
authenticationService.validate(ticket);
|
||||
|
||||
SessionUser user = getSessionUser( sess);
|
||||
|
||||
if ( user == null)
|
||||
// If this isn't the same ticket, invalidate the session
|
||||
if (!ticket.equals(user.getTicket()))
|
||||
{
|
||||
// Start a transaction
|
||||
invalidateSession(req);
|
||||
user = null;
|
||||
}
|
||||
|
||||
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);
|
||||
// If we don't yet have a valid cached user, validate the ticket and create one
|
||||
if ( user == null )
|
||||
{
|
||||
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
|
||||
*
|
||||
|
@@ -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;
|
||||
user = transactionService.getRetryingTransactionHelper().doInTransaction(
|
||||
new RetryingTransactionHelper.RetryingTransactionCallback<SessionUser>()
|
||||
{
|
||||
|
||||
public SessionUser execute() throws Throwable
|
||||
{
|
||||
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);
|
||||
return createUserEnvironment(httpReq.getSession(), userName, authenticationService
|
||||
.getCurrentTicket(), true);
|
||||
}
|
||||
catch (AuthenticationException ex)
|
||||
{
|
||||
if(logger.isDebugEnabled())
|
||||
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();
|
||||
}
|
||||
}
|
||||
catch (Exception tex)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@@ -61,22 +61,7 @@ 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);
|
||||
}
|
||||
|
||||
/* (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);
|
||||
setTicketLogons(true);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@@ -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;
|
||||
|
||||
@@ -59,21 +57,6 @@ 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);
|
||||
}
|
||||
|
||||
/* (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)
|
||||
|
Reference in New Issue
Block a user