Align Alfresco, CIFS and FTP authentication stacks for NTLM passthru, kerberos and LDAP

- PassthruServerFactory created to allows PassthruServers singleton to be shared by CIFS, FTP and Alfresco passthru authenticators
- Also added NTLM + Alfresco (non-passthru) example. Doesn't seem to work yet!
- ExtendedServerConfigurationAccessor interface added BaseSSOAuthenticationFilter to get at local server name info from file server configuration
- toString() added to CIFSAuthenticator so that we can still properly log the authenticator type
- Fixed WebDAVServlet to go through ServerConfigurationAccessor interface to avoid ClassCastException

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@13823 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Dave Ward
2009-04-03 11:29:18 +00:00
parent 6b580c7cc4
commit 7bcaae9af7
3 changed files with 124 additions and 101 deletions

View File

@@ -36,6 +36,7 @@ import javax.servlet.http.HttpServletResponse;
import javax.transaction.UserTransaction; import javax.transaction.UserTransaction;
import org.alfresco.filesys.ServerConfigurationBean; import org.alfresco.filesys.ServerConfigurationBean;
import org.alfresco.jlan.server.config.ServerConfigurationAccessor;
import org.alfresco.repo.security.authentication.AuthenticationContext; import org.alfresco.repo.security.authentication.AuthenticationContext;
import org.alfresco.repo.tenant.TenantService; import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.ServiceRegistry; import org.alfresco.service.ServiceRegistry;
@@ -333,7 +334,7 @@ public class WebDAVServlet extends HttpServlet
// Initialize the root node // Initialize the root node
ServerConfigurationBean fileSrvConfig = (ServerConfigurationBean) context.getBean(ServerConfigurationBean.SERVER_CONFIGURATION); ServerConfigurationAccessor fileSrvConfig = (ServerConfigurationAccessor) context.getBean(ServerConfigurationBean.SERVER_CONFIGURATION);
if ( fileSrvConfig == null) if ( fileSrvConfig == null)
throw new ServletException("File server configuration not available"); throw new ServletException("File server configuration not available");

View File

@@ -425,10 +425,11 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication
// Build a type2 message to send back to the client, containing the challenge // Build a type2 message to send back to the client, containing the challenge
List<TargetInfo> tList = new ArrayList<TargetInfo>(); List<TargetInfo> tList = new ArrayList<TargetInfo>();
tList.add(new TargetInfo(NTLM.TargetServer, m_srvName)); String srvName = getServerName();
tList.add(new TargetInfo(NTLM.TargetServer, srvName));
Type2NTLMMessage type2Msg = new Type2NTLMMessage(); Type2NTLMMessage type2Msg = new Type2NTLMMessage();
type2Msg.buildType2(ntlmFlags, m_srvName, challenge, null, tList); type2Msg.buildType2(ntlmFlags, srvName, challenge, null, tList);
// Store the NTLM logon details, cache the type2 message, and token if using passthru // Store the NTLM logon details, cache the type2 message, and token if using passthru
ntlmDetails = new NTLMLogonDetails(); ntlmDetails = new NTLMLogonDetails();
@@ -652,10 +653,11 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication
onValidate(req, session); onValidate(req, session);
// Update the NTLM logon details in the session // Update the NTLM logon details in the session
String srvName = getServerName();
if (ntlmDetails == null) if (ntlmDetails == null)
{ {
// No cached NTLM details // No cached NTLM details
ntlmDetails = new NTLMLogonDetails(userName, workstation, domain, false, m_srvName); ntlmDetails = new NTLMLogonDetails(userName, workstation, domain, false, srvName);
ntlmDetails.setNTLMHashedPassword(type3Msg.getNTLMHash()); ntlmDetails.setNTLMHashedPassword(type3Msg.getNTLMHash());
session.setAttribute(NTLM_AUTH_DETAILS, ntlmDetails); session.setAttribute(NTLM_AUTH_DETAILS, ntlmDetails);
@@ -665,7 +667,7 @@ public abstract class BaseNTLMAuthenticationFilter extends BaseSSOAuthentication
else else
{ {
// Update the cached NTLM details // Update the cached NTLM details
ntlmDetails.setDetails(userName, workstation, domain, false, m_srvName); ntlmDetails.setDetails(userName, workstation, domain, false, srvName);
ntlmDetails.setNTLMHashedPassword(type3Msg.getNTLMHash()); ntlmDetails.setNTLMHashedPassword(type3Msg.getNTLMHash());
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())

View File

@@ -34,7 +34,8 @@ import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import javax.transaction.UserTransaction; import javax.transaction.UserTransaction;
import org.alfresco.filesys.ServerConfigurationBean; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.filesys.ExtendedServerConfigurationAccessor;
import org.alfresco.jlan.server.auth.ntlm.NTLM; 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;
@@ -87,11 +88,7 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF
// File server configuration // File server configuration
private ServerConfigurationBean serverConfigurationBean; private ExtendedServerConfigurationAccessor serverConfiguration;
// Security configuration section, for domain mappings
private SecurityConfigSection securityConfigSection;
// Various services required by NTLM authenticator // Various services required by NTLM authenticator
@@ -101,10 +98,6 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF
protected NodeService nodeService; protected NodeService nodeService;
protected TransactionService transactionService; protected TransactionService transactionService;
// Local server name, from either the file servers config or DNS host name
protected String m_srvName;
// Login page relative address, if null then login will loop until a valid login is received // Login page relative address, if null then login will loop until a valid login is received
private String m_loginPage; private String m_loginPage;
@@ -116,13 +109,16 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF
// User object attribute name // User object attribute name
private String m_userAttributeName = AUTHENTICATION_USER; private String m_userAttributeName = AUTHENTICATION_USER;
private String m_lastConfiguredServerName;
private String m_lastResolvedServerName;
/** /**
* @param serverConfigurationBean the serverConfigurationBean to set * @param serverConfiguration the serverConfiguration to set
*/ */
public void setServerConfigurationBean(ServerConfigurationBean serverConfigurationBean) public void setServerConfiguration(ExtendedServerConfigurationAccessor serverConfiguration)
{ {
this.serverConfigurationBean = serverConfigurationBean; this.serverConfiguration = serverConfiguration;
} }
/** /**
@@ -163,93 +159,13 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF
public void setTransactionService(TransactionService transactionService) public void setTransactionService(TransactionService transactionService)
{ {
this.transactionService = transactionService; this.transactionService = transactionService;
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/ */
public void afterPropertiesSet() throws Exception public void afterPropertiesSet() throws Exception
{ {
// Get the local server name, try the file server config first
if (serverConfigurationBean != null)
{
m_srvName = serverConfigurationBean.getServerName();
if ( m_srvName.length() == 0)
m_srvName = null;
if (m_srvName != null)
{
try
{
InetAddress resolved = InetAddress.getByName(m_srvName);
if (resolved == null)
{
// Failed to resolve the configured name
m_srvName = serverConfigurationBean.getLocalServerName(true);
}
}
catch (UnknownHostException ex)
{
if (getLogger().isWarnEnabled())
getLogger().warn("NTLM filter, error resolving CIFS host name" + m_srvName);
}
}
// If we still do not have a name use the DNS name of the server, with the domain part removed
if ( m_srvName == null)
{
m_srvName = serverConfigurationBean.getLocalServerName(true);
// DEBUG
if ( getLogger().isInfoEnabled())
getLogger().info("NTLM filter using server name " + m_srvName);
// DEBUG
if ( getLogger().isInfoEnabled())
getLogger().info("NTLM filter using server name " + m_srvName);
}
// Find the security configuration section
securityConfigSection = (SecurityConfigSection)serverConfigurationBean.getConfigSection(SecurityConfigSection.SectionName);
}
else
{
// Get the host name
try
{
// Get the local host name
m_srvName = InetAddress.getLocalHost().getHostName();
// Strip any domain name
int pos = m_srvName.indexOf(".");
if (pos != -1)
{
m_srvName = m_srvName.substring(0, pos - 1);
}
}
catch (UnknownHostException ex)
{
if (getLogger().isErrorEnabled())
getLogger().error("NTLM filter, error getting local host name", ex);
}
}
// Check if the server name is valid
if (m_srvName == null || m_srvName.length() == 0)
{
throw new ServletException("Failed to get local server name");
}
} }
/** /**
@@ -426,7 +342,7 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF
protected final String mapClientAddressToDomain(String clientIP) protected final String mapClientAddressToDomain(String clientIP)
{ {
// Check if there are any domain mappings // Check if there are any domain mappings
SecurityConfigSection securityConfigSection = getSecurityConfigSection();
if (securityConfigSection != null && securityConfigSection.hasDomainMappings() == false) if (securityConfigSection != null && securityConfigSection.hasDomainMappings() == false)
{ {
return null; return null;
@@ -639,5 +555,109 @@ public abstract class BaseSSOAuthenticationFilter implements DependencyInjectedF
} }
return isNTLMSSP; return isNTLMSSP;
} }
/**
* Because the file server configuration may change during the lifetime of this filter, this method checks against
* the last configured server name before returning a cached result
*
* @return resolved local server name
*/
protected synchronized String getServerName()
{
// Get the local server name, try the file server config first
String srvName = null;
if (serverConfiguration != null)
{
srvName = serverConfiguration.getServerName();
if (srvName != null && srvName.length() == 0)
{
srvName = null;
}
}
if (m_lastResolvedServerName != null
&& (m_lastConfiguredServerName == null && srvName == null || m_lastConfiguredServerName.equals(srvName)))
{
return m_lastResolvedServerName;
}
m_lastResolvedServerName = null;
m_lastConfiguredServerName = srvName;
if (serverConfiguration != null)
{
if (m_lastConfiguredServerName != null)
{
try
{
InetAddress resolved = InetAddress.getByName(m_lastConfiguredServerName);
if (resolved == null)
{
// Failed to resolve the configured name
m_lastResolvedServerName = serverConfiguration.getLocalServerName(true);
}
else
{
m_lastResolvedServerName = m_lastConfiguredServerName;
}
}
catch (UnknownHostException ex)
{
if (getLogger().isWarnEnabled())
getLogger().warn("NTLM filter, error resolving CIFS host name" + m_lastConfiguredServerName);
}
}
// If we still do not have a name use the DNS name of the server, with the domain part removed
if (m_lastResolvedServerName == null)
{
m_lastResolvedServerName = serverConfiguration.getLocalServerName(true);
// DEBUG
if (getLogger().isInfoEnabled())
getLogger().info("NTLM filter using server name " + m_lastResolvedServerName);
}
}
else
{
// Get the host name
try
{
// Get the local host name
m_lastResolvedServerName = InetAddress.getLocalHost().getHostName();
// Strip any domain name
int pos = m_lastResolvedServerName.indexOf(".");
if (pos != -1)
{
m_lastResolvedServerName = m_lastResolvedServerName.substring(0, pos - 1);
}
}
catch (UnknownHostException ex)
{
if (getLogger().isErrorEnabled())
getLogger().error("NTLM filter, error getting local host name", ex);
}
}
// Check if the server name is valid
if (m_lastResolvedServerName == null || m_lastResolvedServerName.length() == 0)
{
throw new AlfrescoRuntimeException("Failed to get local server name");
}
return m_lastResolvedServerName;
}
protected SecurityConfigSection getSecurityConfigSection()
{
return serverConfiguration == null ? null : (SecurityConfigSection) serverConfiguration.getConfigSection(SecurityConfigSection.SectionName);
}
} }