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"];
|
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;
|
||||||
}
|
}
|
||||||
|
@@ -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)
|
||||||
|
@@ -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
|
|
||||||
username = authService.getCurrentUserName();
|
|
||||||
|
|
||||||
// Get the user node and home folder
|
|
||||||
|
|
||||||
NodeRef personNodeRef = personService.getPerson(username);
|
user = createUserEnvironment(httpReq.getSession(), authenticationService.getCurrentUserName(), authenticationService.getCurrentTicket(), false);
|
||||||
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,87 +129,36 @@ 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);
|
|
||||||
|
|
||||||
if ( ticket != null && ticket.length() > 0)
|
|
||||||
{
|
|
||||||
// PowerPoint bug fix
|
|
||||||
if (ticket.endsWith(PPT_EXTN))
|
|
||||||
{
|
|
||||||
ticket = ticket.substring(0, ticket.length() - PPT_EXTN.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug
|
String ticket = req.getParameter(ARG_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);
|
|
||||||
|
|
||||||
// Need to create the User instance if not already available
|
if (ticket != null && ticket.length() > 0)
|
||||||
|
{
|
||||||
String currentUsername = authService.getCurrentUserName();
|
// PowerPoint bug fix
|
||||||
|
if (ticket.endsWith(PPT_EXTN))
|
||||||
|
{
|
||||||
|
ticket = ticket.substring(0, ticket.length() - PPT_EXTN.length());
|
||||||
|
}
|
||||||
|
|
||||||
// Start a transaction
|
// Debug
|
||||||
|
|
||||||
tx = transactionService.getUserTransaction();
|
if (logger.isDebugEnabled())
|
||||||
tx.begin();
|
logger.debug("Logon via ticket from " + req.getRemoteHost() + " (" + req.getRemoteAddr() + ":"
|
||||||
|
+ req.getRemotePort() + ")" + " ticket=" + ticket);
|
||||||
NodeRef personRef = personService.getPerson(currentUsername);
|
|
||||||
user = new WebDAVUser( currentUsername, authService.getCurrentTicket(), personRef);
|
// Validate the ticket
|
||||||
NodeRef homeRef = (NodeRef) nodeService.getProperty(personRef, ContentModel.PROP_HOMEFOLDER);
|
|
||||||
|
authenticationService.validate(ticket);
|
||||||
// Check that the home space node exists - else Login cannot proceed
|
|
||||||
|
// Need to create the User instance if not already available
|
||||||
if (nodeService.exists(homeRef) == false)
|
|
||||||
{
|
String currentUsername = authenticationService.getCurrentUserName();
|
||||||
throw new InvalidNodeRefException(homeRef);
|
|
||||||
}
|
user = createUserEnvironment(httpReq.getSession(), currentUsername, ticket, false);
|
||||||
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
|
||||||
|
|
||||||
if ( user == null)
|
if ( user == null)
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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.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,50 +284,24 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the user is already authenticated
|
// Check if the user is already authenticated
|
||||||
|
SessionUser user = getSessionUser(context, req, resp, true);
|
||||||
|
HttpSession httpSess = req.getSession(true);
|
||||||
|
|
||||||
SessionUser user = getSessionUser( httpSess);
|
|
||||||
|
|
||||||
if ( user != null && reqAuth == false)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Debug
|
|
||||||
|
|
||||||
if ( getLogger().isDebugEnabled())
|
|
||||||
getLogger().debug("User " + user.getUserName() + " validate ticket");
|
|
||||||
|
|
||||||
// Validate the user ticket
|
|
||||||
|
|
||||||
authenticationService.validate( user.getTicket());
|
|
||||||
reqAuth = false;
|
|
||||||
|
|
||||||
// Filter validate hook
|
|
||||||
onValidate( context, req, resp);
|
|
||||||
}
|
|
||||||
catch (AuthenticationException ex)
|
|
||||||
{
|
|
||||||
if ( getLogger().isErrorEnabled())
|
|
||||||
getLogger().error("Failed to validate user " + user.getUserName(), ex);
|
|
||||||
|
|
||||||
removeSessionUser( httpSess);
|
|
||||||
|
|
||||||
reqAuth = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the user has been validated and we do not require re-authentication then continue to
|
// 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())
|
||||||
|
@@ -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,22 +594,15 @@ 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;
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
|
||||||
}
|
public SessionUser execute() throws Throwable
|
||||||
};
|
{
|
||||||
userName = AuthenticationUtil.runAs(getUserNameRunAsWork, AuthenticationUtil.SYSTEM_USER_NAME);
|
authenticationComponent.setCurrentUser(userName);
|
||||||
|
return createUserEnvironment(session, userName, authenticationService.getCurrentTicket(), true);
|
||||||
authenticationComponent.setCurrentUser(userName);
|
}
|
||||||
String currentTicket = authenticationService.getCurrentTicket();
|
});
|
||||||
|
|
||||||
NodeRef homeSpaceRef = (NodeRef) nodeService.getProperty(personNodeRef, ContentModel.PROP_HOMEFOLDER);
|
|
||||||
|
|
||||||
// Create the user object to be stored in the session
|
|
||||||
|
|
||||||
user = createUserObject( userName, currentTicket, personNodeRef, homeSpaceRef.getId());
|
|
||||||
|
|
||||||
tx.commit();
|
|
||||||
}
|
|
||||||
catch (Throwable ex)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
tx.rollback();
|
|
||||||
}
|
|
||||||
catch (Exception err)
|
|
||||||
{
|
|
||||||
getLogger().error("Failed to rollback transaction", err);
|
|
||||||
}
|
|
||||||
if (ex instanceof RuntimeException)
|
|
||||||
{
|
|
||||||
throw (RuntimeException)ex;
|
|
||||||
}
|
|
||||||
else if (ex instanceof IOException)
|
|
||||||
{
|
|
||||||
throw (IOException)ex;
|
|
||||||
}
|
|
||||||
else if (ex instanceof ServletException)
|
|
||||||
{
|
|
||||||
throw (ServletException)ex;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new RuntimeException("Authentication setup failed", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the user on the session
|
|
||||||
|
|
||||||
session.setAttribute( getUserAttributeName(), user);
|
|
||||||
session.setAttribute( LOGIN_EXTERNAL_AUTH, Boolean.TRUE);
|
|
||||||
|
|
||||||
return user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
SessionUser user = getSessionUser( sess);
|
if (!ticket.equals(user.getTicket()))
|
||||||
|
{
|
||||||
|
invalidateSession(req);
|
||||||
|
user = null;
|
||||||
|
}
|
||||||
|
|
||||||
if ( user == null)
|
// If we don't yet have a valid cached user, validate the ticket and create one
|
||||||
|
if ( user == null )
|
||||||
{
|
{
|
||||||
// Start a transaction
|
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
|
||||||
*
|
*
|
||||||
|
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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)
|
||||||
*/
|
*/
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
@@ -58,23 +56,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)
|
||||||
|
Reference in New Issue
Block a user