diff --git a/config/alfresco/application-context.xml b/config/alfresco/application-context.xml index fd196884f2..684b0494a1 100644 --- a/config/alfresco/application-context.xml +++ b/config/alfresco/application-context.xml @@ -69,6 +69,7 @@ + + - - - - - - - - - alfrescoAuthentication + + + + ${authentication.chain} - - - + + + + - org.alfresco.repo.security.authentication.AuthenticationComponent org.alfresco.repo.security.authentication.MutableAuthenticationDao - - org.alfresco.jlan.server.SessionListener - - - + + + + + + + + org.alfresco.jlan.server.SessionListener + + + + + + + + + + + cifsAuthenticator @@ -110,13 +120,14 @@ org.alfresco.jlan.server.auth.ICifsAuthenticator + org.alfresco.repo.management.subsystems.ActivateableBean - - - + + + ftpAuthenticator @@ -124,8 +135,13 @@ org.alfresco.jlan.ftp.FTPAuthenticator + org.alfresco.repo.management.subsystems.ActivateableBean + + + + @@ -141,28 +157,21 @@ - - - - - + - - - - - - - - - - + - + + + + + + + localAuthenticationService - + @@ -188,14 +197,32 @@ + + + + + + + + + + + + + + + + authenticationComponent + + + - - diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml index 7559bc04e3..ab11034e75 100644 --- a/config/alfresco/bootstrap-context.xml +++ b/config/alfresco/bootstrap-context.xml @@ -378,13 +378,13 @@ - + true - + @@ -407,7 +407,15 @@ - + + + true + + + + + true diff --git a/config/alfresco/content-services-context.xml b/config/alfresco/content-services-context.xml index 69202f544d..a1004c7b31 100644 --- a/config/alfresco/content-services-context.xml +++ b/config/alfresco/content-services-context.xml @@ -149,7 +149,7 @@ - + @@ -339,7 +339,7 @@ - + @@ -380,7 +380,7 @@ parent="baseContentTransformer" /> - + diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index 329e8b0748..3c0449d925 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -105,6 +105,12 @@ + + + + + + diff --git a/config/alfresco/repository.properties b/config/alfresco/repository.properties index c1ee40b806..929aed7322 100644 --- a/config/alfresco/repository.properties +++ b/config/alfresco/repository.properties @@ -311,3 +311,6 @@ swf.exe=./bin/pdf2swf # Property to enable upgrade from 2.1-A V2.1-A.fixes.to.schema=0 #V2.1-A.fixes.to.schema=82 + +# The default authentication chain +authentication.chain=alfrescoNtlm1:alfrescoNtlm \ No newline at end of file diff --git a/config/alfresco/subsystems/Authentication/alfresco/alfresco-authentication-context.xml b/config/alfresco/subsystems/Authentication/alfresco/alfresco-authentication-context.xml new file mode 100644 index 0000000000..ac0d1843df --- /dev/null +++ b/config/alfresco/subsystems/Authentication/alfresco/alfresco-authentication-context.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + ${alfresco.authentication.allowGuestLogin} + + + + + + + + + + + + + + + + + org.alfresco.repo.security.authentication.AuthenticationComponent + org.alfresco.repo.security.authentication.ntlm.NLTMAuthenticator + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${alfresco.authentication.authenticateCIFS} + + + + \ No newline at end of file diff --git a/config/alfresco/subsystems/Authentication/alfresco/alfresco-authentication.properties b/config/alfresco/subsystems/Authentication/alfresco/alfresco-authentication.properties new file mode 100644 index 0000000000..cc65e562c3 --- /dev/null +++ b/config/alfresco/subsystems/Authentication/alfresco/alfresco-authentication.properties @@ -0,0 +1,2 @@ +alfresco.authentication.allowGuestLogin=true +alfresco.authentication.authenticateCIFS=true diff --git a/config/alfresco/subsystems/Authentication/alfrescoNtlm/alfresco-authentication-context.xml b/config/alfresco/subsystems/Authentication/alfrescoNtlm/alfresco-authentication-context.xml new file mode 100644 index 0000000000..ac0d1843df --- /dev/null +++ b/config/alfresco/subsystems/Authentication/alfrescoNtlm/alfresco-authentication-context.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + ${alfresco.authentication.allowGuestLogin} + + + + + + + + + + + + + + + + + org.alfresco.repo.security.authentication.AuthenticationComponent + org.alfresco.repo.security.authentication.ntlm.NLTMAuthenticator + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${alfresco.authentication.authenticateCIFS} + + + + \ No newline at end of file diff --git a/config/alfresco/subsystems/Authentication/alfrescoNtlm/alfresco-authentication.properties b/config/alfresco/subsystems/Authentication/alfrescoNtlm/alfresco-authentication.properties new file mode 100644 index 0000000000..870859f99a --- /dev/null +++ b/config/alfresco/subsystems/Authentication/alfrescoNtlm/alfresco-authentication.properties @@ -0,0 +1,2 @@ +alfresco.authentication.allowGuestLogin=true +alfresco.authentication.authenticateCIFS=true \ No newline at end of file diff --git a/config/alfresco/subsystems/Authentication/kerberos/kerberos-authentication-context.xml b/config/alfresco/subsystems/Authentication/kerberos/kerberos-authentication-context.xml new file mode 100644 index 0000000000..9fd0d41ffd --- /dev/null +++ b/config/alfresco/subsystems/Authentication/kerberos/kerberos-authentication-context.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + ${kerberos.authentication.realm} + + + ${kerberos.authentication.user.configEntryName} + + + + + + + + + + + + ${kerberos.authentication.defaultAdministratorUserNames} + + + + + + + org.alfresco.repo.security.authentication.AuthenticationComponent + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${kerberos.authentication.authenticateCIFS} + + + ${kerberos.authentication.realm} + + + ${kerberos.authentication.cifs.password} + + + ${kerberos.authentication.cifs.configEntryName} + + + + \ No newline at end of file diff --git a/config/alfresco/subsystems/kerberosAuthentication/kerberos-authentication.properties b/config/alfresco/subsystems/Authentication/kerberos/kerberos-authentication.properties similarity index 68% rename from config/alfresco/subsystems/kerberosAuthentication/kerberos-authentication.properties rename to config/alfresco/subsystems/Authentication/kerberos/kerberos-authentication.properties index fa9e5d9379..00198ffeb0 100644 --- a/config/alfresco/subsystems/kerberosAuthentication/kerberos-authentication.properties +++ b/config/alfresco/subsystems/Authentication/kerberos/kerberos-authentication.properties @@ -2,4 +2,5 @@ kerberos.authentication.realm=ALFRESCO.ORG kerberos.authentication.user.configEntryName=Alfresco kerberos.authentication.defaultAdministratorUserNames= kerberos.authentication.cifs.configEntryName=AlfrescoCIFS -kerberos.authentication.cifs.password=secret \ No newline at end of file +kerberos.authentication.cifs.password=secret +kerberos.authentication.authenticateCIFS=true \ No newline at end of file diff --git a/config/alfresco/subsystems/Authentication/ldap/ldap-authentication-context.xml b/config/alfresco/subsystems/Authentication/ldap/ldap-authentication-context.xml new file mode 100644 index 0000000000..4544b8b249 --- /dev/null +++ b/config/alfresco/subsystems/Authentication/ldap/ldap-authentication-context.xml @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + ${ldap.authentication.userNameFormat} + + + + + + + + + + + + ${ldap.authentication.escapeCommasInBind} + + + ${ldap.authentication.escapeCommasInUid} + + + ${ldap.authentication.allowGuestLogin} + + + ${ldap.authentication.defaultAdministratorUserNames} + + + + + + + org.alfresco.repo.security.authentication.AuthenticationComponent + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${ldap.authentication.java.naming.factory.initial} + + + + + + + ${ldap.authentication.java.naming.provider.url} + + + + + + + + ${ldap.authentication.java.naming.security.authentication} + + + + + + ${ldap.authentication.java.naming.security.principal} + + + + + ${ldap.authentication.java.naming.security.credentials} + + + + + + \ No newline at end of file diff --git a/config/alfresco/subsystems/ldapAuthentication/ldap-authentication.properties b/config/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties similarity index 78% rename from config/alfresco/subsystems/ldapAuthentication/ldap-authentication.properties rename to config/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties index ee3867399a..48d7bee9c6 100644 --- a/config/alfresco/subsystems/ldapAuthentication/ldap-authentication.properties +++ b/config/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties @@ -38,12 +38,3 @@ ldap.authentication.escapeCommasInUid=false # Comma separated list of user names who should be considered users by default ldap.authentication.defaultAdministratorUserNames= - -# Passthru setings, if a CIFS server is in use with Active Directory -ldap.passthru.authentication.useLocalServer=false -ldap.passthru.authentication.domain=DOMAIN -ldap.passthru.authentication.servers= -ldap.passthru.authentication.guestAccess=false -ldap.passthru.authentication.connectTimeout=5000 -ldap.passthru.authentication.offlineCheckInterval=300000 -ldap.passthru.authentication.protocolOrder=NetBIOS,TCPIP diff --git a/config/alfresco/subsystems/passthruAuthentication/passthru-authentication-context.properties b/config/alfresco/subsystems/Authentication/passthru/passthru-authentication-context.properties similarity index 82% rename from config/alfresco/subsystems/passthruAuthentication/passthru-authentication-context.properties rename to config/alfresco/subsystems/Authentication/passthru/passthru-authentication-context.properties index 6618c9afad..286cc7a743 100644 --- a/config/alfresco/subsystems/passthruAuthentication/passthru-authentication-context.properties +++ b/config/alfresco/subsystems/Authentication/passthru/passthru-authentication-context.properties @@ -8,3 +8,5 @@ passthru.authentication.connectTimeout=5000 #Offline server check interval in seconds passthru.authentication.offlineCheckInterval=300 passthru.authentication.protocolOrder=NetBIOS,TCPIP +passthru.authentication.authenticateCIFS=true +passthru.authentication.authenticateFTP=true diff --git a/config/alfresco/subsystems/passthruAuthentication/passthru-authentication-context.xml b/config/alfresco/subsystems/Authentication/passthru/passthru-authentication-context.xml similarity index 66% rename from config/alfresco/subsystems/passthruAuthentication/passthru-authentication-context.xml rename to config/alfresco/subsystems/Authentication/passthru/passthru-authentication-context.xml index 37dd17aff8..12267243ca 100644 --- a/config/alfresco/subsystems/passthruAuthentication/passthru-authentication-context.xml +++ b/config/alfresco/subsystems/Authentication/passthru/passthru-authentication-context.xml @@ -66,13 +66,53 @@ ${passthru.authentication.guestAccess} - + ${passthru.authentication.defaultAdministratorUserNames} + + + + + org.alfresco.repo.security.authentication.AuthenticationComponent + org.alfresco.repo.security.authentication.ntlm.NLTMAuthenticator + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + + + + + + + + + + + + + + + + ${passthru.authentication.authenticateCIFS} + @@ -80,6 +120,9 @@ + + ${passthru.authentication.authenticateFTP} + diff --git a/config/alfresco/subsystems/ldapSynchronization/ldap-synchronisation-context.xml b/config/alfresco/subsystems/Synchronization/ldap/ldap-synchronisation-context.xml similarity index 97% rename from config/alfresco/subsystems/ldapSynchronization/ldap-synchronisation-context.xml rename to config/alfresco/subsystems/Synchronization/ldap/ldap-synchronisation-context.xml index 504bf5d919..3de72ad1f0 100644 --- a/config/alfresco/subsystems/ldapSynchronization/ldap-synchronisation-context.xml +++ b/config/alfresco/subsystems/Synchronization/ldap/ldap-synchronisation-context.xml @@ -40,7 +40,7 @@ - ${ldap.authentication.java.naming.security.credentials} + ${ldap.synchronisation.java.naming.security.credentials} diff --git a/config/alfresco/subsystems/ldapSynchronization/ldap-synchronisation.properties b/config/alfresco/subsystems/Synchronization/ldap/ldap-synchronisation.properties similarity index 100% rename from config/alfresco/subsystems/ldapSynchronization/ldap-synchronisation.properties rename to config/alfresco/subsystems/Synchronization/ldap/ldap-synchronisation.properties diff --git a/config/alfresco/subsystems/alfrescoAuthentication/alfresco-authentication-context.xml b/config/alfresco/subsystems/alfrescoAuthentication/alfresco-authentication-context.xml deleted file mode 100644 index 6be73c9672..0000000000 --- a/config/alfresco/subsystems/alfrescoAuthentication/alfresco-authentication-context.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - ${alfresco.authentication.allowGuestLogin} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/config/alfresco/subsystems/alfrescoAuthentication/alfresco-authentication.properties b/config/alfresco/subsystems/alfrescoAuthentication/alfresco-authentication.properties deleted file mode 100644 index 56b72a9958..0000000000 --- a/config/alfresco/subsystems/alfrescoAuthentication/alfresco-authentication.properties +++ /dev/null @@ -1 +0,0 @@ -alfresco.authentication.allowGuestLogin=true \ No newline at end of file diff --git a/config/alfresco/subsystems/alfrescoNtlmAuthentication/alfresco-authentication-context.xml b/config/alfresco/subsystems/alfrescoNtlmAuthentication/alfresco-authentication-context.xml deleted file mode 100644 index 6be73c9672..0000000000 --- a/config/alfresco/subsystems/alfrescoNtlmAuthentication/alfresco-authentication-context.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - ${alfresco.authentication.allowGuestLogin} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/config/alfresco/subsystems/alfrescoNtlmAuthentication/alfresco-authentication.properties b/config/alfresco/subsystems/alfrescoNtlmAuthentication/alfresco-authentication.properties deleted file mode 100644 index 56b72a9958..0000000000 --- a/config/alfresco/subsystems/alfrescoNtlmAuthentication/alfresco-authentication.properties +++ /dev/null @@ -1 +0,0 @@ -alfresco.authentication.allowGuestLogin=true \ No newline at end of file diff --git a/config/alfresco/subsystems/fileServers/file-servers-context.xml b/config/alfresco/subsystems/fileServers/default/file-servers-context.xml similarity index 97% rename from config/alfresco/subsystems/fileServers/file-servers-context.xml rename to config/alfresco/subsystems/fileServers/default/file-servers-context.xml index 6d06b6bf7f..3ccc5b654c 100644 --- a/config/alfresco/subsystems/fileServers/file-servers-context.xml +++ b/config/alfresco/subsystems/fileServers/default/file-servers-context.xml @@ -30,7 +30,7 @@ - + @@ -147,7 +147,7 @@ - + @@ -199,7 +199,7 @@ - + diff --git a/config/alfresco/subsystems/fileServers/file-servers.properties b/config/alfresco/subsystems/fileServers/default/file-servers.properties similarity index 100% rename from config/alfresco/subsystems/fileServers/file-servers.properties rename to config/alfresco/subsystems/fileServers/default/file-servers.properties diff --git a/config/alfresco/subsystems/kerberosAuthentication/kerberos-authentication-context.xml b/config/alfresco/subsystems/kerberosAuthentication/kerberos-authentication-context.xml deleted file mode 100644 index 0573bf4aae..0000000000 --- a/config/alfresco/subsystems/kerberosAuthentication/kerberos-authentication-context.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - ${kerberos.authentication.realm} - - - ${kerberos.authentication.user.configEntryName} - - - - - - - - - - - - ${kerberos.authentication.defaultAdministratorUserNames} - - - - - - - - - - - - - - - - - - ${kerberos.authentication.realm} - - - ${kerberos.authentication.cifs.password} - - - ${kerberos.authentication.cifs.configEntryName} - - - - - - - - - - \ No newline at end of file diff --git a/config/alfresco/subsystems/ldapAuthentication/ldap-authentication-context.xml b/config/alfresco/subsystems/ldapAuthentication/ldap-authentication-context.xml deleted file mode 100644 index 5840f2dd77..0000000000 --- a/config/alfresco/subsystems/ldapAuthentication/ldap-authentication-context.xml +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - ${ldap.authentication.userNameFormat} - - - - - - - - - - - - ${ldap.authentication.escapeCommasInBind} - - - ${ldap.authentication.escapeCommasInUid} - - - ${ldap.authentication.allowGuestLogin} - - - ${ldap.authentication.defaultAdministratorUserNames} - - - - - - - - - - - ${ldap.authentication.java.naming.factory.initial} - - - - - - - ${ldap.authentication.java.naming.provider.url} - - - - - - - - ${ldap.authentication.java.naming.security.authentication} - - - - - - ${ldap.authentication.java.naming.security.principal} - - - - - ${ldap.authentication.java.naming.security.credentials} - - - - - - - - - - - - - - - ${ldap.passthru.authentication.useLocalServer} - - - ${ldap.passthru.authentication.servers} - - - ${ldap.passthru.authentication.domain} - - - - ${ldap.passthru.authentication.connectTimeout} - - - - ${ldap.passthru.authentication.offlineCheckInterval} - - - ${ldap.passthru.authentication.protocolOrder} - - - true - - - - - - - - - - - - - \ No newline at end of file diff --git a/config/alfresco/subsystems/thirdparty/imagemagick-transform-context.xml b/config/alfresco/subsystems/thirdparty/default/imagemagick-transform-context.xml similarity index 100% rename from config/alfresco/subsystems/thirdparty/imagemagick-transform-context.xml rename to config/alfresco/subsystems/thirdparty/default/imagemagick-transform-context.xml diff --git a/config/alfresco/subsystems/thirdparty/imagemagick-transform.properties b/config/alfresco/subsystems/thirdparty/default/imagemagick-transform.properties similarity index 100% rename from config/alfresco/subsystems/thirdparty/imagemagick-transform.properties rename to config/alfresco/subsystems/thirdparty/default/imagemagick-transform.properties diff --git a/config/alfresco/subsystems/thirdparty/openoffice-transform-context.xml b/config/alfresco/subsystems/thirdparty/default/openoffice-transform-context.xml similarity index 100% rename from config/alfresco/subsystems/thirdparty/openoffice-transform-context.xml rename to config/alfresco/subsystems/thirdparty/default/openoffice-transform-context.xml diff --git a/config/alfresco/subsystems/thirdparty/openoffice-transform.properties b/config/alfresco/subsystems/thirdparty/default/openoffice-transform.properties similarity index 100% rename from config/alfresco/subsystems/thirdparty/openoffice-transform.properties rename to config/alfresco/subsystems/thirdparty/default/openoffice-transform.properties diff --git a/config/alfresco/subsystems/thirdparty/swf-transform-context.xml b/config/alfresco/subsystems/thirdparty/default/swf-transform-context.xml similarity index 100% rename from config/alfresco/subsystems/thirdparty/swf-transform-context.xml rename to config/alfresco/subsystems/thirdparty/default/swf-transform-context.xml diff --git a/config/alfresco/subsystems/thirdparty/swf-transform.properties b/config/alfresco/subsystems/thirdparty/default/swf-transform.properties similarity index 100% rename from config/alfresco/subsystems/thirdparty/swf-transform.properties rename to config/alfresco/subsystems/thirdparty/default/swf-transform.properties diff --git a/config/alfresco/swf-transform-context.xml b/config/alfresco/swf-transform-context.xml index 1524ae163a..bc0a8f759c 100644 --- a/config/alfresco/swf-transform-context.xml +++ b/config/alfresco/swf-transform-context.xml @@ -4,7 +4,7 @@ - + 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 + * ActivatableBeans 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 PropertyBackedBeans 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; + } + +}