diff --git a/source/java/org/alfresco/filesys/ServerConfigurationBean.java b/source/java/org/alfresco/filesys/ServerConfigurationBean.java
index e741928dbd..382fb97da8 100644
--- a/source/java/org/alfresco/filesys/ServerConfigurationBean.java
+++ b/source/java/org/alfresco/filesys/ServerConfigurationBean.java
@@ -84,6 +84,7 @@ import org.alfresco.jlan.util.Platform;
import org.alfresco.jlan.util.StringList;
import org.alfresco.jlan.util.X64;
import org.alfresco.repo.security.authentication.NTLMMode;
+import org.alfresco.repo.security.authentication.ntlm.NLTMAuthenticator;
/**
* Alfresco File Server Configuration Bean Class
@@ -385,11 +386,15 @@ public class ServerConfigurationBean extends AbstractServerConfigurationBean {
// Get the authentication component type
- NTLMMode ntlmMode = m_authenticationComponent.getNTLMMode();
+ NTLMMode ntlmMode = NTLMMode.NONE;
+ if (m_authenticationComponent instanceof NLTMAuthenticator)
+ {
+ ntlmMode = ((NLTMAuthenticator)m_authenticationComponent).getNTLMMode();
+ }
// Set the authenticator class to use
- String authClass = "org.alfresco.filesys.auth.cifs.AlfrescoCifsAuthenticator";
+ String authClass = "org.alfresco.filesys.auth.cifs.AlfrescoCifsAuthenticator";
if (authType.equalsIgnoreCase("passthru"))
{
@@ -1462,11 +1467,15 @@ public class ServerConfigurationBean extends AbstractServerConfigurationBean {
// Get the authentication component type
- NTLMMode ntlmMode = m_authenticationComponent.getNTLMMode();
+ NTLMMode ntlmMode = NTLMMode.NONE;
+ if (m_authenticationComponent instanceof NLTMAuthenticator)
+ {
+ ntlmMode = ((NLTMAuthenticator)m_authenticationComponent).getNTLMMode();
+ }
// Set the authenticator class to use
- String authClass = "org.alfresco.filesys.auth.ftp.AlfrescoFtpAuthenticator";
+ String authClass = "org.alfresco.filesys.auth.ftp.AlfrescoFtpAuthenticator";
if (authType.equalsIgnoreCase("passthru"))
{
diff --git a/source/java/org/alfresco/filesys/auth/cifs/AlfrescoCifsAuthenticator.java b/source/java/org/alfresco/filesys/auth/cifs/AlfrescoCifsAuthenticator.java
index 2cc1ae4c45..3bf73c25cb 100644
--- a/source/java/org/alfresco/filesys/auth/cifs/AlfrescoCifsAuthenticator.java
+++ b/source/java/org/alfresco/filesys/auth/cifs/AlfrescoCifsAuthenticator.java
@@ -72,12 +72,19 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase
*/
protected boolean validateAuthenticationMode()
{
- // Make sure the authentication component supports MD4 hashed passwords or passthru mode
-
- if ( getAuthenticationComponent().getNTLMMode() != NTLMMode.MD4_PROVIDER &&
- getAuthenticationComponent().getNTLMMode() != NTLMMode.PASS_THROUGH)
+ try
+ {
+ // Make sure the authentication component supports MD4 hashed passwords or passthru mode
+
+ if (getNTLMAuthenticator().getNTLMMode() != NTLMMode.MD4_PROVIDER
+ && getNTLMAuthenticator().getNTLMMode() != NTLMMode.PASS_THROUGH)
+ return false;
+ return true;
+ }
+ catch (IllegalStateException e)
+ {
return false;
- return true;
+ }
}
/**
@@ -162,7 +169,7 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase
// Check if MD4 or passthru mode is configured
- else if ( getAuthenticationComponent().getNTLMMode() == NTLMMode.MD4_PROVIDER)
+ else if ( getNTLMAuthenticator().getNTLMMode() == NTLMMode.MD4_PROVIDER)
{
// Start a transaction
@@ -248,7 +255,7 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase
if ( logger.isDebugEnabled())
logger.debug("Authenticated user " + client.getUserName() + " sts=" + getStatusAsString(authSts) +
- " via " + (getAuthenticationComponent().getNTLMMode() == NTLMMode.MD4_PROVIDER ? "MD4" : "Passthru"));
+ " via " + (getNTLMAuthenticator().getNTLMMode() == NTLMMode.MD4_PROVIDER ? "MD4" : "Passthru"));
// Return the authentication status
@@ -296,7 +303,7 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase
if ( logger.isDebugEnabled())
logger.debug("Re-using existing challenge, already authenticated");
}
- else if ( getAuthenticationComponent().getNTLMMode() == NTLMMode.MD4_PROVIDER)
+ else if ( getNTLMAuthenticator().getNTLMMode() == NTLMMode.MD4_PROVIDER)
{
// Create a new authentication context for the session
@@ -311,7 +318,7 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase
// Run the first stage of the passthru authentication to get the challenge
- getAuthenticationComponent().authenticate( authToken);
+ getNTLMAuthenticator().authenticate( authToken);
// Save the authentication token for the second stage of the authentication
@@ -336,7 +343,7 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase
{
// Get the stored MD4 hashed password for the user, or null if the user does not exist
- String md4hash = getAuthenticationComponent().getMD4HashedPassword(client.getUserName());
+ String md4hash = getNTLMAuthenticator().getMD4HashedPassword(client.getUserName());
if ( md4hash != null)
{
@@ -491,7 +498,7 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase
{
// Run the second stage of the passthru authentication
- genAuthToken = getAuthenticationComponent().authenticate( authToken);
+ genAuthToken = getNTLMAuthenticator().authenticate( authToken);
// Check if the user has been logged on as a guest
diff --git a/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java b/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java
index 86f62751ee..3bb68dd05a 100644
--- a/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java
+++ b/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java
@@ -43,9 +43,11 @@ import org.alfresco.jlan.server.filesys.DiskInterface;
import org.alfresco.jlan.server.filesys.DiskSharedDevice;
import org.alfresco.jlan.server.filesys.SrvDiskInfo;
import org.alfresco.model.ContentModel;
+import org.alfresco.repo.management.subsystems.ActivateableBean;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.MD4PasswordEncoder;
import org.alfresco.repo.security.authentication.MD4PasswordEncoderImpl;
+import org.alfresco.repo.security.authentication.ntlm.NLTMAuthenticator;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AuthenticationService;
@@ -55,49 +57,67 @@ import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
/**
* CIFS Authenticator Base Class
- *
*
* Base class for Alfresco CIFS authenticator implementations.
*
* @author gkspencer
*/
-public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements DisposableBean
+public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements ActivateableBean, InitializingBean, DisposableBean
{
// Logging
+ /** The Constant logger. */
protected static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol.auth");
// MD4 hash decoder
+ /** The m_md4 encoder. */
protected MD4PasswordEncoder m_md4Encoder = new MD4PasswordEncoderImpl();
+ /** The authentication component. */
private AuthenticationComponent authenticationComponent;
+ /** The authentication service. */
private AuthenticationService authenticationService;
+ /** The node service. */
private NodeService nodeService;
+ /** The person service. */
private PersonService personService;
+ /** The transaction service. */
private TransactionService transactionService;
+ /** The authority service. */
private AuthorityService authorityService;
+ /** The disk interface. */
private DiskInterface diskInterface;
+ /** Is this component active, i.e. should it be used? */
+ private boolean active = true;
+
// Alfresco configuration
+ /**
+ * Instantiates a new cifs authenticator base.
+ */
public CifsAuthenticatorBase()
{
// The default access mode
setAccessMode(USER_MODE);
}
-
+
/**
- * @param authenticationComponent the authenticationComponent to set
+ * Sets the authentication component.
+ *
+ * @param authenticationComponent
+ * the authenticationComponent to set
*/
public void setAuthenticationComponent(AuthenticationComponent authenticationComponent)
{
@@ -105,7 +125,10 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
}
/**
- * @param authenticationService the authenticationService to set
+ * Sets the authentication service.
+ *
+ * @param authenticationService
+ * the authenticationService to set
*/
public void setAuthenticationService(AuthenticationService authenticationService)
{
@@ -113,7 +136,10 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
}
/**
- * @param nodeService the nodeService to set
+ * Sets the node service.
+ *
+ * @param nodeService
+ * the nodeService to set
*/
public void setNodeService(NodeService nodeService)
{
@@ -121,7 +147,10 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
}
/**
- * @param personService the personService to set
+ * Sets the person service.
+ *
+ * @param personService
+ * the personService to set
*/
public void setPersonService(PersonService personService)
{
@@ -129,7 +158,10 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
}
/**
- * @param transactionService the transactionService to set
+ * Sets the transaction service.
+ *
+ * @param transactionService
+ * the transactionService to set
*/
public void setTransactionService(TransactionService transactionService)
{
@@ -137,7 +169,10 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
}
/**
- * @param authorityService the authorityService to set
+ * Sets the authority service.
+ *
+ * @param authorityService
+ * the authorityService to set
*/
public void setAuthorityService(AuthorityService authorityService)
{
@@ -145,20 +180,46 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
}
/**
- * Set the filesystem driver for the node service based filesystem
+ * Set the filesystem driver for the node service based filesystem.
*
- * @param diskInterface DiskInterface
+ * @param diskInterface
+ * DiskInterface
*/
public void setDiskInterface(DiskInterface diskInterface)
{
this.diskInterface = diskInterface;
}
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.ActivateableBean#isActive()
+ */
+ public boolean isActive()
+ {
+ return active;
+ }
+
/**
- * Initialize the authenticator
+ * Activates or deactivates the bean.
*
- * @param config ServerConfiguration
- * @param params ConfigElement
+ * @param active
+ * true
if the bean is active and initialization should complete
+ */
+ public void setActive(boolean active)
+ {
+ this.active = active;
+ }
+
+ /**
+ * Initialize the authenticator.
+ *
+ * @param config
+ * ServerConfiguration
+ * @param params
+ * ConfigElement
+ * @throws InvalidConfigurationException
+ * the invalid configuration exception
* @exception InvalidConfigurationException
*/
public void initialize(ServerConfiguration config, ConfigElement params) throws InvalidConfigurationException
@@ -181,8 +242,10 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
/**
- * Initialize the authenticator
+ * Initialize the authenticator.
*
+ * @throws InvalidConfigurationException
+ * the invalid configuration exception
* @exception InvalidConfigurationException
*/
@Override
@@ -207,9 +270,24 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
if ( ! validateAuthenticationMode() )
throw new InvalidConfigurationException("Required authentication mode not available");
}
+
+
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
+ */
+ public final void afterPropertiesSet() throws InvalidConfigurationException
+ {
+ // If the bean is active, call the overridable initialize method
+ if (this.active)
+ {
+ initialize();
+ }
+ }
/**
- * Validate that the authentication component supports the required mode
+ * Validate that the authentication component supports the required mode.
*
* @return boolean
*/
@@ -219,10 +297,12 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
}
/**
- * Logon using the guest user account
+ * Logon using the guest user account.
*
- * @param client ClientInfo
- * @param sess SrvSession
+ * @param client
+ * ClientInfo
+ * @param sess
+ * SrvSession
*/
protected void doGuestLogon( ClientInfo client, SrvSession sess)
{
@@ -263,9 +343,10 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
}
/**
- * Get the home folder for the user
+ * Get the home folder for the user.
*
- * @param client ClientInfo
+ * @param client
+ * ClientInfo
*/
protected final void getHomeFolderForUser(ClientInfo client)
{
@@ -313,9 +394,10 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
}
/**
- * Map the case insensitive logon name to the internal person object user name
+ * Map the case insensitive logon name to the internal person object user name.
*
- * @param userName String
+ * @param userName
+ * String
* @return String
*/
protected final String mapUserNameToPerson(String userName)
@@ -373,9 +455,10 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
}
/**
- * Set the current authenticated user context for this thread
+ * Set the current authenticated user context for this thread.
*
- * @param client ClientInfo
+ * @param client
+ * ClientInfo
*/
public void setCurrentUser(ClientInfo client) {
@@ -403,7 +486,7 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
}
/**
- * Return the authentication component
+ * Return the authentication component.
*
* @return AuthenticationComponent
*/
@@ -412,8 +495,23 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
return this.authenticationComponent;
}
+
/**
- * Return the authentication service
+ * Returns an SSO-enabled authentication component.
+ *
+ * @return NLTMAuthenticator
+ */
+ protected final NLTMAuthenticator getNTLMAuthenticator()
+ {
+ if (!(this.authenticationComponent instanceof NLTMAuthenticator))
+ {
+ throw new IllegalStateException("Attempt to use non SSO-enabled authentication component for SSO");
+ }
+ return (NLTMAuthenticator)this.authenticationComponent;
+ }
+
+ /**
+ * Return the authentication service.
*
* @return AuthenticationService
*/
@@ -423,7 +521,7 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
}
/**
- * Return the node service
+ * Return the node service.
*
* @return NodeService
*/
@@ -433,7 +531,7 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
}
/**
- * Return the person service
+ * Return the person service.
*
* @return PersonService
*/
@@ -443,7 +541,7 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
}
/**
- * Return the transaction service
+ * Return the transaction service.
*
* @return TransactionService
*/
@@ -453,7 +551,7 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
}
/**
- * Return the authority service
+ * Return the authority service.
*
* @return AuthorityService
*/
@@ -462,9 +560,10 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
}
/**
- * Check if the user is an administrator user name
+ * Check if the user is an administrator user name.
*
- * @param cInfo ClientInfo
+ * @param cInfo
+ * ClientInfo
*/
protected final void checkForAdminUserName(ClientInfo cInfo) {
@@ -503,9 +602,10 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
}
/**
- * Create a transaction, this will be a wrteable transaction unless the system is in read-only mode.
+ * Create a transaction, this will be a wrteable transaction unless the system is in read-only mode. return
+ * UserTransaction
*
- * return UserTransaction
+ * @return the user transaction
*/
protected final UserTransaction createTransaction()
{
@@ -524,7 +624,10 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator implements
}
/**
- * Handle tidy up on container shutdown
+ * Handle tidy up on container shutdown.
+ *
+ * @throws Exception
+ * the exception
*/
public void destroy() throws Exception
{
diff --git a/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java b/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java
index 3bad9e2a8f..a1e39796c0 100644
--- a/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java
+++ b/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java
@@ -79,6 +79,7 @@ import org.alfresco.jlan.smb.server.VirtualCircuit;
import org.alfresco.jlan.util.DataPacker;
import org.alfresco.jlan.util.HexDump;
import org.alfresco.repo.security.authentication.NTLMMode;
+import org.alfresco.repo.security.authentication.ntlm.NLTMAuthenticator;
import org.ietf.jgss.Oid;
/**
@@ -390,12 +391,12 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement
// Make sure that either Kerberos support is enabled and/or the authentication component
// supports MD4 hashed passwords
- if (isKerberosEnabled() == false && getAuthenticationComponent().getNTLMMode() != NTLMMode.MD4_PROVIDER)
+ if (!isKerberosEnabled() && (!(getAuthenticationComponent() instanceof NLTMAuthenticator) || getNTLMAuthenticator().getNTLMMode() != NTLMMode.MD4_PROVIDER))
{
// Log an error
logger.error("No valid CIFS authentication combination available");
- logger.error("Either enable Kerberos support or use an authentication component that supports MD4 hashed passwords");
+ logger.error("Either enable Kerberos support or use an SSO-enabled authentication component that supports MD4 hashed passwords");
// Throw an exception to stop the CIFS server startup
@@ -1652,7 +1653,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement
// Check if we are using local MD4 password hashes or passthru authentication
- if ( getAuthenticationComponent().getNTLMMode() == NTLMMode.MD4_PROVIDER)
+ if ( getNTLMAuthenticator().getNTLMMode() == NTLMMode.MD4_PROVIDER)
{
// Get the NTLM logon details
@@ -1675,7 +1676,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement
// Get the stored MD4 hashed password for the user, or null if the user does not exist
- String md4hash = getAuthenticationComponent().getMD4HashedPassword(userName);
+ String md4hash = getNTLMAuthenticator().getMD4HashedPassword(userName);
if ( md4hash != null)
{
@@ -1778,7 +1779,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement
// Check if we are using local MD4 password hashes or passthru authentication
- if ( getAuthenticationComponent().getNTLMMode() == NTLMMode.MD4_PROVIDER)
+ if ( getNTLMAuthenticator().getNTLMMode() == NTLMMode.MD4_PROVIDER)
{
// Check for a null logon
@@ -1797,7 +1798,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement
// Get the stored MD4 hashed password for the user, or null if the user does not exist
- String md4hash = getAuthenticationComponent().getMD4HashedPassword(client.getUserName());
+ String md4hash = getNTLMAuthenticator().getMD4HashedPassword(client.getUserName());
if ( md4hash != null)
{
@@ -1903,7 +1904,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement
// Check if we are using local MD4 password hashes or passthru authentication
- if ( getAuthenticationComponent().getNTLMMode() == NTLMMode.MD4_PROVIDER)
+ if ( getNTLMAuthenticator().getNTLMMode() == NTLMMode.MD4_PROVIDER)
{
// Get the NTLM logon details
@@ -1926,7 +1927,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement
// Get the stored MD4 hashed password for the user, or null if the user does not exist
- String md4hash = getAuthenticationComponent().getMD4HashedPassword(userName);
+ String md4hash = getNTLMAuthenticator().getMD4HashedPassword(userName);
if ( md4hash != null)
{
@@ -2021,7 +2022,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement
{
// Check if we are using local MD4 password hashes or passthru authentication
- if ( getAuthenticationComponent().getNTLMMode() == NTLMMode.MD4_PROVIDER)
+ if ( getNTLMAuthenticator().getNTLMMode() == NTLMMode.MD4_PROVIDER)
{
// Check for a null logon
@@ -2040,7 +2041,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement
// Get the stored MD4 hashed password for the user, or null if the user does not exist
- String md4hash = getAuthenticationComponent().getMD4HashedPassword(client.getUserName());
+ String md4hash = getNTLMAuthenticator().getMD4HashedPassword(client.getUserName());
if ( md4hash != null)
{
@@ -2150,7 +2151,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement
// Check if we are using local MD4 password hashes or passthru authentication
- if ( getAuthenticationComponent().getNTLMMode() == NTLMMode.MD4_PROVIDER)
+ if ( getNTLMAuthenticator().getNTLMMode() == NTLMMode.MD4_PROVIDER)
{
// Get the NTLM logon details
@@ -2173,7 +2174,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement
// Get the stored MD4 hashed password for the user, or null if the user does not exist
- String md4hash = getAuthenticationComponent().getMD4HashedPassword(userName);
+ String md4hash = getNTLMAuthenticator().getMD4HashedPassword(userName);
if ( md4hash != null)
{
diff --git a/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java b/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java
index b45171dbec..77d7fa641c 100644
--- a/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java
+++ b/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java
@@ -65,7 +65,9 @@ import org.alfresco.jlan.smb.server.VirtualCircuit;
import org.alfresco.jlan.util.DataPacker;
import org.alfresco.jlan.util.HexDump;
import org.alfresco.model.ContentModel;
+import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.NTLMMode;
+import org.alfresco.repo.security.authentication.ntlm.NLTMAuthenticator;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -1144,7 +1146,9 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements
protected boolean validateAuthenticationMode()
{
// Check if the appropriate authentication component type is configured
- return getAuthenticationComponent().getNTLMMode() != NTLMMode.MD4_PROVIDER;
+ AuthenticationComponent authenticationComponent = getAuthenticationComponent();
+ return !(authenticationComponent instanceof NLTMAuthenticator)
+ || ((NLTMAuthenticator) authenticationComponent).getNTLMMode() != NTLMMode.MD4_PROVIDER;
}
/**
diff --git a/source/java/org/alfresco/filesys/auth/ftp/AlfrescoFtpAuthenticator.java b/source/java/org/alfresco/filesys/auth/ftp/AlfrescoFtpAuthenticator.java
index 16db583a38..7c9dcf72f7 100644
--- a/source/java/org/alfresco/filesys/auth/ftp/AlfrescoFtpAuthenticator.java
+++ b/source/java/org/alfresco/filesys/auth/ftp/AlfrescoFtpAuthenticator.java
@@ -34,9 +34,11 @@ import org.alfresco.jlan.ftp.FTPSrvSession;
import org.alfresco.jlan.server.SrvSession;
import org.alfresco.jlan.server.auth.ClientInfo;
import org.alfresco.jlan.server.auth.PasswordEncryptor;
+import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.MD4PasswordEncoder;
import org.alfresco.repo.security.authentication.MD4PasswordEncoderImpl;
import org.alfresco.repo.security.authentication.NTLMMode;
+import org.alfresco.repo.security.authentication.ntlm.NLTMAuthenticator;
/**
* Alfresco FTP Authenticator Class
@@ -155,9 +157,19 @@ public class AlfrescoFtpAuthenticator extends FTPAuthenticatorBase {
// DEBUG
- if ( logger.isDebugEnabled())
- logger.debug("Authenticated user " + client.getUserName() + " sts=" + authSts +
- " via " + (getAuthenticationComponent().getNTLMMode() == NTLMMode.MD4_PROVIDER ? "MD4" : "Passthru"));
+ if (logger.isDebugEnabled())
+ {
+ AuthenticationComponent authenticationComponent = getAuthenticationComponent();
+ logger
+ .debug("Authenticated user "
+ + client.getUserName()
+ + " sts="
+ + authSts
+ + " via "
+ + (authenticationComponent instanceof NLTMAuthenticator
+ && ((NLTMAuthenticator) authenticationComponent).getNTLMMode() == NTLMMode.MD4_PROVIDER ? "MD4"
+ : "Passthru"));
+ }
// Return the authentication status
diff --git a/source/java/org/alfresco/filesys/auth/ftp/FTPAuthenticatorBase.java b/source/java/org/alfresco/filesys/auth/ftp/FTPAuthenticatorBase.java
index cbfdf4a090..c884c1592a 100644
--- a/source/java/org/alfresco/filesys/auth/ftp/FTPAuthenticatorBase.java
+++ b/source/java/org/alfresco/filesys/auth/ftp/FTPAuthenticatorBase.java
@@ -35,7 +35,9 @@ import org.alfresco.jlan.server.auth.ClientInfo;
import org.alfresco.jlan.server.config.InvalidConfigurationException;
import org.alfresco.jlan.server.config.ServerConfiguration;
import org.alfresco.jlan.server.config.ServerConfigurationAccessor;
+import org.alfresco.repo.management.subsystems.ActivateableBean;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
+import org.alfresco.repo.security.authentication.ntlm.NLTMAuthenticator;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.transaction.TransactionService;
@@ -47,7 +49,7 @@ import org.springframework.beans.factory.DisposableBean;
*
* @author gkspencer
*/
-public abstract class FTPAuthenticatorBase implements FTPAuthenticator, DisposableBean {
+public abstract class FTPAuthenticatorBase implements FTPAuthenticator, ActivateableBean, DisposableBean {
// Logging
@@ -68,7 +70,10 @@ public abstract class FTPAuthenticatorBase implements FTPAuthenticator, Disposab
private AuthorityService authorityService;
- /**
+ /** Is this component active, i.e. should it be used? */
+ private boolean active = true;
+
+ /**
* Default constructor
*/
public FTPAuthenticatorBase() {
@@ -100,6 +105,26 @@ public abstract class FTPAuthenticatorBase implements FTPAuthenticator, Disposab
this.authorityService = authorityService;
}
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.ActivateableBean#isActive()
+ */
+ public boolean isActive()
+ {
+ return active;
+ }
+
+ /**
+ * Activates or deactivates the bean.
+ *
+ * @param active
+ * true
if the bean is active and initialization should complete
+ */
+ public void setActive(boolean active)
+ {
+ this.active = active;
+ }
+
/**
* Initialize the authenticator
*
@@ -162,7 +187,21 @@ public abstract class FTPAuthenticatorBase implements FTPAuthenticator, Disposab
return this.authenticationComponent;
}
- /**
+ /**
+ * Returns an SSO-enabled authentication component.
+ *
+ * @return NLTMAuthenticator
+ */
+ protected final NLTMAuthenticator getNTLMAuthenticator()
+ {
+ if (!(this.authenticationComponent instanceof NLTMAuthenticator))
+ {
+ throw new IllegalStateException("Attempt to use non SSO-enabled authentication component for SSO");
+ }
+ return (NLTMAuthenticator)this.authenticationComponent;
+ }
+
+ /**
* Return the authentication service
*
* @return AuthenticationService
diff --git a/source/java/org/alfresco/filesys/auth/ftp/PassthruFtpAuthenticator.java b/source/java/org/alfresco/filesys/auth/ftp/PassthruFtpAuthenticator.java
index 089d766999..194972a8eb 100644
--- a/source/java/org/alfresco/filesys/auth/ftp/PassthruFtpAuthenticator.java
+++ b/source/java/org/alfresco/filesys/auth/ftp/PassthruFtpAuthenticator.java
@@ -48,7 +48,9 @@ import org.alfresco.jlan.server.config.InvalidConfigurationException;
import org.alfresco.jlan.server.config.SecurityConfigSection;
import org.alfresco.jlan.server.config.ServerConfiguration;
import org.alfresco.jlan.util.IPAddress;
+import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.NTLMMode;
+import org.alfresco.repo.security.authentication.ntlm.NLTMAuthenticator;
/**
* Passthru FTP Authenticator Class
@@ -217,16 +219,17 @@ public class PassthruFtpAuthenticator extends FTPAuthenticatorBase {
public void initialize() throws InvalidConfigurationException
{
super.initialize();
-
- // Check if the appropriate authentication component type is configured
- if (getAuthenticationComponent().getNTLMMode() == NTLMMode.MD4_PROVIDER)
+ // Check if the appropriate authentication component type is configured
+ AuthenticationComponent authenticationComponent = getAuthenticationComponent();
+ if (authenticationComponent instanceof NLTMAuthenticator
+ && ((NLTMAuthenticator) authenticationComponent).getNTLMMode() == NTLMMode.MD4_PROVIDER)
throw new AlfrescoRuntimeException(
"Wrong authentication setup for passthru authenticator (cannot be used with Alfresco users)");
// Create the password encryptor
-
- m_passwordEncryptor = new PasswordEncryptor();
+
+ m_passwordEncryptor = new PasswordEncryptor();
}
/**
diff --git a/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java b/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java
index c68a3dacbe..a56d1349b4 100644
--- a/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java
+++ b/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java
@@ -80,6 +80,7 @@ import org.alfresco.jlan.util.MemorySize;
import org.alfresco.jlan.util.Platform;
import org.alfresco.jlan.util.StringList;
import org.alfresco.jlan.util.X64;
+import org.alfresco.repo.management.subsystems.ActivateableBean;
/**
* Alfresco File Server Configuration Bean Class
@@ -172,6 +173,15 @@ public class ServerConfigurationBean extends AbstractServerConfigurationBean
return;
}
+ // Before we go any further, let's make sure there's a compatible authenticator in the authentication chain.
+ ICifsAuthenticator authenticator = cifsConfigBean.getAuthenticator();
+ if (authenticator == null || authenticator instanceof ActivateableBean && !((ActivateableBean)authenticator).isActive())
+ {
+ logger.warn("No enabled CIFS authenticator found in authentication chain. CIFS Server disabled");
+ removeConfigSection(CIFSConfigSection.SectionName);
+ return;
+ }
+
// Create the CIFS server configuration section
CIFSConfigSection cifsConfig = new CIFSConfigSection(this);
@@ -343,7 +353,6 @@ public class ServerConfigurationBean extends AbstractServerConfigurationBean
// Get the authenticator
- ICifsAuthenticator authenticator = cifsConfigBean.getAuthenticator();
if (authenticator != null)
{
cifsConfig.setAuthenticator(authenticator);
diff --git a/source/java/org/alfresco/repo/management/DefaultManagedApplicationContextFactory.java b/source/java/org/alfresco/repo/management/DefaultManagedApplicationContextFactory.java
deleted file mode 100644
index 5160aba694..0000000000
--- a/source/java/org/alfresco/repo/management/DefaultManagedApplicationContextFactory.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * 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.management;
-
-import java.util.Properties;
-
-import org.alfresco.service.Managed;
-import org.alfresco.util.AbstractLifecycleBean;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.BeanNameAware;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
-import org.springframework.beans.factory.config.PropertiesFactoryBean;
-import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.context.ApplicationEvent;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-
-/**
- * A factory allowing initialisation of an entire 'subsystem' in a child application context. As with other
- * {@link ManagedBean}s, can be stopped, reconfigured, started and tested. Doesn't actually implement FactoryBean
- * because we need first class access to the factory itself to be able to configure its properties.
- */
-public class DefaultManagedApplicationContextFactory extends AbstractLifecycleBean implements
- ManagedApplicationContextFactory, InitializingBean, ApplicationContextAware, BeanNameAware
-{
- private static final long serialVersionUID = 6368629257690177326L;
- private ApplicationContext parent;
- private String beanName;
- private ClassPathXmlApplicationContext applicationContext;
- private Properties properties;
- private boolean autoStart;
-
- /*
- * (non-Javadoc)
- * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.
- * ApplicationContext)
- */
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
- {
- this.parent = applicationContext;
- super.setApplicationContext(applicationContext);
- }
-
- /*
- * (non-Javadoc)
- * @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String)
- */
- public void setBeanName(String name)
- {
- this.beanName = name;
- }
-
- /**
- * @param properties
- * the properties to set
- */
- @Managed(category = "management")
- public void setProperties(Properties properties)
- {
- this.properties = properties;
- }
-
- /**
- * @return the properties
- */
- public Properties getProperties()
- {
- return this.properties;
- }
-
- /**
- * @param autoStart
- * should the application context be started on startup of the parent application context?
- */
- public void setAutoStart(boolean autoStart)
- {
- this.autoStart = autoStart;
- }
-
- /*
- * (non-Javadoc)
- * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
- */
- public void afterPropertiesSet() throws Exception
- {
- PropertiesFactoryBean factory = new PropertiesFactoryBean();
- if (this.properties != null)
- {
- factory.setLocalOverride(true);
- factory.setProperties(this.properties);
- }
- factory.setLocations(this.parent.getResources("classpath*:alfresco/subsystems/" + this.beanName
- + "/*.properties"));
- factory.afterPropertiesSet();
- this.properties = (Properties) factory.getObject();
- }
-
- /*
- * (non-Javadoc)
- * @see org.alfresco.enterprise.repo.management.ConfigurableBean#onStart()
- */
- public void onStart()
- {
- this.applicationContext = new ClassPathXmlApplicationContext(new String[]
- {
- "classpath*:alfresco/subsystems/" + this.beanName + "/*-context.xml"
- }, false, this.parent);
-
- // Add a property placeholder configurer, with the subsystem-scoped default properties
- PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
- configurer.setProperties(this.properties);
- configurer.setIgnoreUnresolvablePlaceholders(true);
- this.applicationContext.addBeanFactoryPostProcessor(configurer);
-
- // Add all the post processors of the parent, e.g. to make sure system placeholders get expanded properly
- for (Object postProcessor : this.parent.getBeansOfType(BeanFactoryPostProcessor.class).values())
- {
- this.applicationContext.addBeanFactoryPostProcessor((BeanFactoryPostProcessor) postProcessor);
- }
-
- this.applicationContext.setClassLoader(parent.getClassLoader());
- this.applicationContext.refresh();
- }
-
- /*
- * (non-Javadoc)
- * @see org.alfresco.enterprise.repo.management.ConfigurableBean#onTest()
- */
- public void onTest()
- {
- this.applicationContext.getBean("testBean");
- }
-
- /*
- * (non-Javadoc)
- * @see org.springframework.beans.factory.DisposableBean#destroy()
- */
- public void destroy() throws Exception
- {
- if (this.applicationContext != null)
- {
- this.applicationContext.close();
- this.applicationContext = null;
- }
- }
-
- /*
- * (non-Javadoc)
- * @see org.alfresco.repo.management.ManagedApplicationContextFactory#getApplicationContext()
- */
- public synchronized ApplicationContext getApplicationContext()
- {
- if (this.applicationContext == null)
- {
- onStart();
- }
- return this.applicationContext;
- }
-
- /*
- * (non-Javadoc)
- * @see org.alfresco.util.AbstractLifecycleBean#onBootstrap(org.springframework.context.ApplicationEvent)
- */
- @Override
- protected void onBootstrap(ApplicationEvent event)
- {
- if (this.autoStart && this.applicationContext == null)
- {
- onStart();
- }
- }
-
- /*
- * (non-Javadoc)
- * @see org.alfresco.util.AbstractLifecycleBean#onShutdown(org.springframework.context.ApplicationEvent)
- */
- @Override
- protected void onShutdown(ApplicationEvent event)
- {
- }
-}
diff --git a/source/java/org/alfresco/repo/management/subsystems/AbstractPropertyBackedBean.java b/source/java/org/alfresco/repo/management/subsystems/AbstractPropertyBackedBean.java
new file mode 100644
index 0000000000..3060baba36
--- /dev/null
+++ b/source/java/org/alfresco/repo/management/subsystems/AbstractPropertyBackedBean.java
@@ -0,0 +1,148 @@
+/*
+ * 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.management.subsystems;
+
+import org.springframework.beans.factory.BeanNameAware;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+
+/**
+ * A base class for {@link PropertyBackedBean}s. Gets its category from its Spring bean name and automatically destroys
+ * itself on server shutdown. Communicates its creation and destruction to a {@link PropertyBackedBeanRegistry}.
+ *
+ * @author dward
+ */
+public abstract class AbstractPropertyBackedBean implements PropertyBackedBean, InitializingBean, DisposableBean,
+ BeanNameAware
+{
+
+ /** The default ID. */
+ protected static final String DEFAULT_ID = "default";
+
+ /** The registry. */
+ private PropertyBackedBeanRegistry registry;
+
+ /** The id. */
+ private String id = DEFAULT_ID;
+
+ /** The category. */
+ private String category;
+
+ /**
+ * Sets the registry.
+ *
+ * @param registry
+ * the registry to set
+ */
+ public void setRegistry(PropertyBackedBeanRegistry registry)
+ {
+ this.registry = registry;
+ }
+
+ /**
+ * Gets the registry.
+ *
+ * @return the registry
+ */
+ public PropertyBackedBeanRegistry getRegistry()
+ {
+ return registry;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String)
+ */
+ public void setBeanName(String name)
+ {
+ this.category = name;
+ }
+
+ /**
+ * Sets the id.
+ *
+ * @param id
+ * the id to set
+ */
+ public void setId(String id)
+ {
+ this.id = id;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
+ */
+ public void afterPropertiesSet() throws Exception
+ {
+ this.registry.register(this);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.SelfDescribingBean#getId()
+ */
+ public String getId()
+ {
+ return this.id;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.PropertyBackedBean#getCategory()
+ */
+ public String getCategory()
+ {
+ return this.category;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.DisposableBean#destroy()
+ */
+ public void destroy()
+ {
+ destroy(false);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.PropertyBackedBean#destroy(boolean)
+ */
+ public void destroy(boolean isPermanent)
+ {
+ stop();
+ this.registry.deregister(this, isPermanent);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.PropertyBackedBean#isUpdateable(java.lang.String)
+ */
+ public boolean isUpdateable(String name)
+ {
+ return true;
+ }
+}
diff --git a/source/java/org/alfresco/repo/management/subsystems/ActivateableBean.java b/source/java/org/alfresco/repo/management/subsystems/ActivateableBean.java
new file mode 100644
index 0000000000..268dc7f337
--- /dev/null
+++ b/source/java/org/alfresco/repo/management/subsystems/ActivateableBean.java
@@ -0,0 +1,44 @@
+/*
+ * 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.management.subsystems;
+
+/**
+ * An interface to be implemented by beans that can be 'turned off' by some configuration setting. When such beans are
+ * inactive, they will not perform any validation checks on initialization and will remain in a state where their
+ * {@link #isActive()} method always returns false
. {@link ChainingSubsystemProxyFactory} will ignore any
+ * ActivatableBean
s whose {@link #isActive()} method returns false
. This allows certain
+ * functions of a chained subsystem (e.g. CIFS authentication, SSO) to be targeted to specific members of the chain.
+ *
+ * @author dward
+ */
+public interface ActivateableBean
+{
+ /**
+ * Determines whether this bean is active.
+ *
+ * @return true
if this bean is active
+ */
+ public boolean isActive();
+}
diff --git a/source/java/org/alfresco/repo/management/ManagedApplicationContextFactory.java b/source/java/org/alfresco/repo/management/subsystems/ApplicationContextFactory.java
similarity index 74%
rename from source/java/org/alfresco/repo/management/ManagedApplicationContextFactory.java
rename to source/java/org/alfresco/repo/management/subsystems/ApplicationContextFactory.java
index 70b340d82e..95f5f9db69 100644
--- a/source/java/org/alfresco/repo/management/ManagedApplicationContextFactory.java
+++ b/source/java/org/alfresco/repo/management/subsystems/ApplicationContextFactory.java
@@ -22,19 +22,17 @@
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
-package org.alfresco.repo.management;
+package org.alfresco.repo.management.subsystems;
import org.springframework.context.ApplicationContext;
/**
- * An interface for {@link ManagedBean}s providing access to a child application context corresonding to a particular
- * subsystem. As with other {@link ManagedBean}s, can be stopped, reconfigured, started and tested. Doesn't actually
- * implement FactoryBean because we need first class access to the factory itself to be able to configure its
- * properties.
+ * An interface providing access to a child application context corresonding to a particular subsystem. As with other
+ * {@link PropertyBackedBean}s, can be stopped, reconfigured, started and tested.
*
* @author dward
*/
-public interface ManagedApplicationContextFactory extends ManagedBean
+public interface ApplicationContextFactory extends PropertyBackedBean
{
/**
* Gets the application context, configured according to the properties of the factory.
diff --git a/source/java/org/alfresco/repo/management/subsystems/ChainingSubsystemProxyFactory.java b/source/java/org/alfresco/repo/management/subsystems/ChainingSubsystemProxyFactory.java
new file mode 100644
index 0000000000..99828630c2
--- /dev/null
+++ b/source/java/org/alfresco/repo/management/subsystems/ChainingSubsystemProxyFactory.java
@@ -0,0 +1,190 @@
+/*
+ * 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.management.subsystems;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+import org.springframework.aop.framework.ProxyFactoryBean;
+import org.springframework.aop.support.DefaultPointcutAdvisor;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+
+/**
+ * A factory bean, used in conjunction with {@link ChildApplicationContextManager} allowing selected interfaces to be
+ * proxied to a chain of child application contexts. To decide the target of a particular method call, the returned
+ * proxy will search the application context chain in sequence and use the first one that has a bean of the required
+ * name or type that doesn't implement the {@link ActivatableBean} interface or whose whose
+ * {@link ActivateableBean#isActive()} method returns true
. This allows certain functions of a chained
+ * subsystem (e.g. CIFS authentication, SSO) to be targeted to specific members of the chain.
+ */
+public class ChainingSubsystemProxyFactory extends ProxyFactoryBean
+{
+ private static final long serialVersionUID = -2646392556551369220L;
+
+ /** The source application context manager. */
+ private ChildApplicationContextManager applicationContextManager;
+
+ /** An optional bean name to look up in the source application contexts. */
+ private String sourceBeanName;
+
+ /** An optional 'fallback' object for when a suitable one could not be found in the chain *. */
+ private Object defaultTarget;
+
+ /**
+ * Instantiates a new chaining subsystem proxy factory.
+ */
+ public ChainingSubsystemProxyFactory()
+ {
+ addAdvisor(new DefaultPointcutAdvisor(new MethodInterceptor()
+ {
+ public Object invoke(MethodInvocation mi) throws Throwable
+ {
+ Method method = mi.getMethod();
+ try
+ {
+ for (String instance : applicationContextManager.getInstanceIds())
+ {
+ if (ChainingSubsystemProxyFactory.this.sourceBeanName == null)
+ {
+ Map, ?> beans = ChainingSubsystemProxyFactory.this.applicationContextManager
+ .getApplicationContext(instance).getBeansOfType(method.getDeclaringClass());
+ Object activeBean = null;
+ for (Object bean : beans.values())
+ {
+ // Ignore inactive beans
+ if (!(bean instanceof ActivateableBean) || ((ActivateableBean) bean).isActive())
+ {
+ if (activeBean == null)
+ {
+ activeBean = bean;
+ }
+ else
+ {
+ throw new RuntimeException("Don't know where to route call to method " + method
+ + ": multiple active beans in context " + instance);
+ }
+ }
+ }
+ if (activeBean != null)
+ {
+ return method.invoke(activeBean, mi.getArguments());
+ }
+ }
+ else
+ {
+ try
+ {
+ Object bean = ChainingSubsystemProxyFactory.this.applicationContextManager
+ .getApplicationContext(instance).getBean(
+ ChainingSubsystemProxyFactory.this.sourceBeanName);
+
+ // Ignore inactive beans
+ if (!(bean instanceof ActivateableBean) || ((ActivateableBean) bean).isActive())
+ {
+ return method.invoke(bean, mi.getArguments());
+ }
+ }
+ catch (NoSuchBeanDefinitionException e)
+ {
+ // Ignore and continue
+ }
+ }
+ }
+
+ // Fall back to the default object if we have one
+ if (defaultTarget != null && method.getDeclaringClass().isAssignableFrom(defaultTarget.getClass()))
+ {
+ return method.invoke(defaultTarget, mi.getArguments());
+ }
+
+ // If this is the isActive() method, we can handle it ourselves!
+ if (method.equals(ActivateableBean.class.getMethod("isActive")))
+ {
+ return Boolean.FALSE;
+ }
+
+ // Otherwise, something has gone wrong with wiring!
+ throw new RuntimeException("Don't know where to route call to method " + method);
+ }
+ catch (InvocationTargetException e)
+ {
+ // Unwrap invocation target exceptions
+ throw e.getTargetException();
+ }
+ }
+ }));
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.aop.framework.AdvisedSupport#setInterfaces(java.lang.Class[])
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public void setInterfaces(Class[] interfaces)
+ {
+ super.setInterfaces(interfaces);
+ // Make it possible to export the object via JMX
+ setTargetClass(getObjectType());
+ }
+
+ /**
+ * Sets the application context manager.
+ *
+ * @param applicationContextManager
+ * the new application context manager
+ */
+ public void setApplicationContextManager(ChildApplicationContextManager applicationContextManager)
+ {
+ this.applicationContextManager = applicationContextManager;
+ }
+
+ /**
+ * Sets an optional bean name to target all calls to in the source application context. If not set, an appropriate
+ * bean is looked up based on method class.
+ *
+ * @param sourceBeanName
+ * the sourceBeanName to set
+ */
+ public void setSourceBeanName(String sourceBeanName)
+ {
+ this.sourceBeanName = sourceBeanName;
+ }
+
+ /**
+ * Sets the default target for method calls, when a suitable target cannot be found in the application context
+ * chain.
+ *
+ * @param defaultTarget
+ * the defaultTarget to set
+ */
+ public void setDefaultTarget(Object defaultTarget)
+ {
+ this.defaultTarget = defaultTarget;
+ }
+}
diff --git a/source/java/org/alfresco/repo/management/subsystems/ChildApplicationContextFactory.java b/source/java/org/alfresco/repo/management/subsystems/ChildApplicationContextFactory.java
new file mode 100644
index 0000000000..902aee8a2e
--- /dev/null
+++ b/source/java/org/alfresco/repo/management/subsystems/ChildApplicationContextFactory.java
@@ -0,0 +1,369 @@
+/*
+ * 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.management.subsystems;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.PropertiesFactoryBean;
+import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.core.io.Resource;
+
+/**
+ * A factory allowing initialization of an entire 'subsystem' in a child application context. As with other
+ * {@link PropertyBackedBean}s, can be stopped, reconfigured, started and tested. Each instance possesses a
+ * typeName
property, that determines where the factory will look for default configuration for the
+ * application context. In addition, its id
property will determine where the factory will look for
+ * override configuration in the extension classpath.
+ *
+ * The factory will search for a Spring application context in the classpath using the following patterns in order:
+ *
+ * - alfresco/subsystems/<category>/<typeName>/*-context.xml
+ * - alfresco/extension/subsystems/<category>/<typeName>/<id/*-context.xml
+ *
+ * The child application context may use ${}
placeholders, and will be configured with a
+ * {@link PropertyPlaceholderConfigurer} initialised with properties files found in classpath matching the following
+ * patterns in order:
+ *
+ * - alfresco/subsystems/<category>/<typeName>/*.properties
+ * - alfresco/extension/subsystems/<category>/<typeName>/<id/*.properties
+ *
+ * This means that the extension classpath can be used to provide instance-specific overrides to product default
+ * settings. Of course, if you are using the Enterprise edition, you might want to use a JMX client such as JConsole to
+ * edit the settings instead!
+ */
+public class ChildApplicationContextFactory extends AbstractPropertyBackedBean implements ApplicationContextAware,
+ ApplicationListener, ApplicationContextFactory
+{
+
+ /** The name of the special read-only property containing the type name. */
+ private static final String TYPE_NAME_PROPERTY = "$type";
+
+ /** The Constant PROPERTIES_SUFFIX. */
+ private static final String PROPERTIES_SUFFIX = "/*.properties";
+
+ /** The Constant CONTEXT_SUFFIX. */
+ private static final String CONTEXT_SUFFIX = "/*-context.xml";
+
+ /** The Constant CLASSPATH_PREFIX. */
+ private static final String CLASSPATH_PREFIX = "classpath*:alfresco/subsystems/";
+
+ /** The Constant EXTENSION_CLASSPATH_PREFIX. */
+ private static final String EXTENSION_CLASSPATH_PREFIX = "classpath*:alfresco/extension/subsystems/";
+
+ /** The logger. */
+ private static Log logger = LogFactory.getLog(ChildApplicationContextFactory.class);
+
+ /** The parent. */
+ private ApplicationContext parent;
+
+ /** The properties. */
+ private Properties properties;
+
+ /** The application context. */
+ private ClassPathXmlApplicationContext applicationContext;
+
+ /** The auto start. */
+ private boolean autoStart;
+
+ /** The type name. */
+ private String typeName;
+
+ /**
+ * Default constructor for container construction.
+ */
+ protected ChildApplicationContextFactory()
+ {
+ }
+
+ /**
+ * Constructor for dynamically created instances, e.g. through {@link DefaultChildApplicationContextManager}.
+ *
+ * @param parent
+ * the parent application context
+ * @param registry
+ * the registry of property backed beans
+ * @param category
+ * the category
+ * @param typeName
+ * the type name
+ * @param id
+ * the instance id
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ */
+ public ChildApplicationContextFactory(ApplicationContext parent, PropertyBackedBeanRegistry registry,
+ String category, String typeName, String id) throws IOException
+ {
+ setApplicationContext(parent);
+ setRegistry(registry);
+ setBeanName(category);
+ setTypeName(typeName);
+ setId(id);
+
+ try
+ {
+ afterPropertiesSet();
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.
+ * ApplicationContext)
+ */
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
+ {
+ this.parent = applicationContext;
+ }
+
+ /**
+ * Indicates whether the application context be started on startup of the parent application context.
+ *
+ * @param autoStart
+ * true
if the application context should be started on startup of the parent application
+ * context
+ */
+ public void setAutoStart(boolean autoStart)
+ {
+ this.autoStart = autoStart;
+ }
+
+ /**
+ * Sets the type name.
+ *
+ * @param typeName
+ * the typeName to set
+ */
+ public void setTypeName(String typeName)
+ {
+ this.typeName = typeName;
+ }
+
+ /**
+ * Gets the type name.
+ *
+ * @return the type name
+ */
+ public String getTypeName()
+ {
+ return this.typeName;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
+ */
+ @Override
+ public void afterPropertiesSet() throws Exception
+ {
+ if (getTypeName() == null)
+ {
+ setTypeName(getId());
+ }
+
+ // Load the property defaults
+ PropertiesFactoryBean factory = new PropertiesFactoryBean();
+
+ Resource[] baseResources = this.parent.getResources(ChildApplicationContextFactory.CLASSPATH_PREFIX
+ + getCategory() + '/' + getTypeName() + ChildApplicationContextFactory.PROPERTIES_SUFFIX);
+ // Allow overrides from the extension classpath
+ Resource[] extensionResources = this.parent
+ .getResources(ChildApplicationContextFactory.EXTENSION_CLASSPATH_PREFIX + getCategory() + '/'
+ + getTypeName() + '/' + getId() + '/' + ChildApplicationContextFactory.PROPERTIES_SUFFIX);
+ Resource[] combinedResources;
+ if (baseResources.length == 0)
+ {
+ combinedResources = extensionResources;
+ }
+ else if (extensionResources.length == 0)
+ {
+ combinedResources = baseResources;
+ }
+ else
+ {
+ combinedResources = new Resource[baseResources.length + extensionResources.length];
+ System.arraycopy(baseResources, 0, combinedResources, 0, baseResources.length);
+ System.arraycopy(extensionResources, 0, combinedResources, baseResources.length, extensionResources.length);
+ }
+ factory.setLocations(combinedResources);
+ factory.afterPropertiesSet();
+ this.properties = (Properties) factory.getObject();
+
+ super.afterPropertiesSet();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.PropertyBackedBean#getPropertyNames()
+ */
+ @SuppressWarnings("unchecked")
+ public synchronized Set getPropertyNames()
+ {
+ Set result = new TreeSet(((Map) this.properties).keySet());
+ result.add(ChildApplicationContextFactory.TYPE_NAME_PROPERTY);
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.PropertyBackedBean#getProperty(java.lang.String)
+ */
+ public synchronized String getProperty(String name)
+ {
+ if (name.equals(ChildApplicationContextFactory.TYPE_NAME_PROPERTY))
+ {
+ return getTypeName();
+ }
+ else
+ {
+ return this.properties.getProperty(name);
+ }
+
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.PropertyBackedBean#setProperty(java.lang.String, java.lang.String)
+ */
+ public void setProperty(String name, String value)
+ {
+ if (name.equals(ChildApplicationContextFactory.TYPE_NAME_PROPERTY))
+ {
+ throw new IllegalStateException("Illegal write to property \""
+ + ChildApplicationContextFactory.TYPE_NAME_PROPERTY + "\"");
+ }
+ if (value == null)
+ {
+ this.properties.remove(name);
+ }
+ else
+ {
+ this.properties.setProperty(name, value);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.AbstractPropertyBackedBean#isUpdateable(java.lang.String)
+ */
+ @Override
+ public boolean isUpdateable(String name)
+ {
+ // Only the type property is read only
+ return !name.equals(ChildApplicationContextFactory.TYPE_NAME_PROPERTY);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.PropertyBackedBean#start()
+ */
+ public synchronized void start()
+ {
+ this.applicationContext = new ClassPathXmlApplicationContext(new String[]
+ {
+ ChildApplicationContextFactory.CLASSPATH_PREFIX + getCategory() + '/' + getTypeName()
+ + ChildApplicationContextFactory.CONTEXT_SUFFIX,
+ ChildApplicationContextFactory.EXTENSION_CLASSPATH_PREFIX + getCategory() + '/' + getTypeName() + '/'
+ + getId() + '/' + ChildApplicationContextFactory.CONTEXT_SUFFIX
+ }, false, this.parent);
+
+ // Add a property placeholder configurer, with the subsystem-scoped default properties
+ PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
+ configurer.setProperties(this.properties);
+ configurer.setIgnoreUnresolvablePlaceholders(true);
+ this.applicationContext.addBeanFactoryPostProcessor(configurer);
+
+ // Add all the post processors of the parent, e.g. to make sure system placeholders get expanded properly
+ for (Object postProcessor : this.parent.getBeansOfType(BeanFactoryPostProcessor.class).values())
+ {
+ this.applicationContext.addBeanFactoryPostProcessor((BeanFactoryPostProcessor) postProcessor);
+ }
+
+ this.applicationContext.setClassLoader(this.parent.getClassLoader());
+ this.applicationContext.refresh();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.PropertyBackedBean#stop()
+ */
+ public void stop()
+ {
+ if (this.applicationContext != null)
+ {
+ this.applicationContext.close();
+ this.applicationContext = null;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.ManagedApplicationContextFactory#getApplicationContext()
+ */
+ public synchronized ApplicationContext getApplicationContext()
+ {
+ if (this.applicationContext == null)
+ {
+ start();
+ }
+ return this.applicationContext;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
+ */
+ public void onApplicationEvent(ApplicationEvent event)
+ {
+ // Automatically refresh the application context on boot up, if required
+ if (this.autoStart && event instanceof ContextRefreshedEvent && event.getSource() == this.parent)
+ {
+ getApplicationContext();
+ }
+ }
+}
diff --git a/source/java/org/alfresco/repo/management/subsystems/ChildApplicationContextManager.java b/source/java/org/alfresco/repo/management/subsystems/ChildApplicationContextManager.java
new file mode 100644
index 0000000000..f82b219438
--- /dev/null
+++ b/source/java/org/alfresco/repo/management/subsystems/ChildApplicationContextManager.java
@@ -0,0 +1,55 @@
+/*
+ * 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.management.subsystems;
+
+import java.util.Collection;
+
+import org.springframework.context.ApplicationContext;
+
+/**
+ * A ChildApplicationContextManager
manages a 'chain' of child application contexts, perhaps corresponding
+ * to the components of a chained subsystem such as authentication. A ChildApplicationContextManager
may
+ * also support the dynamic modification of its chain.
+ *
+ * @author dward
+ */
+public interface ChildApplicationContextManager
+{
+ /**
+ * Gets the ordered collection of identifiers, indicating the ordering of the chain.
+ *
+ * @return an ordered collection of identifiers, indicating the ordering of the chain.
+ */
+ public Collection getInstanceIds();
+
+ /**
+ * Gets the application context with the given identifier.
+ *
+ * @param id
+ * the identifier of the application context to retrieve
+ * @return the application context with the given identifier
+ */
+ public ApplicationContext getApplicationContext(String id);
+}
diff --git a/source/java/org/alfresco/repo/management/subsystems/DefaultChildApplicationContextManager.java b/source/java/org/alfresco/repo/management/subsystems/DefaultChildApplicationContextManager.java
new file mode 100644
index 0000000000..def9255de0
--- /dev/null
+++ b/source/java/org/alfresco/repo/management/subsystems/DefaultChildApplicationContextManager.java
@@ -0,0 +1,352 @@
+/*
+ * 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.management.subsystems;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextRefreshedEvent;
+
+/**
+ * A default {@link ChildApplicationContextManager} implementation that manages a 'chain' of
+ * {@link ChildApplicationContextFactory} objects, perhaps corresponding to the components of a chained subsystem such
+ * as authentication. As with other {@link PropertyBackedBean}s, can be stopped, reconfigured, started and tested. Its
+ * one special chain
property allows an ordered list of {@link ChildApplicationContextFactory} objects to
+ * be managed. This property is a comma separated list with the format:
+ *
+ * - <id1>:<typeName1>,<id2>:<typeName2>,...,<idn>:<typeNamen>
+ *
+ * See {@link ChildApplicationContextManager} for the meanings of <id> and <typeName>. In the enterprise edition,
+ * this property is editable at runtime via JMX. If a new <id> is included in the list then a new
+ * {@link ChildApplicationContextFactory} will be brought into existence. Similarly, if one is removed from the list,
+ * then the corresponding instance will be destroyed. For Alfresco community edition, the chain is best configured
+ * through the {@link #setDefaultChain(String)} method via Spring configuration.
+ *
+ * @author dward
+ */
+public class DefaultChildApplicationContextManager extends AbstractPropertyBackedBean implements
+ ApplicationContextAware, ApplicationListener, ChildApplicationContextManager
+{
+
+ /** The name of the special property that holds the ordering of child instance names. */
+ private static final String ORDER_PROPERTY = "chain";
+
+ /** The parent. */
+ private ApplicationContext parent;
+
+ /** The default type name. */
+ private String defaultTypeName;
+
+ /** The default chain. */
+ private String defaultChain;
+
+ /** The instance ids. */
+ private List instanceIds = new ArrayList(10);
+
+ /** The child application contexts. */
+ private Map childApplicationContexts = new TreeMap();
+
+ /** The auto start. */
+ private boolean autoStart;
+
+ /**
+ * Instantiates a new default child application context manager.
+ */
+ public DefaultChildApplicationContextManager()
+ {
+ setId("manager");
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.
+ * ApplicationContext)
+ */
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
+ {
+ this.parent = applicationContext;
+ }
+
+ /**
+ * Sets the default type name. This is used when a type name is not included after an instance ID in a chain string.
+ *
+ * @param defaultTypeName
+ * the new default type name
+ */
+ public void setDefaultTypeName(String defaultTypeName)
+ {
+ this.defaultTypeName = defaultTypeName;
+ }
+
+ /**
+ * Configures the default chain of {@link ChildApplicationContextFactory} instances. May be set on initialization by
+ * the Spring container.
+ *
+ * @param defaultChain
+ * a comma separated list in the following format:
+ *
+ * - <id1>:<typeName1>,<id2>:<typeName2>,...,<idn>:<typeNamen>
+ *
+ */
+ public void setDefaultChain(String defaultChain)
+ {
+ this.defaultChain = defaultChain;
+ }
+
+ /**
+ * Indicates whether all child application contexts should be started on startup of the parent application context.
+ *
+ * @param autoStart
+ * true
if all child application contexts should be started on startup of the parent
+ * application context
+ */
+ public void setAutoStart(boolean autoStart)
+ {
+ this.autoStart = autoStart;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.AbstractPropertyBackedBean#afterPropertiesSet()
+ */
+ @Override
+ public void afterPropertiesSet() throws Exception
+ {
+ if (this.defaultChain != null && this.defaultChain.length() > 0)
+ {
+ // Use the first type as the default, unless one is specified explicitly
+ if (this.defaultTypeName == null)
+ {
+ updateOrder(this.defaultChain, AbstractPropertyBackedBean.DEFAULT_ID);
+ this.defaultTypeName = this.childApplicationContexts.get(this.instanceIds.get(0)).getTypeName();
+ }
+ else
+ {
+ updateOrder(this.defaultChain, this.defaultTypeName);
+ }
+ }
+ else if (this.defaultTypeName == null)
+ {
+ setDefaultTypeName(AbstractPropertyBackedBean.DEFAULT_ID);
+ }
+
+ super.afterPropertiesSet();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.PropertyBackedBean#start()
+ */
+ public void start()
+ {
+ // Nothing to do
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.PropertyBackedBean#stop()
+ */
+ public void stop()
+ {
+ // Nothing to do
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.AbstractPropertyBackedBean#destroy(boolean)
+ */
+ @Override
+ public void destroy(boolean permanent)
+ {
+ super.destroy(permanent);
+
+ // Cascade the destroy / shutdown
+ for (String id : this.instanceIds)
+ {
+ ChildApplicationContextFactory factory = this.childApplicationContexts.get(id);
+ factory.destroy(permanent);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.PropertyBackedBean#getProperty(java.lang.String)
+ */
+ public synchronized String getProperty(String name)
+ {
+ if (!name.equals(DefaultChildApplicationContextManager.ORDER_PROPERTY))
+ {
+ return null;
+ }
+ return getOrderString();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.PropertyBackedBean#getPropertyNames()
+ */
+ public Set getPropertyNames()
+ {
+ return Collections.singleton(DefaultChildApplicationContextManager.ORDER_PROPERTY);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.PropertyBackedBean#setProperty(java.lang.String, java.lang.String)
+ */
+ public synchronized void setProperty(String name, String value)
+ {
+ if (!name.equals(DefaultChildApplicationContextManager.ORDER_PROPERTY))
+ {
+ throw new IllegalStateException("Illegal attempt to write to property \"" + name + "\"");
+ }
+ updateOrder(value, this.defaultTypeName);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.ChildApplicationContextManager#getInstanceIds()
+ */
+ public synchronized Collection getInstanceIds()
+ {
+ return Collections.unmodifiableList(this.instanceIds);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.management.ChildApplicationContextManager#getApplicationContext(java.lang.String)
+ */
+ public synchronized ApplicationContext getApplicationContext(String id)
+ {
+ ChildApplicationContextFactory child = this.childApplicationContexts.get(id);
+ return child == null ? null : child.getApplicationContext();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
+ */
+ public void onApplicationEvent(ApplicationEvent event)
+ {
+ if (this.autoStart && event instanceof ContextRefreshedEvent && event.getSource() == this.parent)
+ {
+ for (String instance : getInstanceIds())
+ {
+ getApplicationContext(instance);
+ }
+ }
+ }
+
+ /**
+ * Gets the order string.
+ *
+ * @return the order string
+ */
+ private String getOrderString()
+ {
+ StringBuilder orderString = new StringBuilder(100);
+ for (String id : this.instanceIds)
+ {
+ if (orderString.length() > 0)
+ {
+ orderString.append(",");
+ }
+ orderString.append(id).append(':').append(this.childApplicationContexts.get(id).getTypeName());
+ }
+ return orderString.toString();
+ }
+
+ /**
+ * Updates the order from a comma or whitespace separated string.
+ *
+ * @param orderString
+ * the order as a comma or whitespace separated string
+ * @param defaultTypeName
+ * the default type name
+ */
+ private void updateOrder(String orderString, String defaultTypeName)
+ {
+ try
+ {
+ StringTokenizer tkn = new StringTokenizer(orderString, ", \t\n\r\f");
+ List newInstanceIds = new ArrayList(tkn.countTokens());
+ while (tkn.hasMoreTokens())
+ {
+ String instance = tkn.nextToken();
+ int sepIndex = instance.indexOf(':');
+ String id = sepIndex == -1 ? instance : instance.substring(0, sepIndex);
+ String typeName = sepIndex == -1 || sepIndex + 1 >= instance.length() ? defaultTypeName : instance
+ .substring(sepIndex + 1);
+ newInstanceIds.add(id);
+
+ // Look out for new or updated children
+ ChildApplicationContextFactory factory = this.childApplicationContexts.get(id);
+
+ // If we have the same instance ID but a different type, treat that as a destroy and remove
+ if (factory != null && !factory.getTypeName().equals(typeName))
+ {
+ factory.destroy(true);
+ factory = null;
+ }
+ if (factory == null)
+ {
+ this.childApplicationContexts.put(id, new ChildApplicationContextFactory(this.parent,
+ getRegistry(), getCategory(), typeName, "managed$" + id));
+ }
+ }
+
+ // Destroy any children that have been removed
+ Set idsToRemove = new TreeSet(this.childApplicationContexts.keySet());
+ idsToRemove.removeAll(newInstanceIds);
+ for (String id : idsToRemove)
+ {
+ ChildApplicationContextFactory factory = this.childApplicationContexts.remove(id);
+ factory.destroy(true);
+ }
+ this.instanceIds = newInstanceIds;
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/source/java/org/alfresco/repo/management/subsystems/DefaultPropertyBackedBeanRegistry.java b/source/java/org/alfresco/repo/management/subsystems/DefaultPropertyBackedBeanRegistry.java
new file mode 100644
index 0000000000..008f512281
--- /dev/null
+++ b/source/java/org/alfresco/repo/management/subsystems/DefaultPropertyBackedBeanRegistry.java
@@ -0,0 +1,127 @@
+/*
+ * 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.management.subsystems;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.alfresco.repo.domain.schema.SchemaAvailableEvent;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationListener;
+
+/**
+ * A default implementation of {@link PropertyBackedBeanRegistry}. An instance of this class will defer broadcasting
+ * {@link PropertyBackedBeanEvent}s until it is notified that the database schema is available via a
+ * {@link SchemaAvailableEvent}. This allows listeners to potentially reconfigure the beans using persisted database
+ * information.
+ *
+ * @author dward
+ */
+public class DefaultPropertyBackedBeanRegistry implements PropertyBackedBeanRegistry, ApplicationListener
+{
+ /** Is the database schema available yet? */
+ private boolean isSchemaAvailable;
+
+ /** Events deferred until the database schema is available. */
+ private List deferredEvents = new LinkedList();
+
+ /** Registered listeners. */
+ private List listeners = new LinkedList();
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * org.alfresco.repo.management.PropertyBackedBeanRegistry#addListener(org.springframework.context.ApplicationListener
+ * )
+ */
+ public void addListener(ApplicationListener listener)
+ {
+ this.listeners.add(listener);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * org.alfresco.repo.management.PropertyBackedBeanRegistry#register(org.alfresco.repo.management.PropertyBackedBean)
+ */
+ public void register(PropertyBackedBean bean)
+ {
+ broadcastEvent(new PropertyBackedBeanRegisteredEvent(bean));
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * org.alfresco.repo.management.subsystems.PropertyBackedBeanRegistry#deregister(org.alfresco.repo.management.subsystems
+ * .PropertyBackedBean, boolean)
+ */
+ public void deregister(PropertyBackedBean bean, boolean isPermanent)
+ {
+ broadcastEvent(new PropertyBackedBeanUnregisteredEvent(bean, isPermanent));
+ }
+
+ /**
+ * Broadcast event.
+ *
+ * @param event
+ * the event
+ */
+ private void broadcastEvent(PropertyBackedBeanEvent event)
+ {
+ // If the system is up and running, broadcast the event immediately
+ if (this.isSchemaAvailable)
+ {
+ for (ApplicationListener listener : this.listeners)
+ {
+ listener.onApplicationEvent(event);
+ }
+ }
+ // Otherwise, defer broadcasting until the schema available event is handled
+ else
+ {
+ this.deferredEvents.add(event);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
+ */
+ public void onApplicationEvent(ApplicationEvent event)
+ {
+ if (event instanceof SchemaAvailableEvent)
+ {
+ this.isSchemaAvailable = true;
+
+ // Broadcast all the events we had been deferring until this event
+ for (PropertyBackedBeanEvent event1 : this.deferredEvents)
+ {
+ broadcastEvent(event1);
+ }
+ this.deferredEvents.clear();
+ }
+ }
+}
diff --git a/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBean.java b/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBean.java
new file mode 100644
index 0000000000..854b372da7
--- /dev/null
+++ b/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBean.java
@@ -0,0 +1,111 @@
+/*
+ * 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.management.subsystems;
+
+import java.util.Set;
+
+/**
+ * A PropertyBackedBean
is a reconfigurable sub-component or subsystem in the Alfresco server. It exposes
+ * configurable properties, along with {@link #stop()}, {@link #start()} and {@link #destroy(boolean)} methods. To
+ * reconfigure a bean, first ensure it is stopped by calling {@link #stop()}. Then set one or more properties. Then test
+ * out the changes with {@link #start()}. To bring the bean instance out of play (e.g. on server shutdown) call
+ * {@link #destroy(boolean)}. In the Alfresco enterprise edition PropertyBackedBean
s are exposed as
+ * persistent MBeans and can be reconfigured at runtime via JMX.
+ *
+ * @author dward
+ */
+public interface PropertyBackedBean
+{
+ /**
+ * Gets a human readable categorization of this bean, explaining its purpose. This category may be used e.g. in
+ * administration UIs and JMX object names.
+ *
+ * @return the category
+ */
+ public String getCategory();
+
+ /**
+ * Gets an identifier for the bean. Must be unique within the category.
+ *
+ * @return the id
+ */
+ public String getId();
+
+ /**
+ * Gets the names of all properties.
+ *
+ * @return the property names
+ */
+ public Set getPropertyNames();
+
+ /**
+ * Gets a property value.
+ *
+ * @param name
+ * the name
+ * @return the property value
+ */
+ public String getProperty(String name);
+
+ /**
+ * Sets the value of a property. This may only be called after {@link #stop()} and should only be called for
+ * property names for which the {@link #isUpdateable(String)} method returns true
.
+ *
+ * @param name
+ * the property name
+ * @param value
+ * the property value
+ */
+ public void setProperty(String name, String value);
+
+ /**
+ * Checks if a property is updateable.
+ *
+ * @param name
+ * the property name
+ * @return true
if the property is updateable
+ */
+ public boolean isUpdateable(String name);
+
+ /**
+ * Starts up the component, using its new property values.
+ */
+ public void start();
+
+ /**
+ * Stops the component, so that its property values can be changed.
+ */
+ public void stop();
+
+ /**
+ * Releases any resources held by this component.
+ *
+ * @param isPermanent
+ * is the component being destroyed forever, i.e. should persisted values be removed? On server shutdown,
+ * this value would be false
, whereas on the removal of a dynamically created instance, this
+ * value would be true
.
+ */
+ public void destroy(boolean isPermanent);
+}
diff --git a/source/java/org/alfresco/repo/management/ManagedBean.java b/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanEvent.java
similarity index 62%
rename from source/java/org/alfresco/repo/management/ManagedBean.java
rename to source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanEvent.java
index 42489b36d5..a723ec80ef 100644
--- a/source/java/org/alfresco/repo/management/ManagedBean.java
+++ b/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanEvent.java
@@ -22,26 +22,39 @@
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
-package org.alfresco.repo.management;
+package org.alfresco.repo.management.subsystems;
-import org.springframework.beans.factory.DisposableBean;
+import org.springframework.context.ApplicationEvent;
/**
- * An interface for beans that can be reconfigured using an administration UI or JMX console. A bean in use must be
- * 'stopped' before it can be configured with {@link #destroy}. After reconfiguration, it can then be put back into use
- * with {@link #onStart} and if this is successful, further tests can be carried out with {@link #onTest}.
+ * A base class for events emitted by {@link PropertyBackedBean}s.
*
* @author dward
*/
-public interface ManagedBean extends DisposableBean
+public abstract class PropertyBackedBeanEvent extends ApplicationEvent
{
- /**
- * Puts the bean into use after its properties have been set.
- */
- public void onStart();
+
+ private static final long serialVersionUID = 1848914557290327762L;
/**
- * Carries out tests on the bean after it has been started.
+ * The Constructor.
+ *
+ * @param source
+ * the source of the event
*/
- public void onTest();
+ public PropertyBackedBeanEvent(PropertyBackedBean source)
+ {
+ super(source);
+ }
+
+ /**
+ * Gets the bean that emitted the event.
+ *
+ * @return the bean
+ */
+ public PropertyBackedBean getBean()
+ {
+ return (PropertyBackedBean) getSource();
+ }
+
}
diff --git a/source/java/org/alfresco/service/Managed.java b/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanRegisteredEvent.java
similarity index 68%
rename from source/java/org/alfresco/service/Managed.java
rename to source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanRegisteredEvent.java
index 13f4427724..af452b5501 100644
--- a/source/java/org/alfresco/service/Managed.java
+++ b/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanRegisteredEvent.java
@@ -22,28 +22,26 @@
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
-package org.alfresco.service;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
+package org.alfresco.repo.management.subsystems;
/**
- * A Marker annotation for setter methods we want to be exposed through JMX.
+ * An event emitted after a {@link PropertyBackedBean} is initialized.
*
* @author dward
*/
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface Managed
+public class PropertyBackedBeanRegisteredEvent extends PropertyBackedBeanEvent
{
+ private static final long serialVersionUID = -5922059120018335685L;
+
/**
- * A textual label used to group related beans together
+ * The Constructor.
*
- * @return the category
+ * @param source
+ * the source of the event
*/
- String category();
+ public PropertyBackedBeanRegisteredEvent(PropertyBackedBean source)
+ {
+ super(source);
+ }
+
}
diff --git a/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanRegistry.java b/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanRegistry.java
new file mode 100644
index 0000000000..bd1b7fbbf6
--- /dev/null
+++ b/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanRegistry.java
@@ -0,0 +1,67 @@
+/*
+ * 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.management.subsystems;
+
+import org.springframework.context.ApplicationListener;
+
+/**
+ * An object that tracks the initialization and destruction of {@link PropertyBackedBean} instances. A
+ * PropertyBackedBean
should call {@link #register(PropertyBackedBean)} after initialization and
+ * {@link #deregister(PropertyBackedBean, boolean)} when discarded. Other classes may register for notification of these
+ * events by calling {@link #addListener(ApplicationListener)}.
+ *
+ * @author dward
+ */
+public interface PropertyBackedBeanRegistry
+{
+ /**
+ * Registers a listener object that will be notified of register and deregister calls via a
+ * {@link PropertyBackedBeanEvent}.
+ *
+ * @param listener
+ * the listener
+ */
+ public void addListener(ApplicationListener listener);
+
+ /**
+ * Signals that a {@link PropertyBackedBean} has been initialized.
+ *
+ * @param bean
+ * the bean
+ */
+ public void register(PropertyBackedBean bean);
+
+ /**
+ * Signals that {@link PropertyBackedBean#destroy(boolean)} has been called on a bean.
+ *
+ * @param bean
+ * the bean
+ * @param isPermanent
+ * is the component being destroyed forever, i.e. should persisted values be removed? On server shutdown,
+ * this value would be false
, whereas on the removal of a dynamically created instance, this
+ * value would be true
.
+ */
+ public void deregister(PropertyBackedBean bean, boolean isPermanent);
+}
diff --git a/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanUnregisteredEvent.java b/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanUnregisteredEvent.java
new file mode 100644
index 0000000000..c9673e311c
--- /dev/null
+++ b/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanUnregisteredEvent.java
@@ -0,0 +1,61 @@
+/*
+ * 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.management.subsystems;
+
+/**
+ * An event emitted after {@link PropertyBackedBean#destroy(boolean)} is called on a bean.
+ *
+ * @author dward
+ */
+public class PropertyBackedBeanUnregisteredEvent extends PropertyBackedBeanEvent
+{
+ private static final long serialVersionUID = -7878510109531750057L;
+
+ private final boolean isPermanent;
+
+ /**
+ * The Constructor.
+ *
+ * @param source
+ * the source of the event
+ */
+ public PropertyBackedBeanUnregisteredEvent(PropertyBackedBean source, boolean isPermanent)
+ {
+ super(source);
+ this.isPermanent = isPermanent;
+ }
+
+ /**
+ * Is the component being destroyed forever, i.e. should persisted values be removed?
+ *
+ * @return true
if the bean is being destroyed forever. On server shutdown, this value would be
+ * false
, whereas on the removal of a dynamically created instance, this value would be
+ * true
.
+ */
+ public boolean isPermanent()
+ {
+ return isPermanent;
+ }
+}
diff --git a/source/java/org/alfresco/repo/management/ManagedSubsystemProxyFactory.java b/source/java/org/alfresco/repo/management/subsystems/SubsystemProxyFactory.java
similarity index 81%
rename from source/java/org/alfresco/repo/management/ManagedSubsystemProxyFactory.java
rename to source/java/org/alfresco/repo/management/subsystems/SubsystemProxyFactory.java
index d950b7d08b..97f524fa33 100644
--- a/source/java/org/alfresco/repo/management/ManagedSubsystemProxyFactory.java
+++ b/source/java/org/alfresco/repo/management/subsystems/SubsystemProxyFactory.java
@@ -22,7 +22,7 @@
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
-package org.alfresco.repo.management;
+package org.alfresco.repo.management.subsystems;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -34,16 +34,16 @@ import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.aop.support.DefaultPointcutAdvisor;
/**
- * A factory bean, normally used in conjunction with {@link DefaultManagedApplicationContextFactory} allowing selected
+ * A factory bean, normally used in conjunction with {@link ChildApplicationContextFactory} allowing selected
* interfaces in a child application context to be proxied by a bean in the parent application context. This allows
* 'hot-swapping' and reconfiguration of entire subsystems.
*/
-public class ManagedSubsystemProxyFactory extends ProxyFactoryBean
+public class SubsystemProxyFactory extends ProxyFactoryBean
{
private static final long serialVersionUID = -4186421942840611218L;
/** The source application context factory. */
- private ManagedApplicationContextFactory sourceApplicationContextFactory;
+ private ApplicationContextFactory sourceApplicationContextFactory;
/** An optional bean name to look up in the source application context **/
private String sourceBeanName;
@@ -51,7 +51,7 @@ public class ManagedSubsystemProxyFactory extends ProxyFactoryBean
/**
* Instantiates a new managed subsystem proxy factory.
*/
- public ManagedSubsystemProxyFactory()
+ public SubsystemProxyFactory()
{
addAdvisor(new DefaultPointcutAdvisor(new MethodInterceptor()
{
@@ -60,9 +60,9 @@ public class ManagedSubsystemProxyFactory extends ProxyFactoryBean
Method method = mi.getMethod();
try
{
- if (ManagedSubsystemProxyFactory.this.sourceBeanName == null)
+ if (SubsystemProxyFactory.this.sourceBeanName == null)
{
- Map, ?> beans = ManagedSubsystemProxyFactory.this.sourceApplicationContextFactory
+ Map, ?> beans = SubsystemProxyFactory.this.sourceApplicationContextFactory
.getApplicationContext().getBeansOfType(method.getDeclaringClass());
if (beans.size() != 1)
{
@@ -72,8 +72,8 @@ public class ManagedSubsystemProxyFactory extends ProxyFactoryBean
}
else
{
- Object bean = ManagedSubsystemProxyFactory.this.sourceApplicationContextFactory
- .getApplicationContext().getBean(ManagedSubsystemProxyFactory.this.sourceBeanName);
+ Object bean = SubsystemProxyFactory.this.sourceApplicationContextFactory
+ .getApplicationContext().getBean(SubsystemProxyFactory.this.sourceBeanName);
return method.invoke(bean, mi.getArguments());
}
@@ -103,7 +103,7 @@ public class ManagedSubsystemProxyFactory extends ProxyFactoryBean
* @param sourceApplicationContextFactory
* the sourceApplicationContextFactory to set
*/
- public void setSourceApplicationContextFactory(ManagedApplicationContextFactory sourceApplicationContextFactory)
+ public void setSourceApplicationContextFactory(ApplicationContextFactory sourceApplicationContextFactory)
{
this.sourceApplicationContextFactory = sourceApplicationContextFactory;
}
diff --git a/source/java/org/alfresco/repo/management/SwitchableManagedApplicationContextFactory.java b/source/java/org/alfresco/repo/management/subsystems/SwitchableApplicationContextFactory.java
similarity index 53%
rename from source/java/org/alfresco/repo/management/SwitchableManagedApplicationContextFactory.java
rename to source/java/org/alfresco/repo/management/subsystems/SwitchableApplicationContextFactory.java
index 1429f31d9a..49197de975 100644
--- a/source/java/org/alfresco/repo/management/SwitchableManagedApplicationContextFactory.java
+++ b/source/java/org/alfresco/repo/management/subsystems/SwitchableApplicationContextFactory.java
@@ -22,47 +22,53 @@
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
-package org.alfresco.repo.management;
+package org.alfresco.repo.management.subsystems;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
-import org.alfresco.service.Managed;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
- * A configurable proxy for a set of {@link ManagedApplicationContextFactory} beans that allows dynamic selection of one
- * or more alternative subsystems via {@link #setSourceBeanName}. As with other {@link ManagedBean}s, can be stopped,
- * reconfigured, started and tested. Doesn't actually implement FactoryBean because we need first class access to the
- * factory itself to be able to configure its properties.
+ * A configurable proxy for a set of {@link ApplicationContextFactory} beans that allows dynamic selection of one or
+ * more alternative subsystems via a sourceBeanName
property. As with other {@link PropertyBackedBean}s,
+ * can be stopped, reconfigured, started and tested.
*/
-public class SwitchableManagedApplicationContextFactory implements ApplicationContextAware,
- ManagedApplicationContextFactory
+public class SwitchableApplicationContextFactory extends AbstractPropertyBackedBean implements ApplicationContextAware,
+ ApplicationContextFactory
{
+ /**
+ *
+ */
+ private static final String SOURCE_BEAN_PROPERTY = "sourceBeanName";
+
/** The parent application context. */
private ApplicationContext parent;
- /** The bean name of the source {@link ManagedApplicationContextFactory}. */
+ /** The bean name of the source {@link ApplicationContextFactory}. */
private String sourceBeanName;
/** The current source application context factory. */
- private ManagedApplicationContextFactory sourceApplicationContextFactory;
+ private ApplicationContextFactory sourceApplicationContextFactory;
/**
- * Sets the bean name of the source {@link ManagedApplicationContextFactory}.
+ * Sets the bean name of the source {@link ApplicationContextFactory}.
*
* @param sourceBeanName
* the bean name
* @throws Exception
* on error
*/
- @Managed(category = "management")
- public synchronized void setSourceBeanName(String sourceBeanName) throws Exception
+ public synchronized void setSourceBeanName(String sourceBeanName)
{
if (this.sourceApplicationContextFactory != null)
{
- destroy();
+ stop();
this.sourceBeanName = sourceBeanName;
- onStart();
+ start();
}
else
{
@@ -84,34 +90,27 @@ public class SwitchableManagedApplicationContextFactory implements ApplicationCo
* (non-Javadoc)
* @see org.alfresco.enterprise.repo.management.ConfigurableBean#onStart()
*/
- public synchronized void onStart()
+ public synchronized void start()
{
- this.sourceApplicationContextFactory = (ManagedApplicationContextFactory) this.parent
- .getBean(this.sourceBeanName);
- this.sourceApplicationContextFactory.onStart();
+ this.sourceApplicationContextFactory = (ApplicationContextFactory) this.parent.getBean(this.sourceBeanName);
}
/*
* (non-Javadoc)
- * @see org.alfresco.enterprise.repo.management.ConfigurableBean#onTest()
+ * @see org.alfresco.repo.management.SelfDescribingBean#onStop()
*/
- public synchronized void onTest()
+ public void stop()
{
if (this.sourceApplicationContextFactory != null)
{
- this.sourceApplicationContextFactory.onTest();
- }
- }
-
- /*
- * (non-Javadoc)
- * @see org.springframework.beans.factory.DisposableBean#destroy()
- */
- public synchronized void destroy() throws Exception
- {
- if (this.sourceApplicationContextFactory != null)
- {
- this.sourceApplicationContextFactory.destroy();
+ try
+ {
+ this.sourceApplicationContextFactory.stop();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
}
this.sourceApplicationContextFactory = null;
}
@@ -124,8 +123,44 @@ public class SwitchableManagedApplicationContextFactory implements ApplicationCo
{
if (this.sourceApplicationContextFactory == null)
{
- onStart();
+ start();
}
return this.sourceApplicationContextFactory.getApplicationContext();
}
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.PropertyBackedBean#getProperty(java.lang.String)
+ */
+ public synchronized String getProperty(String name)
+ {
+ if (!name.equals(SOURCE_BEAN_PROPERTY))
+ {
+ return null;
+ }
+ return this.sourceBeanName;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.PropertyBackedBean#getPropertyNames()
+ */
+ public Set getPropertyNames()
+ {
+ return Collections.singleton(SOURCE_BEAN_PROPERTY);
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.management.subsystems.PropertyBackedBean#setProperty(java.lang.String, java.lang.String)
+ */
+ public synchronized void setProperty(String name, String value)
+ {
+ if (!name.equals(SOURCE_BEAN_PROPERTY))
+ {
+ throw new IllegalStateException("Illegal attempt to write to property \"" + name + "\"");
+ }
+ if (!parent.containsBean(value))
+ {
+ throw new IllegalStateException("\"" + value + "\" is not a valid bean name");
+ }
+ setSourceBeanName(value);
+ }
}
diff --git a/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java b/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java
index 7eea3be6ed..f4609760fb 100644
--- a/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java
+++ b/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java
@@ -415,30 +415,6 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC
authenticationContext.clearCurrentSecurityContext();
}
- /**
- * The default is not to support Authentication token base authentication
- */
- public Authentication authenticate(Authentication token) throws AuthenticationException
- {
- throw new AlfrescoRuntimeException("Authentication via token not supported");
- }
-
- /**
- * The should only be supported if getNTLMMode() is NTLMMode.MD4_PROVIDER.
- */
- public String getMD4HashedPassword(String userName)
- {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Get the NTML mode - none - supports MD4 hash to integrate - or it can asct as an NTLM authentication
- */
- public NTLMMode getNTLMMode()
- {
- return NTLMMode.NONE;
- }
-
class SetCurrentUserCallback implements RetryingTransactionHelper.RetryingTransactionCallback
{
AuthenticationException ae = null;
@@ -527,7 +503,7 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC
*
* @param defaultAdministratorUserNames
*/
- public void setDefaultAdministratorUserNames(String defaultAdministratorUserNames)
+ public void setDefaultAdministratorUserNameList(String defaultAdministratorUserNames)
{
Set nameSet = new TreeSet();
if (defaultAdministratorUserNames.length() > 0)
diff --git a/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationService.java b/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationService.java
index fa86599246..1011aa9b00 100644
--- a/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationService.java
+++ b/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationService.java
@@ -28,7 +28,6 @@ import java.util.List;
import java.util.Set;
import org.alfresco.repo.cache.SimpleCache;
-import org.alfresco.service.Managed;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.springframework.beans.factory.InitializingBean;
@@ -57,6 +56,7 @@ public abstract class AbstractAuthenticationService implements AuthenticationSer
this.sysAdminCache = sysAdminCache;
}
+ @SuppressWarnings("unchecked")
public void preAuthenticationCheck(String userName) throws AuthenticationException
{
if (sysAdminCache != null)
@@ -77,7 +77,6 @@ public abstract class AbstractAuthenticationService implements AuthenticationSer
}
}
- @Managed(category="Security")
public void setAllowedUsers(List allowedUsers)
{
if (initialised)
@@ -107,7 +106,6 @@ public abstract class AbstractAuthenticationService implements AuthenticationSer
}
}
- @Managed(category="Security")
public void setMaxUsers(int maxUsers)
{
if (initialised)
diff --git a/source/java/org/alfresco/repo/security/authentication/AbstractChainingAuthenticationComponent.java b/source/java/org/alfresco/repo/security/authentication/AbstractChainingAuthenticationComponent.java
new file mode 100644
index 0000000000..90aef2cf8d
--- /dev/null
+++ b/source/java/org/alfresco/repo/security/authentication/AbstractChainingAuthenticationComponent.java
@@ -0,0 +1,162 @@
+/*
+ * 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.security.authentication;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.TreeSet;
+
+import net.sf.acegisecurity.Authentication;
+
+/**
+ * A base class for chaining authentication components. Where appropriate, methods will 'chain' across multiple
+ * {@link AuthenticationComponent} instances, as returned by {@link #getUsableAuthenticationComponents()}.
+ *
+ * @author dward
+ */
+public abstract class AbstractChainingAuthenticationComponent extends AbstractAuthenticationComponent
+{
+
+ /**
+ * Instantiates a new abstract chaining authentication component.
+ */
+ public AbstractChainingAuthenticationComponent()
+ {
+ super();
+ }
+
+ /**
+ * Gets the authentication components across which methods will chain.
+ *
+ * @return the usable authentication components
+ */
+ protected abstract Collection getUsableAuthenticationComponents();
+
+ /**
+ * Chain authentication with user name and password - tries all in order until one works, or fails.
+ *
+ * @param userName
+ * the user name
+ * @param password
+ * the password
+ */
+ @Override
+ protected void authenticateImpl(String userName, char[] password)
+ {
+ for (AuthenticationComponent authComponent : getUsableAuthenticationComponents())
+ {
+ try
+ {
+ authComponent.authenticate(userName, password);
+ return;
+ }
+ catch (AuthenticationException e)
+ {
+ // Ignore and chain
+ }
+ }
+ throw new AuthenticationException("Failed to authenticate");
+ }
+
+ /**
+ * If any implementation supports guest then guest is allowed.
+ *
+ * @return true, if implementation allows guest login
+ */
+ @Override
+ protected boolean implementationAllowsGuestLogin()
+ {
+ for (AuthenticationComponent authComponent : getUsableAuthenticationComponents())
+ {
+ if (authComponent.guestUserAuthenticationAllowed())
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.security.authentication.AbstractAuthenticationComponent#setCurrentUser(java.lang.String,
+ * org.alfresco.repo.security.authentication.AuthenticationComponent.UserNameValidationMode)
+ */
+ @Override
+ public Authentication setCurrentUser(String userName, UserNameValidationMode validationMode)
+ {
+ for (AuthenticationComponent authComponent : getUsableAuthenticationComponents())
+ {
+ try
+ {
+ return authComponent.setCurrentUser(userName, validationMode);
+ }
+ catch (AuthenticationException e)
+ {
+ // Ignore and chain
+ }
+ }
+ throw new AuthenticationException("Failed to set current user " + userName);
+ }
+
+ /**
+ * Set the current user - try all implementations - as some may check the user exists.
+ *
+ * @param userName
+ * the user name
+ * @return the authentication
+ */
+ @Override
+ public Authentication setCurrentUser(String userName)
+ {
+ for (AuthenticationComponent authComponent : getUsableAuthenticationComponents())
+ {
+ try
+ {
+ return authComponent.setCurrentUser(userName);
+ }
+ catch (AuthenticationException e)
+ {
+ // Ignore and chain
+ }
+ }
+ throw new AuthenticationException("Failed to set current user " + userName);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.security.authentication.AbstractAuthenticationComponent#getDefaultAdministratorUserNames()
+ */
+ @Override
+ public Set getDefaultAdministratorUserNames()
+ {
+ Set defaultAdministratorUserNames = new TreeSet();
+ for (AuthenticationComponent authComponent : getUsableAuthenticationComponents())
+ {
+ defaultAdministratorUserNames.addAll(authComponent.getDefaultAdministratorUserNames());
+ }
+ return defaultAdministratorUserNames;
+ }
+
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/security/authentication/AbstractChainingAuthenticationService.java b/source/java/org/alfresco/repo/security/authentication/AbstractChainingAuthenticationService.java
new file mode 100644
index 0000000000..91a0510552
--- /dev/null
+++ b/source/java/org/alfresco/repo/security/authentication/AbstractChainingAuthenticationService.java
@@ -0,0 +1,521 @@
+/*
+ * 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.security.authentication;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.alfresco.service.cmr.security.AuthenticationService;
+import org.alfresco.service.cmr.security.PermissionService;
+
+/**
+ * A base class for chaining authentication services. Where appropriate, methods will 'chain' across multiple
+ * {@link AuthenticationService} instances, as returned by {@link #getUsableAuthenticationServices()}.
+ *
+ * @author dward
+ */
+public abstract class AbstractChainingAuthenticationService extends AbstractAuthenticationService
+{
+
+ /**
+ * Instantiates a new abstract chaining authentication service.
+ */
+ public AbstractChainingAuthenticationService()
+ {
+ super();
+ }
+
+ /**
+ * Gets the mutable authentication service.
+ *
+ * @return the mutable authentication service
+ */
+ public abstract AuthenticationService getMutableAuthenticationService();
+
+ /**
+ * Gets the authentication services across which methods will chain.
+ *
+ * @return the usable authentication services
+ */
+ protected abstract List getUsableAuthenticationServices();
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#createAuthentication(java.lang.String, char[])
+ */
+ public void createAuthentication(String userName, char[] password) throws AuthenticationException
+ {
+ if (getMutableAuthenticationService() == null)
+ {
+ throw new AuthenticationException(
+ "Unable to create authentication as there is no suitable authentication service.");
+ }
+ getMutableAuthenticationService().createAuthentication(userName, password);
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#updateAuthentication(java.lang.String, char[], char[])
+ */
+ public void updateAuthentication(String userName, char[] oldPassword, char[] newPassword)
+ throws AuthenticationException
+ {
+ if (getMutableAuthenticationService() == null)
+ {
+ throw new AuthenticationException(
+ "Unable to update authentication as there is no suitable authentication service.");
+ }
+ getMutableAuthenticationService().updateAuthentication(userName, oldPassword, newPassword);
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#setAuthentication(java.lang.String, char[])
+ */
+ public void setAuthentication(String userName, char[] newPassword) throws AuthenticationException
+ {
+ if (getMutableAuthenticationService() == null)
+ {
+ throw new AuthenticationException(
+ "Unable to set authentication as there is no suitable authentication service.");
+ }
+ getMutableAuthenticationService().setAuthentication(userName, newPassword);
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#deleteAuthentication(java.lang.String)
+ */
+ public void deleteAuthentication(String userName) throws AuthenticationException
+ {
+ if (getMutableAuthenticationService() == null)
+ {
+ throw new AuthenticationException(
+ "Unable to delete authentication as there is no suitable authentication service.");
+ }
+ getMutableAuthenticationService().deleteAuthentication(userName);
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#setAuthenticationEnabled(java.lang.String, boolean)
+ */
+ public void setAuthenticationEnabled(String userName, boolean enabled) throws AuthenticationException
+ {
+ if (getMutableAuthenticationService() == null)
+ {
+ throw new AuthenticationException(
+ "Unable to set authentication enabled as there is no suitable authentication service.");
+ }
+ getMutableAuthenticationService().setAuthenticationEnabled(userName, enabled);
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#getAuthenticationEnabled(java.lang.String)
+ */
+ public boolean getAuthenticationEnabled(String userName) throws AuthenticationException
+ {
+ for (AuthenticationService authService : getUsableAuthenticationServices())
+ {
+ try
+ {
+ if (authService.getAuthenticationEnabled(userName))
+ {
+ return true;
+ }
+ }
+ catch (AuthenticationException e)
+ {
+ // Ignore and chain
+ }
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#authenticate(java.lang.String, char[])
+ */
+ public void authenticate(String userName, char[] password) throws AuthenticationException
+ {
+ preAuthenticationCheck(userName);
+ for (AuthenticationService authService : getUsableAuthenticationServices())
+ {
+ try
+ {
+ authService.authenticate(userName, password);
+ return;
+ }
+ catch (AuthenticationException e)
+ {
+ // Ignore and chain
+ }
+ }
+ throw new AuthenticationException("Failed to authenticate");
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#authenticateAsGuest()
+ */
+ public void authenticateAsGuest() throws AuthenticationException
+ {
+ preAuthenticationCheck(PermissionService.GUEST_AUTHORITY);
+ for (AuthenticationService authService : getUsableAuthenticationServices())
+ {
+ try
+ {
+ authService.authenticateAsGuest();
+ return;
+ }
+ catch (AuthenticationException e)
+ {
+ // Ignore and chain
+ }
+ }
+ throw new AuthenticationException("Guest authentication not supported");
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#guestUserAuthenticationAllowed()
+ */
+ public boolean guestUserAuthenticationAllowed()
+ {
+ for (AuthenticationService authService : getUsableAuthenticationServices())
+ {
+ if (authService.guestUserAuthenticationAllowed())
+ {
+ return true;
+ }
+ }
+ // it isn't allowed in any of the authentication components
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#authenticationExists(java.lang.String)
+ */
+ public boolean authenticationExists(String userName)
+ {
+ for (AuthenticationService authService : getUsableAuthenticationServices())
+ {
+ if (authService.authenticationExists(userName))
+ {
+ return true;
+ }
+ }
+ // it doesn't exist in any of the authentication components
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#getCurrentUserName()
+ */
+ public String getCurrentUserName() throws AuthenticationException
+ {
+ for (AuthenticationService authService : getUsableAuthenticationServices())
+ {
+ try
+ {
+ return authService.getCurrentUserName();
+ }
+ catch (AuthenticationException e)
+ {
+ // Ignore and chain
+ }
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#invalidateUserSession(java.lang.String)
+ */
+ public void invalidateUserSession(String userName) throws AuthenticationException
+ {
+ for (AuthenticationService authService : getUsableAuthenticationServices())
+ {
+ try
+ {
+ authService.invalidateUserSession(userName);
+ return;
+ }
+ catch (AuthenticationException e)
+ {
+ // Ignore and chain
+ }
+ }
+ throw new AuthenticationException("Unable to invalidate user session");
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#invalidateTicket(java.lang.String)
+ */
+ public void invalidateTicket(String ticket) throws AuthenticationException
+ {
+ for (AuthenticationService authService : getUsableAuthenticationServices())
+ {
+ try
+ {
+ authService.invalidateTicket(ticket);
+ return;
+ }
+ catch (AuthenticationException e)
+ {
+ // Ignore and chain
+ }
+ }
+ throw new AuthenticationException("Unable to invalidate ticket");
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#validate(java.lang.String)
+ */
+ public void validate(String ticket) throws AuthenticationException
+ {
+ for (AuthenticationService authService : getUsableAuthenticationServices())
+ {
+ try
+ {
+ authService.validate(ticket);
+ return;
+ }
+ catch (AuthenticationException e)
+ {
+ // Ignore and chain
+ }
+ }
+ throw new AuthenticationException("Unable to validate ticket");
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#getCurrentTicket()
+ */
+ public String getCurrentTicket()
+ {
+ for (AuthenticationService authService : getUsableAuthenticationServices())
+ {
+ try
+ {
+ return authService.getCurrentTicket();
+ }
+ catch (AuthenticationException e)
+ {
+ // Ignore and chain
+ }
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#getNewTicket()
+ */
+ public String getNewTicket()
+ {
+ for (AuthenticationService authService : getUsableAuthenticationServices())
+ {
+ try
+ {
+ return authService.getNewTicket();
+ }
+ catch (AuthenticationException e)
+ {
+ // Ignore and chain
+ }
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#clearCurrentSecurityContext()
+ */
+ public void clearCurrentSecurityContext()
+ {
+ for (AuthenticationService authService : getUsableAuthenticationServices())
+ {
+ try
+ {
+ authService.clearCurrentSecurityContext();
+ return;
+ }
+ catch (AuthenticationException e)
+ {
+ // Ignore and chain
+ }
+ }
+ throw new AuthenticationException("Failed to clear security context");
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#isCurrentUserTheSystemUser()
+ */
+ public boolean isCurrentUserTheSystemUser()
+ {
+ for (AuthenticationService authService : getUsableAuthenticationServices())
+ {
+ try
+ {
+ return authService.isCurrentUserTheSystemUser();
+ }
+ catch (AuthenticationException e)
+ {
+ // Ignore and chain
+ }
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#getDomains()
+ */
+ public Set getDomains()
+ {
+ HashSet domains = new HashSet();
+ for (AuthenticationService authService : getUsableAuthenticationServices())
+ {
+ domains.addAll(authService.getDomains());
+ }
+ return domains;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#getDomainsThatAllowUserCreation()
+ */
+ public Set getDomainsThatAllowUserCreation()
+ {
+ HashSet domains = new HashSet();
+ if (getMutableAuthenticationService() != null)
+ {
+ domains.addAll(getMutableAuthenticationService().getDomainsThatAllowUserCreation());
+ }
+ return domains;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#getDomainsThatAllowUserDeletion()
+ */
+ public Set getDomainsThatAllowUserDeletion()
+ {
+ HashSet domains = new HashSet();
+ if (getMutableAuthenticationService() != null)
+ {
+ domains.addAll(getMutableAuthenticationService().getDomainsThatAllowUserDeletion());
+ }
+ return domains;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#getDomiansThatAllowUserPasswordChanges()
+ */
+ public Set getDomiansThatAllowUserPasswordChanges()
+ {
+ HashSet domains = new HashSet();
+ if (getMutableAuthenticationService() != null)
+ {
+ domains.addAll(getMutableAuthenticationService().getDomiansThatAllowUserPasswordChanges());
+ }
+ return domains;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.security.authentication.AbstractAuthenticationService#getUsersWithTickets(boolean)
+ */
+ @Override
+ public Set getUsersWithTickets(boolean nonExpiredOnly)
+ {
+ HashSet users = new HashSet();
+ for (AuthenticationService authService : getUsableAuthenticationServices())
+ {
+ if (authService instanceof AbstractAuthenticationService)
+ {
+ users.addAll(((AbstractAuthenticationService) authService).getUsersWithTickets(nonExpiredOnly));
+ }
+ }
+ return users;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.security.authentication.AbstractAuthenticationService#countTickets(boolean)
+ */
+ @Override
+ public int countTickets(boolean nonExpiredOnly)
+ {
+ int count = 0;
+ for (TicketComponent tc : getTicketComponents())
+ {
+ count += tc.countTickets(nonExpiredOnly);
+ }
+ return count;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.security.authentication.AbstractAuthenticationService#invalidateTickets(boolean)
+ */
+ @Override
+ public int invalidateTickets(boolean nonExpiredOnly)
+ {
+ int count = 0;
+ for (AuthenticationService authService : getUsableAuthenticationServices())
+ {
+ if (authService instanceof AbstractAuthenticationService)
+ {
+ count += ((AbstractAuthenticationService) authService).invalidateTickets(nonExpiredOnly);
+ }
+ }
+ return count;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.security.authentication.AbstractAuthenticationService#getTicketComponents()
+ */
+ @Override
+ public Set getTicketComponents()
+ {
+ Set tcs = new HashSet();
+ for (AuthenticationService authService : getUsableAuthenticationServices())
+ {
+ if (authService instanceof AbstractAuthenticationService)
+ {
+ tcs.addAll(((AbstractAuthenticationService) authService).getTicketComponents());
+ }
+ }
+ return tcs;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.security.AuthenticationService#getDefaultAdministratorUserNames()
+ */
+ public Set getDefaultAdministratorUserNames()
+ {
+ Set defaultAdministratorUserNames = new TreeSet();
+ for (AuthenticationService authService : getUsableAuthenticationServices())
+ {
+ defaultAdministratorUserNames.addAll(authService.getDefaultAdministratorUserNames());
+ }
+ return defaultAdministratorUserNames;
+ }
+
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/security/authentication/AuthenticationComponent.java b/source/java/org/alfresco/repo/security/authentication/AuthenticationComponent.java
index d9c0e1664f..45e1eb95ca 100644
--- a/source/java/org/alfresco/repo/security/authentication/AuthenticationComponent.java
+++ b/source/java/org/alfresco/repo/security/authentication/AuthenticationComponent.java
@@ -41,15 +41,6 @@ public interface AuthenticationComponent extends AuthenticationContext
* @throws AuthenticationException
*/
public void authenticate(String userName, char[] password) throws AuthenticationException;
-
- /**
- * Authenticate using a token
- *
- * @param token Authentication
- * @return Authentication
- * @throws AuthenticationException
- */
- public Authentication authenticate(Authentication token) throws AuthenticationException;
/**
* Explicitly set the current user to be authenticated.
@@ -76,16 +67,6 @@ public interface AuthenticationComponent extends AuthenticationContext
*/
public boolean guestUserAuthenticationAllowed();
- /**
- * Get the enum that describes NTLM integration
- */
- public NTLMMode getNTLMMode();
-
- /**
- * Get the MD4 password hash, as required by NTLM based authentication methods.
- */
- public String getMD4HashedPassword(String userName);
-
/**
* Gets a set of user names who for this particular authentication system should be considered administrators by
* default. If the security framework is case sensitive these values should be case sensitive user names. If the
diff --git a/source/java/org/alfresco/repo/security/authentication/AuthenticationComponentImpl.java b/source/java/org/alfresco/repo/security/authentication/AuthenticationComponentImpl.java
index 9ac5fb22d8..7597aa9e63 100644
--- a/source/java/org/alfresco/repo/security/authentication/AuthenticationComponentImpl.java
+++ b/source/java/org/alfresco/repo/security/authentication/AuthenticationComponentImpl.java
@@ -29,13 +29,15 @@ import java.io.StringWriter;
import java.util.Collections;
import java.util.Set;
+import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationManager;
import net.sf.acegisecurity.UserDetails;
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
-import org.alfresco.service.Managed;
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.alfresco.repo.security.authentication.ntlm.NLTMAuthenticator;
-public class AuthenticationComponentImpl extends AbstractAuthenticationComponent
+public class AuthenticationComponentImpl extends AbstractAuthenticationComponent implements NLTMAuthenticator
{
private MutableAuthenticationDao authenticationDao;
@@ -61,7 +63,6 @@ public class AuthenticationComponentImpl extends AbstractAuthenticationComponent
*
* @param authenticationDao
*/
- @Managed(category = "Security")
public void setAuthenticationDao(MutableAuthenticationDao authenticationDao)
{
this.authenticationDao = authenticationDao;
@@ -107,16 +108,22 @@ public class AuthenticationComponentImpl extends AbstractAuthenticationComponent
/**
* Get the password hash from the DAO
*/
- @Override
public String getMD4HashedPassword(String userName)
{
return this.authenticationDao.getMD4HashedPassword(userName);
}
+ /**
+ * The default is not to support Authentication token base authentication
+ */
+ public Authentication authenticate(Authentication token) throws AuthenticationException
+ {
+ throw new AlfrescoRuntimeException("Authentication via token not supported");
+ }
+
/**
* This implementation supported MD4 password hashes.
*/
- @Override
public NTLMMode getNTLMMode()
{
return NTLMMode.MD4_PROVIDER;
diff --git a/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java b/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java
index d72f698bdb..0d22e96aaf 100644
--- a/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java
+++ b/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java
@@ -28,7 +28,6 @@ import java.util.Collections;
import java.util.Set;
import org.alfresco.repo.security.authentication.AuthenticationComponent.UserNameValidationMode;
-import org.alfresco.service.Managed;
import org.alfresco.service.cmr.security.PermissionService;
public class AuthenticationServiceImpl extends AbstractAuthenticationService
@@ -52,7 +51,6 @@ public class AuthenticationServiceImpl extends AbstractAuthenticationService
super();
}
- @Managed(category="Security")
public void setAuthenticationDao(MutableAuthenticationDao authenticationDao)
{
this.authenticationDao = authenticationDao;
@@ -63,7 +61,6 @@ public class AuthenticationServiceImpl extends AbstractAuthenticationService
this.ticketComponent = ticketComponent;
}
- @Managed(category="Security")
public void setAuthenticationComponent(AuthenticationComponent authenticationComponent)
{
this.authenticationComponent = authenticationComponent;
diff --git a/source/java/org/alfresco/repo/security/authentication/ChainingAuthenticationComponentImpl.java b/source/java/org/alfresco/repo/security/authentication/ChainingAuthenticationComponentImpl.java
index 3ac9c7e377..7f5d161a42 100644
--- a/source/java/org/alfresco/repo/security/authentication/ChainingAuthenticationComponentImpl.java
+++ b/source/java/org/alfresco/repo/security/authentication/ChainingAuthenticationComponentImpl.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
@@ -18,18 +18,19 @@
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
- * FLOSS exception. You should have recieved a copy of the text describing
+ * FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.security.authentication;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import net.sf.acegisecurity.Authentication;
-import org.alfresco.service.Managed;
+import org.alfresco.repo.security.authentication.ntlm.NLTMAuthenticator;
/**
* A chaining authentication component is required for all the beans that qire up an authentication component and not an
@@ -38,7 +39,7 @@ import org.alfresco.service.Managed;
*
* @author andyh
*/
-public class ChainingAuthenticationComponentImpl extends AbstractAuthenticationComponent
+public class ChainingAuthenticationComponentImpl extends AbstractChainingAuthenticationComponent implements NLTMAuthenticator
{
/**
* NLTM authentication mode - if unset - finds the first component that supports NTLM - if set - finds the first
@@ -72,7 +73,6 @@ public class ChainingAuthenticationComponentImpl extends AbstractAuthenticationC
*
* @param authenticationComponents
*/
- @Managed(category = "Security")
public void setAuthenticationComponents(List authenticationComponents)
{
this.authenticationComponents = authenticationComponents;
@@ -93,44 +93,20 @@ public class ChainingAuthenticationComponentImpl extends AbstractAuthenticationC
*
* @param mutableAuthenticationComponent
*/
- @Managed(category = "Security")
public void setMutableAuthenticationComponent(AuthenticationComponent mutableAuthenticationComponent)
{
this.mutableAuthenticationComponent = mutableAuthenticationComponent;
}
- @Managed(category = "Security")
public void setNtlmMode(NTLMMode ntlmMode)
{
this.ntlmMode = ntlmMode;
}
- /**
- * Chain authentication with user name and password - tries all in order until one works, or fails.
- */
- @Override
- protected void authenticateImpl(String userName, char[] password)
- {
- for (AuthenticationComponent authComponent : getUsableAuthenticationComponents())
- {
- try
- {
- authComponent.authenticate(userName, password);
- return;
- }
- catch (AuthenticationException e)
- {
- // Ignore and chain
- }
- }
- throw new AuthenticationException("Failed to authenticate");
- }
-
/**
* NTLM passthrough authentication - if a mode is defined - the first PASS_THROUGH provider is used - if not, the
* first component that supports NTLM is used if it supports PASS_THROUGH
*/
- @Override
public Authentication authenticate(Authentication token) throws AuthenticationException
{
if (this.ntlmMode != null)
@@ -144,9 +120,14 @@ public class ChainingAuthenticationComponentImpl extends AbstractAuthenticationC
case PASS_THROUGH:
for (AuthenticationComponent authComponent : getUsableAuthenticationComponents())
{
- if (authComponent.getNTLMMode() == NTLMMode.PASS_THROUGH)
+ if (!(authComponent instanceof NLTMAuthenticator))
{
- return authComponent.authenticate(token);
+ continue;
+ }
+ NLTMAuthenticator ssoAuthenticator = (NLTMAuthenticator)authComponent;
+ if (ssoAuthenticator.getNTLMMode() == NTLMMode.PASS_THROUGH)
+ {
+ return ssoAuthenticator.authenticate(token);
}
}
throw new AuthenticationException("No NTLM passthrough authentication to use");
@@ -158,11 +139,16 @@ public class ChainingAuthenticationComponentImpl extends AbstractAuthenticationC
{
for (AuthenticationComponent authComponent : getUsableAuthenticationComponents())
{
- if (authComponent.getNTLMMode() != NTLMMode.NONE)
+ if (!(authComponent instanceof NLTMAuthenticator))
{
- if (authComponent.getNTLMMode() == NTLMMode.PASS_THROUGH)
+ continue;
+ }
+ NLTMAuthenticator ssoAuthenticator = (NLTMAuthenticator)authComponent;
+ if (ssoAuthenticator.getNTLMMode() != NTLMMode.NONE)
+ {
+ if (ssoAuthenticator.getNTLMMode() == NTLMMode.PASS_THROUGH)
{
- return authComponent.authenticate(token);
+ return ssoAuthenticator.authenticate(token);
}
else
{
@@ -179,7 +165,6 @@ public class ChainingAuthenticationComponentImpl extends AbstractAuthenticationC
/**
* Get the MD4 password hash
*/
- @Override
public String getMD4HashedPassword(String userName)
{
if (this.ntlmMode != null)
@@ -193,9 +178,14 @@ public class ChainingAuthenticationComponentImpl extends AbstractAuthenticationC
case MD4_PROVIDER:
for (AuthenticationComponent authComponent : getUsableAuthenticationComponents())
{
- if (authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER)
+ if (!(authComponent instanceof NLTMAuthenticator))
{
- return authComponent.getMD4HashedPassword(userName);
+ continue;
+ }
+ NLTMAuthenticator ssoAuthenticator = (NLTMAuthenticator)authComponent;
+ if (ssoAuthenticator.getNTLMMode() == NTLMMode.MD4_PROVIDER)
+ {
+ return ssoAuthenticator.getMD4HashedPassword(userName);
}
}
throw new AuthenticationException("No MD4 provider available");
@@ -207,16 +197,21 @@ public class ChainingAuthenticationComponentImpl extends AbstractAuthenticationC
{
for (AuthenticationComponent authComponent : getUsableAuthenticationComponents())
{
- if (authComponent.getNTLMMode() != NTLMMode.NONE)
+ if (!(authComponent instanceof NLTMAuthenticator))
{
- if (authComponent.getNTLMMode() == NTLMMode.PASS_THROUGH)
+ continue;
+ }
+ NLTMAuthenticator ssoAuthenticator = (NLTMAuthenticator)authComponent;
+ if (ssoAuthenticator.getNTLMMode() != NTLMMode.NONE)
+ {
+ if (ssoAuthenticator.getNTLMMode() == NTLMMode.PASS_THROUGH)
{
throw new AuthenticationException(
"The first authentication component to support NTLM supports passthrough");
}
else
{
- return authComponent.getMD4HashedPassword(userName);
+ return ssoAuthenticator.getMD4HashedPassword(userName);
}
}
}
@@ -228,7 +223,6 @@ public class ChainingAuthenticationComponentImpl extends AbstractAuthenticationC
/**
* Get the NTLM mode - this is only what is set if one of the implementations provides support for that mode.
*/
- @Override
public NTLMMode getNTLMMode()
{
if (this.ntlmMode != null)
@@ -240,7 +234,12 @@ public class ChainingAuthenticationComponentImpl extends AbstractAuthenticationC
case PASS_THROUGH:
for (AuthenticationComponent authComponent : getUsableAuthenticationComponents())
{
- if (authComponent.getNTLMMode() == NTLMMode.PASS_THROUGH)
+ if (!(authComponent instanceof NLTMAuthenticator))
+ {
+ continue;
+ }
+ NLTMAuthenticator ssoAuthenticator = (NLTMAuthenticator)authComponent;
+ if (ssoAuthenticator.getNTLMMode() == NTLMMode.PASS_THROUGH)
{
return NTLMMode.PASS_THROUGH;
}
@@ -249,7 +248,12 @@ public class ChainingAuthenticationComponentImpl extends AbstractAuthenticationC
case MD4_PROVIDER:
for (AuthenticationComponent authComponent : getUsableAuthenticationComponents())
{
- if (authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER)
+ if (!(authComponent instanceof NLTMAuthenticator))
+ {
+ continue;
+ }
+ NLTMAuthenticator ssoAuthenticator = (NLTMAuthenticator)authComponent;
+ if (ssoAuthenticator.getNTLMMode() == NTLMMode.MD4_PROVIDER)
{
return NTLMMode.MD4_PROVIDER;
}
@@ -263,74 +267,26 @@ public class ChainingAuthenticationComponentImpl extends AbstractAuthenticationC
{
for (AuthenticationComponent authComponent : getUsableAuthenticationComponents())
{
- if (authComponent.getNTLMMode() != NTLMMode.NONE)
+ if (!(authComponent instanceof NLTMAuthenticator))
{
- return authComponent.getNTLMMode();
+ continue;
+ }
+ NLTMAuthenticator ssoAuthenticator = (NLTMAuthenticator)authComponent;
+ if (ssoAuthenticator.getNTLMMode() != NTLMMode.NONE)
+ {
+ return ssoAuthenticator.getNTLMMode();
}
}
return NTLMMode.NONE;
}
}
- /**
- * If any implementation supports guest then guest is allowed
- */
- @Override
- protected boolean implementationAllowsGuestLogin()
- {
- for (AuthenticationComponent authComponent : getUsableAuthenticationComponents())
- {
- if (authComponent.guestUserAuthenticationAllowed())
- {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public Authentication setCurrentUser(String userName, UserNameValidationMode validationMode)
- {
- for (AuthenticationComponent authComponent : getUsableAuthenticationComponents())
- {
- try
- {
- return authComponent.setCurrentUser(userName, validationMode);
- }
- catch (AuthenticationException e)
- {
- // Ignore and chain
- }
- }
- throw new AuthenticationException("Failed to set current user " + userName);
- }
-
- /**
- * Set the current user - try all implementations - as some may check the user exists
- */
- @Override
- public Authentication setCurrentUser(String userName)
- {
- for (AuthenticationComponent authComponent : getUsableAuthenticationComponents())
- {
- try
- {
- return authComponent.setCurrentUser(userName);
- }
- catch (AuthenticationException e)
- {
- // Ignore and chain
- }
- }
- throw new AuthenticationException("Failed to set current user " + userName);
- }
-
/**
* Helper to get authentication components
*
* @return
*/
- private List getUsableAuthenticationComponents()
+ protected Collection getUsableAuthenticationComponents()
{
if (this.mutableAuthenticationComponent == null)
{
diff --git a/source/java/org/alfresco/repo/security/authentication/ChainingAuthenticationServiceImpl.java b/source/java/org/alfresco/repo/security/authentication/ChainingAuthenticationServiceImpl.java
index 323ff7a9dd..3fb849d5dc 100644
--- a/source/java/org/alfresco/repo/security/authentication/ChainingAuthenticationServiceImpl.java
+++ b/source/java/org/alfresco/repo/security/authentication/ChainingAuthenticationServiceImpl.java
@@ -25,459 +25,68 @@
package org.alfresco.repo.security.authentication;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
-import java.util.TreeSet;
-import org.alfresco.service.Managed;
import org.alfresco.service.cmr.security.AuthenticationService;
-import org.alfresco.service.cmr.security.PermissionService;
/**
- * This class implements a simple chaining authentication service.
- *
- * It chains together other authentication services so that authentication can happen against more than one authentication service.
- *
- * The authentication services it uses are stored as a list.
- *
- * Each authentication service must belong to the same domain. This is checked at configuration time.
- *
- * Authentication will try each authentication service in order. If any allow authentication given the user name and password then the user will be accepted.
- *
- * Additions, deletions and password changes are made to one special authentication service. This service will be tried first for authentication. Users can not be created if they
- * exist in another authentication service.
- *
- * To avoid transactional issues in chaining, the services registered with this service must not have transactional wrappers. If not, errors will mark the transaction for roll back
- * and we can not chain down the list of authentication services.
- *
+ * This class implements a simple chaining authentication service. It chains together other authentication services so
+ * that authentication can happen against more than one authentication service. The authentication services it uses are
+ * stored as a list. Each authentication service must belong to the same domain. This is checked at configuration time.
+ * Authentication will try each authentication service in order. If any allow authentication given the user name and
+ * password then the user will be accepted. Additions, deletions and password changes are made to one special
+ * authentication service. This service will be tried first for authentication. Users can not be created if they exist
+ * in another authentication service. To avoid transactional issues in chaining, the services registered with this
+ * service must not have transactional wrappers. If not, errors will mark the transaction for roll back and we can not
+ * chain down the list of authentication services.
*
* @author Andy Hind
*/
-public class ChainingAuthenticationServiceImpl extends AbstractAuthenticationService
+public class ChainingAuthenticationServiceImpl extends AbstractChainingAuthenticationService
{
- private List authenticationServices;
+ List authenticationServices;
- private AuthenticationService mutableAuthenticationService;
+ AuthenticationService mutableAuthenticationService;
public ChainingAuthenticationServiceImpl()
{
super();
}
- public List getAuthenticationServices()
- {
- return authenticationServices;
- }
-
- @Managed(category="Security")
public void setAuthenticationServices(List authenticationServices)
{
this.authenticationServices = authenticationServices;
}
+ @Override
public AuthenticationService getMutableAuthenticationService()
{
- return mutableAuthenticationService;
+ return this.mutableAuthenticationService;
}
- @Managed(category="Security")
public void setMutableAuthenticationService(AuthenticationService mutableAuthenticationService)
{
this.mutableAuthenticationService = mutableAuthenticationService;
}
- public void createAuthentication(String userName, char[] password) throws AuthenticationException
+ @Override
+ protected List getUsableAuthenticationServices()
{
- if (mutableAuthenticationService == null)
+ if (this.mutableAuthenticationService == null)
{
- throw new AuthenticationException(
- "Unable to create authentication as there is no suitable authentication service.");
- }
- mutableAuthenticationService.createAuthentication(userName, password);
- }
-
- public void updateAuthentication(String userName, char[] oldPassword, char[] newPassword)
- throws AuthenticationException
- {
- if (mutableAuthenticationService == null)
- {
- throw new AuthenticationException(
- "Unable to update authentication as there is no suitable authentication service.");
- }
- mutableAuthenticationService.updateAuthentication(userName, oldPassword, newPassword);
-
- }
-
- public void setAuthentication(String userName, char[] newPassword) throws AuthenticationException
- {
- if (mutableAuthenticationService == null)
- {
- throw new AuthenticationException(
- "Unable to set authentication as there is no suitable authentication service.");
- }
- mutableAuthenticationService.setAuthentication(userName, newPassword);
- }
-
- public void deleteAuthentication(String userName) throws AuthenticationException
- {
- if (mutableAuthenticationService == null)
- {
- throw new AuthenticationException(
- "Unable to delete authentication as there is no suitable authentication service.");
- }
- mutableAuthenticationService.deleteAuthentication(userName);
-
- }
-
- public void setAuthenticationEnabled(String userName, boolean enabled) throws AuthenticationException
- {
- if (mutableAuthenticationService == null)
- {
- throw new AuthenticationException(
- "Unable to set authentication enabled as there is no suitable authentication service.");
- }
- mutableAuthenticationService.setAuthenticationEnabled(userName, enabled);
- }
-
- public boolean getAuthenticationEnabled(String userName) throws AuthenticationException
- {
- for (AuthenticationService authService : getUsableAuthenticationServices())
- {
- try
- {
- if (authService.getAuthenticationEnabled(userName))
- {
- return true;
- }
- }
- catch (AuthenticationException e)
- {
- // Ignore and chain
- }
- }
- return false;
- }
-
- public void authenticate(String userName, char[] password) throws AuthenticationException
- {
- preAuthenticationCheck(userName);
- for (AuthenticationService authService : getUsableAuthenticationServices())
- {
- try
- {
- authService.authenticate(userName, password);
- return;
- }
- catch (AuthenticationException e)
- {
- // Ignore and chain
- }
- }
- throw new AuthenticationException("Failed to authenticate");
-
- }
-
- public void authenticateAsGuest() throws AuthenticationException
- {
- preAuthenticationCheck(PermissionService.GUEST_AUTHORITY);
- for (AuthenticationService authService : getUsableAuthenticationServices())
- {
- try
- {
- authService.authenticateAsGuest();
- return;
- }
- catch (AuthenticationException e)
- {
- // Ignore and chain
- }
- }
- throw new AuthenticationException("Guest authentication not supported");
- }
-
- public boolean guestUserAuthenticationAllowed()
- {
- for (AuthenticationService authService : getUsableAuthenticationServices())
- {
- if (authService.guestUserAuthenticationAllowed())
- {
- return true;
- }
- }
- // it isn't allowed in any of the authentication components
- return false;
- }
-
- public boolean authenticationExists(String userName)
- {
- for (AuthenticationService authService : getUsableAuthenticationServices())
- {
- if (authService.authenticationExists(userName))
- {
- return true;
- }
- }
- // it doesn't exist in any of the authentication components
- return false;
- }
-
- public String getCurrentUserName() throws AuthenticationException
- {
- for (AuthenticationService authService : getUsableAuthenticationServices())
- {
- try
- {
- return authService.getCurrentUserName();
- }
- catch (AuthenticationException e)
- {
- // Ignore and chain
- }
- }
- return null;
- }
-
- public void invalidateUserSession(String userName) throws AuthenticationException
- {
- for (AuthenticationService authService : getUsableAuthenticationServices())
- {
- try
- {
- authService.invalidateUserSession(userName);
- return;
- }
- catch (AuthenticationException e)
- {
- // Ignore and chain
- }
- }
- throw new AuthenticationException("Unable to invalidate user session");
-
- }
-
- public void invalidateTicket(String ticket) throws AuthenticationException
- {
- for (AuthenticationService authService : getUsableAuthenticationServices())
- {
- try
- {
- authService.invalidateTicket(ticket);
- return;
- }
- catch (AuthenticationException e)
- {
- // Ignore and chain
- }
- }
- throw new AuthenticationException("Unable to invalidate ticket");
-
- }
-
- public void validate(String ticket) throws AuthenticationException
- {
- for (AuthenticationService authService : getUsableAuthenticationServices())
- {
- try
- {
- authService.validate(ticket);
- return;
- }
- catch (AuthenticationException e)
- {
- // Ignore and chain
- }
- }
- throw new AuthenticationException("Unable to validate ticket");
-
- }
-
- public String getCurrentTicket()
- {
- for (AuthenticationService authService : getUsableAuthenticationServices())
- {
- try
- {
- return authService.getCurrentTicket();
- }
- catch (AuthenticationException e)
- {
- // Ignore and chain
- }
- }
- return null;
- }
-
- public String getNewTicket()
- {
- for (AuthenticationService authService : getUsableAuthenticationServices())
- {
- try
- {
- return authService.getNewTicket();
- }
- catch (AuthenticationException e)
- {
- // Ignore and chain
- }
- }
- return null;
- }
-
- public void clearCurrentSecurityContext()
- {
- for (AuthenticationService authService : getUsableAuthenticationServices())
- {
- try
- {
- authService.clearCurrentSecurityContext();
- return;
- }
- catch (AuthenticationException e)
- {
- // Ignore and chain
- }
- }
- throw new AuthenticationException("Failed to clear security context");
-
- }
-
- public boolean isCurrentUserTheSystemUser()
- {
- for (AuthenticationService authService : getUsableAuthenticationServices())
- {
- try
- {
- return authService.isCurrentUserTheSystemUser();
- }
- catch (AuthenticationException e)
- {
- // Ignore and chain
- }
- }
- return false;
- }
-
- private List getUsableAuthenticationServices()
- {
- if (mutableAuthenticationService == null)
- {
- return authenticationServices;
+ return this.authenticationServices;
}
else
{
ArrayList services = new ArrayList(
- authenticationServices == null ? 1 : (authenticationServices.size() + 1));
- services.add(mutableAuthenticationService);
- if (authenticationServices != null)
+ this.authenticationServices == null ? 1 : this.authenticationServices.size() + 1);
+ services.add(this.mutableAuthenticationService);
+ if (this.authenticationServices != null)
{
- services.addAll(authenticationServices);
+ services.addAll(this.authenticationServices);
}
return services;
}
}
-
- public Set getDomains()
- {
- HashSet domains = new HashSet();
- for (AuthenticationService authService : getUsableAuthenticationServices())
- {
- domains.addAll(authService.getDomains());
- }
- return domains;
- }
-
- public Set getDomainsThatAllowUserCreation()
- {
- HashSet domains = new HashSet();
- if (mutableAuthenticationService != null)
- {
- domains.addAll(mutableAuthenticationService.getDomainsThatAllowUserCreation());
- }
- return domains;
- }
-
- public Set getDomainsThatAllowUserDeletion()
- {
- HashSet domains = new HashSet();
- if (mutableAuthenticationService != null)
- {
- domains.addAll(mutableAuthenticationService.getDomainsThatAllowUserDeletion());
- }
- return domains;
- }
-
- public Set getDomiansThatAllowUserPasswordChanges()
- {
- HashSet domains = new HashSet();
- if (mutableAuthenticationService != null)
- {
- domains.addAll(mutableAuthenticationService.getDomiansThatAllowUserPasswordChanges());
- }
- return domains;
- }
-
- @Override
- public Set getUsersWithTickets(boolean nonExpiredOnly)
- {
- HashSet users = new HashSet();
- for (AuthenticationService authService : getUsableAuthenticationServices())
- {
- if(authService instanceof AbstractAuthenticationService)
- {
- users.addAll( ((AbstractAuthenticationService)authService).getUsersWithTickets(nonExpiredOnly));
- }
- }
- return users;
- }
-
- @Override
- public int countTickets(boolean nonExpiredOnly)
- {
- int count = 0;
- for(TicketComponent tc : getTicketComponents())
- {
- count += tc.countTickets(nonExpiredOnly);
- }
- return count;
- }
-
- @Override
- public int invalidateTickets(boolean nonExpiredOnly)
- {
- int count = 0;
- for (AuthenticationService authService : getUsableAuthenticationServices())
- {
- if(authService instanceof AbstractAuthenticationService)
- {
- count += ((AbstractAuthenticationService)authService).invalidateTickets(nonExpiredOnly);
- }
- }
- return count;
- }
-
- @Override
- public Set getTicketComponents()
- {
- Set tcs = new HashSet();
- for (AuthenticationService authService : getUsableAuthenticationServices())
- {
- if(authService instanceof AbstractAuthenticationService)
- {
- tcs.addAll(((AbstractAuthenticationService)authService).getTicketComponents());
- }
- }
- return tcs;
- }
-
- public Set getDefaultAdministratorUserNames()
- {
- Set defaultAdministratorUserNames = new TreeSet();
- for (AuthenticationService authService : getUsableAuthenticationServices())
- {
- defaultAdministratorUserNames.addAll(authService.getDefaultAdministratorUserNames());
- }
- return defaultAdministratorUserNames;
- }
}
diff --git a/source/java/org/alfresco/repo/security/authentication/DefaultMutableAuthenticationDao.java b/source/java/org/alfresco/repo/security/authentication/DefaultMutableAuthenticationDao.java
index 33a50f7581..3a34ef7382 100644
--- a/source/java/org/alfresco/repo/security/authentication/DefaultMutableAuthenticationDao.java
+++ b/source/java/org/alfresco/repo/security/authentication/DefaultMutableAuthenticationDao.java
@@ -30,7 +30,6 @@ import net.sf.acegisecurity.UserDetails;
import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
import org.alfresco.error.AlfrescoRuntimeException;
-import org.alfresco.service.Managed;
import org.springframework.dao.DataAccessException;
/**
@@ -430,97 +429,81 @@ public class DefaultMutableAuthenticationDao implements MutableAuthenticationDao
// Bean IOC //
// -------- //
- @Managed(category="Security")
public void setAllowCreateUser(boolean allowCreateUser)
{
this.allowCreateUser = allowCreateUser;
}
- @Managed(category="Security")
public void setAllowDeleteUser(boolean allowDeleteUser)
{
this.allowDeleteUser = allowDeleteUser;
}
- @Managed(category="Security")
public void setAllowGetAccountExpiryDate(boolean allowGetAccountExpiryDate)
{
this.allowGetAccountExpiryDate = allowGetAccountExpiryDate;
}
- @Managed(category="Security")
public void setAllowGetAccountHasExpired(boolean allowGetAccountHasExpired)
{
this.allowGetAccountHasExpired = allowGetAccountHasExpired;
}
- @Managed(category="Security")
public void setAllowGetAccountLocked(boolean allowGetAccountLocked)
{
this.allowGetAccountLocked = allowGetAccountLocked;
}
- @Managed(category="Security")
public void setAllowGetCredentialsExpire(boolean allowGetCredentialsExpire)
{
this.allowGetCredentialsExpire = allowGetCredentialsExpire;
}
- @Managed(category="Security")
public void setAllowGetCredentialsExpiryDate(boolean allowGetCredentialsExpiryDate)
{
this.allowGetCredentialsExpiryDate = allowGetCredentialsExpiryDate;
}
- @Managed(category="Security")
public void setAllowGetCredentialsHaveExpired(boolean allowGetCredentialsHaveExpired)
{
this.allowGetCredentialsHaveExpired = allowGetCredentialsHaveExpired;
}
- @Managed(category="Security")
public void setAllowGetEnabled(boolean allowGetEnabled)
{
this.allowGetEnabled = allowGetEnabled;
}
- @Managed(category="Security")
public void setAllowSetAccountExpires(boolean allowSetAccountExpires)
{
this.allowSetAccountExpires = allowSetAccountExpires;
}
- @Managed(category="Security")
public void setAllowSetAccountExpiryDate(boolean allowSetAccountExpiryDate)
{
this.allowSetAccountExpiryDate = allowSetAccountExpiryDate;
}
- @Managed(category="Security")
public void setAllowSetAccountLocked(boolean allowSetAccountLocked)
{
this.allowSetAccountLocked = allowSetAccountLocked;
}
- @Managed(category="Security")
public void setAllowSetCredentialsExpire(boolean allowSetCredentialsExpire)
{
this.allowSetCredentialsExpire = allowSetCredentialsExpire;
}
- @Managed(category="Security")
public void setAllowSetCredentialsExpiryDate(boolean allowSetCredentialsExpiryDate)
{
this.allowSetCredentialsExpiryDate = allowSetCredentialsExpiryDate;
}
- @Managed(category="Security")
public void setAllowSetEnabled(boolean allowSetEnabled)
{
this.allowSetEnabled = allowSetEnabled;
}
- @Managed(category="Security")
public void setAllowUpdateUser(boolean allowUpdateUser)
{
this.allowUpdateUser = allowUpdateUser;
diff --git a/source/java/org/alfresco/repo/security/authentication/SimpleAcceptOrRejectAllAuthenticationComponentImpl.java b/source/java/org/alfresco/repo/security/authentication/SimpleAcceptOrRejectAllAuthenticationComponentImpl.java
index c3704067b4..be6b7deee1 100644
--- a/source/java/org/alfresco/repo/security/authentication/SimpleAcceptOrRejectAllAuthenticationComponentImpl.java
+++ b/source/java/org/alfresco/repo/security/authentication/SimpleAcceptOrRejectAllAuthenticationComponentImpl.java
@@ -24,6 +24,11 @@
*/
package org.alfresco.repo.security.authentication;
+import net.sf.acegisecurity.Authentication;
+
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.alfresco.repo.security.authentication.ntlm.NLTMAuthenticator;
+
/**
* This implementation of an AuthenticationComponent can be configured to accept or reject all attempts to login.
@@ -37,7 +42,7 @@ package org.alfresco.repo.security.authentication;
*
* @author Andy Hind
*/
-public class SimpleAcceptOrRejectAllAuthenticationComponentImpl extends AbstractAuthenticationComponent
+public class SimpleAcceptOrRejectAllAuthenticationComponentImpl extends AbstractAuthenticationComponent implements NLTMAuthenticator
{
private boolean accept = false;
@@ -70,7 +75,6 @@ public class SimpleAcceptOrRejectAllAuthenticationComponentImpl extends Abstract
return accept;
}
- @Override
public String getMD4HashedPassword(String userName)
{
if(accept)
@@ -83,11 +87,16 @@ public class SimpleAcceptOrRejectAllAuthenticationComponentImpl extends Abstract
}
}
- @Override
public NTLMMode getNTLMMode()
{
return NTLMMode.MD4_PROVIDER;
}
-
+ /**
+ * The default is not to support Authentication token base authentication
+ */
+ public Authentication authenticate(Authentication token) throws AuthenticationException
+ {
+ throw new AlfrescoRuntimeException("Authentication via token not supported");
+ }
}
diff --git a/source/java/org/alfresco/repo/security/authentication/jaas/JAASAuthenticationComponent.java b/source/java/org/alfresco/repo/security/authentication/jaas/JAASAuthenticationComponent.java
index cba41a2d58..ce7e5458fd 100644
--- a/source/java/org/alfresco/repo/security/authentication/jaas/JAASAuthenticationComponent.java
+++ b/source/java/org/alfresco/repo/security/authentication/jaas/JAASAuthenticationComponent.java
@@ -40,7 +40,6 @@ import javax.security.sasl.RealmCallback;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.security.authentication.AbstractAuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationException;
-import org.alfresco.service.Managed;
/**
* JAAS based authentication
@@ -104,14 +103,12 @@ public class JAASAuthenticationComponent extends AbstractAuthenticationComponent
// Springification
- @Managed(category="Security")
public void setJaasConfigEntryName(String jaasConfigEntryName)
{
this.jaasConfigEntryName = jaasConfigEntryName;
}
- @Managed(category="Security")
public void setRealm(String realm)
{
this.realm = realm;
diff --git a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPAuthenticationComponentImpl.java b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPAuthenticationComponentImpl.java
index 968847b6ca..3a82fb5052 100644
--- a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPAuthenticationComponentImpl.java
+++ b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPAuthenticationComponentImpl.java
@@ -29,7 +29,6 @@ import javax.naming.directory.InitialDirContext;
import org.alfresco.repo.security.authentication.AbstractAuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationException;
-import org.alfresco.service.Managed;
/**
* Currently expects the cn name of the user which is in a fixed location.
@@ -51,25 +50,21 @@ public class LDAPAuthenticationComponentImpl extends AbstractAuthenticationCompo
super();
}
- @Managed(category="Security")
public void setLDAPInitialDirContextFactory(LDAPInitialDirContextFactory ldapInitialDirContextFactory)
{
this.ldapInitialContextFactory = ldapInitialDirContextFactory;
}
- @Managed(category="Security")
public void setUserNameFormat(String userNameFormat)
{
this.userNameFormat = userNameFormat;
}
- @Managed(category="Security")
public void setEscapeCommasInBind(boolean escapeCommasInBind)
{
this.escapeCommasInBind = escapeCommasInBind;
}
- @Managed(category="Security")
public void setEscapeCommasInUid(boolean escapeCommasInUid)
{
this.escapeCommasInUid = escapeCommasInUid;
diff --git a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java
index 6f85c85154..3575d17b73 100644
--- a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java
+++ b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java
@@ -38,7 +38,6 @@ import javax.naming.directory.BasicAttributes;
import javax.naming.directory.InitialDirContext;
import org.alfresco.repo.security.authentication.AuthenticationException;
-import org.alfresco.service.Managed;
import org.alfresco.util.ApplicationContextHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -61,7 +60,6 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
super();
}
- @Managed(category="Security")
public void setInitialDirContextEnvironment(Map initialDirContextEnvironment)
{
this.initialDirContextEnvironment = initialDirContextEnvironment;
diff --git a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPPersonExportSource.java b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPPersonExportSource.java
index 975be0a5e8..c94c6df89a 100644
--- a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPPersonExportSource.java
+++ b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPPersonExportSource.java
@@ -44,7 +44,6 @@ import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.importer.ExportSource;
import org.alfresco.repo.importer.ExportSourceImporterException;
-import org.alfresco.service.Managed;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
@@ -85,25 +84,21 @@ public class LDAPPersonExportSource implements ExportSource
super();
}
- @Managed(category="Security")
public void setPersonQuery(String personQuery)
{
this.personQuery = personQuery;
}
- @Managed(category="Security")
public void setSearchBase(String searchBase)
{
this.searchBase = searchBase;
}
- @Managed(category="Security")
public void setUserIdAttributeName(String userIdAttributeName)
{
this.userIdAttributeName = userIdAttributeName;
}
- @Managed(category="Security")
public void setLDAPInitialDirContextFactory(LDAPInitialDirContextFactory ldapInitialDirContextFactory)
{
this.ldapInitialContextFactory = ldapInitialDirContextFactory;
@@ -114,7 +109,6 @@ public class LDAPPersonExportSource implements ExportSource
this.personService = personService;
}
- @Managed(category="Security")
public void setAttributeDefaults(Map attributeDefaults)
{
this.attributeDefaults = attributeDefaults;
@@ -125,13 +119,11 @@ public class LDAPPersonExportSource implements ExportSource
this.namespaceService = namespaceService;
}
- @Managed(category="Security")
public void setAttributeMapping(Map attributeMapping)
{
this.attributeMapping = attributeMapping;
}
- @Managed(category="Security")
public void setErrorOnMissingUID(boolean errorOnMissingUID)
{
this.errorOnMissingUID = errorOnMissingUID;
@@ -175,7 +167,7 @@ public class LDAPPersonExportSource implements ExportSource
userSearchCtls.setCountLimit(Integer.MAX_VALUE);
- NamingEnumeration searchResults = ctx.search(searchBase, personQuery, userSearchCtls);
+ NamingEnumeration searchResults = ctx.search(searchBase, personQuery, userSearchCtls);
RESULT_LOOP: while (searchResults.hasMoreElements())
{
SearchResult result = (SearchResult) searchResults.next();
diff --git a/source/java/org/alfresco/repo/security/authentication/ntlm/NLTMAuthenticator.java b/source/java/org/alfresco/repo/security/authentication/ntlm/NLTMAuthenticator.java
new file mode 100644
index 0000000000..9375faf1d7
--- /dev/null
+++ b/source/java/org/alfresco/repo/security/authentication/ntlm/NLTMAuthenticator.java
@@ -0,0 +1,68 @@
+/*
+ * 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.security.authentication.ntlm;
+
+import net.sf.acegisecurity.Authentication;
+
+import org.alfresco.repo.security.authentication.AuthenticationComponent;
+import org.alfresco.repo.security.authentication.AuthenticationException;
+import org.alfresco.repo.security.authentication.NTLMMode;
+
+/**
+ * An specialized {@link AuthenticationComponent} that is capable of handling NTLM authentication directly, either by
+ * 'passing through' to a domain server or by validating an MD4 hashed password. Unlike other authentication methods,
+ * these operations cannot be chained and must be handled by a specific authentication component.
+ *
+ * @author dward
+ */
+public interface NLTMAuthenticator extends AuthenticationComponent
+{
+ /**
+ * Authenticate using a token.
+ *
+ * @param token
+ * Authentication
+ * @return Authentication
+ * @throws AuthenticationException
+ * the authentication exception
+ */
+ public Authentication authenticate(Authentication token) throws AuthenticationException;
+
+ /**
+ * Get the enum that describes NTLM integration.
+ *
+ * @return the NTLM mode
+ */
+ public NTLMMode getNTLMMode();
+
+ /**
+ * Get the MD4 password hash, as required by NTLM based authentication methods.
+ *
+ * @param userName
+ * the user name
+ * @return the m d4 hashed password
+ */
+ public String getMD4HashedPassword(String userName);
+}
diff --git a/source/java/org/alfresco/repo/security/authentication/ntlm/NTLMAuthenticationComponentImpl.java b/source/java/org/alfresco/repo/security/authentication/ntlm/NTLMAuthenticationComponentImpl.java
index 276ed4e967..152e747075 100644
--- a/source/java/org/alfresco/repo/security/authentication/ntlm/NTLMAuthenticationComponentImpl.java
+++ b/source/java/org/alfresco/repo/security/authentication/ntlm/NTLMAuthenticationComponentImpl.java
@@ -67,7 +67,7 @@ import org.springframework.beans.factory.InitializingBean;
*
* @author GKSpencer
*/
-public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationComponent implements InitializingBean
+public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationComponent implements NLTMAuthenticator, InitializingBean
{
// Logging
diff --git a/source/java/org/alfresco/repo/security/authentication/subsystems/SubsystemChainingAuthenticationComponent.java b/source/java/org/alfresco/repo/security/authentication/subsystems/SubsystemChainingAuthenticationComponent.java
new file mode 100644
index 0000000000..a9a2284757
--- /dev/null
+++ b/source/java/org/alfresco/repo/security/authentication/subsystems/SubsystemChainingAuthenticationComponent.java
@@ -0,0 +1,92 @@
+/*
+ * 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.security.authentication.subsystems;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.alfresco.repo.management.subsystems.ChildApplicationContextManager;
+import org.alfresco.repo.security.authentication.AbstractChainingAuthenticationComponent;
+import org.alfresco.repo.security.authentication.AuthenticationComponent;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.context.ApplicationContext;
+
+/**
+ * An authentication component that chains across beans in multiple child application contexts corresponding to
+ * different 'subsystems' in a chain determined by a {@link ChildApplicationContextManager}.
+ *
+ * @author dward
+ */
+public class SubsystemChainingAuthenticationComponent extends AbstractChainingAuthenticationComponent
+{
+ private ChildApplicationContextManager applicationContextManager;
+ private String sourceBeanName;
+
+ /**
+ * @param applicationContextManager
+ * the applicationContextManager to set
+ */
+ public void setApplicationContextManager(ChildApplicationContextManager applicationContextManager)
+ {
+ this.applicationContextManager = applicationContextManager;
+ }
+
+ /**
+ * Sets the name of the bean to look up in the child application contexts.
+ *
+ * @param sourceBeanName
+ * the bean name
+ */
+ public void setSourceBeanName(String sourceBeanName)
+ {
+ this.sourceBeanName = sourceBeanName;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * org.alfresco.repo.security.authentication.AbstractChainingAuthenticationCompent#getUsableAuthenticationComponents
+ * ()
+ */
+ @Override
+ protected Collection getUsableAuthenticationComponents()
+ {
+ List result = new LinkedList();
+ for (String instance : this.applicationContextManager.getInstanceIds())
+ {
+ ApplicationContext context = this.applicationContextManager.getApplicationContext(instance);
+ try
+ {
+ result.add((AuthenticationComponent) context.getBean(sourceBeanName));
+ }
+ catch (NoSuchBeanDefinitionException e)
+ {
+ // Ignore and continue
+ }
+ }
+ return result;
+ }
+}
diff --git a/source/java/org/alfresco/repo/security/authentication/subsystems/SubsystemChainingAuthenticationService.java b/source/java/org/alfresco/repo/security/authentication/subsystems/SubsystemChainingAuthenticationService.java
new file mode 100644
index 0000000000..cbf5b05949
--- /dev/null
+++ b/source/java/org/alfresco/repo/security/authentication/subsystems/SubsystemChainingAuthenticationService.java
@@ -0,0 +1,120 @@
+/*
+ * 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.security.authentication.subsystems;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.alfresco.repo.management.subsystems.ChildApplicationContextManager;
+import org.alfresco.repo.security.authentication.AbstractChainingAuthenticationService;
+import org.alfresco.service.cmr.security.AuthenticationService;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.context.ApplicationContext;
+
+/**
+ * An authentication service that chains across beans in multiple child application contexts corresponding to different
+ * 'subsystems' in a chain determined by a {@link ChildApplicationContextManager}. The first authentication service in
+ * the chain will always be considered to be the 'mutable' authentication service.
+ *
+ * @author dward
+ */
+public class SubsystemChainingAuthenticationService extends AbstractChainingAuthenticationService
+{
+ /** The application context manager. */
+ private ChildApplicationContextManager applicationContextManager;
+
+ /** The source bean name. */
+ private String sourceBeanName;
+
+ /**
+ * Sets the application context manager.
+ *
+ * @param applicationContextManager
+ * the applicationContextManager to set
+ */
+ public void setApplicationContextManager(ChildApplicationContextManager applicationContextManager)
+ {
+ this.applicationContextManager = applicationContextManager;
+ }
+
+ /**
+ * Sets the name of the bean to look up in the child application contexts.
+ *
+ * @param sourceBeanName
+ * the bean name
+ */
+ public void setSourceBeanName(String sourceBeanName)
+ {
+ this.sourceBeanName = sourceBeanName;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * org.alfresco.repo.security.authentication.AbstractChainingAuthenticationService#getMutableAuthenticationService()
+ */
+ @Override
+ public AuthenticationService getMutableAuthenticationService()
+ {
+ for (String instance : this.applicationContextManager.getInstanceIds())
+ {
+ ApplicationContext context = this.applicationContextManager.getApplicationContext(instance);
+ try
+ {
+ return (AuthenticationService) context.getBean(sourceBeanName);
+ }
+ catch (NoSuchBeanDefinitionException e)
+ {
+ // Ignore and continue
+ }
+ }
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * org.alfresco.repo.security.authentication.AbstractChainingAuthenticationService#getUsableAuthenticationServices()
+ */
+ @Override
+ protected List getUsableAuthenticationServices()
+ {
+ List result = new LinkedList();
+ for (String instance : this.applicationContextManager.getInstanceIds())
+ {
+ ApplicationContext context = this.applicationContextManager.getApplicationContext(instance);
+ try
+ {
+ result.add((AuthenticationService) context.getBean(sourceBeanName));
+ }
+ catch (NoSuchBeanDefinitionException e)
+ {
+ // Ignore and continue
+ }
+ }
+ return result;
+ }
+
+}