diff --git a/source/java/org/alfresco/repo/web/filter/beans/BeanProxyFilter.java b/source/java/org/alfresco/repo/web/filter/beans/BeanProxyFilter.java new file mode 100644 index 0000000000..31747d0724 --- /dev/null +++ b/source/java/org/alfresco/repo/web/filter/beans/BeanProxyFilter.java @@ -0,0 +1,90 @@ +/* + * 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.web.filter.beans; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; + +/** + * An adapter from the servlet filter world into the Spring dependency injected world. Simply looks up a + * {@link DependencyInjectedFilter} with a configured bean name and delegates the + * {@link #doFilter(ServletRequest, ServletResponse, FilterChain)} call to that. This allows us to swap in and out + * different implementations for different 'hook points' in web.xml. + * + * @author dward + */ +public class BeanProxyFilter implements Filter +{ + /** + * Name of the init parameter that carries the proxied bean name + */ + private static final String INIT_PARAM_BEAN_NAME = "beanName"; + + private DependencyInjectedFilter filter; + private ServletContext context; + + /** + * Initialize the filter. + * + * @param args + * FilterConfig + * @throws ServletException + * the servlet exception + * @exception ServletException + */ + public void init(FilterConfig args) throws ServletException + { + WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(args.getServletContext()); + this.filter = (DependencyInjectedFilter)ctx.getBean(args.getInitParameter(INIT_PARAM_BEAN_NAME)); + this.context = args.getServletContext(); + } + + /* (non-Javadoc) + * @see javax.servlet.Filter#destroy() + */ + public void destroy() + { + this.filter = null; + } + + /* (non-Javadoc) + * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) + */ + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, + ServletException + { + this.filter.doFilter(this.context, request, response, chain); + } +} diff --git a/source/java/org/alfresco/repo/web/filter/beans/DependencyInjectedFilter.java b/source/java/org/alfresco/repo/web/filter/beans/DependencyInjectedFilter.java new file mode 100644 index 0000000000..033a6935d8 --- /dev/null +++ b/source/java/org/alfresco/repo/web/filter/beans/DependencyInjectedFilter.java @@ -0,0 +1,62 @@ +/* + * 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.web.filter.beans; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +/** + * A bean-like equivalent of a servlet filter, designed to be managed by a Spring container. + * + * @see BeanProxyFilter + * @author dward + */ +public interface DependencyInjectedFilter +{ + /** + * The doFilter method of the Filter is called by the container each time a request/response pair is + * passed through the chain due to a client request for a resource at the end of the chain. The FilterChain passed + * in to this method allows the Filter to pass on the request and response to the next entity in the chain. + *

+ * A typical implementation of this method would follow the following pattern:-
+ * 1. Examine the request
+ * 2. Optionally wrap the request object with a custom implementation to filter content or headers for input + * filtering
+ * 3. Optionally wrap the response object with a custom implementation to filter content or headers for output + * filtering
+ * 4. a) Either invoke the next entity in the chain using the FilterChain object ( + * chain.doFilter()),
+ * 4. b) or not pass on the request/response pair to the next entity in the filter chain to block + * the request processing
+ * 5. Directly set headers on the response after invocation of the next entity in the filter chain. + **/ + public void doFilter(ServletContext context, ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, + ServletException; +} diff --git a/source/java/org/alfresco/repo/web/filter/beans/NullFilter.java b/source/java/org/alfresco/repo/web/filter/beans/NullFilter.java new file mode 100644 index 0000000000..e1f12e0a5f --- /dev/null +++ b/source/java/org/alfresco/repo/web/filter/beans/NullFilter.java @@ -0,0 +1,53 @@ +/* + * 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.web.filter.beans; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +/** + * A Benign filter that does nothing more than invoke the filter chain. Allows strategic points of the filter chain to + * be configured in and out according to the authentication subsystem in use. + * + * @author dward + */ +public class NullFilter implements DependencyInjectedFilter +{ + /* + * (non-Javadoc) + * @see org.alfresco.repo.web.filter.beans.DependencyInjectedFilter#doFilter(javax.servlet.ServletContext, + * javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) + */ + public void doFilter(ServletContext context, ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException + { + chain.doFilter(request, response); + } +} diff --git a/source/java/org/alfresco/repo/webdav/WebDAVServlet.java b/source/java/org/alfresco/repo/webdav/WebDAVServlet.java index 358677b02f..796548b8ea 100644 --- a/source/java/org/alfresco/repo/webdav/WebDAVServlet.java +++ b/source/java/org/alfresco/repo/webdav/WebDAVServlet.java @@ -258,10 +258,16 @@ public class WebDAVServlet extends HttpServlet public void init(ServletConfig config) throws ServletException { super.init(config); + + // Get service registry + WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); - // Get service registry - - WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); + // If no context has been initialised, exit silently so config changes can be made + if (context == null) + { + return; + } + m_serviceRegistry = (ServiceRegistry)context.getBean(ServiceRegistry.SERVICE_REGISTRY); m_transactionService = m_serviceRegistry.getTransactionService(); diff --git a/source/java/org/alfresco/repo/webdav/auth/AuthenticationFilter.java b/source/java/org/alfresco/repo/webdav/auth/AuthenticationFilter.java index 88bdfa9035..d856970bbc 100644 --- a/source/java/org/alfresco/repo/webdav/auth/AuthenticationFilter.java +++ b/source/java/org/alfresco/repo/webdav/auth/AuthenticationFilter.java @@ -27,9 +27,7 @@ package org.alfresco.repo.webdav.auth; import java.io.IOException; -import javax.servlet.Filter; import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; @@ -40,7 +38,7 @@ import javax.transaction.UserTransaction; import org.alfresco.model.ContentModel; import org.alfresco.repo.security.authentication.AuthenticationException; -import org.alfresco.service.ServiceRegistry; +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; @@ -51,15 +49,13 @@ 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; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.context.support.WebApplicationContextUtils; /** * WebDAV Authentication Filter Class * * @author GKSpencer */ -public class AuthenticationFilter implements Filter +public class AuthenticationFilter implements DependencyInjectedFilter { // Debug logging @@ -75,51 +71,58 @@ public class AuthenticationFilter implements Filter private static final String PPT_EXTN = ".ppt"; private static final String VTI_IGNORE = "&vtiIgnore"; - // 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 AuthenticationService authService; + private PersonService personService; + private NodeService nodeService; + private TransactionService transactionService; + /** - * Initialize the filter - * - * @param config FitlerConfig - * @exception ServletException + * @param authService the authService to set */ - public void init(FilterConfig config) throws ServletException + public void setAuthenticationService(AuthenticationService authService) { - // Save the context + this.authService = authService; + } - m_context = config.getServletContext(); + /** + * @param personService the personService to set + */ + public void setPersonService(PersonService personService) + { + this.personService = personService; + } - // Setup the authentication context + /** + * @param nodeService the nodeService to set + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } - 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 + /** + * @param transactionService the transactionService to set + */ + public void setTransactionService(TransactionService transactionService) + { + this.transactionService = transactionService; } /** * Run the authentication filter * + * @param context ServletContext * @param req ServletRequest * @param resp ServletResponse * @param chain FilterChain * @exception ServletException * @exception IOException */ - public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, - ServletException + public void doFilter(ServletContext context, ServletRequest req, ServletResponse resp, FilterChain chain) + throws IOException, ServletException { // Assume it's an HTTP request @@ -163,19 +166,19 @@ public class AuthenticationFilter implements Filter { // Authenticate the user - m_authService.authenticate(username, password.toCharArray()); + authService.authenticate(username, password.toCharArray()); // Set the user name as stored by the back end - username = m_authService.getCurrentUserName(); + username = authService.getCurrentUserName(); // Get the user node and home folder - NodeRef personNodeRef = m_personService.getPerson(username); - NodeRef homeSpaceRef = (NodeRef) m_nodeService.getProperty(personNodeRef, ContentModel.PROP_HOMEFOLDER); + 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, m_authService.getCurrentTicket(), homeSpaceRef); + user = new WebDAVUser(username, authService.getCurrentTicket(), homeSpaceRef); httpReq.getSession().setAttribute(AUTHENTICATION_USER, user); } @@ -213,24 +216,24 @@ public class AuthenticationFilter implements Filter { // Validate the ticket - m_authService.validate(ticket); + authService.validate(ticket); // Need to create the User instance if not already available - String currentUsername = m_authService.getCurrentUserName(); + String currentUsername = authService.getCurrentUserName(); // Start a transaction - tx = m_transactionService.getUserTransaction(); + tx = 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); + 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 (m_nodeService.exists(homeRef) == false) + if (nodeService.exists(homeRef) == false) { throw new InvalidNodeRefException(homeRef); } @@ -289,7 +292,7 @@ public class AuthenticationFilter implements Filter try { // Setup the authentication context - m_authService.validate(user.getTicket()); + authService.validate(user.getTicket()); // Set the current locale diff --git a/source/java/org/alfresco/repo/webdav/auth/BaseKerberosAuthenticationFilter.java b/source/java/org/alfresco/repo/webdav/auth/BaseKerberosAuthenticationFilter.java index 7f30605acf..5423206630 100644 --- a/source/java/org/alfresco/repo/webdav/auth/BaseKerberosAuthenticationFilter.java +++ b/source/java/org/alfresco/repo/webdav/auth/BaseKerberosAuthenticationFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2008 Alfresco Software Limited. + * Copyright (C) 2006-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 @@ -41,7 +41,7 @@ import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import javax.security.sasl.RealmCallback; import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; @@ -84,10 +84,9 @@ public abstract class BaseKerberosAuthenticationFilter extends BaseSSOAuthentica private String m_accountName; private String m_password; - // Kerberos realm and KDC address + // Kerberos realm private String m_krbRealm; - private String m_krbKDC; // Login configuration entry name @@ -96,180 +95,163 @@ public abstract class BaseKerberosAuthenticationFilter extends BaseSSOAuthentica // Server login context private LoginContext m_loginContext; - - // SPNEGO NegTokenInit blob, sent to the client in the SMB negotiate response - - private byte[] m_negTokenInit; - + /** - * Initialize the filter + * Sets the HTTP service account password. (the Principal should be configured in java.login.config) * - * @param args FilterConfig - * @exception ServletException + * @param password + * the password to set */ - public void init(FilterConfig args) throws ServletException + public void setPassword(String password) { - // Call the base SSO filter initialization + this.m_password = password; + } - super.init( args); + /** + * Sets the HTTP service account realm. + * + * @param realm the realm to set + */ + public void setRealm(String realm) + { + m_krbRealm = realm; + } - // Check if Kerberos is enabled, get the Kerberos KDC address + /** + * Sets the HTTP service login configuration entry name. The default is "AlfrescoHTTP". + * + * @param loginEntryName + * the loginEntryName to set + */ + public void setJaasConfigEntryName(String jaasConfigEntryName) + { + m_loginEntryName = jaasConfigEntryName; + } - String kdcAddress = args.getInitParameter("KDC"); - - if (kdcAddress != null && kdcAddress.length() > 0) + + /* (non-Javadoc) + * @see org.alfresco.repo.web.filter.beans.BaseSSOAuthenticationFilter#afterPropertiesSet() + */ + @Override + public void afterPropertiesSet() throws Exception + { + super.afterPropertiesSet(); + + if ( m_krbRealm == null) { - // Set the Kerberos KDC address - - m_krbKDC = kdcAddress; + throw new ServletException("Kerberos realm not specified"); + } - // Get the Kerberos realm + if ( m_password == null) + { + throw new ServletException("HTTP service account password not specified"); + } + + if (m_loginEntryName == null) + { + throw new ServletException("Invalid login entry specified"); + } + + // Get the local host name + String localName = null; + + try + { + localName = InetAddress.getLocalHost().getCanonicalHostName(); + } + catch ( UnknownHostException ex) + { + throw new ServletException( "Failed to get local host name"); + } + + // Create a login context for the HTTP server service + + try + { + // Login the HTTP server service - String krbRealm = args.getInitParameter("Realm"); - if ( krbRealm != null && krbRealm.length() > 0) - { - // Set the Kerberos realm - - m_krbRealm = krbRealm; - } - else - throw new ServletException("Kerberos realm not specified"); - - // Get the HTTP service account password - - String srvPassword = args.getInitParameter("Password"); - if ( srvPassword != null && srvPassword.length() > 0) - { - // Set the HTTP service account password - - m_password = srvPassword; - } - else - throw new ServletException("HTTP service account password not specified"); - - // Get the login configuration entry name - - String loginEntry = args.getInitParameter("LoginEntry"); - - if ( loginEntry != null) - { - if ( loginEntry.length() > 0) - { - // Set the login configuration entry name to use - - m_loginEntryName = loginEntry; - } - else - throw new ServletException("Invalid login entry specified"); - } - - // Get the local host name - - String localName = null; - - try - { - localName = InetAddress.getLocalHost().getCanonicalHostName(); - } - catch ( UnknownHostException ex) - { - throw new ServletException( "Failed to get local host name"); - } - - // Create a login context for the HTTP server service - - try - { - // Login the HTTP server service - - m_loginContext = new LoginContext( m_loginEntryName, this); - m_loginContext.login(); - - // DEBUG - - if ( getLogger().isDebugEnabled()) - getLogger().debug( "HTTP Kerberos login successful"); - } - catch ( LoginException ex) - { - // Debug - - if ( getLogger().isErrorEnabled()) - getLogger().error("HTTP Kerberos web filter error", ex); - - throw new ServletException("Failed to login HTTP server service"); - } - - // Get the HTTP service account name from the subject - - Subject subj = m_loginContext.getSubject(); - Principal princ = subj.getPrincipals().iterator().next(); - - m_accountName = princ.getName(); + m_loginContext = new LoginContext( m_loginEntryName, this); + m_loginContext.login(); // DEBUG if ( getLogger().isDebugEnabled()) - getLogger().debug("Logged on using principal " + m_accountName); + getLogger().debug( "HTTP Kerberos login successful"); + } + catch ( LoginException ex) + { + // Debug - // Create the Oid list for the SPNEGO NegTokenInit, include NTLMSSP for fallback + if ( getLogger().isErrorEnabled()) + getLogger().error("HTTP Kerberos web filter error", ex); - Vector mechTypes = new Vector(); - - mechTypes.add(OID.KERBEROS5); - mechTypes.add(OID.MSKERBEROS5); + throw new ServletException("Failed to login HTTP server service"); + } - // Build the SPNEGO NegTokenInit blob + // Get the HTTP service account name from the subject + + Subject subj = m_loginContext.getSubject(); + Principal princ = subj.getPrincipals().iterator().next(); + + m_accountName = princ.getName(); + + // DEBUG + + if ( getLogger().isDebugEnabled()) + getLogger().debug("Logged on using principal " + m_accountName); + + // Create the Oid list for the SPNEGO NegTokenInit, include NTLMSSP for fallback + + Vector mechTypes = new Vector(); + + mechTypes.add(OID.KERBEROS5); + mechTypes.add(OID.MSKERBEROS5); - try - { - // Build the mechListMIC principle - // - // Note: This field is not as specified - - String mecListMIC = null; - - StringBuilder mic = new StringBuilder(); - mic.append( localName); - mic.append("$@"); - mic.append( m_krbRealm); - - mecListMIC = mic.toString(); - - // Build the SPNEGO NegTokenInit that contains the authentication types that the HTTP server accepts - - NegTokenInit negTokenInit = new NegTokenInit(mechTypes, mecListMIC); - - // Encode the NegTokenInit blob - - m_negTokenInit = negTokenInit.encode(); - } - catch (IOException ex) - { - // Debug - - if ( getLogger().isErrorEnabled()) - getLogger().error("Error creating SPNEGO NegTokenInit blob", ex); - - throw new ServletException("Failed to create SPNEGO NegTokenInit blob"); - } - } + // Build the SPNEGO NegTokenInit blob + + try + { + // Build the mechListMIC principle + // + // Note: This field is not as specified + + String mecListMIC = null; + + StringBuilder mic = new StringBuilder(); + mic.append( localName); + mic.append("$@"); + mic.append( m_krbRealm); + + mecListMIC = mic.toString(); + + // Build the SPNEGO NegTokenInit that contains the authentication types that the HTTP server accepts + + NegTokenInit negTokenInit = new NegTokenInit(mechTypes, mecListMIC); + + // Encode the NegTokenInit blob + negTokenInit.encode(); + } + catch (IOException ex) + { + // Debug + + if ( getLogger().isErrorEnabled()) + getLogger().error("Error creating SPNEGO NegTokenInit blob", ex); + + throw new ServletException("Failed to create SPNEGO NegTokenInit blob"); + } } - /** - * Run the filter - * - * @param sreq ServletRequest - * @param sresp ServletResponse - * @param chain FilterChain - * @exception IOException - * @exception ServletException + + /* + * (non-Javadoc) + * @see org.alfresco.repo.web.filter.beans.DependencyInjectedFilter#doFilter(javax.servlet.ServletContext, + * javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) */ - public void doFilter(ServletRequest sreq, ServletResponse sresp, FilterChain chain) throws IOException, - ServletException + public void doFilter(ServletContext context, ServletRequest sreq, ServletResponse sresp, FilterChain chain) + throws IOException, ServletException { - // Get the HTTP request/response/session - + // Get the HTTP request/response/session HttpServletRequest req = (HttpServletRequest) sreq; HttpServletResponse resp = (HttpServletResponse) sresp; @@ -327,7 +309,7 @@ public abstract class BaseKerberosAuthenticationFilter extends BaseSSOAuthentica // Validate the user ticket - m_authService.validate( user.getTicket()); + authenticationService.validate( user.getTicket()); reqAuth = false; // Filter validate hook diff --git a/source/java/org/alfresco/repo/webdav/auth/BaseNTLMAuthenticationFilter.java b/source/java/org/alfresco/repo/webdav/auth/BaseNTLMAuthenticationFilter.java index ed305e184d..0c89857932 100644 --- a/source/java/org/alfresco/repo/webdav/auth/BaseNTLMAuthenticationFilter.java +++ b/source/java/org/alfresco/repo/webdav/auth/BaseNTLMAuthenticationFilter.java @@ -33,7 +33,7 @@ import java.util.List; import java.util.Random; import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; @@ -114,54 +114,47 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication // Disable NTLMv2 support private boolean m_disableNTLMv2 = false; - - /** - * Initialize the filter - * - * @param args FilterConfig - * - * @exception ServletException - */ - public void init(FilterConfig args) throws ServletException - { - // Call the base SSO filter initialization - - super.init( args); - // Check that the authentication component supports the required mode + + /** + * @param mapUnknownUserToGuest should an unknown user be mapped to guest? + */ + public void setMapUnknownUserToGuest(boolean mapUnknownUserToGuest) + { + m_mapUnknownUserToGuest = mapUnknownUserToGuest; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.web.filter.beans.BaseSSOAuthenticationFilter#afterPropertiesSet() + */ + @Override + public void afterPropertiesSet() throws Exception + { + // Call the base SSO filter initialization + super.afterPropertiesSet(); + + // Check that the authentication component supports the required mode - if (m_authComponent.getNTLMMode() != NTLMMode.MD4_PROVIDER && - m_authComponent.getNTLMMode() != NTLMMode.PASS_THROUGH) + if (authenticationComponent.getNTLMMode() != NTLMMode.MD4_PROVIDER && + authenticationComponent.getNTLMMode() != NTLMMode.PASS_THROUGH) { throw new ServletException("Required authentication mode not available"); } // Check if guest access is to be allowed - - String guestAccess = args.getInitParameter("AllowGuest"); - if (guestAccess != null) - { - m_allowGuest = Boolean.parseBoolean(guestAccess); - - if (getLogger().isDebugEnabled() && m_allowGuest) - getLogger().debug("NTLM filter guest access allowed"); - } + m_allowGuest = this.authenticationComponent.guestUserAuthenticationAllowed(); + + if (getLogger().isDebugEnabled() && m_allowGuest) + getLogger().debug("NTLM filter guest access allowed"); // Check if unknown users should be mapped to guest access - - String mapUnknownToGuest = args.getInitParameter("MapUnknownUserToGuest"); - if (mapUnknownToGuest != null) - { - m_mapUnknownUserToGuest = Boolean.parseBoolean(mapUnknownToGuest); - - if (getLogger().isDebugEnabled() && m_mapUnknownUserToGuest) - getLogger().debug("NTLM filter map unknown users to guest"); - } + if (getLogger().isDebugEnabled() && m_mapUnknownUserToGuest) + getLogger().debug("NTLM filter map unknown users to guest"); // Set the NTLM flags depending on the authentication component supporting MD4 passwords, // or is using passthru auth - if (m_authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER && m_disableNTLMv2 == false) + if (authenticationComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER && m_disableNTLMv2 == false) { // Allow the client to use an NTLMv2 logon @@ -174,18 +167,13 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication m_ntlmFlags = NTLM_FLAGS_NTLM1; } } + - /** - * Run the filter - * - * @param sreq ServletRequest - * @param sresp ServletResponse - * @param chain FilterChain - * @exception IOException - * @exception ServletException + /* (non-Javadoc) + * @see org.alfresco.repo.web.filter.beans.DependencyInjectedFilter#doFilter(javax.servlet.ServletContext, javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) */ - public void doFilter(ServletRequest sreq, ServletResponse sresp, FilterChain chain) throws IOException, - ServletException + public void doFilter(ServletContext context, ServletRequest sreq, ServletResponse sresp, FilterChain chain) + throws IOException, ServletException { // Get the HTTP request/response/session HttpServletRequest req = (HttpServletRequest) sreq; @@ -239,7 +227,7 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication getLogger().debug("User " + user.getUserName() + " validate ticket"); // Validate the user ticket - m_authService.validate(user.getTicket()); + authenticationService.validate(user.getTicket()); reqAuth = false; // Filter validate hook @@ -349,13 +337,6 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication } } } - - /** - * Delete the servlet filter - */ - public void destroy() - { - } /** * Process a type 1 NTLM message @@ -369,8 +350,6 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication protected void processType1(Type1NTLMMessage type1Msg, HttpServletRequest req, HttpServletResponse res, HttpSession session) throws IOException { - Log logger = getLogger(); - if (getLogger().isDebugEnabled()) getLogger().debug("Received type1 " + type1Msg); @@ -409,7 +388,7 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication byte[] challenge = null; NTLMPassthruToken authToken = null; - if (m_authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER) + if (authenticationComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER) { // Generate a random 8 byte challenge @@ -432,7 +411,7 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication authToken = new NTLMPassthruToken(domain); // Run the first stage of the passthru authentication to get the challenge - m_authComponent.authenticate(authToken); + authenticationComponent.authenticate(authToken); // Get the challenge from the token if (authToken.getChallenge() != null) @@ -529,7 +508,7 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication logger.debug("User " + user.getUserName() + " validate ticket"); // Validate the user ticket - m_authService.validate(user.getTicket()); + authenticationService.validate(user.getTicket()); onValidate(req, session); } @@ -551,10 +530,10 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication else { // Check if we are using local MD4 password hashes or passthru authentication - if (m_authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER) + if (authenticationComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER) { // Check if guest logons are allowed and this is a guest logon - if (m_allowGuest && userName.equalsIgnoreCase(m_authComponent.getGuestUserName())) + if (m_allowGuest && userName.equalsIgnoreCase(authenticationComponent.getGuestUserName())) { // Indicate that the user has been authenticated authenticated = true; @@ -577,7 +556,7 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication if (m_mapUnknownUserToGuest) { // Reset the user name to be the guest user - userName = m_authComponent.getGuestUserName(); + userName = authenticationComponent.getGuestUserName(); authenticated = true; if (logger.isDebugEnabled()) @@ -614,17 +593,17 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication try { // Run the second stage of the passthru authentication - m_authComponent.authenticate(authToken); + authenticationComponent.authenticate(authToken); authenticated = true; // Check if the user has been logged on as guest if (authToken.isGuestLogon()) { - userName = m_authComponent.getGuestUserName(); + userName = authenticationComponent.getGuestUserName(); } // Set the authentication context - m_authComponent.setCurrentUser(userName); + authenticationComponent.setCurrentUser(userName); } catch (BadCredentialsException ex) { @@ -656,7 +635,7 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication // user already exists - revalidate ticket to authenticate the current user thread try { - m_authService.validate(user.getTicket()); + authenticationService.validate(user.getTicket()); } catch (AuthenticationException ex) { @@ -1018,13 +997,13 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication String md4hash = null; // Wrap the auth component calls in a transaction - UserTransaction tx = m_transactionService.getUserTransaction(); + UserTransaction tx = transactionService.getUserTransaction(); try { tx.begin(); // Get the stored MD4 hashed password for the user, or null if the user does not exist - md4hash = m_authComponent.getMD4HashedPassword(userName); + md4hash = authenticationComponent.getMD4HashedPassword(userName); } catch (Throwable ex) { diff --git a/source/java/org/alfresco/repo/webdav/auth/BaseSSOAuthenticationFilter.java b/source/java/org/alfresco/repo/webdav/auth/BaseSSOAuthenticationFilter.java index e1e7821a13..bdd1875dab 100644 --- a/source/java/org/alfresco/repo/webdav/auth/BaseSSOAuthenticationFilter.java +++ b/source/java/org/alfresco/repo/webdav/auth/BaseSSOAuthenticationFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -28,9 +28,6 @@ import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; -import javax.servlet.Filter; -import javax.servlet.FilterConfig; -import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -48,15 +45,14 @@ 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.service.ServiceRegistry; +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.web.context.WebApplicationContext; -import org.springframework.web.context.support.WebApplicationContextUtils; +import org.springframework.beans.factory.InitializingBean; /** * Base class with common code and initialisation for single signon authentication filters. @@ -64,7 +60,7 @@ import org.springframework.web.context.support.WebApplicationContextUtils; * @author gkspencer * @author kroast */ -public abstract class BaseSSOAuthenticationFilter implements Filter +public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedFilter, InitializingBean { // Constants // @@ -85,29 +81,25 @@ public abstract class BaseSSOAuthenticationFilter implements Filter protected static final String WEBDAV_AUTH_USER = "_alfDAVAuthTicket"; - // Allow an authenitcation 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"; - - // Servlet context, required to get authentication service - - protected ServletContext m_context; - + // File server configuration - private ServerConfigurationBean m_srvConfig; + private ServerConfigurationBean serverConfigurationBean; // Security configuration section, for domain mappings - private SecurityConfigSection m_secConfig; + private SecurityConfigSection securityConfigSection; // Various services required by NTLM authenticator - protected AuthenticationService m_authService; - protected AuthenticationComponent m_authComponent; - protected PersonService m_personService; - protected NodeService m_nodeService; - protected TransactionService m_transactionService; + protected AuthenticationService authenticationService; + protected AuthenticationComponent authenticationComponent; + protected PersonService personService; + protected NodeService nodeService; + protected TransactionService transactionService; // Local server name, from either the file servers config or DNS host name @@ -124,39 +116,66 @@ public abstract class BaseSSOAuthenticationFilter implements Filter // User object attribute name private String m_userAttributeName = AUTHENTICATION_USER; + + /** + * @param serverConfigurationBean the serverConfigurationBean to set + */ + public void setServerConfigurationBean(ServerConfigurationBean serverConfigurationBean) + { + this.serverConfigurationBean = serverConfigurationBean; + } /** - * Initialize the filter - * - * @param args FilterConfig - * - * @exception ServletException + * @param authenticationService the authenticationService to set */ - public void init(FilterConfig args) throws ServletException + public void setAuthenticationService(AuthenticationService authenticationService) { - // Save the servlet context, needed to get hold of the authentication service + this.authenticationService = authenticationService; + } - m_context = args.getServletContext(); - - // Setup the authentication context + /** + * @param authenticationComponent the authenticationComponent to set + */ + public void setAuthenticationComponent(AuthenticationComponent authenticationComponent) + { + this.authenticationComponent = authenticationComponent; + } - WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(m_context); - - ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); - m_nodeService = serviceRegistry.getNodeService(); - m_transactionService = serviceRegistry.getTransactionService(); - m_authService = serviceRegistry.getAuthenticationService(); - - m_authComponent = (AuthenticationComponent) ctx.getBean("AuthenticationComponent"); - m_personService = (PersonService) ctx.getBean("personService"); - - m_srvConfig = (ServerConfigurationBean) ctx.getBean(ServerConfigurationBean.SERVER_CONFIGURATION); - + /** + * @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; + } + + + + /* (non-Javadoc) + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + public void afterPropertiesSet() throws Exception + { // Get the local server name, try the file server config first - - if (m_srvConfig != null) + if (serverConfigurationBean != null) { - m_srvName = m_srvConfig.getServerName(); + m_srvName = serverConfigurationBean.getServerName(); if (m_srvName != null) { @@ -167,13 +186,13 @@ public abstract class BaseSSOAuthenticationFilter implements Filter { // Failed to resolve the configured name - m_srvName = m_srvConfig.getLocalServerName(true); + m_srvName = serverConfigurationBean.getLocalServerName(true); } } catch (UnknownHostException ex) { - if (getLogger().isErrorEnabled()) - getLogger().error("NTLM filter, error resolving CIFS host name", ex); + if (getLogger().isWarnEnabled()) + getLogger().warn("NTLM filter, error resolving CIFS host name" + m_srvName); } } @@ -181,12 +200,17 @@ public abstract class BaseSSOAuthenticationFilter implements Filter if ( m_srvName == null) { - m_srvName = m_srvConfig.getLocalServerName(true); + m_srvName = serverConfigurationBean.getLocalServerName(true); + + // DEBUG + + if ( getLogger().isInfoEnabled()) + getLogger().info("NTLM filter using server name " + m_srvName); } // Find the security configuration section - m_secConfig = (SecurityConfigSection)m_srvConfig.getConfigSection(SecurityConfigSection.SectionName); + securityConfigSection = (SecurityConfigSection)serverConfigurationBean.getConfigSection(SecurityConfigSection.SectionName); } else { @@ -221,13 +245,6 @@ public abstract class BaseSSOAuthenticationFilter implements Filter } } - /** - * Delete the servlet filter - */ - public void destroy() - { - } - /** * Create the user object that will be stored in the session * @@ -291,7 +308,7 @@ public abstract class BaseSSOAuthenticationFilter implements Filter { SessionUser user = null; - UserTransaction tx = m_transactionService.getUserTransaction(); + UserTransaction tx = transactionService.getUserTransaction(); try { @@ -299,22 +316,22 @@ public abstract class BaseSSOAuthenticationFilter implements Filter // Setup User object and Home space ID etc. - final NodeRef personNodeRef = m_personService.getPerson(userName); + final NodeRef personNodeRef = personService.getPerson(userName); // Use the system user context to do the user lookup RunAsWork getUserNameRunAsWork = new RunAsWork() { public String doWork() throws Exception { - return (String) m_nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME); + return (String) nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME); } }; userName = AuthenticationUtil.runAs(getUserNameRunAsWork, AuthenticationUtil.SYSTEM_USER_NAME); - m_authComponent.setCurrentUser(userName); - String currentTicket = m_authService.getCurrentTicket(); + authenticationComponent.setCurrentUser(userName); + String currentTicket = authenticationService.getCurrentTicket(); - NodeRef homeSpaceRef = (NodeRef) m_nodeService.getProperty(personNodeRef, ContentModel.PROP_HOMEFOLDER); + NodeRef homeSpaceRef = (NodeRef) nodeService.getProperty(personNodeRef, ContentModel.PROP_HOMEFOLDER); // Create the user object to be stored in the session @@ -403,17 +420,17 @@ public abstract class BaseSSOAuthenticationFilter implements Filter { // Check if there are any domain mappings - if (m_secConfig != null && m_secConfig.hasDomainMappings() == false) + if (securityConfigSection != null && securityConfigSection.hasDomainMappings() == false) { return null; } - if (m_secConfig != null) + if (securityConfigSection != null) { // Convert the client IP address to an integer value int clientAddr = IPAddress.parseNumericAddress(clientIP); - for (DomainMapping domainMap : m_secConfig.getDomainMappings()) + for (DomainMapping domainMap : securityConfigSection.getDomainMappings()) { if (domainMap.isMemberOfDomain(clientAddr)) { @@ -458,7 +475,7 @@ public abstract class BaseSSOAuthenticationFilter implements Filter { // Validate the ticket - m_authService.validate(ticket); + authenticationService.validate(ticket); SessionUser user = getSessionUser( sess); @@ -466,15 +483,15 @@ public abstract class BaseSSOAuthenticationFilter implements Filter { // Start a transaction - tx = m_transactionService.getUserTransaction(); + tx = transactionService.getUserTransaction(); tx.begin(); // Need to create the User instance if not already available - String currentUsername = m_authService.getCurrentUserName(); + String currentUsername = authenticationService.getCurrentUserName(); - NodeRef personRef = m_personService.getPerson(currentUsername); - user = createUserObject( currentUsername, m_authService.getCurrentTicket(), personRef, null); + NodeRef personRef = personService.getPerson(currentUsername); + user = createUserObject( currentUsername, authenticationService.getCurrentTicket(), personRef, null); tx.commit(); tx = null; diff --git a/source/java/org/alfresco/repo/webdav/auth/KerberosAuthenticationFilter.java b/source/java/org/alfresco/repo/webdav/auth/KerberosAuthenticationFilter.java index c2ea5ca0d2..e3df1ba6d4 100644 --- a/source/java/org/alfresco/repo/webdav/auth/KerberosAuthenticationFilter.java +++ b/source/java/org/alfresco/repo/webdav/auth/KerberosAuthenticationFilter.java @@ -26,8 +26,6 @@ package org.alfresco.repo.webdav.auth; import java.io.IOException; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @@ -48,17 +46,16 @@ public class KerberosAuthenticationFilter extends BaseKerberosAuthenticationFilt private static Log logger = LogFactory.getLog(KerberosAuthenticationFilter.class); - /** - * Initialize the filter - * - * @param args FilterConfig - * @exception ServletException + + /* (non-Javadoc) + * @see org.alfresco.repo.webdav.auth.BaseKerberosAuthenticationFilter#afterPropertiesSet() */ - public void init(FilterConfig args) throws ServletException + @Override + public void afterPropertiesSet() throws Exception { - // Call the base Kerberos filter initialization - - super.init( args); + // Call the base Kerberos filter initialization + + super.afterPropertiesSet(); // Enable ticket based logons diff --git a/source/java/org/alfresco/repo/webdav/auth/NTLMAuthenticationFilter.java b/source/java/org/alfresco/repo/webdav/auth/NTLMAuthenticationFilter.java index 7619f2ada2..105bfda98e 100644 --- a/source/java/org/alfresco/repo/webdav/auth/NTLMAuthenticationFilter.java +++ b/source/java/org/alfresco/repo/webdav/auth/NTLMAuthenticationFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -26,8 +26,6 @@ package org.alfresco.repo.webdav.auth; import java.io.IOException; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @@ -46,16 +44,15 @@ public class NTLMAuthenticationFilter extends BaseNTLMAuthenticationFilter { // Debug logging private static Log logger = LogFactory.getLog(NTLMAuthenticationFilter.class); + - /** - * Initialize the filter - * - * @param args FilterConfig - * @exception ServletException + /* (non-Javadoc) + * @see org.alfresco.repo.webdav.auth.BaseNTLMAuthenticationFilter#afterPropertiesSet() */ - public void init(FilterConfig args) throws ServletException + @Override + public void afterPropertiesSet() throws Exception { - super.init(args); + super.afterPropertiesSet(); // Enable ticket based logons