From 972dd9a4ba98394f21c6c4cec28513381532479b Mon Sep 17 00:00:00 2001 From: Dave Ward Date: Wed, 1 Apr 2009 13:22:06 +0000 Subject: [PATCH] MOB-651: Decouple File Servers from Config Service and Authenticators - Minor JLAN changes (backward compatible) - CIFSAuthenticator implements an interface (to allow dynamic proxying to authentication subsystem) - CIFSAuthenticator accesses ServerConfiguration via ServerConfigurationAccessor interface and doesn't retain references to config sections (again to allow dynamic proxying and hot swapping) - ConfigSections have way of directly setting container initialised authenticators, sharemappers, etc. - Authenticators, etc. still support initialisation from config service in backward compatible manner. - Most of ServerConfigurationBean moved to AbstractServerConfigurationBean superclass. - New org.alfresco.filesys.config package with ServerConfigurationBean implementation and supporting classes that can be initialised by a Spring container. - File server authenticators moved into authentication subsystem. TODO: Kerberos and NTLM git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@13795 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../authentication-services-context.xml | 4 + config/alfresco/bootstrap-context.xml | 43 +- config/alfresco/core-services-context.xml | 8 - config/alfresco/file-servers.properties | 11 - config/alfresco/network-protocol-context.xml | 70 +- .../alfresco-authentication-context.xml | 104 +- .../fileServers/file-servers-context.xml | 398 ++++ .../fileServers/file-servers.properties | 23 + .../AbstractServerConfigurationBean.java | 942 ++++++++ .../filesys/AlfrescoConfigSection.java | 2 +- .../org/alfresco/filesys/CIFSServerBean.java | 26 +- .../alfresco/filesys/NullSessionListener.java | 51 + .../filesys/ServerConfigurationBean.java | 949 +------- .../filesys/alfresco/AlfrescoContext.java | 125 +- .../filesys/alfresco/AlfrescoDiskDriver.java | 10 +- .../filesys/alfresco/DesktopAction.java | 268 ++- .../alfresco/ExtendedDiskInterface.java | 45 + .../filesys/alfresco/HomeShareMapper.java | 57 +- .../alfresco/MultiTenantShareMapper.java | 79 +- .../auth/cifs/AlfrescoCifsAuthenticator.java | 36 +- .../auth/cifs/CifsAuthenticatorBase.java | 271 ++- .../cifs/EnterpriseCifsAuthenticator.java | 602 ++--- .../auth/cifs/PassthruCifsAuthenticator.java | 510 +++-- .../auth/ftp/AlfrescoFtpAuthenticator.java | 13 +- .../auth/ftp/FTPAuthenticatorBase.java | 96 +- .../auth/ftp/PassthruFtpAuthenticator.java | 936 ++++---- .../auth/nfs/AlfrescoRpcAuthenticator.java | 749 +++--- .../filesys/auth/nfs/UserMapping.java | 129 ++ .../org/alfresco/filesys/avm/AVMContext.java | 744 +++--- .../alfresco/filesys/avm/AVMDiskDriver.java | 254 ++- .../alfresco/filesys/avm/AVMShareMapper.java | 73 +- .../filesys/config/CIFSConfigBean.java | 518 +++++ .../filesys/config/CoreServerConfigBean.java | 132 ++ .../config/DomainMappingConfigBean.java | 155 ++ .../filesys/config/FTPConfigBean.java | 253 +++ .../config/GlobalDesktopActionConfigBean.java | 132 ++ .../config/MemoryPacketConfigBean.java | 108 + .../filesys/config/NFSConfigBean.java | 302 +++ .../filesys/config/NetBIOSSMBConfigBean.java | 180 ++ .../filesys/config/SecurityConfigBean.java | 161 ++ .../config/ServerConfigurationBean.java | 2012 +++++++++++++++++ .../filesys/config/TcpipSMBConfigBean.java | 108 + .../filesys/config/WINSConfigBean.java | 108 + .../config/Win32NetBIOSConfigBean.java | 108 + .../alfresco/filesys/repo/ContentContext.java | 233 +- .../filesys/repo/ContentDiskDriver.java | 238 +- .../filesys/repo/HomeShareMapper.java | 36 +- .../repo/desk/JavaScriptDesktopAction.java | 289 ++- ...faultManagedApplicationContextFactory.java | 44 +- 49 files changed, 9469 insertions(+), 3276 deletions(-) delete mode 100644 config/alfresco/file-servers.properties create mode 100644 config/alfresco/subsystems/fileServers/file-servers-context.xml create mode 100644 config/alfresco/subsystems/fileServers/file-servers.properties create mode 100644 source/java/org/alfresco/filesys/AbstractServerConfigurationBean.java create mode 100644 source/java/org/alfresco/filesys/NullSessionListener.java create mode 100644 source/java/org/alfresco/filesys/alfresco/ExtendedDiskInterface.java create mode 100644 source/java/org/alfresco/filesys/auth/nfs/UserMapping.java create mode 100644 source/java/org/alfresco/filesys/config/CIFSConfigBean.java create mode 100644 source/java/org/alfresco/filesys/config/CoreServerConfigBean.java create mode 100644 source/java/org/alfresco/filesys/config/DomainMappingConfigBean.java create mode 100644 source/java/org/alfresco/filesys/config/FTPConfigBean.java create mode 100644 source/java/org/alfresco/filesys/config/GlobalDesktopActionConfigBean.java create mode 100644 source/java/org/alfresco/filesys/config/MemoryPacketConfigBean.java create mode 100644 source/java/org/alfresco/filesys/config/NFSConfigBean.java create mode 100644 source/java/org/alfresco/filesys/config/NetBIOSSMBConfigBean.java create mode 100644 source/java/org/alfresco/filesys/config/SecurityConfigBean.java create mode 100644 source/java/org/alfresco/filesys/config/ServerConfigurationBean.java create mode 100644 source/java/org/alfresco/filesys/config/TcpipSMBConfigBean.java create mode 100644 source/java/org/alfresco/filesys/config/WINSConfigBean.java create mode 100644 source/java/org/alfresco/filesys/config/Win32NetBIOSConfigBean.java diff --git a/config/alfresco/authentication-services-context.xml b/config/alfresco/authentication-services-context.xml index cf126285e8..b0215eafd9 100644 --- a/config/alfresco/authentication-services-context.xml +++ b/config/alfresco/authentication-services-context.xml @@ -93,6 +93,10 @@ org.alfresco.repo.security.authentication.AuthenticationComponent org.alfresco.repo.security.authentication.MutableAuthenticationDao + org.alfresco.jlan.server.auth.ICifsAuthenticator + org.alfresco.jlan.ftp.FTPAuthenticator + + org.alfresco.jlan.server.SessionListener diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml index 28d13be08a..85a67a374a 100644 --- a/config/alfresco/bootstrap-context.xml +++ b/config/alfresco/bootstrap-context.xml @@ -368,36 +368,25 @@ - - - - - - + + + + true + - - - - - + + + + + + + + org.alfresco.jlan.server.config.ServerConfigurationAccessor + + + - - - - - - - - - - - - - - - - diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index 22246fcc77..e5f4d42089 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -143,14 +143,6 @@ value="${alfresco.jmx.dir}/alfresco-jmxrmi.access"/> - - - - - - - diff --git a/config/alfresco/file-servers.properties b/config/alfresco/file-servers.properties deleted file mode 100644 index 42ebedfef8..0000000000 --- a/config/alfresco/file-servers.properties +++ /dev/null @@ -1,11 +0,0 @@ -filesystem.name=Alfresco - -cifs.enabled=true -cifs.localname=${localname} -cifs.domain= -cifs.broadcast=255.255.255.255 -cifs.bindto=0.0.0.0 - -ftp.enabled=true - -nfs.enabled=false diff --git a/config/alfresco/network-protocol-context.xml b/config/alfresco/network-protocol-context.xml index cf9396e598..b57067d0db 100644 --- a/config/alfresco/network-protocol-context.xml +++ b/config/alfresco/network-protocol-context.xml @@ -3,29 +3,6 @@ - - - - classpath:alfresco/file-servers.xml - classpath:alfresco/extension/file-servers-custom.xml - - - - - - - - - - - classpath:alfresco/file-servers.properties - - - - SYSTEM_PROPERTIES_MODE_OVERRIDE - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/alfresco/subsystems/alfrescoAuthentication/alfresco-authentication-context.xml b/config/alfresco/subsystems/alfrescoAuthentication/alfresco-authentication-context.xml index 2d969dd10a..6be73c9672 100644 --- a/config/alfresco/subsystems/alfrescoAuthentication/alfresco-authentication-context.xml +++ b/config/alfresco/subsystems/alfrescoAuthentication/alfresco-authentication-context.xml @@ -1,52 +1,62 @@ - - - - - - - - - ${alfresco.authentication.allowGuestLogin} - - - - - - - - - - - + + + + + + + + + ${alfresco.authentication.allowGuestLogin} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/config/alfresco/subsystems/fileServers/file-servers-context.xml b/config/alfresco/subsystems/fileServers/file-servers-context.xml new file mode 100644 index 0000000000..5cb2e6a16d --- /dev/null +++ b/config/alfresco/subsystems/fileServers/file-servers-context.xml @@ -0,0 +1,398 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${cifs.enabled} + + + ${cifs.serverName} + + + ${cifs.domain} + + + Alfresco CIFS Server + + + + ${cifs.broadcast} + + + + ${cifs.bindto} + + + + + + + ${cifs.tcpipSMB.port} + + + linux,solaris,macosx + + + + + + + ${cifs.bindto} + + + ${cifs.netBIOSSMB.sessionPort} + + + ${cifs.netBIOSSMB.namePort} + + + ${cifs.netBIOSSMB.datagramPort} + + + linux,solaris,macosx + + + + + + true + + + 5 + + + + + + + + true + + + 5 + + + + + + + + + + + ${cifs.WINS.autoDetectEnabled} + + + ${cifs.WINS.primary} + + + ${cifs.WINS.secondary} + + + + + + Negotiate,Socket + + + + + + ${ftp.enabled} + + + + ${ftp.port} + + + + + + + + + + + + + + ${nfs.enabled} + + + + + + + + + + ${filesystem.name} + + + workspace://SpacesStore + + + /app:company_home + + + + __AlfrescoClient.url + + + http://${localname}:8080/alfresco/ + + + + true + + + + + + + + + + + + + + + + + + + AVM + + + true + + + site,staging,author + + + + + + + + + + + + \ No newline at end of file diff --git a/config/alfresco/subsystems/fileServers/file-servers.properties b/config/alfresco/subsystems/fileServers/file-servers.properties new file mode 100644 index 0000000000..02e6030a82 --- /dev/null +++ b/config/alfresco/subsystems/fileServers/file-servers.properties @@ -0,0 +1,23 @@ +filesystem.name=Alfresco + +cifs.enabled=true +cifs.serverName=${localname}A +cifs.domain= +cifs.broadcast=255.255.255.255 +# An empty value indicates bind to all available network adapters +cifs.bindto= +# Can be mapped to non-privileged ports, then use firewall rules to forward requests from the standard ports +cifs.tcpipSMB.port=445 +cifs.netBIOSSMB.sessionPort=139 +cifs.netBIOSSMB.namePort=137 +cifs.netBIOSSMB.datagramPort=138 + +# Optional WINS server primary and secondary IP addresses. Ignored if autoDetectEnabled=true +cifs.WINS.autoDetectEnabled=true +cifs.WINS.primary=1.2.3.4 +cifs.WINS.secondary=5.6.7.8 + +ftp.enabled=true +ftp.port=21 + +nfs.enabled=false diff --git a/source/java/org/alfresco/filesys/AbstractServerConfigurationBean.java b/source/java/org/alfresco/filesys/AbstractServerConfigurationBean.java new file mode 100644 index 0000000000..65c4152f4b --- /dev/null +++ b/source/java/org/alfresco/filesys/AbstractServerConfigurationBean.java @@ -0,0 +1,942 @@ +/* + * 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.filesys; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.EnumSet; +import java.util.Enumeration; +import java.util.Locale; +import java.util.StringTokenizer; + +import net.sf.acegisecurity.AuthenticationManager; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.filesys.alfresco.AlfrescoClientInfoFactory; +import org.alfresco.filesys.alfresco.ExtendedDiskInterface; +import org.alfresco.jlan.debug.DebugConfigSection; +import org.alfresco.jlan.ftp.FTPConfigSection; +import org.alfresco.jlan.netbios.NetBIOSName; +import org.alfresco.jlan.netbios.NetBIOSNameList; +import org.alfresco.jlan.netbios.NetBIOSSession; +import org.alfresco.jlan.netbios.win32.Win32NetBIOS; +import org.alfresco.jlan.oncrpc.nfs.NFSConfigSection; +import org.alfresco.jlan.server.auth.ClientInfo; +import org.alfresco.jlan.server.config.GlobalConfigSection; +import org.alfresco.jlan.server.config.InvalidConfigurationException; +import org.alfresco.jlan.server.config.ServerConfiguration; +import org.alfresco.jlan.smb.server.CIFSConfigSection; +import org.alfresco.jlan.util.IPAddress; +import org.alfresco.jlan.util.Platform; +import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.repo.tenant.TenantService; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.transaction.TransactionService; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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; + +/** + * Alfresco File Server Configuration Bean Class + * + * @author gkspencer + */ +public abstract class AbstractServerConfigurationBean extends ServerConfiguration implements ApplicationListener, ApplicationContextAware { + + // Debug logging + + protected static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol"); + + // IP address representing null + + public static final String BIND_TO_IGNORE = "0.0.0.0"; + + // SMB/CIFS session debug type strings + // + // Must match the bit mask order + + protected static final String m_sessDbgStr[] = { "NETBIOS", "STATE", "RXDATA", "TXDATA", "DUMPDATA", "NEGOTIATE", "TREE", "SEARCH", "INFO", "FILE", + "FILEIO", "TRANSACT", "ECHO", "ERROR", "IPC", "LOCK", "PKTTYPE", "DCERPC", "STATECACHE", "TIMING", "NOTIFY", + "STREAMS", "SOCKET", "PKTPOOL", "PKTSTATS", "THREADPOOL", "BENCHMARK" }; + + // FTP server debug type strings + + protected static final String m_ftpDebugStr[] = { "STATE", "SEARCH", "INFO", "FILE", "FILEIO", "ERROR", "PKTTYPE", + "TIMING", "DATAPORT", "DIRECTORY" }; + + // Default FTP server port + + protected static final int DefaultFTPServerPort = 21; + + // Default FTP anonymous account name + + protected static final String DefaultFTPAnonymousAccount = "anonymous"; + + // NFS server debug type strings + + protected static final String m_nfsDebugStr[] = { "RXDATA", "TXDATA", "DUMPDATA", "SEARCH", "INFO", "FILE", + "FILEIO", "ERROR", "TIMING", "DIRECTORY", "SESSION" }; + + // Token name to substitute current server name into the CIFS server name + + protected static final String TokenLocalName = "${localname}"; + + // Default thread pool size + + protected static final int DefaultThreadPoolInit = 25; + protected static final int DefaultThreadPoolMax = 50; + + // Default memory pool settings + + protected static final int[] DefaultMemoryPoolBufSizes = { 256, 4096, 16384, 66000 }; + protected static final int[] DefaultMemoryPoolInitAlloc = { 20, 20, 5, 5 }; + protected static final int[] DefaultMemoryPoolMaxAlloc = { 100, 50, 50, 50 }; + + + // Memory pool allocation limits + + protected static final int MemoryPoolMinimumAllocation = 5; + protected static final int MemoryPoolMaximumAllocation = 500; + + // Maximum session timeout + + protected static final int MaxSessionTimeout = 60 * 60; // 1 hour + + // Authentication manager + + private AuthenticationManager m_authenticationManager; + + // Disk interface to use for shared filesystems + + private ExtendedDiskInterface m_repoDiskInterface; + + // AVM filesystem interface + + private ExtendedDiskInterface m_avmDiskInterface; + + // Runtime platform type + + private Platform.Type m_platform = Platform.Type.Unchecked; + + // flag to indicate successful initialization + + private boolean m_initialised; + + // Main authentication service, public API + + private AuthenticationService m_authenticationService; + + // Authentication component, for internal functions + + protected AuthenticationComponent m_authenticationComponent; + + // Various services + + private NodeService m_nodeService; + private PersonService m_personService; + private TransactionService m_transactionService; + protected TenantService m_tenantService; + private SearchService m_searchService; + private NamespaceService m_namespaceService; + private AuthorityService m_authorityService; + + // Local server name and domain/workgroup name + + private String m_localName; + private String m_localDomain; + + // Disable use of native code on Windows, do not use any JNI calls + + protected boolean m_disableNativeCode = false; + + /** + * Default constructor + */ + public AbstractServerConfigurationBean() + { + super ( ""); + } + + /** + * Class constructor + * + * @param srvName String + */ + public AbstractServerConfigurationBean( String srvName) + { + super( srvName); + } + + /** + * Set the authentication manager + * + * @param authenticationManager AuthenticationManager + */ + public void setAuthenticationManager(AuthenticationManager authenticationManager) + { + m_authenticationManager = authenticationManager; + } + + /** + * Set the authentication service + * + * @param authenticationService AuthenticationService + */ + public void setAuthenticationService(AuthenticationService authenticationService) + { + m_authenticationService = authenticationService; + } + + /** + * Set the filesystem driver for the node service based filesystem + * + * @param diskInterface DiskInterface + */ + public void setDiskInterface(ExtendedDiskInterface diskInterface) + { + m_repoDiskInterface = diskInterface; + } + + /** + * Set the filesystem driver for the AVM based filesystem + * + */ + public void setAvmDiskInterface(ExtendedDiskInterface diskInterface) + { + m_avmDiskInterface = diskInterface; + } + + /** + * Set the authentication component + * + * @param component AuthenticationComponent + */ + public void setAuthenticationComponent(AuthenticationComponent component) + { + m_authenticationComponent = component; + } + + /** + * Set the node service + * + * @param service NodeService + */ + public void setNodeService(NodeService service) + { + m_nodeService = service; + } + + /** + * Set the person service + * + * @param service PersonService + */ + public void setPersonService(PersonService service) + { + m_personService = service; + } + + /** + * Set the transaction service + * + * @param service TransactionService + */ + public void setTransactionService(TransactionService service) + { + m_transactionService = service; + } + + /** + * Set the tenant service + * + * @param tenantService TenantService + */ + public void setTenantService(TenantService tenantService) + { + m_tenantService = tenantService; + } + + /** + * Set the search service + * + * @param searchService SearchService + */ + public void setSearchService(SearchService searchService) + { + m_searchService = searchService; + } + + /** + * Set the namespace service + * + * @param namespaceService NamespaceService + */ + public void setNamespaceService(NamespaceService namespaceService) + { + m_namespaceService = namespaceService; + } + + /** + * Set the authority service + * + * @param authService AuthorityService + */ + public void setAuthorityService(AuthorityService authService) + { + m_authorityService = authService; + } + + /** + * Check if the configuration has been initialized + * + * @return Returns true if the configuration was fully initialised + */ + public boolean isInitialised() + { + return m_initialised; + } + + /** + * Check if the SMB server is enabled + * + * @return boolean + */ + public final boolean isSMBServerEnabled() + { + return hasConfigSection( CIFSConfigSection.SectionName); + } + + /** + * Check if the FTP server is enabled + * + * @return boolean + */ + public final boolean isFTPServerEnabled() + { + return hasConfigSection( FTPConfigSection.SectionName); + } + + /** + * Check if the NFS server is enabled + * + * @return boolean + */ + public final boolean isNFSServerEnabled() + { + return hasConfigSection( NFSConfigSection.SectionName); + } + + /** + * Return the repository disk interface to be used to create shares + * + * @return DiskInterface + */ + public final ExtendedDiskInterface getRepoDiskInterface() + { + return m_repoDiskInterface; + } + + /** + * Return the disk interface to be used to create AVM filesystem shares + * + * @return DiskInterface + */ + public final ExtendedDiskInterface getAvmDiskInterface() + { + return m_avmDiskInterface; + } + + /** + * Initialize the configuration using the configuration service + */ + public void init() + { + // Check that all required properties have been set + + if (m_authenticationManager == null) + { + throw new AlfrescoRuntimeException("Property 'authenticationManager' not set"); + } + else if (m_authenticationComponent == null) + { + throw new AlfrescoRuntimeException("Property 'authenticationComponent' not set"); + } + else if (m_authenticationService == null) + { + throw new AlfrescoRuntimeException("Property 'authenticationService' not set"); + } + else if (m_nodeService == null) + { + throw new AlfrescoRuntimeException("Property 'nodeService' not set"); + } + else if (m_personService == null) + { + throw new AlfrescoRuntimeException("Property 'personService' not set"); + } + else if (m_transactionService == null) + { + throw new AlfrescoRuntimeException("Property 'transactionService' not set"); + } + else if (m_repoDiskInterface == null) + { + throw new AlfrescoRuntimeException("Property 'diskInterface' not set"); + } + else if (m_authorityService == null) + { + throw new AlfrescoRuntimeException("Property 'authorityService' not set"); + } + + // Set the platform type + + determinePlatformType(); + + // Create the debug output configuration using a logger for all file server debug output + + DebugConfigSection debugConfig = new DebugConfigSection( this); + try + { + debugConfig.setDebug("org.alfresco.filesys.debug.FileServerDebugInterface", null); + } + catch ( InvalidConfigurationException ex) + { + } + + // Create the global configuration and Alfresco configuration sections + + new GlobalConfigSection( this); + new AlfrescoConfigSection( this); + + // Install the Alfresco client information factory + + ClientInfo.setFactory( new AlfrescoClientInfoFactory()); + + // Initialize the filesystems + + boolean filesysInitOK = false; + + try + { + // Process the core server configuration + processCoreServerConfig(); + + // Process the security configuration + processSecurityConfig(); + + // Process the filesystems configuration + processFilesystemsConfig(); + + // Indicate that the filesystems were initialized + filesysInitOK = true; + } + catch (Exception ex) + { + // Configuration error + + logger.error("File server configuration error, " + ex.getMessage(), ex); + } + + // Initialize the CIFS and FTP servers, if the filesystem(s) initialized successfully + + if ( filesysInitOK == true) + { + // Initialize the CIFS server + + try + { + + // Process the CIFS server configuration + processCIFSServerConfig(); + + // Log the successful startup + logger.info("CIFS server " + (isSMBServerEnabled() ? "" : "NOT ") + "started"); + } + catch (UnsatisfiedLinkError ex) + { + // Error accessing the Win32NetBIOS DLL code + + logger.error("Error accessing Win32 NetBIOS, check DLL is on the path"); + + // Disable the CIFS server + + removeConfigSection( CIFSConfigSection.SectionName); + } + catch (Throwable ex) + { + // Configuration error + + logger.error("CIFS server configuration error, " + ex.getMessage(), ex); + + // Disable the CIFS server + + removeConfigSection( CIFSConfigSection.SectionName); + } + + // Initialize the FTP server + + try + { + // Process the FTP server configuration + processFTPServerConfig(); + + // Log the successful startup + + logger.info("FTP server " + (isFTPServerEnabled() ? "" : "NOT ") + "started"); + } + catch (Exception ex) + { + // Configuration error + + logger.error("FTP server configuration error, " + ex.getMessage(), ex); + } + + // Initialize the NFS server + + try + { + // Process the NFS server configuration + processNFSServerConfig(); + + // Log the successful startup + + logger.info("NFS server " + (isNFSServerEnabled() ? "" : "NOT ") + "started"); + } + catch (Exception ex) + { + // Configuration error + + logger.error("NFS server configuration error, " + ex.getMessage(), ex); + } + } + else + { + // Log the error + + logger.error("CIFS and FTP servers not started due to filesystem initialization error"); + } + } + + protected abstract void processCoreServerConfig() throws InvalidConfigurationException; + + protected abstract void processSecurityConfig(); + + protected abstract void processFilesystemsConfig(); + + protected abstract void processCIFSServerConfig(); + + protected abstract void processNFSServerConfig(); + + protected abstract void processFTPServerConfig(); + + /** + * Close the configuration bean + */ + public final void closeConfiguration() + { + super.closeConfiguration(); + } + + /** + * Determine the platform type + */ + private final void determinePlatformType() + { + if ( m_platform == Platform.Type.Unchecked) + m_platform = Platform.isPlatformType(); + } + + /** + * Parse the platforms attribute returning the set of platform ids + * + * @param platformStr String + * @return EnumSet + */ + protected final EnumSet parsePlatformString(String platformStr) + { + // Split the platform string and build up a set of platform types + + EnumSet platformTypes = EnumSet.noneOf(Platform.Type.class); + if (platformStr == null || platformStr.length() == 0) + return platformTypes; + + StringTokenizer token = new StringTokenizer(platformStr.toUpperCase(Locale.ENGLISH), ","); + String typ = null; + + try + { + while (token.hasMoreTokens()) + { + + // Get the current platform type string and validate + + typ = token.nextToken().trim(); + Platform.Type platform = Platform.Type.valueOf(typ); + + if (platform != Platform.Type.Unknown) + platformTypes.add(platform); + else + throw new AlfrescoRuntimeException("Invalid platform type, " + typ); + } + } + catch (IllegalArgumentException ex) + { + throw new AlfrescoRuntimeException("Invalid platform type, " + typ); + } + + // Return the platform types + + return platformTypes; + } + + /** + * Get the local server name and optionally trim the domain name + * + * @param trimDomain boolean + * @return String + */ + public final String getLocalServerName(boolean trimDomain) + { + // Check if the name has already been set + + if (m_localName != null) + return m_localName; + + // Find the local server name + + String srvName = null; + + if (getPlatformType() == Platform.Type.WINDOWS && !isNativeCodeDisabled()) + { + // Get the local name via JNI + + srvName = Win32NetBIOS.GetLocalNetBIOSName(); + } + else + { + // Get the DNS name of the local system + + try + { + srvName = InetAddress.getLocalHost().getHostName(); + } + catch (UnknownHostException ex) + { + } + } + + // Strip the domain name + + if (trimDomain && srvName != null) + { + int pos = srvName.indexOf("."); + if (pos != -1) + srvName = srvName.substring(0, pos); + } + + // Save the local server name + + m_localName = srvName; + + // Return the local server name + + return srvName; + } + + /** + * Get the local domain/workgroup name + * + * @return String + */ + public final String getLocalDomainName() + { + // Check if the local domain has been set + + if (m_localDomain != null) + return m_localDomain; + + // Find the local domain name + + String domainName = null; + + if (getPlatformType() == Platform.Type.WINDOWS && !isNativeCodeDisabled()) + { + // Get the local domain/workgroup name via JNI + + domainName = Win32NetBIOS.GetLocalDomainName(); + + // Debug + + if (logger.isDebugEnabled()) + logger.debug("Local domain name is " + domainName + " (via JNI)"); + } + else + { + NetBIOSName nbName = null; + + try + { + // Try and find the browse master on the local network + + nbName = NetBIOSSession.FindName(NetBIOSName.BrowseMasterName, NetBIOSName.BrowseMasterGroup, 5000); + + // Log the browse master details + + if (logger.isDebugEnabled()) + logger.debug("Found browse master at " + nbName.getIPAddressString(0)); + + // Get the NetBIOS name list from the browse master + + NetBIOSNameList nbNameList = NetBIOSSession.FindNamesForAddress(nbName.getIPAddressString(0)); + if (nbNameList != null) + { + nbName = nbNameList.findName(NetBIOSName.MasterBrowser, false); + // Set the domain/workgroup name + if (nbName != null) + domainName = nbName.getName(); + } + } + catch (IOException ex) + { + } + } + + // Save the local domain name + + m_localDomain = domainName; + + // Return the local domain/workgroup name + + return domainName; + } + + /** + * Parse an adapter name string and return the matching address + * + * @param adapter String + * @return InetAddress + * @exception InvalidConfigurationException + */ + protected final InetAddress parseAdapterName(String adapter) + throws InvalidConfigurationException { + + NetworkInterface ni = null; + + try { + ni = NetworkInterface.getByName( adapter); + } + catch (SocketException ex) { + throw new InvalidConfigurationException( "Invalid adapter name, " + adapter); + } + + if ( ni == null) + throw new InvalidConfigurationException( "Invalid network adapter name, " + adapter); + + // Get the IP address for the adapter + + InetAddress adapAddr = null; + Enumeration addrEnum = ni.getInetAddresses(); + + while ( addrEnum.hasMoreElements() && adapAddr == null) { + + // Get the current address + + InetAddress addr = addrEnum.nextElement(); + if ( IPAddress.isNumericAddress( addr.getHostAddress())) + adapAddr = addr; + } + + // Check if we found the IP address to bind to + + if ( adapAddr == null) + throw new InvalidConfigurationException( "Adapter " + adapter + " does not have a valid IP address"); + + // Return the adapter address + + return adapAddr; + } + + private ApplicationContext applicationContext = null; + + + /* (non-Javadoc) + * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) + */ + public void onApplicationEvent(ApplicationEvent event) + { + if (event instanceof ContextRefreshedEvent) + { + ContextRefreshedEvent refreshEvent = (ContextRefreshedEvent)event; + ApplicationContext refreshContext = refreshEvent.getApplicationContext(); + if (refreshContext != null && refreshContext.equals(applicationContext)) + { + // Initialize the bean + + init(); + } + } + } + + /* (non-Javadoc) + * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) + */ + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException + { + this.applicationContext = applicationContext; + } + + /** + * Return the authentication service + * + * @return AuthenticationService + */ + protected final AuthenticationService getAuthenticationService() + { + return m_authenticationService; + } + + /** + * Return the authentication component + * + * @return AuthenticationComponent + */ + protected final AuthenticationComponent getAuthenticationComponent() + { + return m_authenticationComponent; + } + + /** + * Return the node service + * + * @return NodeService + */ + protected final NodeService getNodeService() + { + return m_nodeService; + } + + /** + * Return the person service + * + * @return PersonService + */ + protected final PersonService getPersonService() + { + return m_personService; + } + + /** + * Return the transaction service + * + * @return TransactionService + */ + protected final TransactionService getTransactionService() + { + return m_transactionService; + } + + /** + * Return the tenant service + * + * @return TenantService + */ + protected final TenantService getTenantService() + { + return m_tenantService; + } + + /** + * Return the search service + * + * @return SearchService + */ + protected final SearchService getSearchService() + { + return m_searchService; + } + + /** + * Return the namespace service + * + * @return NamespaceService + */ + protected final NamespaceService getNamespaceService() + { + return m_namespaceService; + } + + /** + * Check if native code calls are disabled + * + * @return boolean + */ + public final boolean isNativeCodeDisabled() + { + return m_disableNativeCode; + } + + /** + * Return the named bean + * + * @param beanName String + * @return Object + */ + public final Object getBean( String beanName) + { + return applicationContext.getBean( beanName); + } + + /** + * Return the applicatin context + * + * @return ApplicationContext + */ + public final ApplicationContext getApplicationsContext() + { + return applicationContext; + } + + /** + * Return the authority service + * + * @return AuthorityService + */ + public final AuthorityService getAuthorityService() + { + return m_authorityService; + } +} diff --git a/source/java/org/alfresco/filesys/AlfrescoConfigSection.java b/source/java/org/alfresco/filesys/AlfrescoConfigSection.java index 7c5472d8af..7aa25a99e6 100644 --- a/source/java/org/alfresco/filesys/AlfrescoConfigSection.java +++ b/source/java/org/alfresco/filesys/AlfrescoConfigSection.java @@ -78,7 +78,7 @@ public class AlfrescoConfigSection extends ConfigSection { * * @param config ServerConfigurationBean */ - public AlfrescoConfigSection(ServerConfigurationBean config) { + public AlfrescoConfigSection(AbstractServerConfigurationBean config) { super( SectionName, config); // Copy values from the server configuration bean diff --git a/source/java/org/alfresco/filesys/CIFSServerBean.java b/source/java/org/alfresco/filesys/CIFSServerBean.java index 7aa45cf6a4..5fdf747c50 100644 --- a/source/java/org/alfresco/filesys/CIFSServerBean.java +++ b/source/java/org/alfresco/filesys/CIFSServerBean.java @@ -27,14 +27,16 @@ package org.alfresco.filesys; import java.io.IOException; import java.io.PrintStream; import java.net.SocketException; -import java.util.Vector; +import java.util.LinkedList; +import java.util.List; +import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.jlan.netbios.server.NetBIOSNameServer; import org.alfresco.jlan.server.NetworkServer; +import org.alfresco.jlan.server.SessionListener; import org.alfresco.jlan.server.config.ServerConfiguration; import org.alfresco.jlan.smb.server.CIFSConfigSection; import org.alfresco.jlan.smb.server.SMBServer; -import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.util.AbstractLifecycleBean; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -60,7 +62,8 @@ public class CIFSServerBean extends AbstractLifecycleBean // List of CIFS server components - private Vector serverList = new Vector(); + private List serverList = new LinkedList(); + private List sessionListeners = new LinkedList(); /** * Class constructor @@ -72,6 +75,11 @@ public class CIFSServerBean extends AbstractLifecycleBean m_filesysConfig = serverConfig; } + public void setSessionListeners(List sessionListeners) + { + this.sessionListeners = sessionListeners; + } + /** * Return the server configuration * @@ -112,8 +120,16 @@ public class CIFSServerBean extends AbstractLifecycleBean serverList.add(new NetBIOSNameServer(m_filesysConfig)); // Create the SMB server - - serverList.add(new SMBServer(m_filesysConfig)); + SMBServer smbServer = new SMBServer(m_filesysConfig); + serverList.add(smbServer); + + // Install any SMB server listeners so they receive callbacks when sessions are + // opened/closed on the SMB server (e.g. for Authenticators) + + for (SessionListener sessionListener : this.sessionListeners) + { + smbServer.addSessionListener(sessionListener); + } // Add the servers to the configuration diff --git a/source/java/org/alfresco/filesys/NullSessionListener.java b/source/java/org/alfresco/filesys/NullSessionListener.java new file mode 100644 index 0000000000..fa5f95ff2e --- /dev/null +++ b/source/java/org/alfresco/filesys/NullSessionListener.java @@ -0,0 +1,51 @@ +/* + * 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.filesys; + +import org.alfresco.jlan.server.SessionListener; +import org.alfresco.jlan.server.SrvSession; + +/** + * A benign implementation of the SessionListener interface. Allows the authentication subsystems to share a uniform + * interface. Those without a need for a live session listeners can use this bean. + * + * @author dward + */ +public class NullSessionListener implements SessionListener +{ + + public void sessionClosed(SrvSession sess) + { + } + + public void sessionCreated(SrvSession sess) + { + } + + public void sessionLoggedOn(SrvSession sess) + { + } + +} diff --git a/source/java/org/alfresco/filesys/ServerConfigurationBean.java b/source/java/org/alfresco/filesys/ServerConfigurationBean.java index 5a453ca5a5..cc7d773dbc 100644 --- a/source/java/org/alfresco/filesys/ServerConfigurationBean.java +++ b/source/java/org/alfresco/filesys/ServerConfigurationBean.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 @@ -38,21 +38,28 @@ import java.util.ArrayList; import java.util.EnumSet; import java.util.Enumeration; import java.util.List; -import java.util.Locale; import java.util.StringTokenizer; -import org.alfresco.jlan.debug.DebugConfigSection; +import org.alfresco.config.Config; +import org.alfresco.config.ConfigElement; +import org.alfresco.config.ConfigLookupContext; +import org.alfresco.config.ConfigService; +import org.alfresco.config.element.GenericConfigElement; +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.filesys.alfresco.DesktopAction; +import org.alfresco.filesys.alfresco.DesktopActionException; +import org.alfresco.filesys.alfresco.DesktopActionTable; +import org.alfresco.filesys.avm.AVMContext; +import org.alfresco.filesys.avm.AVMDiskDriver; +import org.alfresco.filesys.repo.ContentContext; import org.alfresco.jlan.ftp.FTPConfigSection; import org.alfresco.jlan.ftp.FTPPath; import org.alfresco.jlan.ftp.InvalidPathException; -import org.alfresco.jlan.netbios.NetBIOSName; -import org.alfresco.jlan.netbios.NetBIOSNameList; import org.alfresco.jlan.netbios.NetBIOSSession; import org.alfresco.jlan.netbios.RFCNetBIOSProtocol; import org.alfresco.jlan.netbios.win32.Win32NetBIOS; import org.alfresco.jlan.oncrpc.nfs.NFSConfigSection; -import org.alfresco.jlan.server.auth.CifsAuthenticator; -import org.alfresco.jlan.server.auth.ClientInfo; +import org.alfresco.jlan.server.auth.ICifsAuthenticator; import org.alfresco.jlan.server.auth.acl.ACLParseException; import org.alfresco.jlan.server.auth.acl.AccessControl; import org.alfresco.jlan.server.auth.acl.AccessControlList; @@ -62,10 +69,8 @@ import org.alfresco.jlan.server.auth.passthru.DomainMapping; import org.alfresco.jlan.server.auth.passthru.RangeDomainMapping; import org.alfresco.jlan.server.auth.passthru.SubnetDomainMapping; import org.alfresco.jlan.server.config.CoreServerConfigSection; -import org.alfresco.jlan.server.config.GlobalConfigSection; 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.server.core.DeviceContextException; import org.alfresco.jlan.server.core.ShareType; import org.alfresco.jlan.server.filesys.DiskInterface; @@ -78,51 +83,14 @@ 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.config.Config; -import org.alfresco.config.ConfigElement; -import org.alfresco.config.ConfigLookupContext; -import org.alfresco.config.ConfigService; -import org.alfresco.config.element.GenericConfigElement; -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.filesys.alfresco.AlfrescoClientInfoFactory; -import org.alfresco.filesys.alfresco.DesktopAction; -import org.alfresco.filesys.alfresco.DesktopActionException; -import org.alfresco.filesys.alfresco.DesktopActionTable; -import org.alfresco.filesys.alfresco.HomeShareMapper; -import org.alfresco.filesys.avm.AVMContext; -import org.alfresco.filesys.avm.AVMDiskDriver; -import org.alfresco.filesys.repo.ContentContext; -import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.NTLMMode; -import org.alfresco.repo.tenant.TenantService; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.search.SearchService; -import org.alfresco.service.cmr.security.AuthenticationService; -import org.alfresco.service.cmr.security.AuthorityService; -import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.transaction.TransactionService; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -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; - -import net.sf.acegisecurity.AuthenticationManager; /** * Alfresco File Server Configuration Bean Class * * @author gkspencer */ -public class ServerConfigurationBean extends ServerConfiguration implements ApplicationListener, ApplicationContextAware { - - // Debug logging - - protected static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol"); +public class ServerConfigurationBean extends AbstractServerConfigurationBean { // Filesystem configuration constants @@ -138,115 +106,11 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl public static final String SERVER_CONFIGURATION = "fileServerConfiguration"; - // IP address representing null - - public static final String BIND_TO_IGNORE = "0.0.0.0"; - - // SMB/CIFS session debug type strings - // - // Must match the bit mask order - - private static final String m_sessDbgStr[] = { "NETBIOS", "STATE", "RXDATA", "TXDATA", "DUMPDATA", "NEGOTIATE", "TREE", "SEARCH", "INFO", "FILE", - "FILEIO", "TRANSACT", "ECHO", "ERROR", "IPC", "LOCK", "PKTTYPE", "DCERPC", "STATECACHE", "TIMING", "NOTIFY", - "STREAMS", "SOCKET", "PKTPOOL", "PKTSTATS", "THREADPOOL", "BENCHMARK" }; - - // FTP server debug type strings - - private static final String m_ftpDebugStr[] = { "STATE", "SEARCH", "INFO", "FILE", "FILEIO", "ERROR", "PKTTYPE", - "TIMING", "DATAPORT", "DIRECTORY" }; - - // Default FTP server port - - private static final int DefaultFTPServerPort = 21; - - // Default FTP anonymous account name - - private static final String DefaultFTPAnonymousAccount = "anonymous"; - - // NFS server debug type strings - - private static final String m_nfsDebugStr[] = { "RXDATA", "TXDATA", "DUMPDATA", "SEARCH", "INFO", "FILE", - "FILEIO", "ERROR", "TIMING", "DIRECTORY", "SESSION" }; - - // Token name to substitute current server name into the CIFS server name - - private static final String TokenLocalName = "${localname}"; - - // Default thread pool size - - private static final int DefaultThreadPoolInit = 25; - private static final int DefaultThreadPoolMax = 50; - - // Default memory pool settings - - private static final int[] DefaultMemoryPoolBufSizes = { 256, 4096, 16384, 66000 }; - private static final int[] DefaultMemoryPoolInitAlloc = { 20, 20, 5, 5 }; - private static final int[] DefaultMemoryPoolMaxAlloc = { 100, 50, 50, 50 }; - - // Memory pool packet size limits - - private static final int MemoryPoolMinimumPacketSize = 256; - private static final int MemoryPoolMaximumPacketSize = 128 * (int) MemorySize.KILOBYTE; - - // Memory pool allocation limits - - private static final int MemoryPoolMinimumAllocation = 5; - private static final int MemoryPoolMaximumAllocation = 500; - - // Maximum session timeout - - private static final int MaxSessionTimeout = 60 * 60; // 1 hour - - // Authentication manager - - private AuthenticationManager m_authenticationManager; - // Configuration service - private ConfigService m_configService; - // Disk interface to use for shared filesystems + private ConfigLookupContext configCtx; - private DiskInterface m_repoDiskInterface; - - // AVM filesystem interface - - private DiskInterface m_avmDiskInterface; - - // Runtime platform type - - private Platform.Type m_platform = Platform.Type.Unchecked; - - // flag to indicate successful initialization - - private boolean m_initialised; - - // Main authentication service, public API - - private AuthenticationService m_authenticationService; - - // Authentication component, for internal functions - - private AuthenticationComponent m_authenticationComponent; - - // Various services - - private NodeService m_nodeService; - private PersonService m_personService; - private TransactionService m_transactionService; - private TenantService m_tenantService; - private SearchService m_searchService; - private NamespaceService m_namespaceService; - private AuthorityService m_authorityService; - - // Local server name and domain/workgroup name - - private String m_localName; - private String m_localDomain; - - // Disable use of native code on Windows, do not use any JNI calls - - private boolean m_disableNativeCode = false; /** * Default constructor @@ -266,26 +130,6 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl super( srvName); } - /** - * Set the authentication manager - * - * @param authenticationManager AuthenticationManager - */ - public void setAuthenticationManager(AuthenticationManager authenticationManager) - { - m_authenticationManager = authenticationManager; - } - - /** - * Set the authentication service - * - * @param authenticationService AuthenticationService - */ - public void setAuthenticationService(AuthenticationService authenticationService) - { - m_authenticationService = authenticationService; - } - /** * Set the configuration service * @@ -296,372 +140,29 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl m_configService = configService; } - /** - * Set the filesystem driver for the node service based filesystem - * - * @param diskInterface DiskInterface - */ - public void setDiskInterface(DiskInterface diskInterface) - { - m_repoDiskInterface = diskInterface; - } - - /** - * Set the filesystem driver for the AVM based filesystem - * - */ - public void setAvmDiskInterface(DiskInterface diskInterface) - { - m_avmDiskInterface = diskInterface; - } - - /** - * Set the authentication component - * - * @param component AuthenticationComponent - */ - public void setAuthenticationComponent(AuthenticationComponent component) - { - m_authenticationComponent = component; - } - - /** - * Set the node service - * - * @param service NodeService - */ - public void setNodeService(NodeService service) - { - m_nodeService = service; - } - - /** - * Set the person service - * - * @param service PersonService - */ - public void setPersonService(PersonService service) - { - m_personService = service; - } - - /** - * Set the transaction service - * - * @param service TransactionService - */ - public void setTransactionService(TransactionService service) - { - m_transactionService = service; - } - - /** - * Set the tenant service - * - * @param tenantService TenantService - */ - public void setTenantService(TenantService tenantService) - { - m_tenantService = tenantService; - } - - /** - * Set the search service - * - * @param searchService SearchService - */ - public void setSearchService(SearchService searchService) - { - m_searchService = searchService; - } - - /** - * Set the namespace service - * - * @param namespaceService NamespaceService - */ - public void setNamespaceService(NamespaceService namespaceService) - { - m_namespaceService = namespaceService; - } - - /** - * Set the authority service - * - * @param authService AuthorityService - */ - public void setAuthorityService(AuthorityService authService) - { - m_authorityService = authService; - } - - /** - * Check if the configuration has been initialized - * - * @return Returns true if the configuration was fully initialised - */ - public boolean isInitialised() - { - return m_initialised; - } - - /** - * Check if the SMB server is enabled - * - * @return boolean - */ - public final boolean isSMBServerEnabled() - { - return hasConfigSection( CIFSConfigSection.SectionName); - } - - /** - * Check if the FTP server is enabled - * - * @return boolean - */ - public final boolean isFTPServerEnabled() - { - return hasConfigSection( FTPConfigSection.SectionName); - } - - /** - * Check if the NFS server is enabled - * - * @return boolean - */ - public final boolean isNFSServerEnabled() - { - return hasConfigSection( NFSConfigSection.SectionName); - } - - /** - * Return the repository disk interface to be used to create shares - * - * @return DiskInterface - */ - public final DiskInterface getRepoDiskInterface() - { - return m_repoDiskInterface; - } - - /** - * Return the disk interface to be used to create AVM filesystem shares - * - * @return DiskInterface - */ - public final DiskInterface getAvmDiskInterface() - { - return m_avmDiskInterface; - } - /** * Initialize the configuration using the configuration service */ public void init() { // Check that all required properties have been set - - if (m_authenticationManager == null) - { - throw new AlfrescoRuntimeException("Property 'authenticationManager' not set"); - } - else if (m_authenticationComponent == null) - { - throw new AlfrescoRuntimeException("Property 'authenticationComponent' not set"); - } - else if (m_authenticationService == null) - { - throw new AlfrescoRuntimeException("Property 'authenticationService' not set"); - } - else if (m_nodeService == null) - { - throw new AlfrescoRuntimeException("Property 'nodeService' not set"); - } - else if (m_personService == null) - { - throw new AlfrescoRuntimeException("Property 'personService' not set"); - } - else if (m_transactionService == null) - { - throw new AlfrescoRuntimeException("Property 'transactionService' not set"); - } - else if (m_repoDiskInterface == null) - { - throw new AlfrescoRuntimeException("Property 'diskInterface' not set"); - } - else if (m_configService == null) + if (m_configService == null) { throw new AlfrescoRuntimeException("Property 'configService' not set"); } - else if (m_authorityService == null) - { - throw new AlfrescoRuntimeException("Property 'authorityService' not set"); - } // Create the configuration context - - ConfigLookupContext configCtx = new ConfigLookupContext(ConfigArea); - - // Set the platform type - - determinePlatformType(); - - // Create the debug output configuration using a logger for all file server debug output + configCtx = new ConfigLookupContext(ConfigArea); - DebugConfigSection debugConfig = new DebugConfigSection( this); - try - { - debugConfig.setDebug("org.alfresco.filesys.debug.FileServerDebugInterface", null); - } - catch ( InvalidConfigurationException ex) - { - } - - // Create the global configuration and Alfresco configuration sections - - new GlobalConfigSection( this); - new AlfrescoConfigSection( this); - - // Install the Alfresco client information factory - - ClientInfo.setFactory( new AlfrescoClientInfoFactory()); - - // Initialize the filesystems - - boolean filesysInitOK = false; - Config config = null; - - try - { - // Process the core server configuration - - config = m_configService.getConfig(ConfigCoreServer, configCtx); - processCoreServerConfig( config); - - // Process the security configuration - - config = m_configService.getConfig(ConfigSecurity, configCtx); - processSecurityConfig( config); - - // Process the filesystems configuration - - config = m_configService.getConfig(ConfigFilesystems, configCtx); - processFilesystemsConfig( config); - - // Indicate that the filesystems were initialized - - filesysInitOK = true; - } - catch (Exception ex) - { - // Configuration error - - logger.error("File server configuration error, " + ex.getMessage(), ex); - } - - // Initialize the CIFS and FTP servers, if the filesystem(s) initialized successfully - - if ( filesysInitOK == true) - { - // Initialize the CIFS server - - try - { - - // Process the CIFS server configuration - - config = m_configService.getConfig(ConfigCIFS, configCtx); - processCIFSServerConfig(config); - - // Log the successful startup - - logger.info("CIFS server " + (isSMBServerEnabled() ? "" : "NOT ") + "started"); - } - catch (UnsatisfiedLinkError ex) - { - // Error accessing the Win32NetBIOS DLL code - - logger.error("Error accessing Win32 NetBIOS, check DLL is on the path"); - - // Disable the CIFS server - - removeConfigSection( CIFSConfigSection.SectionName); - } - catch (Throwable ex) - { - // Configuration error - - logger.error("CIFS server configuration error, " + ex.getMessage(), ex); - - // Disable the CIFS server - - removeConfigSection( CIFSConfigSection.SectionName); - } - - // Initialize the FTP server - - try - { - // Process the FTP server configuration - - config = m_configService.getConfig(ConfigFTP, configCtx); - processFTPServerConfig(config); - - // Log the successful startup - - logger.info("FTP server " + (isFTPServerEnabled() ? "" : "NOT ") + "started"); - } - catch (Exception ex) - { - // Configuration error - - logger.error("FTP server configuration error, " + ex.getMessage(), ex); - } - - // Initialize the NFS server - - try - { - // Process the NFS server configuration - - config = m_configService.getConfig(ConfigNFS, configCtx); - processNFSServerConfig(config); - - // Log the successful startup - - logger.info("NFS server " + (isNFSServerEnabled() ? "" : "NOT ") + "started"); - } - catch (Exception ex) - { - // Configuration error - - logger.error("NFS server configuration error, " + ex.getMessage(), ex); - } - } - else - { - // Log the error - - logger.error("CIFS and FTP servers not started due to filesystem initialization error"); - } + super.init(); } /** - * Close the configuration bean + * Process the CIFS server configuration */ - public final void closeConfiguration() + protected void processCIFSServerConfig() { - super.closeConfiguration(); - } - - /** - * Determine the platform type - */ - private final void determinePlatformType() - { - if ( m_platform == Platform.Type.Unchecked) - m_platform = Platform.isPlatformType(); + processCIFSServerConfig(m_configService.getConfig(ConfigCIFS, configCtx)); } /** @@ -930,7 +431,7 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl // Initialize and set the authenticator class - cifsConfig.setAuthenticator(authClass, authElem, CifsAuthenticator.USER_MODE, allowGuest); + cifsConfig.setAuthenticator(authClass, authElem, ICifsAuthenticator.USER_MODE, allowGuest); } else throw new AlfrescoRuntimeException("CIFS authenticator not specified"); @@ -1719,6 +1220,14 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl } } + /** + * Process the FTP server configuration + */ + protected void processFTPServerConfig() + { + processFTPServerConfig(m_configService.getConfig(ConfigFTP, configCtx)); + } + /** * Process the FTP server configuration * @@ -1988,6 +1497,14 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl } + /** + * Process the NFS server configuration + */ + protected void processNFSServerConfig() + { + processNFSServerConfig(m_configService.getConfig(ConfigNFS, configCtx)); + } + /** * Process the NFS server configuration * @@ -2217,6 +1734,14 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl } } + /** + * Process the filesystems configuration + */ + protected void processFilesystemsConfig() + { + processFilesystemsConfig(m_configService.getConfig(ConfigFilesystems, configCtx)); + } + /** * Process the filesystems configuration * @@ -2448,6 +1973,14 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl } } + /** + * Process the security configuration + */ + protected void processSecurityConfig() + { + processSecurityConfig(m_configService.getConfig(ConfigSecurity, configCtx)); + } + /** * Process the security configuration * @@ -2606,6 +2139,18 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl } } + /** + * Process the core server configuration + * + * @param config Config + * @exception InvalidConfigurationException + */ + protected void processCoreServerConfig() + throws InvalidConfigurationException + { + processCoreServerConfig(m_configService.getConfig(ConfigCoreServer, configCtx)); + } + /** * Process the core server configuration * @@ -3041,365 +2586,5 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl return desktopActions; } - - /** - * Parse the platforms attribute returning the set of platform ids - * - * @param platformStr String - * @return EnumSet - */ - private final EnumSet parsePlatformString(String platformStr) - { - // Split the platform string and build up a set of platform types - - EnumSet platformTypes = EnumSet.noneOf(Platform.Type.class); - if (platformStr == null || platformStr.length() == 0) - return platformTypes; - - StringTokenizer token = new StringTokenizer(platformStr.toUpperCase(Locale.ENGLISH), ","); - String typ = null; - - try - { - while (token.hasMoreTokens()) - { - - // Get the current platform type string and validate - - typ = token.nextToken().trim(); - Platform.Type platform = Platform.Type.valueOf(typ); - - if (platform != Platform.Type.Unknown) - platformTypes.add(platform); - else - throw new AlfrescoRuntimeException("Invalid platform type, " + typ); - } - } - catch (IllegalArgumentException ex) - { - throw new AlfrescoRuntimeException("Invalid platform type, " + typ); - } - - // Return the platform types - - return platformTypes; - } - - /** - * Get the local server name and optionally trim the domain name - * - * @param trimDomain boolean - * @return String - */ - public final String getLocalServerName(boolean trimDomain) - { - // Check if the name has already been set - if (m_localName != null) - return m_localName; - - // Find the local server name - - String srvName = null; - - if (getPlatformType() == Platform.Type.WINDOWS && isNativeCodeDisabled() == false) - { - // Get the local name via JNI - - srvName = Win32NetBIOS.GetLocalNetBIOSName(); - } - else - { - // Get the DNS name of the local system - - try - { - srvName = InetAddress.getLocalHost().getHostName(); - } - catch (UnknownHostException ex) - { - } - } - - // Strip the domain name - - if (trimDomain && srvName != null) - { - int pos = srvName.indexOf("."); - if (pos != -1) - srvName = srvName.substring(0, pos); - } - - // Save the local server name - - m_localName = srvName; - - // Return the local server name - - return srvName; - } - - /** - * Get the local domain/workgroup name - * - * @return String - */ - public final String getLocalDomainName() - { - // Check if the local domain has been set - - if (m_localDomain != null) - return m_localDomain; - - // Find the local domain name - - String domainName = null; - - if (getPlatformType() == Platform.Type.WINDOWS && isNativeCodeDisabled() == false) - { - // Get the local domain/workgroup name via JNI - - domainName = Win32NetBIOS.GetLocalDomainName(); - - // Debug - - if (logger.isDebugEnabled()) - logger.debug("Local domain name is " + domainName + " (via JNI)"); - } - else - { - NetBIOSName nbName = null; - - try - { - // Try and find the browse master on the local network - - nbName = NetBIOSSession.FindName(NetBIOSName.BrowseMasterName, NetBIOSName.BrowseMasterGroup, 5000); - - // Log the browse master details - - if (logger.isDebugEnabled()) - logger.debug("Found browse master at " + nbName.getIPAddressString(0)); - - // Get the NetBIOS name list from the browse master - - NetBIOSNameList nbNameList = NetBIOSSession.FindNamesForAddress(nbName.getIPAddressString(0)); - if (nbNameList != null) - { - nbName = nbNameList.findName(NetBIOSName.MasterBrowser, false); - // Set the domain/workgroup name - if (nbName != null) - domainName = nbName.getName(); - } - } - catch (IOException ex) - { - } - } - - // Save the local domain name - - m_localDomain = domainName; - - // Return the local domain/workgroup name - - return domainName; - } - - /** - * Parse an adapter name string and return the matching address - * - * @param adapter String - * @return InetAddress - * @exception InvalidConfigurationException - */ - protected final InetAddress parseAdapterName(String adapter) - throws InvalidConfigurationException { - - NetworkInterface ni = null; - - try { - ni = NetworkInterface.getByName( adapter); - } - catch (SocketException ex) { - throw new InvalidConfigurationException( "Invalid adapter name, " + adapter); - } - - if ( ni == null) - throw new InvalidConfigurationException( "Invalid network adapter name, " + adapter); - - // Get the IP address for the adapter - - InetAddress adapAddr = null; - Enumeration addrEnum = ni.getInetAddresses(); - - while ( addrEnum.hasMoreElements() && adapAddr == null) { - - // Get the current address - - InetAddress addr = addrEnum.nextElement(); - if ( IPAddress.isNumericAddress( addr.getHostAddress())) - adapAddr = addr; - } - - // Check if we found the IP address to bind to - - if ( adapAddr == null) - throw new InvalidConfigurationException( "Adapter " + adapter + " does not have a valid IP address"); - - // Return the adapter address - - return adapAddr; - } - - private ApplicationContext applicationContext = null; - - - /* (non-Javadoc) - * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) - */ - public void onApplicationEvent(ApplicationEvent event) - { - if (event instanceof ContextRefreshedEvent) - { - ContextRefreshedEvent refreshEvent = (ContextRefreshedEvent)event; - ApplicationContext refreshContext = refreshEvent.getApplicationContext(); - if (refreshContext != null && refreshContext.equals(applicationContext)) - { - // Initialize the bean - - init(); - } - } - } - - /* (non-Javadoc) - * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) - */ - public void setApplicationContext(ApplicationContext applicationContext) - throws BeansException - { - this.applicationContext = applicationContext; - } - - /** - * Return the authentication service - * - * @return AuthenticationService - */ - protected final AuthenticationService getAuthenticationService() - { - return m_authenticationService; - } - - /** - * Return the authentication component - * - * @return AuthenticationComponent - */ - protected final AuthenticationComponent getAuthenticationComponent() - { - return m_authenticationComponent; - } - - /** - * Return the node service - * - * @return NodeService - */ - protected final NodeService getNodeService() - { - return m_nodeService; - } - - /** - * Return the person service - * - * @return PersonService - */ - protected final PersonService getPersonService() - { - return m_personService; - } - - /** - * Return the transaction service - * - * @return TransactionService - */ - protected final TransactionService getTransactionService() - { - return m_transactionService; - } - - /** - * Return the tenant service - * - * @return TenantService - */ - protected final TenantService getTenantService() - { - return m_tenantService; - } - - /** - * Return the search service - * - * @return SearchService - */ - protected final SearchService getSearchService() - { - return m_searchService; - } - - /** - * Return the namespace service - * - * @return NamespaceService - */ - protected final NamespaceService getNamespaceService() - { - return m_namespaceService; - } - - /** - * Check if native code calls are disabled - * - * @return boolean - */ - public final boolean isNativeCodeDisabled() - { - return m_disableNativeCode; - } - - /** - * Return the named bean - * - * @param beanName String - * @return Object - */ - public final Object getBean( String beanName) - { - return applicationContext.getBean( beanName); - } - - /** - * Return the applicatin context - * - * @return ApplicationContext - */ - public final ApplicationContext getApplicationsContext() - { - return applicationContext; - } - - /** - * Return the authority service - * - * @return AuthorityService - */ - public final AuthorityService getAuthorityService() - { - return m_authorityService; - } } diff --git a/source/java/org/alfresco/filesys/alfresco/AlfrescoContext.java b/source/java/org/alfresco/filesys/alfresco/AlfrescoContext.java index c60208f906..5390f21635 100644 --- a/source/java/org/alfresco/filesys/alfresco/AlfrescoContext.java +++ b/source/java/org/alfresco/filesys/alfresco/AlfrescoContext.java @@ -24,15 +24,20 @@ */ package org.alfresco.filesys.alfresco; +import java.net.InetAddress; import java.util.Enumeration; +import java.util.List; +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.filesys.config.GlobalDesktopActionConfigBean; +import org.alfresco.filesys.state.FileStateReaper; +import org.alfresco.filesys.state.FileStateTable; import org.alfresco.jlan.server.filesys.DiskDeviceContext; import org.alfresco.jlan.server.filesys.DiskInterface; import org.alfresco.jlan.server.filesys.FileSystem; import org.alfresco.jlan.server.filesys.SrvDiskInfo; import org.alfresco.jlan.server.filesys.pseudo.PseudoFileInterface; -import org.alfresco.filesys.state.FileStateReaper; -import org.alfresco.filesys.state.FileStateTable; +import org.springframework.beans.factory.InitializingBean; /** @@ -42,8 +47,12 @@ import org.alfresco.filesys.state.FileStateTable; * * @author GKSpencer */ -public abstract class AlfrescoContext extends DiskDeviceContext +public abstract class AlfrescoContext extends DiskDeviceContext implements InitializingBean { + // Token name to substitute current servers DNS name or TCP/IP address into the webapp URL + + private static final String TokenLocalName = "${localname}"; + // File state table and associated file state reaper private FileStateTable m_stateTable; @@ -60,22 +69,15 @@ public abstract class AlfrescoContext extends DiskDeviceContext // Desktop actions + private GlobalDesktopActionConfigBean m_globalDesktopActionConfig = new GlobalDesktopActionConfigBean(); private DesktopActionTable m_desktopActions; // I/O control handler private IOControlHandler m_ioHandler; - - /** - * Class constructor - * - * @param filesysName String - * @param devName String - */ - public AlfrescoContext(String filesysName, String devName) + + public AlfrescoContext() { - super(filesysName, devName); - // Default the filesystem to look like an 80Gb sized disk with 90% free space setDiskInformation(new SrvDiskInfo(2560000, 64, 512, 2304000)); @@ -83,7 +85,17 @@ public abstract class AlfrescoContext extends DiskDeviceContext // Set parameters setFilesystemAttributes(FileSystem.CasePreservedNames + FileSystem.UnicodeOnDisk + - FileSystem.CaseSensitiveSearch); + FileSystem.CaseSensitiveSearch); + } + + + public void setDisableChangeNotification(boolean disableChangeNotification) + { + enableChangeHandler(!disableChangeNotification); + } + + public void afterPropertiesSet() + { } /** @@ -237,7 +249,7 @@ public abstract class AlfrescoContext extends DiskDeviceContext */ public final boolean hasIOHandler() { - return m_ioHandler != null ? true : false; + return m_ioHandler != null; } /** @@ -290,9 +302,48 @@ public abstract class AlfrescoContext extends DiskDeviceContext public final void setURLPrefix(String urlPrefix) { m_urlPathPrefix = urlPrefix; - + if ( urlPrefix != null) + { + // Make sure the web prefix has a trailing slash + + if ( !urlPrefix.endsWith("/")) + urlPrefix = urlPrefix + "/"; + + // Check if the URL path name contains the local name token + + int pos = urlPrefix.indexOf(TokenLocalName); + if (pos != -1) + { + + // Get the local server name + + String srvName = "localhost"; + + try + { + srvName = InetAddress.getLocalHost().getHostName(); + } + catch ( Exception ex) + { + } + + // Rebuild the host name substituting the token with the local server name + + StringBuilder hostStr = new StringBuilder(); + + hostStr.append( urlPrefix.substring(0, pos)); + hostStr.append(srvName); + + pos += TokenLocalName.length(); + if (pos < urlPrefix.length()) + hostStr.append( urlPrefix.substring(pos)); + + m_urlPathPrefix = hostStr.toString(); + } + enabledPseudoFileInterface(); + } } /** @@ -303,9 +354,15 @@ public abstract class AlfrescoContext extends DiskDeviceContext public final void setURLFileName(String urlFileName) { m_urlFileName = urlFileName; - - if ( urlFileName != null) - enabledPseudoFileInterface(); + + // URL file name must end with .url + if (urlFileName != null) + { + if (!urlFileName.endsWith(".url")) + throw new AlfrescoRuntimeException("URL link file must end with .url, " + urlFileName); + + enabledPseudoFileInterface(); + } } /** @@ -337,6 +394,36 @@ public abstract class AlfrescoContext extends DiskDeviceContext } } + + /** + * Set the desktop actions + * + * @param desktopActions DesktopAction List + */ + public final void setDesktopActions(List desktopActions) + { + // Enumerate the desktop actions and add to this filesystem + + for (DesktopAction desktopAction : desktopActions) + { + addDesktopAction(desktopAction); + } + + // Note it is assumed that a AlfrescoDiskDriver.register() call will initialise the I/O control handler + } + + protected void setGlobalDesktopActionConfig(GlobalDesktopActionConfigBean desktopActionConfig) + { + m_globalDesktopActionConfig = desktopActionConfig; + } + + + protected GlobalDesktopActionConfigBean getGlobalDesktopActionConfig() + { + return m_globalDesktopActionConfig; + } + + /** * Create the I/O control handler for this filesystem type * diff --git a/source/java/org/alfresco/filesys/alfresco/AlfrescoDiskDriver.java b/source/java/org/alfresco/filesys/alfresco/AlfrescoDiskDriver.java index 4ac694cd67..19810bdb1b 100644 --- a/source/java/org/alfresco/filesys/alfresco/AlfrescoDiskDriver.java +++ b/source/java/org/alfresco/filesys/alfresco/AlfrescoDiskDriver.java @@ -26,6 +26,8 @@ package org.alfresco.filesys.alfresco; import javax.transaction.Status; import javax.transaction.UserTransaction; +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.filesys.state.FileStateReaper; import org.alfresco.jlan.server.SrvSession; import org.alfresco.jlan.server.filesys.IOControlNotImplementedException; import org.alfresco.jlan.server.filesys.IOCtlInterface; @@ -35,8 +37,6 @@ import org.alfresco.jlan.server.filesys.TreeConnection; import org.alfresco.jlan.smb.SMBException; import org.alfresco.jlan.smb.SMBStatus; import org.alfresco.jlan.util.DataBuffer; -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.filesys.state.FileStateReaper; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.transaction.TransactionService; import org.apache.commons.logging.Log; @@ -49,15 +49,11 @@ import org.apache.commons.logging.LogFactory; * * @author gkspencer */ -public class AlfrescoDiskDriver implements IOCtlInterface, TransactionalFilesystemInterface { +public abstract class AlfrescoDiskDriver implements IOCtlInterface, TransactionalFilesystemInterface, ExtendedDiskInterface { // Logging private static final Log logger = LogFactory.getLog(AlfrescoDiskDriver.class); - - // Transaction logging - - private static final Log txLogger = LogFactory.getLog( "org.alfresco.fileserver.transaction"); // Service registry for desktop actions diff --git a/source/java/org/alfresco/filesys/alfresco/DesktopAction.java b/source/java/org/alfresco/filesys/alfresco/DesktopAction.java index 13513daafb..b8ab347a80 100644 --- a/source/java/org/alfresco/filesys/alfresco/DesktopAction.java +++ b/source/java/org/alfresco/filesys/alfresco/DesktopAction.java @@ -37,13 +37,14 @@ import org.alfresco.config.ConfigElement; import org.alfresco.service.ServiceRegistry; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.InitializingBean; /** * Desktop Action Class * * @author gkspencer */ -public abstract class DesktopAction { +public abstract class DesktopAction implements InitializingBean{ // Logging @@ -103,6 +104,10 @@ public abstract class DesktopAction { private PseudoFile m_pseudoFile; + private String m_filename; + + private String m_path; + // Desktop action attributes private int m_attributes; @@ -113,6 +118,7 @@ public abstract class DesktopAction { // Filesystem driver and context + private DiskSharedDevice m_diskSharedDevice; private AlfrescoDiskDriver m_filesysDriver; private AlfrescoContext m_filesysContext; @@ -309,6 +315,10 @@ public abstract class DesktopAction { // Perform standard initialization standardInitialize(global, config, fileSys); + + // Complete initialization + + afterPropertiesSet(); } /** @@ -322,18 +332,9 @@ public abstract class DesktopAction { public void standardInitialize(ConfigElement global, ConfigElement config, DiskSharedDevice fileSys) throws DesktopActionException { - // Save the filesystem device and I/O handler - - if ( fileSys.getContext() instanceof AlfrescoContext) - { - m_filesysDriver = (AlfrescoDiskDriver) fileSys.getDiskInterface(); - m_filesysContext = (AlfrescoContext) fileSys.getDiskContext(); - } - else - throw new DesktopActionException("Desktop action requires an Alfresco filesystem driver"); - + setDiskSharedDevice(fileSys); + // Check for standard config values - ConfigElement elem = config.getChild("name"); if ( elem != null && elem.getValue().length() > 0) { @@ -349,41 +350,14 @@ public abstract class DesktopAction { ConfigElement name = config.getChild("filename"); if ( name == null || name.getValue() == null || name.getValue().length() == 0) throw new DesktopActionException("Desktop action pseudo name not specified"); + setFilename(name.getValue()); // Get the local path to the executable ConfigElement path = findConfigElement("path", global, config); if ( path == null || path.getValue() == null || path.getValue().length() == 0) throw new DesktopActionException("Desktop action executable path not specified"); - - // Check that the application exists on the local filesystem - - URL appURL = this.getClass().getClassLoader().getResource(path.getValue()); - if ( appURL == null) - throw new DesktopActionException("Failed to find drag and drop application, " + path.getValue()); - - // Decode the URL path, it might contain escaped characters - - String appURLPath = null; - try - { - appURLPath = URLDecoder.decode( appURL.getFile(), "UTF-8"); - } - catch ( UnsupportedEncodingException ex) - { - throw new DesktopActionException("Failed to decode drag/drop path, " + ex.getMessage()); - } - - // Check that the drag/drop file exists - - File appFile = new File(appURLPath); - if ( appFile.exists() == false) - throw new DesktopActionException("Drag and drop application not found, " + path.getValue()); - - // Create the pseudo file for the action - - PseudoFile pseudoFile = new LocalPseudoFile(name.getValue(), appFile.getAbsolutePath()); - setPseudoFile(pseudoFile); + setPath(path.getValue()); // Check if confirmations should be switched off for the action @@ -393,47 +367,9 @@ public abstract class DesktopAction { // Check if the webapp URL has been specified ConfigElement webURL = findConfigElement("webpath", global, config); - if ( webURL != null) + if ( webURL != null && webURL.getValue() != null && webURL.getValue().length() > 0) { - // Check if the path name contains the local name token - - String webPath = webURL.getValue(); - if ( webPath.endsWith("/") == false) - webPath = webPath + "/"; - - int pos = webPath.indexOf(TokenLocalName); - if (pos != -1) - { - - // Get the local server name - - String srvName = "localhost"; - - try - { - srvName = InetAddress.getLocalHost().getHostName(); - } - catch ( Exception ex) - { - } - - // Rebuild the host name substituting the token with the local server name - - StringBuilder hostStr = new StringBuilder(); - - hostStr.append(webPath.substring(0, pos)); - hostStr.append(srvName); - - pos += TokenLocalName.length(); - if (pos < webPath.length()) - hostStr.append(webPath.substring(pos)); - - webPath = hostStr.toString(); - } - - // Set the URL path - - setWebappURL( webPath); + setWebappURL(webURL.getValue()); } // Check if debug output is enabled for the action @@ -441,14 +377,133 @@ public abstract class DesktopAction { ConfigElement debug = findConfigElement("debug", global, config); if ( debug != null) setDebug(true); - - // DEBUG - - if ( logger.isDebugEnabled() && hasDebug()) - logger.debug("Initialized desktop action " + getName() + ", pseudo name " + name.getValue()); } - /** + + public void afterPropertiesSet() throws DesktopActionException + { + if (m_diskSharedDevice == null) + throw new DesktopActionException("Desktop action requires an Alfresco filesystem driver"); + + // Save the filesystem device and I/O handler + + if ( m_diskSharedDevice.getContext() instanceof AlfrescoContext) + { + m_filesysDriver = (AlfrescoDiskDriver) m_diskSharedDevice.getDiskInterface(); + m_filesysContext = (AlfrescoContext) m_diskSharedDevice.getDiskContext(); + } + else + throw new DesktopActionException("Desktop action requires an Alfresco filesystem driver"); + + // Check for standard config values + + if ( m_name == null || m_name.length() == 0) + throw new DesktopActionException("Desktop action name not specified"); + + // Get the pseudo file name + if (m_pseudoFile == null) + { + if ( m_filename == null || m_filename.length() == 0) + throw new DesktopActionException("Desktop action pseudo name not specified"); + + // Get the local path to the executable + if (m_path== null || m_path.length() == 0) + { + m_path = m_filesysContext.getGlobalDesktopActionConfig().getPath(); + } + if ( m_path == null || m_path.length() == 0) + throw new DesktopActionException("Desktop action executable path not specified"); + + // Check that the application exists on the local filesystem + + URL appURL = this.getClass().getClassLoader().getResource(m_path); + if ( appURL == null) + throw new DesktopActionException("Failed to find drag and drop application, " + m_path); + + // Decode the URL path, it might contain escaped characters + + String appURLPath = null; + try + { + appURLPath = URLDecoder.decode( appURL.getFile(), "UTF-8"); + } + catch ( UnsupportedEncodingException ex) + { + throw new DesktopActionException("Failed to decode drag/drop path, " + ex.getMessage()); + } + + // Check that the drag/drop file exists + + File appFile = new File(appURLPath); + if ( appFile.exists() == false) + throw new DesktopActionException("Drag and drop application not found, " + appFile); + + // Create the pseudo file for the action + + PseudoFile pseudoFile = new LocalPseudoFile(m_filename, appFile.getAbsolutePath()); + setPseudoFile(pseudoFile); + } + + // Check if confirmations should be switched off for the action + + if ( m_filesysContext.getGlobalDesktopActionConfig().getNoConfirm() && hasPreProcessAction(PreConfirmAction)) + setPreProcessActions(getPreProcessActions() - PreConfirmAction); + + // Check if the webapp URL has been specified + + if (m_webappURL == null || m_webappURL.length() == 0) + { + m_webappURL = m_filesysContext.getGlobalDesktopActionConfig().getWebpath(); + } + if ( m_webappURL != null && m_webappURL.length() > 0) + { + // Check if the path name contains the local name token + if ( !m_webappURL.endsWith("/")) + m_webappURL = m_webappURL + "/"; + + int pos = m_webappURL.indexOf(TokenLocalName); + if (pos != -1) + { + + // Get the local server name + + String srvName = "localhost"; + + try + { + srvName = InetAddress.getLocalHost().getHostName(); + } + catch ( Exception ex) + { + } + + // Rebuild the host name substituting the token with the local server name + + StringBuilder hostStr = new StringBuilder(); + + hostStr.append(m_webappURL.substring(0, pos)); + hostStr.append(srvName); + + pos += TokenLocalName.length(); + if (pos < m_webappURL.length()) + hostStr.append(m_webappURL.substring(pos)); + + m_webappURL = hostStr.toString(); + } + } + + // Check if debug output is enabled for the action + + if ( m_filesysContext.getGlobalDesktopActionConfig().getDebug()) + setDebug(true); + + // DEBUG + + if ( logger.isDebugEnabled() && hasDebug()) + logger.debug("Initialized desktop action " + getName() + ", pseudo name " + m_pseudoFile.getFileName()); + } + + /** * Find the required configuration element in the local or global config * * @param name String @@ -492,7 +547,7 @@ public abstract class DesktopAction { * * @param pre int */ - protected final void setPreProcessActions(int pre) + public final void setPreProcessActions(int pre) { m_clientPreActions = pre; } @@ -502,7 +557,7 @@ public abstract class DesktopAction { * * @param name String */ - protected final void setName(String name) + public final void setName(String name) { m_name = name; } @@ -512,22 +567,51 @@ public abstract class DesktopAction { * * @param pseudoFile PseudoFile */ - protected final void setPseudoFile(PseudoFile pseudoFile) + public final void setPseudoFile(PseudoFile pseudoFile) { m_pseudoFile = pseudoFile; } - /** + /** + * Set the associated pseudo file name + * + * @param filename the file name + */ + public void setFilename(String filename) + { + this.m_filename = filename; + } + + /** + * Set the physical path of the associated pseudo file + * + * @param path the path + */ + public void setPath(String path) + { + this.m_path = path; + } + + /** * Enable debug output * * @param ena boolean */ - protected final void setDebug(boolean ena) + public final void setDebug(boolean ena) { m_debug = ena; } /** + * Sets the disk shared device. + * @param diskSharedDevice + */ + public void setDiskSharedDevice(DiskSharedDevice diskSharedDevice) + { + m_diskSharedDevice = diskSharedDevice; + } + + /** * Set the webapp URL * * @param urlStr String diff --git a/source/java/org/alfresco/filesys/alfresco/ExtendedDiskInterface.java b/source/java/org/alfresco/filesys/alfresco/ExtendedDiskInterface.java new file mode 100644 index 0000000000..a72b5ccad5 --- /dev/null +++ b/source/java/org/alfresco/filesys/alfresco/ExtendedDiskInterface.java @@ -0,0 +1,45 @@ +/* + * 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.filesys.alfresco; + +import org.alfresco.jlan.server.core.DeviceContext; +import org.alfresco.jlan.server.core.DeviceContextException; +import org.alfresco.jlan.server.filesys.DiskInterface; + +/** + * @author dward + */ +public interface ExtendedDiskInterface extends DiskInterface +{ + /** + * Register an independently created device context object for this instance of the shared device. Useful, e.g. when + * context singleton configuration managed by a container. + * + * @param context + * the device context + * @exception DeviceContextException + */ + public void registerContext(DeviceContext ctx) throws DeviceContextException; +} diff --git a/source/java/org/alfresco/filesys/alfresco/HomeShareMapper.java b/source/java/org/alfresco/filesys/alfresco/HomeShareMapper.java index 2078eaabf1..23db652734 100644 --- a/source/java/org/alfresco/filesys/alfresco/HomeShareMapper.java +++ b/source/java/org/alfresco/filesys/alfresco/HomeShareMapper.java @@ -35,10 +35,12 @@ import org.alfresco.jlan.server.SrvSession; import org.alfresco.jlan.server.auth.InvalidUserException; import org.alfresco.jlan.server.config.InvalidConfigurationException; import org.alfresco.jlan.server.config.ServerConfiguration; +import org.alfresco.jlan.server.config.ServerConfigurationAccessor; import org.alfresco.jlan.server.core.ShareMapper; import org.alfresco.jlan.server.core.ShareType; import org.alfresco.jlan.server.core.SharedDevice; import org.alfresco.jlan.server.core.SharedDeviceList; +import org.alfresco.jlan.server.filesys.DiskInterface; import org.alfresco.jlan.server.filesys.DiskSharedDevice; import org.alfresco.jlan.server.filesys.FilesystemsConfigSection; import org.apache.commons.logging.Log; @@ -64,10 +66,9 @@ public class HomeShareMapper implements ShareMapper // Server configuration - private ServerConfiguration m_config; + private ServerConfigurationAccessor m_config; - private AlfrescoConfigSection m_alfConfig; - private FilesystemsConfigSection m_fsysConfig; + private DiskInterface m_repoDiskInterface; // Home folder share name @@ -77,6 +78,27 @@ public class HomeShareMapper implements ShareMapper private boolean m_debug; + + public void setConfig(ServerConfiguration config) + { + m_config = config; + } + + public void setRepoDiskInterface(DiskInterface diskInterface) + { + m_repoDiskInterface = diskInterface; + } + + public void setHomeShareName(String shareName) + { + m_homeShareName = shareName; + } + + public void setDebug(boolean m_debug) + { + this.m_debug = m_debug; + } + /** * Default constructor */ @@ -95,21 +117,20 @@ public class HomeShareMapper implements ShareMapper { // Save the server configuration - m_config = config; + setConfig(config); - m_alfConfig = (AlfrescoConfigSection) m_config.getConfigSection( AlfrescoConfigSection.SectionName); - m_fsysConfig = (FilesystemsConfigSection) m_config.getConfigSection( FilesystemsConfigSection.SectionName); + setRepoDiskInterface(((AlfrescoConfigSection) m_config.getConfigSection( AlfrescoConfigSection.SectionName)).getRepoDiskInterface()); // Check if the home share name has been specified String homeName = params.getAttribute("name"); if ( homeName != null && homeName.length() > 0) - m_homeShareName = homeName; + setHomeShareName(homeName); // Check if debug is enabled if (params != null && params.getChild("debug") != null) - m_debug = true; + setDebug(true); } /** @@ -165,7 +186,7 @@ public class HomeShareMapper implements ShareMapper // Make a copy of the global share list and add the per session dynamic shares - SharedDeviceList shrList = new SharedDeviceList(m_fsysConfig.getShares()); + SharedDeviceList shrList = new SharedDeviceList(getFilesystemsConfigSection().getShares()); if ( sess != null && sess.hasDynamicShares()) { @@ -256,14 +277,14 @@ public class HomeShareMapper implements ShareMapper // Find the required share by name/type. Use a case sensitive search first, if that fails use a case // insensitive search. - - share = m_fsysConfig.getShares().findShare(name, typ, false); + FilesystemsConfigSection filesystemsConfigSection = getFilesystemsConfigSection(); + share = filesystemsConfigSection.getShares().findShare(name, typ, false); if ( share == null) { // Try a case insensitive search for the required share - share = m_fsysConfig.getShares().findShare(name, typ, true); + share = filesystemsConfigSection.getShares().findShare(name, typ, true); } } @@ -334,7 +355,7 @@ public class HomeShareMapper implements ShareMapper { // Create the disk driver and context - ContentDiskDriver diskDrv = ( ContentDiskDriver) m_alfConfig.getRepoDiskInterface(); + ContentDiskDriver diskDrv = ( ContentDiskDriver) getRepoDiskInterface(); ContentContext diskCtx = new ContentContext( getHomeFolderName(), "", "", client.getHomeFolder()); diskCtx.enableStateTable( true, diskDrv.getStateReaper()); @@ -343,4 +364,14 @@ public class HomeShareMapper implements ShareMapper return new DiskSharedDevice(getHomeFolderName(), diskDrv, diskCtx, SharedDevice.Temporary); } + + protected DiskInterface getRepoDiskInterface() + { + return m_repoDiskInterface; + } + + protected FilesystemsConfigSection getFilesystemsConfigSection() + { + return (FilesystemsConfigSection)m_config.getConfigSection(FilesystemsConfigSection.SectionName); + } } diff --git a/source/java/org/alfresco/filesys/alfresco/MultiTenantShareMapper.java b/source/java/org/alfresco/filesys/alfresco/MultiTenantShareMapper.java index 8be033716a..895cef7f6d 100644 --- a/source/java/org/alfresco/filesys/alfresco/MultiTenantShareMapper.java +++ b/source/java/org/alfresco/filesys/alfresco/MultiTenantShareMapper.java @@ -38,13 +38,14 @@ import org.alfresco.jlan.server.filesys.FilesystemsConfigSection; import org.alfresco.jlan.server.filesys.SrvDiskInfo; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; +import org.springframework.beans.factory.InitializingBean; /** * Multi Tenant Share Mapper Class * * @author gkspencer */ -public class MultiTenantShareMapper implements ShareMapper, ConfigurationListener { +public class MultiTenantShareMapper implements ShareMapper, ConfigurationListener, InitializingBean { // Server configuration and configuration sections @@ -75,7 +76,24 @@ public class MultiTenantShareMapper implements ShareMapper, ConfigurationListene public MultiTenantShareMapper() { } - /** + + public void setServerConfiguration(ServerConfiguration config) + { + this.m_config = config; + } + + public void setTenantShareName(String shareName) + { + m_tenantShareName = shareName; + } + + public void setDebug(boolean debug) + { + this.m_debug = debug; + } + + + /** * Initialize the share mapper * * @param config ServerConfiguration @@ -87,25 +105,8 @@ public class MultiTenantShareMapper implements ShareMapper, ConfigurationListene // Save the server configuration - m_config = config; + setServerConfiguration(config); - // Filesystem configuration will usually be initialized after the security configuration so we need to plug in - // a listener to initialize it later - - m_filesysConfig = (FilesystemsConfigSection) m_config.getConfigSection( FilesystemsConfigSection.SectionName); - - // Get the Alfresco configuration section - - m_alfrescoConfig = (AlfrescoConfigSection) m_config.getConfigSection( AlfrescoConfigSection.SectionName); - - if ( m_filesysConfig == null || m_alfrescoConfig == null) - m_config.addListener( this); - - // Find the content filesystem details to be used for hte tenant shares - - if ( m_filesysConfig != null) - findContentShareDetails(); - // Check if a tenant share name has been specified ConfigElement tenantShareName = params.getChild( "TenantShareName"); @@ -115,7 +116,7 @@ public class MultiTenantShareMapper implements ShareMapper, ConfigurationListene // Validate the share name if ( tenantShareName.getValue() != null && tenantShareName.getValue().length() > 0) - m_tenantShareName = tenantShareName.getValue(); + setTenantShareName(tenantShareName.getValue()); else throw new InvalidConfigurationException("Invalid tenant share name"); } @@ -123,14 +124,38 @@ public class MultiTenantShareMapper implements ShareMapper, ConfigurationListene // Check if debug is enabled if ( params.getChild("debug") != null) - m_debug = true; - - // Create the tenant share lists table - - m_tenantShareLists = new Hashtable(); + setDebug(true); + + // Complete initialization + afterPropertiesSet(); } - /** + public void afterPropertiesSet() + { + // Filesystem configuration will usually be initialized after the security configuration so we need to plug in + // a listener to initialize it later + + m_filesysConfig = (FilesystemsConfigSection) m_config.getConfigSection( FilesystemsConfigSection.SectionName); + + // Get the Alfresco configuration section + + m_alfrescoConfig = (AlfrescoConfigSection) m_config.getConfigSection( AlfrescoConfigSection.SectionName); + + if ( m_filesysConfig == null || m_alfrescoConfig == null) + m_config.addListener( this); + + // Find the content filesystem details to be used for the tenant shares + + if ( m_filesysConfig != null) + findContentShareDetails(); + + // Create the tenant share lists table + + m_tenantShareLists = new Hashtable(); + } + + + /** * Check if debug output is enabled * * @return boolean diff --git a/source/java/org/alfresco/filesys/auth/cifs/AlfrescoCifsAuthenticator.java b/source/java/org/alfresco/filesys/auth/cifs/AlfrescoCifsAuthenticator.java index 8e5f72d589..2cc1ae4c45 100644 --- a/source/java/org/alfresco/filesys/auth/cifs/AlfrescoCifsAuthenticator.java +++ b/source/java/org/alfresco/filesys/auth/cifs/AlfrescoCifsAuthenticator.java @@ -34,8 +34,8 @@ import net.sf.acegisecurity.Authentication; import org.alfresco.filesys.alfresco.AlfrescoClientInfo; import org.alfresco.jlan.server.SrvSession; import org.alfresco.jlan.server.auth.AuthContext; -import org.alfresco.jlan.server.auth.CifsAuthenticator; import org.alfresco.jlan.server.auth.ClientInfo; +import org.alfresco.jlan.server.auth.ICifsAuthenticator; import org.alfresco.jlan.server.auth.NTLanManAuthContext; import org.alfresco.jlan.server.core.SharedDevice; import org.alfresco.jlan.smb.server.SMBSrvSession; @@ -92,7 +92,7 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase // Check that the client is an Alfresco client if ( client instanceof AlfrescoClientInfo == false) - return CifsAuthenticator.AUTH_DISALLOW; + return ICifsAuthenticator.AUTH_DISALLOW; AlfrescoClientInfo alfClient = (AlfrescoClientInfo) client; @@ -107,7 +107,7 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase if ( logger.isDebugEnabled()) logger.debug("Null CIFS logon allowed"); - return CifsAuthenticator.AUTH_ALLOW; + return ICifsAuthenticator.AUTH_ALLOW; } // Check if the client is already authenticated, and it is not a null logon @@ -271,7 +271,7 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase // // Main authentication is handled by authenticateUser() - return CifsAuthenticator.Writeable; + return ICifsAuthenticator.Writeable; } /** @@ -343,7 +343,7 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase // Check if the client has supplied an NTLM hashed password, if not then do not allow access if ( client.getPassword() == null) - return CifsAuthenticator.AUTH_BADPASSWORD; + return ICifsAuthenticator.AUTH_BADPASSWORD; try { @@ -362,7 +362,7 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase if ( sess.hasAuthenticationContext() && sess.getAuthenticationContext() instanceof NTLanManAuthContext) authCtx = (NTLanManAuthContext) sess.getAuthenticationContext(); else - return CifsAuthenticator.AUTH_DISALLOW; + return ICifsAuthenticator.AUTH_DISALLOW; // Generate the local hash of the password using the same challenge @@ -387,12 +387,12 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase } if ( clientHash == null || clientHash.length != localHash.length) - return CifsAuthenticator.AUTH_BADPASSWORD; + return ICifsAuthenticator.AUTH_BADPASSWORD; for ( int i = 0; i < clientHash.length; i++) { if ( clientHash[i] != localHash[i]) - return CifsAuthenticator.AUTH_BADPASSWORD; + return ICifsAuthenticator.AUTH_BADPASSWORD; } // Logging @@ -415,7 +415,7 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase // Passwords match, grant access - return CifsAuthenticator.AUTH_ALLOW; + return ICifsAuthenticator.AUTH_ALLOW; } catch (NoSuchAlgorithmException ex) { @@ -423,7 +423,7 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase // Error during password check, do not allow access - return CifsAuthenticator.AUTH_DISALLOW; + return ICifsAuthenticator.AUTH_DISALLOW; } // Check if this is an SMB/CIFS null session logon. @@ -431,11 +431,11 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase // The null session will only be allowed to connect to the IPC$ named pipe share. if (client.isNullSession() && sess instanceof SMBSrvSession) - return CifsAuthenticator.AUTH_ALLOW; + return ICifsAuthenticator.AUTH_ALLOW; // User does not exist, check if guest access is allowed - return allowGuest() ? CifsAuthenticator.AUTH_GUEST : CifsAuthenticator.AUTH_DISALLOW; + return allowGuest() ? ICifsAuthenticator.AUTH_GUEST : ICifsAuthenticator.AUTH_DISALLOW; } /** @@ -450,19 +450,19 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase { // Default logon status to disallow - int authSts = CifsAuthenticator.AUTH_DISALLOW; + int authSts = ICifsAuthenticator.AUTH_DISALLOW; // Get the authentication token for the session AuthContext authCtx = sess.getAuthenticationContext(); if ( authCtx == null || authCtx instanceof AuthTokenAuthContext == false) - return CifsAuthenticator.AUTH_DISALLOW; + return ICifsAuthenticator.AUTH_DISALLOW; AuthTokenAuthContext tokenCtx = (AuthTokenAuthContext) authCtx; NTLMPassthruToken authToken = tokenCtx.getToken(); if ( authToken == null) - return CifsAuthenticator.AUTH_DISALLOW; + return ICifsAuthenticator.AUTH_DISALLOW; // Get the appropriate hashed password for the algorithm @@ -476,7 +476,7 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase { // Invalid/unsupported algorithm specified - return CifsAuthenticator.AUTH_DISALLOW; + return ICifsAuthenticator.AUTH_DISALLOW; } // Set the username and hashed password in the authentication token @@ -505,7 +505,7 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase // Allow the user access as a guest - authSts = CifsAuthenticator.AUTH_GUEST; + authSts = ICifsAuthenticator.AUTH_GUEST; // Indicate that this is a guest logon @@ -517,7 +517,7 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase // Allow the user full access to the server - authSts = CifsAuthenticator.AUTH_ALLOW; + authSts = ICifsAuthenticator.AUTH_ALLOW; // Indicate that this is a normal user logon diff --git a/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java b/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java index a26a3b99d7..9e9abe2675 100644 --- a/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java +++ b/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.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,7 +18,7 @@ * 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" */ @@ -72,10 +72,86 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator // MD4 hash decoder protected MD4PasswordEncoder m_md4Encoder = new MD4PasswordEncoderImpl(); + + private AuthenticationComponent authenticationComponent; + + private AuthenticationService authenticationService; + + private NodeService nodeService; + + private PersonService personService; + + private TransactionService transactionService; + + private AuthorityService authorityService; + + private DiskInterface diskInterface; // Alfresco configuration - protected AlfrescoConfigSection m_alfrescoConfig; + public CifsAuthenticatorBase() + { + // The default access mode + setAccessMode(USER_MODE); + } + + /** + * @param authenticationComponent the authenticationComponent to set + */ + public void setAuthenticationComponent(AuthenticationComponent authenticationComponent) + { + this.authenticationComponent = authenticationComponent; + } + + /** + * @param authenticationService the authenticationService to set + */ + public void setAuthenticationService(AuthenticationService authenticationService) + { + this.authenticationService = authenticationService; + } + + /** + * @param nodeService the nodeService to set + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * @param personService the personService to set + */ + public void setPersonService(PersonService personService) + { + this.personService = personService; + } + + /** + * @param transactionService the transactionService to set + */ + public void setTransactionService(TransactionService transactionService) + { + this.transactionService = transactionService; + } + + /** + * @param authorityService the authorityService to set + */ + public void setAuthorityService(AuthorityService authorityService) + { + this.authorityService = authorityService; + } + + /** + * Set the filesystem driver for the node service based filesystem + * + * @param diskInterface DiskInterface + */ + public void setDiskInterface(DiskInterface diskInterface) + { + this.diskInterface = diskInterface; + } /** * Initialize the authenticator @@ -86,24 +162,48 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator */ public void initialize(ServerConfiguration config, ConfigElement params) throws InvalidConfigurationException { - super.initialize(config, params); - // Get the alfresco configuration section, required to get hold of various services/components - m_alfrescoConfig = (AlfrescoConfigSection) config.getConfigSection( AlfrescoConfigSection.SectionName); + AlfrescoConfigSection alfrescoConfig = (AlfrescoConfigSection) config.getConfigSection( AlfrescoConfigSection.SectionName); + // Copy over relevant bean properties for backward compatibility + setAuthenticationComponent(alfrescoConfig.getAuthenticationComponent()); + setAuthenticationService(alfrescoConfig.getAuthenticationService()); + setNodeService(alfrescoConfig.getNodeService()); + setPersonService(alfrescoConfig.getPersonService()); + setTransactionService(alfrescoConfig.getTransactionService()); + setAuthorityService(alfrescoConfig.getAuthorityService()); + setDiskInterface(alfrescoConfig.getRepoDiskInterface()); + + super.initialize(config, params); + } + + + /** + * Initialize the authenticator + * + * @exception InvalidConfigurationException + */ + @Override + public void initialize() throws InvalidConfigurationException + { + super.initialize(); + // Check that the required authentication classes are available - if ( m_alfrescoConfig == null || getAuthenticationComponent() == null) + if ( getAuthenticationComponent() == null) throw new InvalidConfigurationException("Authentication component not available"); + // Propagate the allow guest flag + setAllowGuest(allowGuest() || getAuthenticationComponent().guestUserAuthenticationAllowed()); + // Set the guest user name setGuestUserName( getAuthenticationComponent().getGuestUserName()); // Check that the authentication component is the required type for this authenticator - if ( validateAuthenticationMode() == false) + if ( ! validateAuthenticationMode() ) throw new InvalidConfigurationException("Required authentication mode not available"); } @@ -150,7 +250,6 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator // Create a dynamic share for the guest user, create the disk driver and context - DiskInterface diskDrv = m_alfrescoConfig.getRepoDiskInterface(); DiskDeviceContext diskCtx = new ContentContext(client.getUserName(), "", "", alfClient.getHomeFolder()); // Default the filesystem to look like an 80Gb sized disk with 90% free space @@ -159,7 +258,7 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator // Create a temporary shared device for the users home directory - sess.addDynamicShare( new DiskSharedDevice( client.getUserName(), diskDrv, diskCtx, SharedDevice.Temporary)); + sess.addDynamicShare( new DiskSharedDevice( client.getUserName(), this.diskInterface, diskCtx, SharedDevice.Temporary)); } /** @@ -222,24 +321,24 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator { // Get the home folder for the user - UserTransaction tx = m_alfrescoConfig.getTransactionService().getUserTransaction(); + UserTransaction tx = getTransactionService().getUserTransaction(); String personName = null; try { tx.begin(); - personName = m_alfrescoConfig.getPersonService().getUserIdentifier( userName); + personName = getPersonService().getUserIdentifier( userName); tx.commit(); // Check if the person exists if (personName == null) { - - tx = m_alfrescoConfig.getTransactionService().getNonPropagatingUserTransaction( false); - tx.begin(); - - m_alfrescoConfig.getPersonService().getPerson( userName); - personName = m_alfrescoConfig.getPersonService().getUserIdentifier( userName); + + tx = getTransactionService().getNonPropagatingUserTransaction( false); + tx.begin(); + + getPersonService().getPerson( userName); + personName = getPersonService().getUserIdentifier( userName); tx.commit(); } @@ -309,7 +408,7 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator */ protected final AuthenticationComponent getAuthenticationComponent() { - return m_alfrescoConfig.getAuthenticationComponent(); + return this.authenticationComponent; } /** @@ -319,7 +418,7 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator */ protected final AuthenticationService getAuthenticationService() { - return m_alfrescoConfig.getAuthenticationService(); + return this.authenticationService; } /** @@ -329,7 +428,7 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator */ protected final NodeService getNodeService() { - return m_alfrescoConfig.getNodeService(); + return this.nodeService; } /** @@ -339,7 +438,7 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator */ protected final PersonService getPersonService() { - return m_alfrescoConfig.getPersonService(); + return this.personService; } /** @@ -349,77 +448,77 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator */ protected final TransactionService getTransactionService() { - return m_alfrescoConfig.getTransactionService(); + return this.transactionService; } - /** - * Return the authority service - * - * @return AuthorityService - */ - protected final AuthorityService getAuthorityService() { - return m_alfrescoConfig.getAuthorityService(); - } + /** + * Return the authority service + * + * @return AuthorityService + */ + protected final AuthorityService getAuthorityService() { + return this.authorityService; + } - /** - * Check if the user is an administrator user name - * - * @param cInfo ClientInfo - */ - protected final void checkForAdminUserName(ClientInfo cInfo) { - - // Check if the user name is an administrator + /** + * Check if the user is an administrator user name + * + * @param cInfo ClientInfo + */ + protected final void checkForAdminUserName(ClientInfo cInfo) { + + // Check if the user name is an administrator - UserTransaction tx = createTransaction(); + UserTransaction tx = createTransaction(); - try { - tx.begin(); + try { + tx.begin(); - if ( cInfo.getLogonType() == ClientInfo.LogonNormal && getAuthorityService().isAdminAuthority(cInfo.getUserName())) { - - // Indicate that this is an administrator logon + if ( cInfo.getLogonType() == ClientInfo.LogonNormal && getAuthorityService().isAdminAuthority(cInfo.getUserName())) { + + // Indicate that this is an administrator logon - cInfo.setLogonType(ClientInfo.LogonAdmin); - } - tx.commit(); - } - catch (Throwable ex) { - try { - tx.rollback(); - } - catch (Throwable ex2) { - logger.error("Failed to rollback transaction", ex2); - } + cInfo.setLogonType(ClientInfo.LogonAdmin); + } + tx.commit(); + } + catch (Throwable ex) { + try { + tx.rollback(); + } + catch (Throwable ex2) { + logger.error("Failed to rollback transaction", ex2); + } - // Re-throw the exception + // Re-throw the exception - if ( ex instanceof RuntimeException) { - throw (RuntimeException) ex; - } - else { - throw new RuntimeException("Error during execution of transaction.", ex); - } - } - } - - /** - * Create a transaction, this will be a wrteable transaction unless the system is in read-only mode. - * - * return UserTransaction - */ - protected final UserTransaction createTransaction() - { - // Get the transaction service - - TransactionService txService = getTransactionService(); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Using " + (txService.isReadOnly() ? "ReadOnly" : "Write") + " transaction"); - - // Create the transaction - - return txService.getUserTransaction( txService.isReadOnly() ? true : false); - } + if ( ex instanceof RuntimeException) { + throw (RuntimeException) ex; + } + else { + throw new RuntimeException("Error during execution of transaction.", ex); + } + } + } + + /** + * Create a transaction, this will be a wrteable transaction unless the system is in read-only mode. + * + * return UserTransaction + */ + protected final UserTransaction createTransaction() + { + // Get the transaction service + + TransactionService txService = getTransactionService(); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Using " + (txService.isReadOnly() ? "ReadOnly" : "Write") + " transaction"); + + // Create the transaction + + return txService.getUserTransaction( txService.isReadOnly() ? true : false); + } } \ No newline at end of file diff --git a/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java b/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java index c34de229c1..3bad9e2a8f 100644 --- a/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java +++ b/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.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,7 +18,7 @@ * 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" */ @@ -93,64 +93,122 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement // Constants // // Default login configuration entry name - - private static final String LoginConfigEntry = "AlfrescoCIFS"; - + + private static final String LoginConfigEntry = "AlfrescoCIFS"; + // NTLM flags mask, used to mask out features that are not supported - + private static final int NTLM_FLAGS = NTLM.Flag56Bit + NTLM.Flag128Bit + NTLM.FlagLanManKey + NTLM.FlagNegotiateNTLM + NTLM.FlagNTLM2Key + NTLM.FlagNegotiateUnicode; - + // Use NTLMSSP or SPNEGO - - private boolean m_useRawNTLMSSP; - + + private boolean m_useRawNTLMSSP = true; + // Flag to control whether NTLMv1 is accepted - - private boolean m_acceptNTLMv1; - + + private boolean m_acceptNTLMv1 = true; + // Kerberos settings // // Account name and password for server ticket // // The account name must be built from the CIFS server name, in the format :- // - // cifs/@ - + // cifs/@ + private String m_accountName; private String m_password; - - // Kerberos realm and KDC address - + + // Kerberos realm + private String m_krbRealm; - private String m_krbKDC; - + // Login configuration entry name - - private String m_loginEntryName = LoginConfigEntry; + + private String m_loginEntryName = LoginConfigEntry; // Server login context - + private LoginContext m_loginContext; - + // SPNEGO NegTokenInit blob, sent to the client in the SMB negotiate response - + + private Vector m_mechTypes; private byte[] m_negTokenInit; - + private String m_mecListMIC; + + private boolean kerberosDebug; + + private boolean disableNTLM; + /** * Class constructor */ public EnterpriseCifsAuthenticator() { - setExtendedSecurity( true); + setExtendedSecurity(true); } - + /** - * Initialize the authenticator + * Sets the HTTP service account password. (the Principal should be configured in java.login.config) + * + * @param password + * the password to set + */ + public void setPassword(String password) + { + this.m_password = password; + } + + /** + * Sets the HTTP service account realm. + * + * @param realm + * the realm to set + */ + public void setRealm(String realm) + { + m_krbRealm = realm; + } + + /** + * Sets the HTTP service login configuration entry name. + * + * @param loginEntryName + * the loginEntryName to set + */ + public void setJaasConfigEntryName(String jaasConfigEntryName) + { + m_loginEntryName = jaasConfigEntryName; + } + + public void setKerberosDebug(boolean kerberosDebug) + { + this.kerberosDebug = kerberosDebug; + } + + public void setDisableNTLM(boolean disableNTLM) + { + this.disableNTLM = disableNTLM; + } + + public void setUseSPNEGO(boolean useSPNEGO) + { + m_useRawNTLMSSP = !useSPNEGO; + } + + public void setDisallowNTLMv1(boolean disallowNTLMv1) + { + this.m_acceptNTLMv1 = !disallowNTLMv1; + } + + /** + * Initialize the authenticator (via the config service) * * @param config ServerConfiguration * @param params ConfigElement @@ -158,237 +216,268 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement */ public void initialize(ServerConfiguration config, ConfigElement params) throws InvalidConfigurationException { - super.initialize(config, params); - // Check if Java API Kerberos debug output should be enabled - - if ( params.getChild("kerberosDebug") != null) - { - // Enable Kerberos API debug output - - System.setProperty( "sun.security.jgss.debug", "true"); - System.setProperty( "sun.security.krb5.debug", "true"); - } - - // Check if Kerberos is enabled, get the Kerberos KDC address - ConfigElement kdcAddress = params.getChild("KDC"); - - if (kdcAddress != null && kdcAddress.getValue() != null && kdcAddress.getValue().length() > 0) + setKerberosDebug(params.getChild("kerberosDebug") != null); + + // Check if Kerberos is enabled, get the Kerberos realm + ConfigElement krbRealm = params.getChild("Realm"); + if (krbRealm != null && krbRealm.getValue() != null && krbRealm.getValue().length() > 0) { - // Set the Kerberos KDC address - - m_krbKDC = kdcAddress.getValue(); - - // Get the Kerberos realm - - ConfigElement krbRealm = params.getChild("Realm"); - if ( krbRealm != null && krbRealm.getValue() != null && krbRealm.getValue().length() > 0) - { - // Set the Kerberos realm - - m_krbRealm = krbRealm.getValue(); - } - else - throw new InvalidConfigurationException("Kerberos realm not specified"); - + setRealm(krbRealm.getValue()); + // Get the CIFS service account password - + ConfigElement srvPassword = params.getChild("Password"); - if ( srvPassword != null && srvPassword.getValue() != null && srvPassword.getValue().length() > 0) + if (srvPassword != null && srvPassword.getValue() != null && srvPassword.getValue().length() > 0) { - // Set the CIFS service account password - - m_password = srvPassword.getValue(); + setPassword(srvPassword.getValue()); } else throw new InvalidConfigurationException("CIFS service account password not specified"); - + // Get the login configuration entry name - + ConfigElement loginEntry = params.getChild("LoginEntry"); - - if ( loginEntry != null) + + if (loginEntry != null) { - if ( loginEntry.getValue() != null && loginEntry.getValue().length() > 0) + if (loginEntry.getValue() != null && loginEntry.getValue().length() > 0) { // Set the login configuration entry name to use - - m_loginEntryName = loginEntry.getValue(); + setJaasConfigEntryName(loginEntry.getValue()); } else throw new InvalidConfigurationException("Invalid login entry specified"); } - - // Create a login context for the CIFS server service - - try - { - // Login the CIFS server service - - m_loginContext = new LoginContext( m_loginEntryName, this); - m_loginContext.login(); - } - catch ( LoginException ex) - { - // Debug - - if ( logger.isErrorEnabled()) - logger.error("CIFS Kerberos authenticator error", ex); - - throw new InvalidConfigurationException("Failed to login CIFS server service"); - } - // Get the CIFS service account name from the subject - - Subject subj = m_loginContext.getSubject(); - Principal princ = subj.getPrincipals().iterator().next(); - - m_accountName = princ.getName(); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Logged on using principal " + m_accountName); - - // Create the Oid list for the SPNEGO NegTokenInit, include NTLMSSP for fallback - - Vector mechTypes = new Vector(); + setDisableNTLM(params.getChild("disableNTLM") != null); - // DEBUG - - if ( logger.isDebugEnabled()) - { - logger.debug("Enabling mechTypes :-"); - logger.debug(" Kerberos5"); - logger.debug(" MS-Kerberos5"); - } - - // Always enable Kerberos - - mechTypes.add(OID.KERBEROS5); - mechTypes.add(OID.MSKERBEROS5); - - if ( params.getChild("disableNTLM") == null) - { - mechTypes.add(OID.NTLMSSP); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug(" NTLMSSP"); - } - - // Build the SPNEGO NegTokenInit blob - - try - { - // Build the mechListMIC principle - // - // Note: This field is not as specified - - String mecListMIC = null; - - StringBuilder mic = new StringBuilder(); - - mic.append("cifs/"); - mic.append( config.getServerName().toLowerCase()); - mic.append("@"); - mic.append( m_krbRealm); - - mecListMIC = mic.toString(); - - // Build the SPNEGO NegTokenInit that contains the authentication types that the CIFS server accepts - - NegTokenInit negTokenInit = new NegTokenInit(mechTypes, mecListMIC); - - // Encode the NegTokenInit blob - - m_negTokenInit = negTokenInit.encode(); - } - catch (IOException ex) - { - // Debug - - if ( logger.isErrorEnabled()) - logger.error("Error creating SPNEGO NegTokenInit blob", ex); - - throw new InvalidConfigurationException("Failed to create SPNEGO NegTokenInit blob"); - } - // Indicate that SPNEGO security blobs are being used - - m_useRawNTLMSSP = false; + setUseSPNEGO(true); } else { // Check if raw NTLMSSP or SPNEGO/NTLMSSP should be used - - ConfigElement useSpnego = params.getChild("useSPNEGO"); - - if ( useSpnego != null) - { - // Create the Oid list for the SPNEGO NegTokenInit - - Vector mechTypes = new Vector(); - - mechTypes.add( OID.NTLMSSP); - - // Build the SPNEGO NegTokenInit blob - - try - { - // Build the SPNEGO NegTokenInit that contains the authentication types that the CIFS server accepts - - NegTokenInit negTokenInit = new NegTokenInit(mechTypes, null); - - // Encode the NegTokenInit blob - - m_negTokenInit = negTokenInit.encode(); - } - catch (IOException ex) - { - // Debug - - if ( logger.isErrorEnabled()) - logger.error("Error creating SPNEGO NegTokenInit blob", ex); - - throw new InvalidConfigurationException("Failed to create SPNEGO NegTokenInit blob"); - } - - // Indicate that SPNEGO security blobs are being used - - m_useRawNTLMSSP = false; - } - else - { - // Use raw NTLMSSP security blobs - - m_useRawNTLMSSP = true; - } + setUseSPNEGO(params.getChild("useSPNEGO") != null); } - + // Check if NTLMv1 logons are accepted - - ConfigElement disallowNTLMv1 = params.getChild("disallowNTLMv1"); - - m_acceptNTLMv1 = disallowNTLMv1 != null ? false : true; - - // 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) + + setDisallowNTLMv1(params.getChild("disallowNTLMv1") != null); + + // Trigger super class initialisation + super.initialize(config, params); + } + + + /** + * Initialize the authenticator (after properties have been set) + * + * @exception InvalidConfigurationException + */ + @Override + public void initialize() throws InvalidConfigurationException + { + super.initialize(); + + // Check if Java API Kerberos debug output should be enabled + + if (this.kerberosDebug) { - // Log an error - + // Enable Kerberos API debug output + + System.setProperty("sun.security.jgss.debug", "true"); + System.setProperty("sun.security.krb5.debug", "true"); + } + + // Check if Kerberos is enabled + if (m_krbRealm != null && m_krbRealm.length() > 0) + { + + // Get the CIFS service account password + if (m_password == null || m_password.length() == 0) + { + throw new InvalidConfigurationException("CIFS service account password not specified"); + } + + // Get the login configuration entry name + if (m_loginEntryName == null || m_loginEntryName.length() == 0) + { + throw new InvalidConfigurationException("Invalid login entry specified"); + } + + // Create a login context for the CIFS server service + + try + { + // Login the CIFS server service + + m_loginContext = new LoginContext(m_loginEntryName, this); + m_loginContext.login(); + } + catch (LoginException ex) + { + // Debug + + if (logger.isErrorEnabled()) + logger.error("CIFS Kerberos authenticator error", ex); + + throw new InvalidConfigurationException("Failed to login CIFS server service"); + } + + // Get the CIFS service account name from the subject + + Subject subj = m_loginContext.getSubject(); + Principal princ = subj.getPrincipals().iterator().next(); + + m_accountName = princ.getName(); + + // DEBUG + + if (logger.isDebugEnabled()) + logger.debug("Logged on using principal " + m_accountName); + + // Create the Oid list for the SPNEGO NegTokenInit, include NTLMSSP for fallback + + m_mechTypes = new Vector(); + + // DEBUG + + if (logger.isDebugEnabled()) + { + logger.debug("Enabling mechTypes :-"); + logger.debug(" Kerberos5"); + logger.debug(" MS-Kerberos5"); + } + + // Always enable Kerberos + + m_mechTypes.add(OID.KERBEROS5); + m_mechTypes.add(OID.MSKERBEROS5); + + if (!disableNTLM) + { + m_mechTypes.add(OID.NTLMSSP); + + // DEBUG + + if (logger.isDebugEnabled()) + logger.debug(" NTLMSSP"); + } + + // Indicate that SPNEGO security blobs are being used + + m_useRawNTLMSSP = false; + } + // Check if raw NTLMSSP or SPNEGO/NTLMSSP should be used + else if (!m_useRawNTLMSSP) + { + // SPNEGO security blobs are being used + + // Create the Oid list for the SPNEGO NegTokenInit + + m_mechTypes = new Vector(); + + m_mechTypes.add(OID.NTLMSSP); + + } + else + { + // Use raw NTLMSSP security blobs + } + + // 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) + { + // 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"); - - // Throw an exception to stop the CIFS server startup - + + // Throw an exception to stop the CIFS server startup + throw new AlfrescoRuntimeException("Invalid CIFS authenticator configuration"); } } + + /** + * As the mechListMIC principle may vary according to the CIFS server configuration, initialisation and retrieval of + * the cached SPNEGO NegTokenInit has been moved to this method. + * + * @return encoded SPNEGO NegTokenInit + * @throws AuthenticatorException + */ + private synchronized byte[] getNegTokenInit() throws AuthenticatorException + { + String mecListMIC = null; + + // Check if Kerberos is enabled + byte[] encoded = null; + if (m_krbRealm != null && m_krbRealm.length() > 0) + { + // Build the mechListMIC principle + // + // Note: This field is not as specified + + StringBuilder mic = new StringBuilder(); + + mic.append("cifs/"); + mic.append(this.m_config.getServerName().toLowerCase()); + mic.append("@"); + mic.append(m_krbRealm); + + mecListMIC = mic.toString(); + + // If the principal is the same, use the cached pre-encoded version + if (mecListMIC.equals(m_mecListMIC)) + { + encoded = m_negTokenInit; + } + } + // Check if raw NTLMSSP or SPNEGO/NTLMSSP should be used + else if (!m_useRawNTLMSSP) + { + encoded = m_negTokenInit; + } + else + { + return null; + } + + if (encoded != null) + { + return encoded; + } + + // Build the SPNEGO NegTokenInit blob + + try + { + // Build the SPNEGO NegTokenInit that contains the authentication types that the CIFS server accepts + + NegTokenInit negTokenInit = new NegTokenInit(m_mechTypes, mecListMIC); + + // Encode the NegTokenInit blob + + encoded = negTokenInit.encode(); + m_negTokenInit = encoded; + m_mecListMIC = mecListMIC; + } + catch (IOException ex) + { + // Debug + + if (logger.isErrorEnabled()) + logger.error("Error creating SPNEGO NegTokenInit blob", ex); + + throw new AuthenticatorException("Failed to create SPNEGO NegTokenInit blob"); + } + + return encoded; + } /** * Determine if Kerberos support is enabled @@ -397,7 +486,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement */ private final boolean isKerberosEnabled() { - return m_krbKDC != null && m_loginContext != null; + return m_krbRealm != null && m_loginContext != null; } /** @@ -409,7 +498,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement { return m_useRawNTLMSSP; } - + /** * Determine if NTLMv1 logons are accepted * @@ -419,7 +508,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement { return m_acceptNTLMv1; } - + /** * JAAS callback handler * @@ -430,27 +519,27 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { // Process the callback list - + for (int i = 0; i < callbacks.length; i++) { // Request for user name - + if (callbacks[i] instanceof NameCallback) { NameCallback cb = (NameCallback) callbacks[i]; -// cb.setName(m_accountName); + // cb.setName(m_accountName); cb.setName(""); } - + // Request for password else if (callbacks[i] instanceof PasswordCallback) { PasswordCallback cb = (PasswordCallback) callbacks[i]; cb.setPassword(m_password.toCharArray()); } - + // Request for realm - + else if (callbacks[i] instanceof RealmCallback) { RealmCallback cb = (RealmCallback) callbacks[i]; @@ -472,7 +561,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement { return 8; } - + /** * Return the server capability flags * @@ -484,7 +573,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement Capability.NTStatus + Capability.LargeFiles + Capability.LargeRead + Capability.LargeWrite + Capability.ExtendedSecurity; } - + /** * Generate the CIFS negotiate response packet, the authenticator should add authentication specific fields * to the response. @@ -495,44 +584,45 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement * @exception AuthenticatorException */ public void generateNegotiateResponse(SMBSrvSession sess, SMBSrvPacket respPkt, boolean extendedSecurity) - throws AuthenticatorException + throws AuthenticatorException { // If the client does not support extended security then return a standard negotiate response // with an 8 byte challenge - - if ( extendedSecurity == false) + + if (extendedSecurity == false) { - super.generateNegotiateResponse( sess, respPkt, extendedSecurity); + super.generateNegotiateResponse(sess, respPkt, extendedSecurity); return; } - + // Make sure the extended security negotiation flag is set - - if (( respPkt.getFlags2() & SMBSrvPacket.FLG2_EXTENDEDSECURITY) == 0) - respPkt.setFlags2( respPkt.getFlags2() + SMBSrvPacket.FLG2_EXTENDEDSECURITY); - + + if ((respPkt.getFlags2() & SMBSrvPacket.FLG2_EXTENDEDSECURITY) == 0) + respPkt.setFlags2(respPkt.getFlags2() + SMBSrvPacket.FLG2_EXTENDEDSECURITY); + // Get the negotiate response byte area position - + int pos = respPkt.getByteOffset(); byte[] buf = respPkt.getBuffer(); - + // Pack the CIFS server GUID into the negotiate response UUID serverGUID = sess.getSMBServer().getServerGUID(); - - System.arraycopy( serverGUID.getBytes(), 0, buf, pos, 16); + + System.arraycopy(serverGUID.getBytes(), 0, buf, pos, 16); pos += 16; - + // If SPNEGO is enabled then pack the NegTokenInit blob - if ( useRawNTLMSSP() == false) + if (useRawNTLMSSP() == false) { - System.arraycopy( m_negTokenInit, 0, buf, pos, m_negTokenInit.length); - pos += m_negTokenInit.length; + byte[] negTokenInit = getNegTokenInit(); + System.arraycopy(negTokenInit, 0, buf, pos, m_negTokenInit.length); + pos += negTokenInit.length; } // Set the negotiate response length - + respPkt.setByteCount(pos - respPkt.getByteOffset()); } diff --git a/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java b/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java index a3189f5316..13a8173969 100644 --- a/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java +++ b/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.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,7 +18,7 @@ * 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" */ @@ -40,8 +40,8 @@ import org.alfresco.jlan.server.SessionListener; import org.alfresco.jlan.server.SrvSession; import org.alfresco.jlan.server.auth.AuthContext; import org.alfresco.jlan.server.auth.AuthenticatorException; -import org.alfresco.jlan.server.auth.CifsAuthenticator; import org.alfresco.jlan.server.auth.ClientInfo; +import org.alfresco.jlan.server.auth.ICifsAuthenticator; import org.alfresco.jlan.server.auth.NTLanManAuthContext; import org.alfresco.jlan.server.auth.ntlm.NTLM; import org.alfresco.jlan.server.auth.ntlm.NTLMMessage; @@ -68,6 +68,7 @@ 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.NTLMMode; import org.alfresco.service.cmr.repository.NodeRef; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -97,7 +98,7 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements // Passthru keep alive interval - public final static long PassthruKeepAliveInterval = 60000L; // 60 seconds + public final static long PassthruKeepAliveInterval = 60000L; // 60 seconds // NTLM flags mask, used to mask out features that are not supported @@ -118,6 +119,16 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements // Sessions that are currently in the negotiate/session setup state private Hashtable m_sessions; + + private Integer timeout; + + private String server; + + private String domain; + + private String protocolOrder; + + private Integer offlineCheckInterval; /** * Passthru Authenticator Constructor @@ -129,6 +140,31 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements // Allocate the session table m_sessions = new Hashtable(); + } + + public void setTimeout(int timeout) + { + this.timeout = timeout; + } + + public void setServer(String server) + { + this.server = server; + } + + public void setDomain(String domain) + { + this.domain = domain; + } + + public void setProtocolOrder(String protocolOrder) + { + this.protocolOrder = protocolOrder; + } + + public void setOfflineCheckInterval(Integer offlineCheckInterval) + { + this.offlineCheckInterval = offlineCheckInterval; } /** @@ -143,7 +179,7 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements */ public int authenticateShareConnect(ClientInfo client, SharedDevice share, String sharePwd, SrvSession sess) { - return CifsAuthenticator.Writeable; + return ICifsAuthenticator.Writeable; } /** @@ -159,7 +195,7 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements // Check that the client is an Alfresco client if ( client instanceof AlfrescoClientInfo == false) - return CifsAuthenticator.AUTH_DISALLOW; + return ICifsAuthenticator.AUTH_DISALLOW; AlfrescoClientInfo alfClient = (AlfrescoClientInfo) client; @@ -172,11 +208,11 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements if ( logger.isDebugEnabled()) logger.debug("Null CIFS logon allowed, sess = " + sess.getUniqueId()); - return CifsAuthenticator.AUTH_ALLOW; + return ICifsAuthenticator.AUTH_ALLOW; } // Start a transaction - + UserTransaction tx = createTransaction(); int authSts = AUTH_DISALLOW; @@ -262,7 +298,7 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements // Allow the user access as a guest - authSts = CifsAuthenticator.AUTH_GUEST; + authSts = ICifsAuthenticator.AUTH_GUEST; // Debug @@ -279,8 +315,8 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements if ( personName != null) { - // Use the person name as the current user - + // Use the person name as the current user + alfClient.setAuthenticationToken( getAuthenticationComponent().setCurrentUser(personName)); // DEBUG @@ -290,7 +326,7 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements // Allow the user full access to the server - authSts = CifsAuthenticator.AUTH_ALLOW; + authSts = ICifsAuthenticator.AUTH_ALLOW; // Debug @@ -298,7 +334,7 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements logger.debug("Passthru authenticate user=" + client.getUserName() + ", FULL"); } else if ( logger.isDebugEnabled()) - logger.debug("Failed to find person matching user " + username); + logger.debug("Failed to find person matching user " + username); } } catch (Exception ex) @@ -406,50 +442,50 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements { // Make sure the SMB server listener is installed - if ( m_server == null) - { - // Install the server listener - - m_server = sess.getSMBServer(); + if ( m_server == null) + { + // Install the server listener + + m_server = sess.getSMBServer(); m_server.addSessionListener(this); - } - + } + // Open a connection to the authentication server, use normal session setup AuthContext authCtx = null; - + try { - // Try and map the client address to a domain - - String domain = mapClientAddressToDomain( sess.getRemoteAddress()); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Mapped client " + sess.getRemoteAddress() + " to domain " + domain); - - AuthenticateSession authSess = m_passthruServers.openSession( false, domain); - if (authSess != null) - { - - // Create an entry in the active sessions table for the new session - - PassthruDetails passDetails = new PassthruDetails(sess, authSess); - m_sessions.put(sess.getUniqueId(), passDetails); - - // Use the challenge key returned from the authentication server - - authCtx = new NTLanManAuthContext( authSess.getEncryptionKey()); - sess.setAuthenticationContext( authCtx); - - // DEBUG - - if (logger.isDebugEnabled()) - logger.debug("Passthru sessId=" + authSess.getSessionId() + ", auth ctx=" + authCtx); - } - else if ( logger.isDebugEnabled()) - logger.debug("Failed to open a passthru session, mapped domain = " + domain); + // Try and map the client address to a domain + + String domain = mapClientAddressToDomain( sess.getRemoteAddress()); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Mapped client " + sess.getRemoteAddress() + " to domain " + domain); + + AuthenticateSession authSess = m_passthruServers.openSession( false, domain); + if (authSess != null) + { + + // Create an entry in the active sessions table for the new session + + PassthruDetails passDetails = new PassthruDetails(sess, authSess); + m_sessions.put(sess.getUniqueId(), passDetails); + + // Use the challenge key returned from the authentication server + + authCtx = new NTLanManAuthContext( authSess.getEncryptionKey()); + sess.setAuthenticationContext( authCtx); + + // DEBUG + + if (logger.isDebugEnabled()) + logger.debug("Passthru sessId=" + authSess.getSessionId() + ", auth ctx=" + authCtx); + } + else if ( logger.isDebugEnabled()) + logger.debug("Failed to open a passthru session, mapped domain = " + domain); } catch (Exception ex) { @@ -528,7 +564,7 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements { // Process the standard password session setup - super.processSessionSetup( sess, reqPkt); + super.processSessionSetup( sess, reqPkt); return; } @@ -618,7 +654,7 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements try { - + // Check if the blob has the NTLMSSP signature if ( secBlobLen >= NTLM.Signature.length) { @@ -633,7 +669,7 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements isNTLMSSP = true; } - // Process the security blob + // Process the security blob if ( isNTLMSSP == true) { @@ -648,8 +684,8 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements } else { - // Invalid blob type - + // Invalid blob type + throw new SMBSrvException( SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); } } @@ -762,20 +798,20 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements if ( uid == VirtualCircuit.InvalidUID) { - // DEBUG + // DEBUG - if ( logger.isDebugEnabled() && sess.hasDebug( SMBSrvSession.DBG_NEGOTIATE)) - logger.debug("Failed to allocate UID for virtual circuit, " + vc); + if ( logger.isDebugEnabled() && sess.hasDebug( SMBSrvSession.DBG_NEGOTIATE)) + logger.debug("Failed to allocate UID for virtual circuit, " + vc); - // Failed to allocate a UID + // Failed to allocate a UID - throw new SMBSrvException(SMBStatus.NTLogonFailure, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); + throw new SMBSrvException(SMBStatus.NTLogonFailure, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); } else if ( logger.isDebugEnabled() && sess.hasDebug( SMBSrvSession.DBG_NEGOTIATE)) { - // DEBUG + // DEBUG - logger.debug("Allocated UID=" + uid + " for VC=" + vc); + logger.debug("Allocated UID=" + uid + " for VC=" + vc); } } @@ -1148,20 +1184,24 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements } } + @Override + protected boolean validateAuthenticationMode() + { + // Check if the appropriate authentication component type is configured + return getAuthenticationComponent().getNTLMMode() != NTLMMode.MD4_PROVIDER; + } + /** - * Initialzie the authenticator + * Initialize the authenticator via the config service * - * @param config ServerConfiguration - * @param params ConfigElement + * @param config + * ServerConfiguration + * @param params + * ConfigElement * @exception InvalidConfigurationException */ public void initialize(ServerConfiguration config, ConfigElement params) throws InvalidConfigurationException { - - // Call the base class - - super.initialize(config, params); - // Check if the offline check interval has been specified ConfigElement checkInterval = params.getChild("offlineCheckInterval"); @@ -1171,27 +1211,128 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements { // Validate the check interval value - int offlineCheck = Integer.parseInt(checkInterval.getValue()); + setOfflineCheckInterval(Integer.parseInt(checkInterval.getValue())); - // Range check the value - - if ( offlineCheck < MinCheckInterval || offlineCheck > MaxCheckInterval) - throw new InvalidConfigurationException("Invalid offline check interval, valid range is " + MinCheckInterval + " to " + MaxCheckInterval); - - // Set the offline check interval for offline passthru servers - - m_passthruServers = new PassthruServers( offlineCheck); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Using offline check interval of " + offlineCheck + " seconds"); } catch (NumberFormatException ex) { throw new InvalidConfigurationException("Invalid offline check interval specified"); } } + + // Check if the session timeout has been specified + + ConfigElement sessTmoElem = params.getChild("Timeout"); + if (sessTmoElem != null) + { + + try + { + + // Validate the session timeout value + + setTimeout(Integer.parseInt(sessTmoElem.getValue())); + } + catch (NumberFormatException ex) + { + throw new InvalidConfigurationException("Invalid timeout value specified"); + } + } + + // Check if the local server should be used + + // Note that this option is not supported for singleton bean initialization, because the local server name is + // part of the file server subsystem rather than the authentication subsystem + + if (params.getChild("LocalServer") != null) + { + + // Get the local server name, trim the domain name + String server = getCIFSConfig().getServerName(); + if(server == null) + throw new AlfrescoRuntimeException("Passthru authenticator failed to get local server name"); + setServer(server); + } + + // Check if a server name has been specified + + ConfigElement srvNamesElem = params.getChild("Server"); + + if (srvNamesElem != null && srvNamesElem.getValue().length() > 0) + { + setServer(srvNamesElem.getValue()); + } + + // Check if the local domain/workgroup should be used + + if (params.getChild("LocalDomain") != null) + { + // Get the local domain/workgroup name + + setDomain(getCIFSConfig().getDomainName()); + } + + // Check if a domain name has been specified + + ConfigElement domNameElem = params.getChild("Domain"); + + if (domNameElem != null && domNameElem.getValue().length() > 0) + { + setDomain(domNameElem.getValue()); + } + + // Check if a protocol order has been set + + ConfigElement protoOrderElem = params.getChild("ProtocolOrder"); + + if (protoOrderElem != null && protoOrderElem.getValue().length() > 0) + { + setProtocolOrder(protoOrderElem.getValue()); + } + + // Call the base class + super.initialize(config, params); + + // Install the SMB server listener so we receive callbacks when sessions are + // opened/closed on the SMB server + + SMBServer smbServer = (SMBServer) config.findServer( "SMB"); + if ( smbServer != null) + smbServer.addSessionListener(this); + + // Note that for container-based initialization, session listeners can be registered directly on CIFSSeverBean + } + + + /** + * Initialize the authenticator (after properties have been set) + * + * @exception InvalidConfigurationException + */ + @Override + public void initialize() throws InvalidConfigurationException + { + // Call the base class + super.initialize(); + + // Check if the offline check interval has been specified + + if ( this.offlineCheckInterval != null) + { + // Range check the value + + if ( this.offlineCheckInterval < MinCheckInterval || this.offlineCheckInterval > MaxCheckInterval) + throw new InvalidConfigurationException("Invalid offline check interval, valid range is " + MinCheckInterval + " to " + MaxCheckInterval); + + // Set the offline check interval for offline passthru servers + + m_passthruServers = new PassthruServers( this.offlineCheckInterval); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Using offline check interval of " + this.offlineCheckInterval + " seconds"); + } else { // Create the passthru server list with the default offline check interval @@ -1206,62 +1347,29 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements // Check if the session timeout has been specified - ConfigElement sessTmoElem = params.getChild("Timeout"); - if (sessTmoElem != null) + if (this.timeout != null) { - try - { - - // Validate the session timeout value - - int sessTmo = Integer.parseInt(sessTmoElem.getValue()); - // Range check the timeout - if ( sessTmo < MinSessionTmo || sessTmo > MaxSessionTmo) + if ( this.timeout < MinSessionTmo || this.timeout > MaxSessionTmo) throw new InvalidConfigurationException("Invalid session timeout, valid range is " + MinSessionTmo + " to " + MaxSessionTmo); // Set the session timeout for connecting to an authentication server - m_passthruServers.setConnectionTimeout( sessTmo); - } - catch (NumberFormatException ex) - { - throw new InvalidConfigurationException("Invalid timeout value specified"); - } - } - - // Check if the local server should be used - - String srvList = null; - - if (params.getChild("LocalServer") != null) - { - - // Get the local server name, trim the domain name - - srvList = getCIFSConfig().getServerName(); - if(srvList == null) - throw new AlfrescoRuntimeException("Passthru authenticator failed to get local server name"); + m_passthruServers.setConnectionTimeout( this.timeout); } // Check if a server name has been specified - ConfigElement srvNamesElem = params.getChild("Server"); - - if (srvNamesElem != null && srvNamesElem.getValue().length() > 0) + String srvList = null; + if (this.server != null && this.server.length() > 0) { - // Check if the server name was already set - - if (srvList != null) - throw new AlfrescoRuntimeException("Set passthru server via local server or specify name"); - // Get the passthru authenticator server name - srvList = srvNamesElem.getValue(); + srvList = this.server; } // If the passthru server name has been set initialize the passthru connection @@ -1279,20 +1387,9 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements String domainName = null; - // Check if the local domain/workgroup should be used - - if (params.getChild("LocalDomain") != null) - { - // Get the local domain/workgroup name - - domainName = getCIFSConfig().getDomainName(); - } - // Check if a domain name has been specified - ConfigElement domNameElem = params.getChild("Domain"); - - if (domNameElem != null && domNameElem.getValue().length() > 0) + if (this.domain != null && this.domain.length() > 0) { // Check if the authentication server has already been set, ie. server name was also specified @@ -1300,7 +1397,7 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements if (srvList != null) throw new AlfrescoRuntimeException("Specify server or domain name for passthru authentication"); - domainName = domNameElem.getValue(); + domainName = this.domain; } // If the domain name has been set initialize the passthru connection @@ -1320,76 +1417,69 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements } } - // Check if a protocol order has been set - - ConfigElement protoOrderElem = params.getChild("ProtocolOrder"); - - if ( protoOrderElem != null && protoOrderElem.getValue().length() > 0) - { - // Parse the protocol order list - - StringTokenizer tokens = new StringTokenizer( protoOrderElem.getValue(), ","); - int primaryProto = Protocol.None; - int secondaryProto = Protocol.None; - - // There should only be one or two tokens - - if ( tokens.countTokens() > 2) - throw new AlfrescoRuntimeException("Invalid protocol order list, " + protoOrderElem.getValue()); - - // Get the primary protocol - - if ( tokens.hasMoreTokens()) - { - // Parse the primary protocol - - String primaryStr = tokens.nextToken(); - - if ( primaryStr.equalsIgnoreCase( "TCPIP")) - primaryProto = Protocol.NativeSMB; - else if ( primaryStr.equalsIgnoreCase( "NetBIOS")) - primaryProto = Protocol.TCPNetBIOS; - else - throw new AlfrescoRuntimeException("Invalid protocol type, " + primaryStr); - - // Check if there is a secondary protocol, and validate - - if ( tokens.hasMoreTokens()) - { - // Parse the secondary protocol - - String secondaryStr = tokens.nextToken(); - - if ( secondaryStr.equalsIgnoreCase( "TCPIP") && primaryProto != Protocol.NativeSMB) - secondaryProto = Protocol.NativeSMB; - else if ( secondaryStr.equalsIgnoreCase( "NetBIOS") && primaryProto != Protocol.TCPNetBIOS) - secondaryProto = Protocol.TCPNetBIOS; - else - throw new AlfrescoRuntimeException("Invalid secondary protocol, " + secondaryStr); - } - } - - // Set the protocol order used for passthru authentication sessions - - AuthSessionFactory.setProtocolOrder( primaryProto, secondaryProto); - - // DEBUG - - if (logger.isDebugEnabled()) - logger.debug("Protocol order primary=" + Protocol.asString(primaryProto) + ", secondary=" + Protocol.asString(secondaryProto)); - } - + // Check if a protocol order has been set + + if ( this.protocolOrder != null && this.protocolOrder.length() > 0) + { + // Parse the protocol order list + + StringTokenizer tokens = new StringTokenizer( this.protocolOrder, ","); + int primaryProto = Protocol.None; + int secondaryProto = Protocol.None; + + // There should only be one or two tokens + + if ( tokens.countTokens() > 2) + throw new AlfrescoRuntimeException("Invalid protocol order list, " + this.protocolOrder); + + // Get the primary protocol + + if ( tokens.hasMoreTokens()) + { + // Parse the primary protocol + + String primaryStr = tokens.nextToken(); + + if ( primaryStr.equalsIgnoreCase( "TCPIP")) + primaryProto = Protocol.NativeSMB; + else if ( primaryStr.equalsIgnoreCase( "NetBIOS")) + primaryProto = Protocol.TCPNetBIOS; + else + throw new AlfrescoRuntimeException("Invalid protocol type, " + primaryStr); + + // Check if there is a secondary protocol, and validate + + if ( tokens.hasMoreTokens()) + { + // Parse the secondary protocol + + String secondaryStr = tokens.nextToken(); + + if ( secondaryStr.equalsIgnoreCase( "TCPIP") && primaryProto != Protocol.NativeSMB) + secondaryProto = Protocol.NativeSMB; + else if ( secondaryStr.equalsIgnoreCase( "NetBIOS") && primaryProto != Protocol.TCPNetBIOS) + secondaryProto = Protocol.TCPNetBIOS; + else + throw new AlfrescoRuntimeException("Invalid secondary protocol, " + secondaryStr); + } + } + + // Set the protocol order used for passthru authentication sessions + + AuthSessionFactory.setProtocolOrder( primaryProto, secondaryProto); + + // DEBUG + + if (logger.isDebugEnabled()) + logger.debug("Protocol order primary=" + Protocol.asString(primaryProto) + ", secondary=" + Protocol.asString(secondaryProto)); + } + // Check if we have an authentication server if (m_passthruServers.getTotalServerCount() == 0) - throw new AlfrescoRuntimeException("No valid authentication servers found for passthru"); - - // Install the SMB server listener so we receive callbacks when sessions are - // opened/closed on the SMB server + throw new AlfrescoRuntimeException("No valid authentication servers found for passthru"); - SMBServer smbServer = (SMBServer) config.findServer( "SMB"); - if ( smbServer != null) - smbServer.addSessionListener(this); + // Note that for container-based initialization, session listeners can be registered directly on CIFSSeverBean } /** @@ -1476,13 +1566,13 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements */ public void sessionLoggedOn(SrvSession sess) { - // Check the client information for the session - - ClientInfo cInfo = sess.getClientInformation(); - - if ( cInfo == null || cInfo.isNullSession()) - return; - + // Check the client information for the session + + ClientInfo cInfo = sess.getClientInformation(); + + if ( cInfo == null || cInfo.isNullSession()) + return; + // Check if there is an active session to the authentication server for this local // session diff --git a/source/java/org/alfresco/filesys/auth/ftp/AlfrescoFtpAuthenticator.java b/source/java/org/alfresco/filesys/auth/ftp/AlfrescoFtpAuthenticator.java index 520d164165..16db583a38 100644 --- a/source/java/org/alfresco/filesys/auth/ftp/AlfrescoFtpAuthenticator.java +++ b/source/java/org/alfresco/filesys/auth/ftp/AlfrescoFtpAuthenticator.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 @@ -29,25 +29,14 @@ import javax.transaction.UserTransaction; import net.sf.acegisecurity.Authentication; -import org.alfresco.config.ConfigElement; -import org.alfresco.filesys.AlfrescoConfigSection; import org.alfresco.filesys.alfresco.AlfrescoClientInfo; -import org.alfresco.jlan.ftp.FTPAuthenticator; 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.jlan.server.config.InvalidConfigurationException; -import org.alfresco.jlan.server.config.ServerConfiguration; -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.service.cmr.security.AuthenticationService; -import org.alfresco.service.cmr.security.AuthorityService; -import org.alfresco.service.transaction.TransactionService; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; /** * Alfresco FTP Authenticator Class diff --git a/source/java/org/alfresco/filesys/auth/ftp/FTPAuthenticatorBase.java b/source/java/org/alfresco/filesys/auth/ftp/FTPAuthenticatorBase.java index 37acaa2b45..e1b598166c 100644 --- a/source/java/org/alfresco/filesys/auth/ftp/FTPAuthenticatorBase.java +++ b/source/java/org/alfresco/filesys/auth/ftp/FTPAuthenticatorBase.java @@ -34,6 +34,7 @@ import org.alfresco.jlan.ftp.FTPSrvSession; 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.security.authentication.AuthenticationComponent; import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.AuthorityService; @@ -51,38 +52,90 @@ public abstract class FTPAuthenticatorBase implements FTPAuthenticator { protected static final Log logger = LogFactory.getLog("org.alfresco.ftp.protocol.auth"); - // Alfresco configuration section - private AlfrescoConfigSection m_alfrescoConfig; + protected ServerConfigurationAccessor serverConfiguration; + + private AuthenticationComponent authenticationComponent; + + + private AuthenticationService authenticationService; + + + private TransactionService transactionService; + + + private AuthorityService authorityService; + /** * Default constructor */ public FTPAuthenticatorBase() { } - /** - * Initialize the authenticator - * + + public void setConfig(ServerConfigurationAccessor config) + { + this.serverConfiguration = config; + } + + public void setAuthenticationComponent(AuthenticationComponent authenticationComponent) + { + this.authenticationComponent = authenticationComponent; + } + + public void setAuthenticationService(AuthenticationService authenticationService) + { + this.authenticationService = authenticationService; + } + + public void setTransactionService(TransactionService transactionService) + { + this.transactionService = transactionService; + } + + public void setAuthorityService(AuthorityService authorityService) + { + this.authorityService = authorityService; + } + + /** + * Initialize the authenticator + * * @param config ServerConfiguration * @param params ConfigElement - * @exception InvalidConfigurationException - */ - public void initialize(ServerConfiguration config, ConfigElement params) - throws InvalidConfigurationException { + * @exception InvalidConfigurationException + */ + public void initialize(ServerConfiguration config, ConfigElement params) throws InvalidConfigurationException + { + setConfig(config); - // Get the alfresco configuration section, required to get hold of various - // services/components + // Get the alfresco configuration section, required to get hold of various services/components + + AlfrescoConfigSection alfrescoConfig = (AlfrescoConfigSection) config.getConfigSection( AlfrescoConfigSection.SectionName); + + // Copy over relevant bean properties for backward compatibility + setAuthenticationComponent(alfrescoConfig.getAuthenticationComponent()); + setAuthenticationService(alfrescoConfig.getAuthenticationService()); + setTransactionService(alfrescoConfig.getTransactionService()); + setAuthorityService(alfrescoConfig.getAuthorityService()); - m_alfrescoConfig = (AlfrescoConfigSection) config.getConfigSection(AlfrescoConfigSection.SectionName); + // Complete initialization + initialize(); + } - // Check that the required authentication classes are available - - if ( m_alfrescoConfig == null || getAuthenticationComponent() == null) - throw new InvalidConfigurationException("Authentication component not available"); + /** + * Initialize the authenticator (after properties have been set) + * + * @exception InvalidConfigurationException + */ + public void initialize() throws InvalidConfigurationException + { + if ( this.serverConfiguration == null) + throw new InvalidConfigurationException("server configuration accessor property not set"); } - /** + /** * Authenticate the user * * @param client ClientInfo @@ -97,6 +150,7 @@ public abstract class FTPAuthenticatorBase implements FTPAuthenticator { public void closeAuthenticator() { } + /** * Return the authentication componenet @@ -104,7 +158,7 @@ public abstract class FTPAuthenticatorBase implements FTPAuthenticator { * @return AuthenticationComponent */ protected final AuthenticationComponent getAuthenticationComponent() { - return m_alfrescoConfig.getAuthenticationComponent(); + return this.authenticationComponent; } /** @@ -113,7 +167,7 @@ public abstract class FTPAuthenticatorBase implements FTPAuthenticator { * @return AuthenticationService */ protected final AuthenticationService getAuthenticationService() { - return m_alfrescoConfig.getAuthenticationService(); + return this.authenticationService; } /** @@ -122,7 +176,7 @@ public abstract class FTPAuthenticatorBase implements FTPAuthenticator { * @return TransactionService */ protected final TransactionService getTransactionService() { - return m_alfrescoConfig.getTransactionService(); + return this.transactionService; } /** @@ -131,7 +185,7 @@ public abstract class FTPAuthenticatorBase implements FTPAuthenticator { * @return AuthorityService */ protected final AuthorityService getAuthorityService() { - return m_alfrescoConfig.getAuthorityService(); + return this.authorityService; } /** diff --git a/source/java/org/alfresco/filesys/auth/ftp/PassthruFtpAuthenticator.java b/source/java/org/alfresco/filesys/auth/ftp/PassthruFtpAuthenticator.java index 3e339dae0e..9b9b4cab67 100644 --- a/source/java/org/alfresco/filesys/auth/ftp/PassthruFtpAuthenticator.java +++ b/source/java/org/alfresco/filesys/auth/ftp/PassthruFtpAuthenticator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2008 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,7 +18,7 @@ * 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" */ @@ -51,6 +51,7 @@ import org.alfresco.jlan.server.config.SecurityConfigSection; import org.alfresco.jlan.server.config.ServerConfiguration; import org.alfresco.jlan.smb.Protocol; import org.alfresco.jlan.util.IPAddress; +import org.alfresco.repo.security.authentication.NTLMMode; /** * Passthru FTP Authenticator Class @@ -59,51 +60,78 @@ import org.alfresco.jlan.util.IPAddress; */ public class PassthruFtpAuthenticator extends FTPAuthenticatorBase { - // Constants + // Constants - public final static int DefaultSessionTmo = 5000; // 5 seconds - public final static int MinSessionTmo = 2000; // 2 seconds - public final static int MaxSessionTmo = 30000; // 30 seconds + public final static int DefaultSessionTmo = 5000; // 5 seconds + public final static int MinSessionTmo = 2000; // 2 seconds + public final static int MaxSessionTmo = 30000; // 30 seconds public final static int MinCheckInterval = 10; // 10 seconds public final static int MaxCheckInterval = 15 * 60; // 15 minutes - // Passthru keep alive interval + // Passthru keep alive interval - public final static long PassthruKeepAliveInterval = 60000L; // 60 seconds + public final static long PassthruKeepAliveInterval = 60000L; // 60 seconds - // Passthru servers used to authenticate users + // Passthru servers used to authenticate users - private PassthruServers m_passthruServers; + private PassthruServers m_passthruServers; - // Password encryption, for CIFS NTLM style encryption/hashing - - private PasswordEncryptor m_passwordEncryptor; - - // Security configuration - - private SecurityConfigSection m_securityConfig; - - /** - * Initialize the authenticator - * + // Password encryption, for CIFS NTLM style encryption/hashing + + private PasswordEncryptor m_passwordEncryptor; + + private Integer timeout; + + private String server; + + private String domain; + + private String protocolOrder; + + private Integer offlineCheckInterval; + + public void setTimeout(Integer timeout) + { + this.timeout = timeout; + } + + public void setServer(String server) + { + this.server = server; + } + + public void setDomain(String domain) + { + this.domain = domain; + } + + public void setProtocolOrder(String protocolOrder) + { + this.protocolOrder = protocolOrder; + } + + public void setOfflineCheckInterval(Integer offlineCheckInterval) + { + this.offlineCheckInterval = offlineCheckInterval; + } + + protected SecurityConfigSection getSecurityConfig() + { + return (SecurityConfigSection) this.serverConfiguration.getConfigSection(SecurityConfigSection.SectionName); + } + + /** + * Initialize the authenticator + * * @param config ServerConfiguration * @param params ConfigElement - * @exception InvalidConfigurationException - */ + * @exception InvalidConfigurationException + */ + @Override public void initialize(ServerConfiguration config, ConfigElement params) throws InvalidConfigurationException { - super.initialize(config, params); - - // Get the security configuration, for domain mapping - - m_securityConfig = (SecurityConfigSection) config.getConfigSection(SecurityConfigSection.SectionName); - - // Create the password encryptor - - m_passwordEncryptor = new PasswordEncryptor(); - // Check if the offline check interval has been specified ConfigElement checkInterval = params.getChild("offlineCheckInterval"); @@ -113,27 +141,133 @@ public class PassthruFtpAuthenticator extends FTPAuthenticatorBase { { // Validate the check interval value - int offlineCheck = Integer.parseInt(checkInterval.getValue()); - - // Range check the value - - if ( offlineCheck < MinCheckInterval || offlineCheck > MaxCheckInterval) - throw new InvalidConfigurationException("Invalid offline check interval, valid range is " + MinCheckInterval + " to " + MaxCheckInterval); - - // Set the offline check interval for offline passthru servers - - m_passthruServers = new PassthruServers( offlineCheck); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Using offline check interval of " + offlineCheck + " seconds"); + setOfflineCheckInterval(Integer.parseInt(checkInterval.getValue())); } catch (NumberFormatException ex) { throw new InvalidConfigurationException("Invalid offline check interval specified"); } } + + // Check if the session timeout has been specified + + ConfigElement sessTmoElem = params.getChild("Timeout"); + if (sessTmoElem != null) + { + + try + { + + // Validate the session timeout value + + setTimeout(Integer.parseInt(sessTmoElem.getValue())); + + } + catch (NumberFormatException ex) + { + throw new InvalidConfigurationException("Invalid timeout value specified"); + } + } + + // Get the server configuration bean + + ServerConfigurationBean configBean = null; + + if ( config instanceof ServerConfigurationBean) + configBean = (ServerConfigurationBean) config; + + // Check if the local server should be used + + if ( params.getChild("LocalServer") != null && configBean != null) { + + // Get the local server name, trim the domain name + + String server = configBean.getLocalServerName( true); + if ( server == null) + throw new AlfrescoRuntimeException("Passthru authenticator failed to get local server name"); + + setServer(server); + } + + // Check if a server name has been specified + + ConfigElement srvNamesElem = params.getChild("Server"); + + if (srvNamesElem != null && srvNamesElem.getValue().length() > 0) + { + setServer(srvNamesElem.getValue()); + } + + // Check if the local domain/workgroup should be used + + if ( params.getChild("LocalDomain") != null && configBean != null) { + + // Get the local domain/workgroup name + + setDomain(configBean.getLocalDomainName()); + } + + // Check if a domain name has been specified + + ConfigElement domNameElem = params.getChild("Domain"); + + if (domNameElem != null && domNameElem.getValue().length() > 0) + { + + setDomain(domNameElem.getValue()); + } + + // Check if a protocol order has been set + + ConfigElement protoOrderElem = params.getChild("ProtocolOrder"); + + if (protoOrderElem != null && protoOrderElem.getValue().length() > 0) + { + setProtocolOrder(protoOrderElem.getValue()); + } + + super.initialize(config, params); + } + + + /** + * Initialize the authenticator (after properties have been set) + * + * @exception InvalidConfigurationException + */ + @Override + public void initialize() throws InvalidConfigurationException + { + super.initialize(); + + // Check if the appropriate authentication component type is configured + + if (getAuthenticationComponent().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(); + + // Check if the offline check interval has been specified + + if ( this.offlineCheckInterval != null) + { + // Range check the value + + if ( this.offlineCheckInterval < MinCheckInterval || this.offlineCheckInterval > MaxCheckInterval) + throw new InvalidConfigurationException("Invalid offline check interval, valid range is " + MinCheckInterval + " to " + MaxCheckInterval); + + // Set the offline check interval for offline passthru servers + + m_passthruServers = new PassthruServers( this.offlineCheckInterval); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Using offline check interval of " + this.offlineCheckInterval + " seconds"); + } else { // Create the passthru server list with the default offline check interval @@ -141,329 +275,281 @@ public class PassthruFtpAuthenticator extends FTPAuthenticatorBase { m_passthruServers = new PassthruServers(); } - // Check if the session timeout has been specified + // Check if the session timeout has been specified + + if (this.timeout != null) + { + + // Range check the timeout + + if (this.timeout < MinSessionTmo || this.timeout > MaxSessionTmo) + throw new InvalidConfigurationException("Invalid session timeout, valid range is " + MinSessionTmo + + " to " + MaxSessionTmo); + + // Set the session timeout for connecting to an authentication server + + m_passthruServers.setConnectionTimeout(this.timeout); + } + + // Check if a server name has been specified + + String srvList = null; + + if ( this.server != null && this.server.length() > 0) { + + // Get the passthru authenticator server name + + srvList = this.server; + } + + // If the passthru server name has been set initialize the passthru connection + + if ( srvList != null) { + // Initialize using a list of server names/addresses + + m_passthruServers.setServerList(srvList); + } + else { + + // Get the domain/workgroup name + + String domainName = null; + + // Check if a domain name has been specified + + if ( this.domain != null && this.domain.length() > 0) { + + // Check if the authentication server has already been set, ie. server name was also + // specified + + if ( srvList != null) + throw new AlfrescoRuntimeException("Specify server or domain name for passthru authentication"); + + domainName = this.domain; + } + + // If the domain name has been set initialize the passthru connection + + if ( domainName != null) { + try { + // Initialize using the domain + + m_passthruServers.setDomain(domainName); + } + catch (IOException ex) { + throw new AlfrescoRuntimeException("Error setting passthru domain, " + ex.getMessage()); + } + } + } + + // Check if a protocol order has been set + + if ( this.protocolOrder != null && this.protocolOrder.length() > 0) + { + // Parse the protocol order list + + StringTokenizer tokens = new StringTokenizer( this.protocolOrder, ","); + int primaryProto = Protocol.None; + int secondaryProto = Protocol.None; + + // There should only be one or two tokens + + if ( tokens.countTokens() > 2) + throw new AlfrescoRuntimeException("Invalid protocol order list, " + this.protocolOrder); + + // Get the primary protocol + + if ( tokens.hasMoreTokens()) + { + // Parse the primary protocol + + String primaryStr = tokens.nextToken(); + + if ( primaryStr.equalsIgnoreCase( "TCPIP")) + primaryProto = Protocol.NativeSMB; + else if ( primaryStr.equalsIgnoreCase( "NetBIOS")) + primaryProto = Protocol.TCPNetBIOS; + else + throw new AlfrescoRuntimeException("Invalid protocol type, " + primaryStr); + + // Check if there is a secondary protocol, and validate + + if ( tokens.hasMoreTokens()) + { + // Parse the secondary protocol + + String secondaryStr = tokens.nextToken(); + + if ( secondaryStr.equalsIgnoreCase( "TCPIP") && primaryProto != Protocol.NativeSMB) + secondaryProto = Protocol.NativeSMB; + else if ( secondaryStr.equalsIgnoreCase( "NetBIOS") && primaryProto != Protocol.TCPNetBIOS) + secondaryProto = Protocol.TCPNetBIOS; + else + throw new AlfrescoRuntimeException("Invalid secondary protocol, " + secondaryStr); + } + } + + // Set the protocol order used for passthru authentication sessions + + AuthSessionFactory.setProtocolOrder( primaryProto, secondaryProto); + + // DEBUG + + if (logger.isDebugEnabled()) + logger.debug("Protocol order primary=" + Protocol.asString(primaryProto) + ", secondary=" + Protocol.asString(secondaryProto)); + } + + // Check if we have an authentication server + + if ( m_passthruServers.getTotalServerCount() == 0) + throw new AlfrescoRuntimeException("No valid authentication servers found for passthru"); + } + + /** + * Authenticate the user + * + * @param client ClientInfo + * @param sess FTPSrvSession + * @return boolean + */ + public boolean authenticateUser(ClientInfo client, FTPSrvSession sess) { + + // Check that the client is an Alfresco client + + if ( client instanceof AlfrescoClientInfo == false) + return false; + + // Check if this is a guest logon + + boolean authSts = false; + UserTransaction tx = null; + + try { + if ( client.isGuest()) { + + // Get a guest authentication token + + doGuestLogon((AlfrescoClientInfo) client, sess); + + // Indicate logged on as guest + + authSts = true; + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Authenticated guest user " + client.getUserName() + " sts=" + authSts); + + // Return the guest status + + return authSts; + } + + // Start a transaction + + tx = getTransactionService().getUserTransaction(false); + tx.begin(); + + // Perform passthru authentication check + + authSts = doPassthruUserAuthentication(client, sess); + + // Check if the user is an administrator + + if ( authSts == true && client.getLogonType() == ClientInfo.LogonNormal) + checkForAdminUserName( client); + } + catch (Exception ex) { + if ( logger.isDebugEnabled()) + logger.debug(ex); + } + finally { + + // Commit the transaction + + if ( tx != null) { + try { + + // Commit or rollback the transaction + + if ( tx.getStatus() == Status.STATUS_MARKED_ROLLBACK) { + + // Transaction is marked for rollback + + tx.rollback(); + } + else { + // Commit the transaction + + tx.commit(); + } + } + catch (Exception ex) { + } + } + } + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Authenticated user " + client.getUserName() + " sts=" + authSts + " via Passthru"); + + // Return the authentication status + + return authSts; + } + + /** + * Logon using the guest user account + * + * @param client AlfrescoClientInfo + * @param sess SrvSession + */ + protected void doGuestLogon(AlfrescoClientInfo client, SrvSession sess) { + + // Get a guest authentication token + + getAuthenticationService().authenticateAsGuest(); + Authentication authToken = getAuthenticationComponent().getCurrentAuthentication(); + + client.setAuthenticationToken(authToken); + + // Mark the client as being a guest logon - ConfigElement sessTmoElem = params.getChild("Timeout"); - if ( sessTmoElem != null) { + client.setGuest(true); + } - try { - - // Validate the session timeout value - - int sessTmo = Integer.parseInt(sessTmoElem.getValue()); - - // Range check the timeout - - if ( sessTmo < MinSessionTmo || sessTmo > MaxSessionTmo) - throw new InvalidConfigurationException("Invalid session timeout, valid range is " + MinSessionTmo + " to " - + MaxSessionTmo); - - // Set the session timeout for connecting to an authentication server - - m_passthruServers.setConnectionTimeout(sessTmo); - } - catch (NumberFormatException ex) { - throw new InvalidConfigurationException("Invalid timeout value specified"); - } - } - - // Get the server configuration bean - - ServerConfigurationBean configBean = null; - - if ( config instanceof ServerConfigurationBean) - configBean = (ServerConfigurationBean) config; - - // Check if the local server should be used - - String srvList = null; - - if ( params.getChild("LocalServer") != null && configBean != null) { - - // Get the local server name, trim the domain name - - srvList = configBean.getLocalServerName( true); - if ( srvList == null) - throw new AlfrescoRuntimeException("Passthru authenticator failed to get local server name"); - } - - // Check if a server name has been specified - - ConfigElement srvNamesElem = params.getChild("Server"); - - if ( srvNamesElem != null && srvNamesElem.getValue().length() > 0) { - - // Check if the server name was already set - - if ( srvList != null) - throw new AlfrescoRuntimeException("Set passthru server via local server or specify name"); - - // Get the passthru authenticator server name - - srvList = srvNamesElem.getValue(); - } - - // If the passthru server name has been set initialize the passthru connection - - if ( srvList != null) { - // Initialize using a list of server names/addresses - - m_passthruServers.setServerList(srvList); - } - else { - - // Get the domain/workgroup name - - String domainName = null; - - // Check if the local domain/workgroup should be used - - if ( params.getChild("LocalDomain") != null && configBean != null) { - - // Get the local domain/workgroup name - - domainName = configBean.getLocalDomainName(); - } - - // Check if a domain name has been specified - - ConfigElement domNameElem = params.getChild("Domain"); - - if ( domNameElem != null && domNameElem.getValue().length() > 0) { - - // Check if the authentication server has already been set, ie. server name was also - // specified - - if ( srvList != null) - throw new AlfrescoRuntimeException("Specify server or domain name for passthru authentication"); - - domainName = domNameElem.getValue(); - } - - // If the domain name has been set initialize the passthru connection - - if ( domainName != null) { - try { - // Initialize using the domain - - m_passthruServers.setDomain(domainName); - } - catch (IOException ex) { - throw new AlfrescoRuntimeException("Error setting passthru domain, " + ex.getMessage()); - } - } - } - - // Check if a protocol order has been set - - ConfigElement protoOrderElem = params.getChild("ProtocolOrder"); - - if ( protoOrderElem != null && protoOrderElem.getValue().length() > 0) - { - // Parse the protocol order list - - StringTokenizer tokens = new StringTokenizer( protoOrderElem.getValue(), ","); - int primaryProto = Protocol.None; - int secondaryProto = Protocol.None; - - // There should only be one or two tokens - - if ( tokens.countTokens() > 2) - throw new AlfrescoRuntimeException("Invalid protocol order list, " + protoOrderElem.getValue()); - - // Get the primary protocol - - if ( tokens.hasMoreTokens()) - { - // Parse the primary protocol - - String primaryStr = tokens.nextToken(); - - if ( primaryStr.equalsIgnoreCase( "TCPIP")) - primaryProto = Protocol.NativeSMB; - else if ( primaryStr.equalsIgnoreCase( "NetBIOS")) - primaryProto = Protocol.TCPNetBIOS; - else - throw new AlfrescoRuntimeException("Invalid protocol type, " + primaryStr); - - // Check if there is a secondary protocol, and validate - - if ( tokens.hasMoreTokens()) - { - // Parse the secondary protocol - - String secondaryStr = tokens.nextToken(); - - if ( secondaryStr.equalsIgnoreCase( "TCPIP") && primaryProto != Protocol.NativeSMB) - secondaryProto = Protocol.NativeSMB; - else if ( secondaryStr.equalsIgnoreCase( "NetBIOS") && primaryProto != Protocol.TCPNetBIOS) - secondaryProto = Protocol.TCPNetBIOS; - else - throw new AlfrescoRuntimeException("Invalid secondary protocol, " + secondaryStr); - } - } - - // Set the protocol order used for passthru authentication sessions - - AuthSessionFactory.setProtocolOrder( primaryProto, secondaryProto); - - // DEBUG - - if (logger.isDebugEnabled()) - logger.debug("Protocol order primary=" + Protocol.asString(primaryProto) + ", secondary=" + Protocol.asString(secondaryProto)); - } - - // Check if we have an authentication server - - if ( m_passthruServers.getTotalServerCount() == 0) - throw new AlfrescoRuntimeException("No valid authentication servers found for passthru"); - } - - /** - * Authenticate the user - * - * @param client ClientInfo - * @param sess FTPSrvSession - * @return boolean - */ - public boolean authenticateUser(ClientInfo client, FTPSrvSession sess) { - - // Check that the client is an Alfresco client - - if ( client instanceof AlfrescoClientInfo == false) - return false; - - // Check if this is a guest logon - - boolean authSts = false; - UserTransaction tx = null; - - try { - if ( client.isGuest()) { - - // Get a guest authentication token - - doGuestLogon((AlfrescoClientInfo) client, sess); - - // Indicate logged on as guest - - authSts = true; - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Authenticated guest user " + client.getUserName() + " sts=" + authSts); - - // Return the guest status - - return authSts; - } - - // Start a transaction - - tx = getTransactionService().getUserTransaction(false); - tx.begin(); - - // Perform passthru authentication check - - authSts = doPassthruUserAuthentication(client, sess); - - // Check if the user is an administrator - - if ( authSts == true && client.getLogonType() == ClientInfo.LogonNormal) - checkForAdminUserName( client); - } - catch (Exception ex) { - if ( logger.isDebugEnabled()) - logger.debug(ex); - } - finally { - - // Commit the transaction - - if ( tx != null) { - try { - - // Commit or rollback the transaction - - if ( tx.getStatus() == Status.STATUS_MARKED_ROLLBACK) { - - // Transaction is marked for rollback - - tx.rollback(); - } - else { - // Commit the transaction - - tx.commit(); - } - } - catch (Exception ex) { - } - } - } - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Authenticated user " + client.getUserName() + " sts=" + authSts + " via Passthru"); - - // Return the authentication status - - return authSts; - } - - /** - * Logon using the guest user account - * - * @param client AlfrescoClientInfo - * @param sess SrvSession - */ - protected void doGuestLogon(AlfrescoClientInfo client, SrvSession sess) { - - // Get a guest authentication token - - getAuthenticationService().authenticateAsGuest(); - Authentication authToken = getAuthenticationComponent().getCurrentAuthentication(); - - client.setAuthenticationToken(authToken); - - // Mark the client as being a guest logon - - client.setGuest(true); - } - - /** - * Perform passthru authentication - * - * @param client Client information - * @param sess Server session - * @return boolean - */ - private final boolean doPassthruUserAuthentication(ClientInfo client, SrvSession sess) { - - // Authenticate the FTP user by opening a session to a remote CIFS server - - boolean authSts = false; - AuthenticateSession authSess = null; - + /** + * Perform passthru authentication + * + * @param client Client information + * @param sess Server session + * @return boolean + */ + private final boolean doPassthruUserAuthentication(ClientInfo client, SrvSession sess) { + + // Authenticate the FTP user by opening a session to a remote CIFS server + + boolean authSts = false; + AuthenticateSession authSess = null; + try { - // Try and map the client address to a domain - - String domain = mapClientAddressToDomain( sess.getRemoteAddress()); - - authSess = m_passthruServers.openSession( false, domain); - - if (authSess != null) - { - // Use the challenge key returned from the authentication server to generate the hashed password + // Try and map the client address to a domain + + String domain = mapClientAddressToDomain( sess.getRemoteAddress()); + + authSess = m_passthruServers.openSession( false, domain); + + if (authSess != null) + { + // Use the challenge key returned from the authentication server to generate the hashed password - byte[] challenge = authSess.getEncryptionKey(); - byte[] ntlmHash = m_passwordEncryptor.generateEncryptedPassword( client.getPasswordAsString(), challenge, PasswordEncryptor.NTLM1, client.getUserName(), null); - - // Run the passthru authentication second stage - + byte[] challenge = authSess.getEncryptionKey(); + byte[] ntlmHash = m_passwordEncryptor.generateEncryptedPassword( client.getPasswordAsString(), challenge, PasswordEncryptor.NTLM1, client.getUserName(), null); + + // Run the passthru authentication second stage + authSess.doSessionSetup(client.getDomain(), client.getUserName(), null, null, ntlmHash, 0); // Check if the user has been logged on as a guest @@ -485,100 +571,100 @@ public class PassthruFtpAuthenticator extends FTPAuthenticatorBase { } else { - // Set the current user to be authenticated, save the authentication token + // Set the current user to be authenticated, save the authentication token - AlfrescoClientInfo alfClient = (AlfrescoClientInfo) client; - alfClient.setAuthenticationToken(getAuthenticationComponent().setCurrentUser(client.getUserName())); + AlfrescoClientInfo alfClient = (AlfrescoClientInfo) client; + alfClient.setAuthenticationToken(getAuthenticationComponent().setCurrentUser(client.getUserName())); - // Passwords match, grant access + // Passwords match, grant access - authSts = true; - client.setLogonType( ClientInfo.LogonNormal); + authSts = true; + client.setLogonType( ClientInfo.LogonNormal); - // Logging + // Logging - if ( logger.isInfoEnabled()) - logger.info("Logged on user " + client.getUserName() + " ( address " + sess.getRemoteAddress() + ")"); + if ( logger.isInfoEnabled()) + logger.info("Logged on user " + client.getUserName() + " ( address " + sess.getRemoteAddress() + ")"); } - // Close the passthru authentication session + // Close the passthru authentication session authSess.CloseSession(); authSess = null; - } + } } catch (Exception ex) { logger.error("Passthru error", ex); } finally { - - // Make sure the authentication session has been closed - - if ( authSess != null) { - try { - authSess.CloseSession(); - } - catch( Exception ex) { - } - } + + // Make sure the authentication session has been closed + + if ( authSess != null) { + try { + authSess.CloseSession(); + } + catch( Exception ex) { + } + } } - // Return the logon status + // Return the logon status - return authSts; - } + return authSts; + } - /** - * Map a client IP address to a domain - * - * @param clientIP InetAddress - * @return String - */ - protected final String mapClientAddressToDomain(InetAddress clientIP) { + /** + * Map a client IP address to a domain + * + * @param clientIP InetAddress + * @return String + */ + protected final String mapClientAddressToDomain(InetAddress clientIP) { - // Check if there are any domain mappings + // Check if there are any domain mappings - if ( m_securityConfig.hasDomainMappings() == false) - return null; + if ( !getSecurityConfig().hasDomainMappings() ) + return null; - // Convert the client IP address to an integer value + // Convert the client IP address to an integer value - int clientAddr = IPAddress.asInteger(clientIP); + int clientAddr = IPAddress.asInteger(clientIP); - for (DomainMapping domainMap : m_securityConfig.getDomainMappings()) { + for (DomainMapping domainMap : getSecurityConfig().getDomainMappings()) { - if ( domainMap.isMemberOfDomain(clientAddr)) { + if ( domainMap.isMemberOfDomain(clientAddr)) { - // DEBUG + // DEBUG - if ( logger.isDebugEnabled()) - logger.debug("Mapped client IP " + clientIP + " to domain " + domainMap.getDomain()); + if ( logger.isDebugEnabled()) + logger.debug("Mapped client IP " + clientIP + " to domain " + domainMap.getDomain()); - return domainMap.getDomain(); - } - } + return domainMap.getDomain(); + } + } - // DEBUG + // DEBUG - if ( logger.isDebugEnabled()) - logger.debug("Failed to map client IP " + clientIP + " to a domain"); + if ( logger.isDebugEnabled()) + logger.debug("Failed to map client IP " + clientIP + " to a domain"); - // No domain mapping for the client address + // No domain mapping for the client address - return null; - } - - /** - * Close the authenticator - */ - public void closeAuthenticator() - { - super.closeAuthenticator(); - + return null; + } + + /** + * Close the authenticator + */ + public void closeAuthenticator() + { + super.closeAuthenticator(); + // Close the passthru authentication server list if ( m_passthruServers != null) m_passthruServers.shutdown(); - } + } } diff --git a/source/java/org/alfresco/filesys/auth/nfs/AlfrescoRpcAuthenticator.java b/source/java/org/alfresco/filesys/auth/nfs/AlfrescoRpcAuthenticator.java index 424f3b7440..1de1ef6e83 100644 --- a/source/java/org/alfresco/filesys/auth/nfs/AlfrescoRpcAuthenticator.java +++ b/source/java/org/alfresco/filesys/auth/nfs/AlfrescoRpcAuthenticator.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 @@ -14,16 +14,18 @@ * 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 recieved a copy of the text describing - * the FLOSS exception, and it is also available here: + + * 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.filesys.auth.nfs; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import javax.transaction.Status; @@ -42,9 +44,11 @@ import org.alfresco.jlan.server.SrvSession; import org.alfresco.jlan.server.auth.ClientInfo; import org.alfresco.jlan.server.config.InvalidConfigurationException; import org.alfresco.jlan.server.config.ServerConfiguration; +import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.service.transaction.TransactionService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.InitializingBean; /** * Alfresco RPC Authenticator Class @@ -53,198 +57,215 @@ import org.apache.commons.logging.LogFactory; * * @author gkspencer */ -public class AlfrescoRpcAuthenticator implements RpcAuthenticator { +public class AlfrescoRpcAuthenticator implements RpcAuthenticator, InitializingBean { - // Debug logging + // Debug logging - private static final Log logger = LogFactory.getLog("org.alfresco.nfs.protocol.auth"); + private static final Log logger = LogFactory.getLog("org.alfresco.nfs.protocol.auth"); - // Authentication types aupported by this implementation + // Authentication types aupported by this implementation - private int[] _authTypes = { AuthType.Unix }; + private int[] _authTypes = { AuthType.Unix }; - // UID/GID to username conversions - - private HashMap m_idMap; - - // Alfresco configuration - - protected AlfrescoConfigSection m_alfrescoConfig; - - /** - * Authenticate an RPC client and create a unique session id key. - * - * @param authType int - * @param rpc RpcPacket - * @return Object - * @throws RpcAuthenticationException - */ - public Object authenticateRpcClient(int authType, RpcPacket rpc) - throws RpcAuthenticationException { + // UID/GID to username conversions + + private HashMap m_idMap; + + private List userMappings; - // Create a unique session key depending on the authentication type + private AuthenticationComponent authenticationComponent; - Object sessKey = null; + private TransactionService transactionService; - if (authType == AuthType.Unix) { + public void setUserMappings(List userMappings) + { + this.userMappings = userMappings; + } - // Get the gid and uid from the credentials data in the request + public void setAuthenticationComponent(AuthenticationComponent authenticationComponent) + { + this.authenticationComponent = authenticationComponent; + } - rpc.positionAtCredentialsData(); - rpc.skipBytes(4); - int nameLen = rpc.unpackInt(); - rpc.skipBytes(nameLen); + public void setTransactionService(TransactionService transactionService) + { + this.transactionService = transactionService; + } - int uid = rpc.unpackInt(); - int gid = rpc.unpackInt(); + /** + * Authenticate an RPC client and create a unique session id key. + * + * @param authType int + * @param rpc RpcPacket + * @return Object + * @throws RpcAuthenticationException + */ + public Object authenticateRpcClient(int authType, RpcPacket rpc) + throws RpcAuthenticationException { - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug( "RpcAuth: Type=Unix uid=" + uid + ", gid=" + gid); - - // Check that there is a user name mapping for the uid/gid - - Integer idKey = new Integer((gid << 16) + uid); - String userName = m_idMap.get( idKey); - - if ( userName == null) - throw new RpcAuthenticationException( NFS.StsAccess); - - // Check if the Unix authentication session table is valid + // Create a unique session key depending on the authentication type - sessKey = new Long((((long) rpc.getClientAddress().hashCode()) << 32) + (gid << 16) + uid); - } - else if ( authType == AuthType.Null) - { - // Set the session key for the null authentication - - sessKey = new Integer(rpc.getClientAddress().hashCode()); + Object sessKey = null; - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug( "RpcAuth: Type=Null client=" + rpc.getClientAddress()); - } + if (authType == AuthType.Unix) { - // Check if the session key is valid, if not then the authentication - // type is unsupported + // Get the gid and uid from the credentials data in the request - if (sessKey == null) - throw new RpcAuthenticationException(Rpc.AuthBadCred, "Unsupported auth type, " + authType); + rpc.positionAtCredentialsData(); + rpc.skipBytes(4); + int nameLen = rpc.unpackInt(); + rpc.skipBytes(nameLen); - // DEBUG + int uid = rpc.unpackInt(); + int gid = rpc.unpackInt(); - if (logger.isDebugEnabled()) - logger.debug("RpcAuth: RPC from " + rpc.getClientDetails() - + ", authType=" + AuthType.getTypeAsString(authType) - + ", sessKey=" + sessKey); + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug( "RpcAuth: Type=Unix uid=" + uid + ", gid=" + gid); + + // Check that there is a user name mapping for the uid/gid + + Integer idKey = new Integer((gid << 16) + uid); + String userName = m_idMap.get( idKey); + + if ( userName == null) + throw new RpcAuthenticationException( NFS.StsAccess); + + // Check if the Unix authentication session table is valid - // Return the session key + sessKey = new Long((((long) rpc.getClientAddress().hashCode()) << 32) + (gid << 16) + uid); + } + else if ( authType == AuthType.Null) + { + // Set the session key for the null authentication + + sessKey = new Integer(rpc.getClientAddress().hashCode()); - return sessKey; - } + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug( "RpcAuth: Type=Null client=" + rpc.getClientAddress()); + } - /** - * Return the authentication types that are supported by this - * implementation. - * - * @return int[] - */ - public int[] getRpcAuthenticationTypes() { - return _authTypes; - } + // Check if the session key is valid, if not then the authentication + // type is unsupported - /** - * Return the client information for the specified RPC request - * - * @param sessKey Object - * @param rpc RpcPacket - * @return ClientInfo - */ - public ClientInfo getRpcClientInformation(Object sessKey, RpcPacket rpc) - { - // Create a client information object to hold the client details + if (sessKey == null) + throw new RpcAuthenticationException(Rpc.AuthBadCred, "Unsupported auth type, " + authType); - ClientInfo cInfo = null; + // DEBUG - // Get the authentication type + if (logger.isDebugEnabled()) + logger.debug("RpcAuth: RPC from " + rpc.getClientDetails() + + ", authType=" + AuthType.getTypeAsString(authType) + + ", sessKey=" + sessKey); - int authType = rpc.getCredentialsType(); + // Return the session key - // Unpack the client details from the RPC request + return sessKey; + } - if ( authType == AuthType.Unix) { + /** + * Return the authentication types that are supported by this + * implementation. + * + * @return int[] + */ + public int[] getRpcAuthenticationTypes() { + return _authTypes; + } - // Unpack the credentials data + /** + * Return the client information for the specified RPC request + * + * @param sessKey Object + * @param rpc RpcPacket + * @return ClientInfo + */ + public ClientInfo getRpcClientInformation(Object sessKey, RpcPacket rpc) + { + // Create a client information object to hold the client details - rpc.positionAtCredentialsData(); - rpc.skipBytes(4); // stamp id + ClientInfo cInfo = null; - String clientAddr = rpc.unpackString(); - int uid = rpc.unpackInt(); - int gid = rpc.unpackInt(); + // Get the authentication type - // Check for an additional groups list + int authType = rpc.getCredentialsType(); - int grpLen = rpc.unpackInt(); - int[] groups = null; - - if (grpLen > 0) { - groups = new int[grpLen]; - rpc.unpackIntArray(groups); - } + // Unpack the client details from the RPC request - // Get the user name mapping for the uid/gid and authenticate - - Integer idKey = new Integer((gid << 16) + uid); - String userName = m_idMap.get( idKey); + if ( authType == AuthType.Unix) { - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug( "RpcClientInfo: username=" + userName + ", uid=" + uid + ", gid=" + gid); - - // Create the client information if there is a valid mapping + // Unpack the credentials data - if ( userName != null) - { - // Create the client information and fill in relevant fields - - cInfo = ClientInfo.getFactory().createInfo( userName, null); - - cInfo.setNFSAuthenticationType( authType); - cInfo.setClientAddress( clientAddr); - cInfo.setUid( uid); - cInfo.setGid( gid); + rpc.positionAtCredentialsData(); + rpc.skipBytes(4); // stamp id - cInfo.setGroupsList(groups); - } - - // DEBUG - - if (logger.isDebugEnabled()) - logger.debug("RpcAuth: Client info, type=" + AuthType.getTypeAsString(authType) + ", name=" - + clientAddr + ", uid=" + uid + ", gid=" + gid + ", groups=" + grpLen); - } - else if ( authType == AuthType.Null) - { - // Create the client information - - cInfo = ClientInfo.getFactory().createInfo( "", null); - cInfo.setClientAddress(rpc.getClientAddress().getHostAddress()); + String clientAddr = rpc.unpackString(); + int uid = rpc.unpackInt(); + int gid = rpc.unpackInt(); - // DEBUG + // Check for an additional groups list - if (logger.isDebugEnabled()) - logger.debug("RpcAuth: Client info, type=" + AuthType.getTypeAsString(authType) + ", addr=" - + rpc.getClientAddress().getHostAddress()); - } + int grpLen = rpc.unpackInt(); + int[] groups = null; + + if (grpLen > 0) { + groups = new int[grpLen]; + rpc.unpackIntArray(groups); + } - // Return the client information + // Get the user name mapping for the uid/gid and authenticate + + Integer idKey = new Integer((gid << 16) + uid); + String userName = m_idMap.get( idKey); - return cInfo; - } + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug( "RpcClientInfo: username=" + userName + ", uid=" + uid + ", gid=" + gid); + + // Create the client information if there is a valid mapping + + if ( userName != null) + { + // Create the client information and fill in relevant fields + + cInfo = ClientInfo.getFactory().createInfo( userName, null); + + cInfo.setNFSAuthenticationType( authType); + cInfo.setClientAddress( clientAddr); + cInfo.setUid( uid); + cInfo.setGid( gid); + + cInfo.setGroupsList(groups); + } + + // DEBUG + + if (logger.isDebugEnabled()) + logger.debug("RpcAuth: Client info, type=" + AuthType.getTypeAsString(authType) + ", name=" + + clientAddr + ", uid=" + uid + ", gid=" + gid + ", groups=" + grpLen); + } + else if ( authType == AuthType.Null) + { + // Create the client information + + cInfo = ClientInfo.getFactory().createInfo( "", null); + cInfo.setClientAddress(rpc.getClientAddress().getHostAddress()); + + // DEBUG + + if (logger.isDebugEnabled()) + logger.debug("RpcAuth: Client info, type=" + AuthType.getTypeAsString(authType) + ", addr=" + + rpc.getClientAddress().getHostAddress()); + } + + // Return the client information + + return cInfo; + } /** * Set the current authenticated user context for this thread @@ -254,8 +275,8 @@ public class AlfrescoRpcAuthenticator implements RpcAuthenticator { */ public void setCurrentUser( SrvSession sess, ClientInfo client) { - // Start a transaction - + // Start a transaction + UserTransaction tx = createTransaction(); try @@ -264,62 +285,62 @@ public class AlfrescoRpcAuthenticator implements RpcAuthenticator { tx.begin(); - // Check the account type and setup the authentication context - - if ( client == null || client.isNullSession() || client instanceof AlfrescoClientInfo == false) - { - // Clear the authentication, null user should not be allowed to do any service calls - - m_alfrescoConfig.getAuthenticationComponent().clearCurrentSecurityContext(); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Clear security context, client=" + client); - } - else if ( client.isGuest() == false) - { - // Access the Alfresco client - - AlfrescoClientInfo alfClient = (AlfrescoClientInfo) client; - - // Check if the authentication token has been set for the client - - if ( alfClient.hasAuthenticationToken() == false) - { - // Set the current user and retrieve the authentication token - - m_alfrescoConfig.getAuthenticationComponent().setCurrentUser( client.getUserName()); - alfClient.setAuthenticationToken( m_alfrescoConfig.getAuthenticationComponent().getCurrentAuthentication()); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Set user name=" + client.getUserName() + ", token=" + alfClient.getAuthenticationToken()); - } - else - { - // Set the authentication context for the request - - m_alfrescoConfig.getAuthenticationComponent().setCurrentAuthentication( alfClient.getAuthenticationToken()); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Set user using auth token, token=" + alfClient.getAuthenticationToken()); - } - } - else - { - // Enable guest access for the request - - m_alfrescoConfig.getAuthenticationComponent().setGuestUserAsCurrentUser(); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Set guest user"); - } + // Check the account type and setup the authentication context + + if ( client == null || client.isNullSession() || client instanceof AlfrescoClientInfo == false) + { + // Clear the authentication, null user should not be allowed to do any service calls + + getAuthenticationComponent().clearCurrentSecurityContext(); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Clear security context, client=" + client); + } + else if ( client.isGuest() == false) + { + // Access the Alfresco client + + AlfrescoClientInfo alfClient = (AlfrescoClientInfo) client; + + // Check if the authentication token has been set for the client + + if ( alfClient.hasAuthenticationToken() == false) + { + // Set the current user and retrieve the authentication token + + getAuthenticationComponent().setCurrentUser( client.getUserName()); + alfClient.setAuthenticationToken( getAuthenticationComponent().getCurrentAuthentication()); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Set user name=" + client.getUserName() + ", token=" + alfClient.getAuthenticationToken()); + } + else + { + // Set the authentication context for the request + + getAuthenticationComponent().setCurrentAuthentication( alfClient.getAuthenticationToken()); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Set user using auth token, token=" + alfClient.getAuthenticationToken()); + } + } + else + { + // Enable guest access for the request + + getAuthenticationComponent().setGuestUserAsCurrentUser(); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Set guest user"); + } } catch ( Exception ex) { @@ -356,129 +377,179 @@ public class AlfrescoRpcAuthenticator implements RpcAuthenticator { } } - /** - * Initialize the RPC authenticator - * - * @param config ServerConfiguration - * @param params NameValueList - * @throws InvalidConfigurationException - */ - public void initialize(ServerConfiguration config, ConfigElement params) - throws InvalidConfigurationException { + /** + * Initialize the RPC authenticator + * + * @param config ServerConfiguration + * @param params NameValueList + * @throws InvalidConfigurationException + */ + public void initialize(ServerConfiguration config, ConfigElement params) + throws InvalidConfigurationException { + + // Get the alfresco configuration section, required to get hold of various services/components + AlfrescoConfigSection alfrescoConfig = (AlfrescoConfigSection) config.getConfigSection( AlfrescoConfigSection.SectionName); + + // Copy over relevant bean properties for backward compatibility + setAuthenticationComponent(alfrescoConfig.getAuthenticationComponent()); + setTransactionService(alfrescoConfig.getTransactionService()); - // Get the Alfresco configuration section, for access to services + // Check for the user mappings + + ConfigElement userMappings = params.getChild("userMappings"); + if ( userMappings != null) + { + // Allocate the id mappings table + List mappings = new LinkedList(); + + // Get the user map elements + + List userMaps = userMappings.getChildren(); + + // Process the user list + + for ( ConfigElement userElem : userMaps) + { + // Validate the element type + + if ( userElem.getName().equalsIgnoreCase( "user")) + { + // Get the user name, user id and group id + + String userName = userElem.getAttribute("name"); + String uidStr = userElem.getAttribute("uid"); + String gidStr = userElem.getAttribute("gid"); + + if ( userName == null || userName.length() == 0) + throw new InvalidConfigurationException("Empty user name, or name not specified"); + + if ( uidStr == null || uidStr.length() == 0) + throw new InvalidConfigurationException("Invalid uid, or uid not specified, for user " + userName); + + if ( gidStr == null || gidStr.length() == 0) + throw new InvalidConfigurationException("Invalid gid, or gid not specified, for user " + userName); + + // Parse the uid/gid + + int uid = -1; + int gid = -1; + + try + { + uid = Integer.parseInt( uidStr); + } + catch ( NumberFormatException ex) + { + throw new InvalidConfigurationException("Invalid uid value, " + uidStr + " for user " + userName); + } + + try + { + gid = Integer.parseInt( gidStr); + } + catch ( NumberFormatException ex) + { + throw new InvalidConfigurationException("Invalid gid value, " + gidStr + " for user " + userName); + } + + mappings.add(new UserMapping(userName,uid ,gid )); + } + } + setUserMappings(mappings); + } + + afterPropertiesSet(); + } - m_alfrescoConfig = (AlfrescoConfigSection) config.getConfigSection( AlfrescoConfigSection.SectionName); - - // Check for the user mappings - - ConfigElement userMappings = params.getChild("userMappings"); - if ( userMappings != null) - { - // Allocate the id mappings table - - m_idMap = new HashMap(); - - // Get the user map elements - - List userMaps = userMappings.getChildren(); - - // Process the user list - - for ( ConfigElement userElem : userMaps) - { - // Validate the element type - - if ( userElem.getName().equalsIgnoreCase( "user")) - { - // Get the user name, user id and group id - - String userName = userElem.getAttribute("name"); - String uidStr = userElem.getAttribute("uid"); - String gidStr = userElem.getAttribute("gid"); - - if ( userName == null || userName.length() == 0) - throw new InvalidConfigurationException("Empty user name, or name not specified"); - - if ( uidStr == null || uidStr.length() == 0) - throw new InvalidConfigurationException("Invalid uid, or uid not specified, for user " + userName); - - if ( gidStr == null || gidStr.length() == 0) - throw new InvalidConfigurationException("Invalid gid, or gid not specified, for user " + userName); - - // Parse the uid/gid - - int uid = -1; - int gid = -1; - - try - { - uid = Integer.parseInt( uidStr); - } - catch ( NumberFormatException ex) - { - throw new InvalidConfigurationException("Invalid uid value, " + uidStr + " for user " + userName); - } - - try - { - gid = Integer.parseInt( gidStr); - } - catch ( NumberFormatException ex) - { - throw new InvalidConfigurationException("Invalid gid value, " + gidStr + " for user " + userName); - } - - // Check if the mapping already exists - - Integer idKey = new Integer(( gid << 16) + uid); - if ( m_idMap.containsKey( idKey) == false) - { - // Add the username uid/gid mapping - - m_idMap.put( idKey, userName); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Added RPC user mapping for user " + userName + " uid=" + uid + ", gid=" + gid); - } - else if ( logger.isDebugEnabled()) - { - // DEBUG - - logger.debug("Ignored duplicate mapping for uid=" + uid + ", gid=" + gid); - } - } - else - throw new InvalidConfigurationException( "Invalid user mapping, " + userElem.getName()); - } - } - - // Make sure there are some user mappings - - if ( m_idMap == null || m_idMap.size() == 0) - throw new InvalidConfigurationException("No user mappings for RPC authenticator"); - } - - /** - * Create a transaction, this will be a wrteable transaction unless the system is in read-only mode. - * - * return UserTransaction - */ - protected final UserTransaction createTransaction() - { - // Get the transaction service - - TransactionService txService = m_alfrescoConfig.getTransactionService(); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Using " + (txService.isReadOnly() ? "ReadOnly" : "Write") + " transaction"); - - // Create the transaction - - return txService.getUserTransaction( txService.isReadOnly() ? true : false); - } + /** + * Initialize the RPC authenticator + * @throws InvalidConfigurationException + */ + public void afterPropertiesSet() throws InvalidConfigurationException + { + // Check for the user mappings + + if ( this.userMappings != null) + { + // Allocate the id mappings table + + m_idMap = new HashMap(this.userMappings.size() * 2); + + // Process the user list + + for ( UserMapping userElem : this.userMappings) + { + // Validate the element type + + if ( userElem.getName().equalsIgnoreCase( "user")) + { + // Get the user name, user id and group id + + String userName = userElem.getName(); + + if ( userName == null || userName.length() == 0) + throw new InvalidConfigurationException("Empty user name, or name not specified"); + + // Check if the mapping already exists + + Integer idKey = new Integer(( userElem.getGid() << 16) + userElem.getUid()); + if ( m_idMap.containsKey( idKey) == false) + { + // Add the username uid/gid mapping + + m_idMap.put( idKey, userName); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Added RPC user mapping for user " + userName + " uid=" + userElem.getUid() + ", gid=" + userElem.getGid()); + } + else if ( logger.isDebugEnabled()) + { + // DEBUG + + logger.debug("Ignored duplicate mapping for uid=" + userElem.getUid() + ", gid=" + userElem.getGid()); + } + } + else + throw new InvalidConfigurationException( "Invalid user mapping, " + userElem.getName()); + } + } + + // Make sure there are some user mappings + + if ( m_idMap == null || m_idMap.size() == 0) + throw new InvalidConfigurationException("No user mappings for RPC authenticator"); + } + + /** + * Create a transaction, this will be a wrteable transaction unless the system is in read-only mode. + * + * return UserTransaction + */ + protected final UserTransaction createTransaction() + { + // Get the transaction service + + TransactionService txService = getTransactionService(); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Using " + (txService.isReadOnly() ? "ReadOnly" : "Write") + " transaction"); + + // Create the transaction + + return txService.getUserTransaction( txService.isReadOnly() ? true : false); + } + + protected AuthenticationComponent getAuthenticationComponent() + { + return this.authenticationComponent; + } + + protected TransactionService getTransactionService() + { + return this.transactionService; + } } diff --git a/source/java/org/alfresco/filesys/auth/nfs/UserMapping.java b/source/java/org/alfresco/filesys/auth/nfs/UserMapping.java new file mode 100644 index 0000000000..0f3c071c23 --- /dev/null +++ b/source/java/org/alfresco/filesys/auth/nfs/UserMapping.java @@ -0,0 +1,129 @@ +/* + * 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.filesys.auth.nfs; + +/** + * Represents a user mapping for the {@link AlfrescoRpcAuthenticator}. + */ +public class UserMapping +{ + + /** The name. */ + private String name; + + /** The uid. */ + private int uid; + + /** The gid. */ + private int gid; + + /** + * Default constructor for container initialisation. + */ + public UserMapping() + { + } + + /** + * The Constructor. + * + * @param name + * the name + * @param uid + * the uid + * @param gid + * the gid + */ + public UserMapping(String name, int uid, int gid) + { + super(); + this.name = name; + this.uid = uid; + this.gid = gid; + } + + /** + * Gets the name. + * + * @return the name + */ + public String getName() + { + return name; + } + + /** + * Sets the name. + * + * @param name + * the new name + */ + public void setName(String name) + { + this.name = name; + } + + /** + * Gets the uid. + * + * @return the uid + */ + public int getUid() + { + return uid; + } + + /** + * Sets the uid. + * + * @param uid + * the new uid + */ + public void setUid(int uid) + { + this.uid = uid; + } + + /** + * Gets the gid. + * + * @return the gid + */ + public int getGid() + { + return gid; + } + + /** + * Sets the gid. + * + * @param gid + * the new gid + */ + public void setGid(int gid) + { + this.gid = gid; + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/filesys/avm/AVMContext.java b/source/java/org/alfresco/filesys/avm/AVMContext.java index faa8eadadb..4ff2854fe9 100644 --- a/source/java/org/alfresco/filesys/avm/AVMContext.java +++ b/source/java/org/alfresco/filesys/avm/AVMContext.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 @@ -14,15 +14,20 @@ * 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 recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" */ + + * 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.filesys.avm; +import java.util.StringTokenizer; + +import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.filesys.alfresco.AlfrescoContext; import org.alfresco.filesys.alfresco.IOControlHandler; import org.alfresco.filesys.state.FileState; @@ -47,26 +52,26 @@ import org.apache.commons.logging.LogFactory; * @author GKSpencer */ public class AVMContext extends AlfrescoContext - implements CreateStoreCallback, PurgeStoreCallback, CreateVersionCallback, PurgeVersionCallback { + implements CreateStoreCallback, PurgeStoreCallback, CreateVersionCallback, PurgeVersionCallback { // Logging private static final Log logger = LogFactory.getLog(AVMContext.class); - // Constants - // - // Version id that indicates the head version - - public static final int VERSION_HEAD = -1; - - // Store types to show in the virtualization view - - public static final int ShowNormalStores = 0x0001; + // Constants + // + // Version id that indicates the head version + + public static final int VERSION_HEAD = -1; + + // Store types to show in the virtualization view + + public static final int ShowNormalStores = 0x0001; public static final int ShowSiteStores = 0x0002; - public static final int ShowStagingStores = 0x0004; - public static final int ShowAuthorStores = 0x0008; - public static final int ShowPreviewStores = 0x0010; - + public static final int ShowStagingStores = 0x0004; + public static final int ShowAuthorStores = 0x0008; + public static final int ShowPreviewStores = 0x0010; + // Store, root path and version private String m_storePath; @@ -74,18 +79,14 @@ public class AVMContext extends AlfrescoContext // Flag to indicate if the virtualization view is enabled // - // The first set of folders then map to the stores and the second layer map to the versions with + // The first set of folders then map to the stores and the second layer map to the versions with // paths below. private boolean m_virtualView; - // Associated AVM filesystem driver - - private AVMDiskDriver m_avmDriver; - // Virtualization view filtering options - private int m_showOptions; + private int m_showOptions = ShowStagingStores + ShowAuthorStores; // List of newly created store names that need adding into the virtualization view @@ -96,6 +97,17 @@ public class AVMContext extends AlfrescoContext private boolean m_allowAdminStagingWrites; + // Auto create the store if it doesn't exist? + + private boolean m_createStore; + + /** + * Default constructor allowing initialization by container. + */ + public AVMContext() + { + } + /** * Class constructor * @@ -107,17 +119,15 @@ public class AVMContext extends AlfrescoContext */ public AVMContext( String filesysName, String storePath, int version) { - super( filesysName, storePath + "(" + version + ")"); - - // Set the store root path, remove any trailing slash as relative paths will be appended to this value - - m_storePath = storePath; - if ( m_storePath.endsWith( "/")) - m_storePath = m_storePath.substring(0, m_storePath.length() - 1); - - // Set the store version to use - - m_version = version; + setDeviceName(filesysName); + + // Set the store root path + setStorePath(storePath); + + // Set the store version to use + setVersion(version); + + afterPropertiesSet(); } /** @@ -131,21 +141,109 @@ public class AVMContext extends AlfrescoContext */ public AVMContext( String filesysName, int showOptions, AVMDiskDriver avmDriver) { - super( filesysName, "VirtualView"); - - // Enable the virtualization view - - m_virtualView = true; - m_showOptions = showOptions; + setDeviceName(filesysName); + + // Enable the virtualization view + setVirtualView(true); + setShowOptions(showOptions); - m_newStoresLock = new Object(); - m_newStores = new StringList(); - - // Save the associated filesystem driver - - m_avmDriver = avmDriver; + afterPropertiesSet(); + } + + public void setStorePath(String path) + { + this.m_storePath = path; + } + + public void setVersion(int version) + { + this.m_version = version; + } + + public void setShowOptions(int showOptions) + { + this.m_showOptions = showOptions; } + public void setStores(String showAttr) + { + if ( showAttr != null) + { + // Split the show options string + + StringTokenizer tokens = new StringTokenizer( showAttr, ","); + StringList optList = new StringList(); + + while ( tokens.hasMoreTokens()) + optList.addString( tokens.nextToken().trim().toLowerCase()); + + // Build the show options mask + + this.m_showOptions = 0; + + if ( optList.containsString("normal")) + this.m_showOptions += ShowNormalStores; + + if ( optList.containsString("site")) + this.m_showOptions += ShowSiteStores; + + if ( optList.containsString("author")) + this.m_showOptions += ShowAuthorStores; + + if ( optList.containsString("preview")) + this.m_showOptions += ShowPreviewStores; + + if ( optList.containsString("staging")) + this.m_showOptions += ShowStagingStores; + } + } + + public void setVirtualView(boolean isVirtualView) + { + this.m_virtualView = isVirtualView; + } + + public boolean getCreateStore() + { + return m_createStore; + } + + public void setCreateStore(boolean createStore) + { + m_createStore = createStore; + } + + @Override + public void afterPropertiesSet() + { + + if (m_virtualView) + { + // A context for a view onto all stores/versions within AVM. + m_newStoresLock = new Object(); + m_newStores = new StringList(); + + setShareName("VirtualView"); + } + else + { + if (m_storePath == null + || m_storePath.length() == 0) + throw new AlfrescoRuntimeException("Device missing init value: storePath"); + + // A context for a normal view onto a single store/version within AVM. + if (m_storePath.endsWith("/")) + m_storePath = m_storePath.substring(0, m_storePath.length() - 1); + + // Range check the version id + if (m_version < 0 && m_version != AVMContext.VERSION_HEAD) + throw new AlfrescoRuntimeException("Invalid store version id specified, " + m_version); + + setShareName(m_storePath + "(" + m_version + ")"); + } + super.afterPropertiesSet(); + } + /** * Return the filesystem type, either FileSystem.TypeFAT or FileSystem.TypeNTFS. * @@ -173,7 +271,7 @@ public class AVMContext extends AlfrescoContext */ public final int isVersion() { - return m_version; + return m_version; } /** @@ -183,7 +281,7 @@ public class AVMContext extends AlfrescoContext */ public final boolean isVirtualizationView() { - return m_virtualView; + return m_virtualView; } /** @@ -192,7 +290,7 @@ public class AVMContext extends AlfrescoContext * @return boolean */ public final boolean allowAdminStagingWrites() { - return m_allowAdminStagingWrites; + return m_allowAdminStagingWrites; } /** @@ -201,7 +299,7 @@ public class AVMContext extends AlfrescoContext * @param writeable boolean */ public final void setAllowAdminStaginWrites(boolean writeable) { - m_allowAdminStagingWrites = writeable; + m_allowAdminStagingWrites = writeable; } /** @@ -210,9 +308,9 @@ public class AVMContext extends AlfrescoContext * @return boolean */ protected final boolean hasNewStoresQueued() { - if ( m_newStores == null || m_newStores.numberOfStrings() == 0) - return false; - return true; + if ( m_newStores == null || m_newStores.numberOfStrings() == 0) + return false; + return true; } /** @@ -221,15 +319,15 @@ public class AVMContext extends AlfrescoContext * @return StringList */ protected StringList getNewStoresQueue() { - - StringList storesQueue = null; - - synchronized ( m_newStoresLock) { - storesQueue = m_newStores; - m_newStores = new StringList(); - } - - return storesQueue; + + StringList storesQueue = null; + + synchronized ( m_newStoresLock) { + storesQueue = m_newStores; + m_newStores = new StringList(); + } + + return storesQueue; } /** @@ -239,7 +337,7 @@ public class AVMContext extends AlfrescoContext */ public final boolean showNormalStores() { - return (m_showOptions & ShowNormalStores) != 0 ? true : false; + return (m_showOptions & ShowNormalStores) != 0 ? true : false; } /** @@ -259,7 +357,7 @@ public class AVMContext extends AlfrescoContext */ public final boolean showAuthorStores() { - return (m_showOptions & ShowAuthorStores) != 0 ? true : false; + return (m_showOptions & ShowAuthorStores) != 0 ? true : false; } /** @@ -269,7 +367,7 @@ public class AVMContext extends AlfrescoContext */ public final boolean showPreviewStores() { - return (m_showOptions & ShowPreviewStores) != 0 ? true : false; + return (m_showOptions & ShowPreviewStores) != 0 ? true : false; } /** @@ -279,7 +377,7 @@ public class AVMContext extends AlfrescoContext */ public final boolean showStagingStores() { - return (m_showOptions & ShowStagingStores) != 0 ? true : false; + return (m_showOptions & ShowStagingStores) != 0 ? true : false; } /** @@ -290,41 +388,41 @@ public class AVMContext extends AlfrescoContext */ public final boolean showStoreType(int storeType) { - boolean showStore = false; - - switch (storeType) - { - case StoreType.Normal: - showStore = showNormalStores(); - break; + boolean showStore = false; + + switch (storeType) + { + case StoreType.Normal: + showStore = showNormalStores(); + break; case StoreType.SiteStore: showStore = showSiteStores(); break; - case StoreType.WebAuthorMain: - showStore = showAuthorStores(); - break; - case StoreType.WebStagingMain: - showStore = showStagingStores(); - break; - case StoreType.WebAuthorPreview: - case StoreType.WebStagingPreview: - showStore = showPreviewStores(); - break; - } - - return showStore; + case StoreType.WebAuthorMain: + showStore = showAuthorStores(); + break; + case StoreType.WebStagingMain: + showStore = showStagingStores(); + break; + case StoreType.WebAuthorPreview: + case StoreType.WebStagingPreview: + showStore = showPreviewStores(); + break; + } + + return showStore; } /** * Close the filesystem context */ - public void CloseContext() { - - // Call the base class - - super.CloseContext(); - } - + public void CloseContext() { + + // Call the base class + + super.CloseContext(); + } + /** * Create the I/O control handler for this filesystem type * @@ -333,246 +431,246 @@ public class AVMContext extends AlfrescoContext */ protected IOControlHandler createIOHandler( DiskInterface filesysDriver) { - return null; + return null; } - /** - * Create store call back handler - * - * @param storeName String - * @param versionID int - */ - public void storeCreated(String storeName) - { - // Not interested if the virtualization view is not enabled - - if ( isVirtualizationView() == false) - return; - - // Make sure the file state cache is enabled - - FileStateTable fsTable = getStateTable(); - if ( fsTable == null) - return; - - // Find the file state for the root folder - - FileState rootState = fsTable.findFileState( FileName.DOS_SEPERATOR_STR, true, true); + /** + * Create store call back handler + * + * @param storeName String + * @param versionID int + */ + public void storeCreated(String storeName) + { + // Not interested if the virtualization view is not enabled + + if ( isVirtualizationView() == false) + return; + + // Make sure the file state cache is enabled + + FileStateTable fsTable = getStateTable(); + if ( fsTable == null) + return; + + // Find the file state for the root folder + + FileState rootState = fsTable.findFileState( FileName.DOS_SEPERATOR_STR, true, true); - if ( rootState != null) - { - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Queueing new store " + storeName + " for addition to virtualization view"); - - // Add the new store name to the list to be picked up by the next file server access - // to the filesystem - - synchronized ( m_newStoresLock) { - - // Add the new store name - - m_newStores.addString( storeName); - } - } - } - - /** - * Purge store call back handler - * - * @param storeName String - */ - public void storePurged(String storeName) - { - // Not interested if the virtualization view is not enabled - - if ( isVirtualizationView() == false) - return; - - // Make sure the file state cache is enabled - - FileStateTable fsTable = getStateTable(); - if ( fsTable == null) - return; - - // Find the file state for the root folder - - FileState rootState = fsTable.findFileState( FileName.DOS_SEPERATOR_STR); - - if ( rootState != null && rootState.hasPseudoFiles()) - { - // Remove the pseudo folder for the store + if ( rootState != null) + { + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Queueing new store " + storeName + " for addition to virtualization view"); + + // Add the new store name to the list to be picked up by the next file server access + // to the filesystem + + synchronized ( m_newStoresLock) { + + // Add the new store name + + m_newStores.addString( storeName); + } + } + } + + /** + * Purge store call back handler + * + * @param storeName String + */ + public void storePurged(String storeName) + { + // Not interested if the virtualization view is not enabled + + if ( isVirtualizationView() == false) + return; + + // Make sure the file state cache is enabled + + FileStateTable fsTable = getStateTable(); + if ( fsTable == null) + return; + + // Find the file state for the root folder + + FileState rootState = fsTable.findFileState( FileName.DOS_SEPERATOR_STR); + + if ( rootState != null && rootState.hasPseudoFiles()) + { + // Remove the pseudo folder for the store - rootState.getPseudoFileList().removeFile( storeName, false); - - // Build the filesystem relative path to the deleted store folder - - StringBuilder pathStr = new StringBuilder(); - - pathStr.append( FileName.DOS_SEPERATOR); - pathStr.append( storeName); + rootState.getPseudoFileList().removeFile( storeName, false); + + // Build the filesystem relative path to the deleted store folder + + StringBuilder pathStr = new StringBuilder(); + + pathStr.append( FileName.DOS_SEPERATOR); + pathStr.append( storeName); - // Remove the file state for the deleted store - - String storePath = pathStr.toString(); - fsTable.removeFileState( storePath); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug( "Removed pseudo folder for purged store " + storeName); - - // Update the file state modify time - - rootState.updateModifyDateTime(); - - // Send a change notification for the deleted folder - - if ( hasChangeHandler()) - { - // Send the change notification - - getChangeHandler().notifyDirectoryChanged(NotifyChange.ActionRemoved, storePath); - } - } - } + // Remove the file state for the deleted store + + String storePath = pathStr.toString(); + fsTable.removeFileState( storePath); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug( "Removed pseudo folder for purged store " + storeName); + + // Update the file state modify time + + rootState.updateModifyDateTime(); + + // Send a change notification for the deleted folder + + if ( hasChangeHandler()) + { + // Send the change notification + + getChangeHandler().notifyDirectoryChanged(NotifyChange.ActionRemoved, storePath); + } + } + } - /** - * Create version call back handler - * - * @param storeName String - * @param versionID int - */ - public void versionCreated(String storeName, int versionID) - { - // Not interested if the virtualization view is not enabled - - if ( isVirtualizationView() == false) - return; - - // Make sure the file state cache is enabled - - FileStateTable fsTable = getStateTable(); - if ( fsTable == null) - return; + /** + * Create version call back handler + * + * @param storeName String + * @param versionID int + */ + public void versionCreated(String storeName, int versionID) + { + // Not interested if the virtualization view is not enabled + + if ( isVirtualizationView() == false) + return; + + // Make sure the file state cache is enabled + + FileStateTable fsTable = getStateTable(); + if ( fsTable == null) + return; - // Build the path to the store version folder - - StringBuilder pathStr = new StringBuilder(); + // Build the path to the store version folder + + StringBuilder pathStr = new StringBuilder(); - pathStr.append( FileName.DOS_SEPERATOR); - pathStr.append( storeName); - pathStr.append( FileName.DOS_SEPERATOR); - pathStr.append( AVMPath.VersionsFolder); - - // Find the file state for the store versions folder - - FileState verState = fsTable.findFileState( pathStr.toString()); + pathStr.append( FileName.DOS_SEPERATOR); + pathStr.append( storeName); + pathStr.append( FileName.DOS_SEPERATOR); + pathStr.append( AVMPath.VersionsFolder); + + // Find the file state for the store versions folder + + FileState verState = fsTable.findFileState( pathStr.toString()); - if ( verState != null) - { - // Create the version folder name - - StringBuilder verStr = new StringBuilder(); - - verStr.append( AVMPath.VersionFolderPrefix); - verStr.append( versionID); - - String verName = verStr.toString(); - - // Add a pseudo folder for the new version + if ( verState != null) + { + // Create the version folder name + + StringBuilder verStr = new StringBuilder(); + + verStr.append( AVMPath.VersionFolderPrefix); + verStr.append( versionID); + + String verName = verStr.toString(); + + // Add a pseudo folder for the new version - pathStr.append( FileName.DOS_SEPERATOR); - pathStr.append( verName); - - verState.addPseudoFile( new VersionPseudoFile( verName, pathStr.toString())); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug( "Added pseudo folder for new version " + storeName + ":/" + verName); - - // Send a change notification for the new folder - - if ( hasChangeHandler()) - { - // Build the filesystem relative path to the new version folder - - pathStr.append( FileName.DOS_SEPERATOR); - pathStr.append( verName); - - // Send the change notification - + pathStr.append( FileName.DOS_SEPERATOR); + pathStr.append( verName); + + verState.addPseudoFile( new VersionPseudoFile( verName, pathStr.toString())); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug( "Added pseudo folder for new version " + storeName + ":/" + verName); + + // Send a change notification for the new folder + + if ( hasChangeHandler()) + { + // Build the filesystem relative path to the new version folder + + pathStr.append( FileName.DOS_SEPERATOR); + pathStr.append( verName); + + // Send the change notification + getChangeHandler().notifyDirectoryChanged(NotifyChange.ActionAdded, pathStr.toString()); - } - } - } + } + } + } - /** - * Purge version call back handler - * - * @param storeName String - */ - public void versionPurged(String storeName, int versionID) - { - // Not interested if the virtualization view is not enabled - - if ( isVirtualizationView() == false) - return; - - // Make sure the file state cache is enabled - - FileStateTable fsTable = getStateTable(); - if ( fsTable == null) - return; + /** + * Purge version call back handler + * + * @param storeName String + */ + public void versionPurged(String storeName, int versionID) + { + // Not interested if the virtualization view is not enabled + + if ( isVirtualizationView() == false) + return; + + // Make sure the file state cache is enabled + + FileStateTable fsTable = getStateTable(); + if ( fsTable == null) + return; - // Build the path to the store version folder - - StringBuilder pathStr = new StringBuilder(); + // Build the path to the store version folder + + StringBuilder pathStr = new StringBuilder(); - pathStr.append( FileName.DOS_SEPERATOR); - pathStr.append( storeName); - pathStr.append( FileName.DOS_SEPERATOR); - pathStr.append( AVMPath.VersionsFolder); - - // Find the file state for the store versions folder - - FileState verState = fsTable.findFileState( pathStr.toString()); + pathStr.append( FileName.DOS_SEPERATOR); + pathStr.append( storeName); + pathStr.append( FileName.DOS_SEPERATOR); + pathStr.append( AVMPath.VersionsFolder); + + // Find the file state for the store versions folder + + FileState verState = fsTable.findFileState( pathStr.toString()); - if ( verState != null && verState.hasPseudoFiles()) - { - // Create the version folder name - - StringBuilder verStr = new StringBuilder(); - - verStr.append( AVMPath.VersionFolderPrefix); - verStr.append( versionID); - - String verName = verStr.toString(); - - // Remove the pseudo folder for the purged version - - verState.getPseudoFileList().removeFile( verName, true); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug( "Removed pseudo folder for purged version " + storeName + ":/" + verName); - - // Send a change notification for the deleted folder - - if ( hasChangeHandler()) - { - // Build the filesystem relative path to the deleted version folder - - pathStr.append( FileName.DOS_SEPERATOR); - pathStr.append( verName); - - // Send the change notification - + if ( verState != null && verState.hasPseudoFiles()) + { + // Create the version folder name + + StringBuilder verStr = new StringBuilder(); + + verStr.append( AVMPath.VersionFolderPrefix); + verStr.append( versionID); + + String verName = verStr.toString(); + + // Remove the pseudo folder for the purged version + + verState.getPseudoFileList().removeFile( verName, true); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug( "Removed pseudo folder for purged version " + storeName + ":/" + verName); + + // Send a change notification for the deleted folder + + if ( hasChangeHandler()) + { + // Build the filesystem relative path to the deleted version folder + + pathStr.append( FileName.DOS_SEPERATOR); + pathStr.append( verName); + + // Send the change notification + getChangeHandler().notifyDirectoryChanged(NotifyChange.ActionRemoved, pathStr.toString()); - } - } - } + } + } + } } diff --git a/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java b/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java index 518bfa86ea..f83be0f7f6 100644 --- a/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java +++ b/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java @@ -94,7 +94,6 @@ import org.apache.commons.logging.LogFactory; */ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { - // Logging private static final Log logger = LogFactory.getLog(AVMDiskDriver.class); @@ -286,6 +285,151 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface public DeviceContext createContext(String shareName, ConfigElement cfg) throws DeviceContextException { + AVMContext context = null; + + try + { + // Check if the share is a virtualization view + + ConfigElement virtElem = cfg.getChild("virtualView"); + if (virtElem != null) + { + // Check if virtualization view show options have been specified + + int showOptions = AVMContext.ShowStagingStores + AVMContext.ShowAuthorStores; + + String showAttr = virtElem.getAttribute( "stores"); + if ( showAttr != null) + { + // Split the show options string + + StringTokenizer tokens = new StringTokenizer( showAttr, ","); + StringList optList = new StringList(); + + while ( tokens.hasMoreTokens()) + optList.addString( tokens.nextToken().trim().toLowerCase()); + + // Build the show options mask + + showOptions = 0; + + if ( optList.containsString("normal")) + showOptions += AVMContext.ShowNormalStores; + + if ( optList.containsString("site")) + showOptions += AVMContext.ShowSiteStores; + + if ( optList.containsString("author")) + showOptions += AVMContext.ShowAuthorStores; + + if ( optList.containsString("preview")) + showOptions += AVMContext.ShowPreviewStores; + + if ( optList.containsString("staging")) + showOptions += AVMContext.ShowStagingStores; + } + else if ( cfg.getChild("showAllSandboxes") != null) + { + // Old style show options + + showOptions = AVMContext.ShowNormalStores + AVMContext.ShowSiteStores + + AVMContext.ShowAuthorStores + AVMContext.ShowPreviewStores + + AVMContext.ShowStagingStores; + } + + // Create the context + + context = new AVMContext(shareName, showOptions, this); + + // Check if the admin user should be allowed to write to the web project staging stores + + if ( cfg.getChild("adminWriteable") != null) + context.setAllowAdminStaginWrites( true); + + } + else + { + // Get the store path + + ConfigElement storeElement = cfg.getChild(KEY_STORE); + if (storeElement == null + || storeElement.getValue() == null || storeElement.getValue().length() == 0) + throw new DeviceContextException("Device missing init value: " + KEY_STORE); + + String storePath = storeElement.getValue(); + + // Get the version if specified, or default to the head version + + int version = AVMContext.VERSION_HEAD; + + ConfigElement versionElem = cfg.getChild(KEY_VERSION); + if (versionElem != null) + { + // Check if the version is valid + + if (versionElem.getValue() == null || versionElem.getValue().length() == 0) + throw new DeviceContextException("Store version not specified"); + + // Validate the version id + + try + { + version = Integer.parseInt(versionElem.getValue()); + } + catch (NumberFormatException ex) + { + throw new DeviceContextException("Invalid store version specified, " + + versionElem.getValue()); + } + + // Range check the version id + + if (version < 0 && version != AVMContext.VERSION_HEAD) + throw new DeviceContextException("Invalid store version id specified, " + version); + } + + // Create the context + + context = new AVMContext(shareName, storePath, version); + + // Check if the create flag is enabled + + ConfigElement createStore = cfg.getChild(KEY_CREATE); + context.setCreateStore(createStore != null); + + // Enable file state caching + + context.enableStateTable(true, getStateReaper()); + } + + } + catch (Exception ex) + { + logger.error("Error during create context", ex); + + // Rethrow the exception + + throw new DeviceContextException("Driver setup error, " + ex.getMessage()); + } + + // Register the context bean + registerContext(context); + + // Return the context for this shared filesystem + return context; + } + + /** + * Register a device context object for this instance of the shared + * device. + * + * @param context the device context + * @exception DeviceContextException + */ + public void registerContext(DeviceContext ctx) + throws DeviceContextException + { + AVMContext context = (AVMContext)ctx; // Use the system user as the authenticated context for the filesystem initialization try @@ -297,8 +441,6 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface UserTransaction tx = getTransactionService().getUserTransaction(false); - AVMContext context = null; - try { // Start the transaction @@ -308,65 +450,12 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface // Check if the share is a virtualization view - ConfigElement virtElem = cfg.getChild("virtualView"); - if (virtElem != null) + if (context.isVirtualizationView()) { - // Check if virtualization view show options have been specified - - int showOptions = AVMContext.ShowStagingStores + AVMContext.ShowAuthorStores; - - String showAttr = virtElem.getAttribute( "stores"); - if ( showAttr != null) - { - // Split the show options string - - StringTokenizer tokens = new StringTokenizer( showAttr, ","); - StringList optList = new StringList(); - - while ( tokens.hasMoreTokens()) - optList.addString( tokens.nextToken().trim().toLowerCase()); - - // Build the show options mask - - showOptions = 0; - - if ( optList.containsString("normal")) - showOptions += AVMContext.ShowNormalStores; - - if ( optList.containsString("site")) - showOptions += AVMContext.ShowSiteStores; - - if ( optList.containsString("author")) - showOptions += AVMContext.ShowAuthorStores; - - if ( optList.containsString("preview")) - showOptions += AVMContext.ShowPreviewStores; - - if ( optList.containsString("staging")) - showOptions += AVMContext.ShowStagingStores; - } - else if ( cfg.getChild("showAllSandboxes") != null) - { - // Old style show options - - showOptions = AVMContext.ShowNormalStores + AVMContext.ShowSiteStores + - AVMContext.ShowAuthorStores + AVMContext.ShowPreviewStores + - AVMContext.ShowStagingStores; - } - - // Create the context - - context = new AVMContext(shareName, showOptions, this); - // Enable file state caching context.enableStateTable(true, getStateReaper()); - // Check if the admin user should be allowed to write to the web project staging stores - - if ( cfg.getChild("adminWriteable") != null) - context.setAllowAdminStaginWrites( true); - // Plug the virtualization view context into the various store/version call back listeners // so that store/version pseudo folders can be kept in sync with AVM @@ -383,47 +472,10 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface else { // Get the store path + String storePath = context.getStorePath(); - ConfigElement storeElement = cfg.getChild(KEY_STORE); - if (storeElement == null - || storeElement.getValue() == null || storeElement.getValue().length() == 0) - throw new DeviceContextException("Device missing init value: " + KEY_STORE); - - String storePath = storeElement.getValue(); - - // Get the version if specified, or default to the head version - - int version = AVMContext.VERSION_HEAD; - - ConfigElement versionElem = cfg.getChild(KEY_VERSION); - if (versionElem != null) - { - // Check if the version is valid - - if (versionElem.getValue() == null || versionElem.getValue().length() == 0) - throw new DeviceContextException("Store version not specified"); - - // Validate the version id - - try - { - version = Integer.parseInt(versionElem.getValue()); - } - catch (NumberFormatException ex) - { - throw new DeviceContextException("Invalid store version specified, " - + versionElem.getValue()); - } - - // Range check the version id - - if (version < 0 && version != AVMContext.VERSION_HEAD) - throw new DeviceContextException("Invalid store version id specified, " + version); - } - - // Check if the create flag is enabled - - ConfigElement createStore = cfg.getChild(KEY_CREATE); + // Get the version + int version = context.isVersion(); // Validate the store path @@ -432,7 +484,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { // Check if the store should be created - if (createStore == null || version != AVMContext.VERSION_HEAD) + if (!context.getCreateStore()|| version != AVMContext.VERSION_HEAD) throw new DeviceContextException("Invalid store path/version, " + storePath + " (" + version + ")"); @@ -532,10 +584,6 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface throw new DeviceContextException("Failed to create new store " + storePath); } - // Create the context - - context = new AVMContext(shareName, storePath, version); - // Enable file state caching context.enableStateTable(true, getStateReaper()); @@ -572,8 +620,6 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface } // Return the context for this shared filesystem - - return context; } finally { diff --git a/source/java/org/alfresco/filesys/avm/AVMShareMapper.java b/source/java/org/alfresco/filesys/avm/AVMShareMapper.java index 858850d90c..9b5a2e2b52 100644 --- a/source/java/org/alfresco/filesys/avm/AVMShareMapper.java +++ b/source/java/org/alfresco/filesys/avm/AVMShareMapper.java @@ -42,6 +42,7 @@ import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.avm.AVMWrongTypeException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.InitializingBean; /** * AVM Filesystem Share Mapper Class @@ -50,7 +51,7 @@ import org.apache.commons.logging.LogFactory; * * @author gkspencer */ -public class AVMShareMapper implements ShareMapper { +public class AVMShareMapper implements ShareMapper, InitializingBean { // Logging @@ -84,6 +85,16 @@ public class AVMShareMapper implements ShareMapper { { } + public void setServerConfiguration(ServerConfiguration config) + { + this.m_config = config; + } + + public void setDebug(boolean debug) + { + this.m_debug = debug; + } + /** * Initialize the share mapper * @@ -95,14 +106,24 @@ public class AVMShareMapper implements ShareMapper { { // Save the server configuration - m_config = config; - m_filesysConfig = (FilesystemsConfigSection) m_config.getConfigSection(FilesystemsConfigSection.SectionName); - + setServerConfiguration(config); + // Check if debug is enabled if (params != null && params.getChild("debug") != null) - m_debug = true; + setDebug(true); + // Complete the initialization + afterPropertiesSet(); + } + + public void afterPropertiesSet() + { + // Save the server configuration + + m_filesysConfig = (FilesystemsConfigSection) m_config.getConfigSection(FilesystemsConfigSection.SectionName); + + // Build the list of available AVM share names m_avmShareNames = new StringList(); @@ -112,27 +133,27 @@ public class AVMShareMapper implements ShareMapper { while ( shrEnum.hasMoreElements()) { - // Get the current shared device and check if it is an AVM filesystem device - - SharedDevice curShare = shrEnum.nextElement(); - - try - { - if ( curShare.getInterface() instanceof AVMDiskDriver) - { - // Add the shared filesystem name to the list of AVM shares - - m_avmShareNames.addString( curShare.getName()); - - // Set the AVM filesystem driver to be used when creating dynamic shares - - if ( m_driver == null) - m_driver = (AVMDiskDriver) curShare.getInterface(); - } - } - catch ( InvalidDeviceInterfaceException ex) - { - } + // Get the current shared device and check if it is an AVM filesystem device + + SharedDevice curShare = shrEnum.nextElement(); + + try + { + if ( curShare.getInterface() instanceof AVMDiskDriver) + { + // Add the shared filesystem name to the list of AVM shares + + m_avmShareNames.addString( curShare.getName()); + + // Set the AVM filesystem driver to be used when creating dynamic shares + + if ( m_driver == null) + m_driver = (AVMDiskDriver) curShare.getInterface(); + } + } + catch ( InvalidDeviceInterfaceException ex) + { + } } } diff --git a/source/java/org/alfresco/filesys/config/CIFSConfigBean.java b/source/java/org/alfresco/filesys/config/CIFSConfigBean.java new file mode 100644 index 0000000000..f8826ecdd0 --- /dev/null +++ b/source/java/org/alfresco/filesys/config/CIFSConfigBean.java @@ -0,0 +1,518 @@ +/* + * 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.filesys.config; + +import org.alfresco.jlan.server.auth.ICifsAuthenticator; + +// TODO: Auto-generated Javadoc +/** + * The Class CIFSConfigBean. + * + * @author dward + */ +public class CIFSConfigBean +{ + + /** The server enabled. */ + private boolean serverEnabled; + + /** The disable native code. */ + private boolean disableNativeCode; + + /** The broadcast addess. */ + private String broadcastAddress; + + /** The server name. */ + private String serverName; + + /** The domain name. */ + private String domainName; + + /** The server comment. */ + private String serverComment; + + /** The bind to adapter. */ + private String bindToAdapter; + + /** The bind to address. */ + private String bindToAddress; + + /** The authenticator. */ + private ICifsAuthenticator authenticator; + + /** The host accouncer enabled. */ + private boolean hostAccouncerEnabled; + + /** The host accounce interval. */ + private Integer hostAccounceInterval; + + /** The net biossmb. */ + private NetBIOSSMBConfigBean netBIOSSMB; + + /** The tcpip smb. */ + private TcpipSMBConfigBean tcpipSMB; + + /** The win32 net bios. */ + private Win32NetBIOSConfigBean win32NetBIOS; + + /** The win32 host announcer enabled. */ + private boolean win32HostAnnouncerEnabled; + + /** The win32 host announce interval. */ + private Integer win32HostAnnounceInterval; + + /** The WINS config. */ + private WINSConfigBean winsConfig; + + /** The session debug flags. */ + private String sessionDebugFlags; + + /** The disable nio. */ + private boolean disableNIO; + + /** The session timeout. */ + private Integer sessionTimeout; + + /** + * Checks if is server enabled. + * + * @return true, if is server enabled + */ + public boolean getServerEnabled() + { + return serverEnabled; + } + + /** + * Sets the server enabled. + * + * @param serverEnabled + * the new server enabled + */ + public void setServerEnabled(boolean serverEnabled) + { + this.serverEnabled = serverEnabled; + } + + /** + * Checks if is disable native code. + * + * @return true, if is disable native code + */ + public boolean getDisableNativeCode() + { + return disableNativeCode; + } + + /** + * Sets the disable native code. + * + * @param disableNativeCode + * the new disable native code + */ + public void setDisableNativeCode(boolean disableNativeCode) + { + this.disableNativeCode = disableNativeCode; + } + + /** + * Gets the broadcast address. + * + * @return the broadcast address + */ + public String getBroadcastAddress() + { + return broadcastAddress; + } + + /** + * Sets the broadcast address. + * + * @param broadcastAddress + * the new broadcast address + */ + public void setBroadcastAddress(String broadcastAddress) + { + this.broadcastAddress = broadcastAddress; + } + + /** + * Gets the server name. + * + * @return the server name + */ + public String getServerName() + { + return serverName; + } + + /** + * Sets the server name. + * + * @param serverName + * the new server name + */ + public void setServerName(String serverName) + { + this.serverName = serverName; + } + + /** + * Gets the domain name. + * + * @return the domain name + */ + public String getDomainName() + { + return domainName; + } + + /** + * Sets the domain name. + * + * @param domainName + * the new domain name + */ + public void setDomainName(String domainName) + { + this.domainName = domainName; + } + + /** + * Gets the server comment. + * + * @return the server comment + */ + public String getServerComment() + { + return serverComment; + } + + /** + * Sets the server comment. + * + * @param serverComment + * the new server comment + */ + public void setServerComment(String serverComment) + { + this.serverComment = serverComment; + } + + /** + * Gets the bind to adapter. + * + * @return the bind to adapter + */ + public String getBindToAdapter() + { + return bindToAdapter; + } + + /** + * Sets the bind to adapter. + * + * @param bindToAdapter + * the new bind to adapter + */ + public void setBindToAdapter(String bindToAdapter) + { + this.bindToAdapter = bindToAdapter; + } + + /** + * Gets the bind to address. + * + * @return the bind to address + */ + public String getBindToAddress() + { + return bindToAddress; + } + + /** + * Sets the bind to address. + * + * @param bindToAddress + * the new bind to address + */ + public void setBindToAddress(String bindToAddress) + { + this.bindToAddress = bindToAddress; + } + + /** + * Gets the authenticator. + * + * @return the authenticator + */ + public ICifsAuthenticator getAuthenticator() + { + return authenticator; + } + + /** + * Sets the authenticator. + * + * @param authenticator + * the new authenticator + */ + public void setAuthenticator(ICifsAuthenticator authenticator) + { + this.authenticator = authenticator; + } + + /** + * Checks if is host accouncer enabled. + * + * @return true, if is host accouncer enabled + */ + public boolean getHostAccouncerEnabled() + { + return hostAccouncerEnabled; + } + + /** + * Sets the host accouncer enabled. + * + * @param hostAccouncerEnabled + * the new host accouncer enabled + */ + public void setHostAccouncerEnabled(boolean hostAccouncerEnabled) + { + this.hostAccouncerEnabled = hostAccouncerEnabled; + } + + /** + * Gets the host accounce interval. + * + * @return the host accounce interval + */ + public Integer getHostAccounceInterval() + { + return hostAccounceInterval; + } + + /** + * Sets the host accounce interval. + * + * @param hostAccounceInterval + * the new host accounce interval + */ + public void setHostAccounceInterval(Integer hostAccounceInterval) + { + this.hostAccounceInterval = hostAccounceInterval; + } + + /** + * Gets the net biossmb. + * + * @return the net biossmb + */ + public NetBIOSSMBConfigBean getNetBIOSSMB() + { + return netBIOSSMB; + } + + /** + * Sets the net biossmb. + * + * @param netBIOSSMB + * the new net biossmb + */ + public void setNetBIOSSMB(NetBIOSSMBConfigBean netBIOSSMB) + { + this.netBIOSSMB = netBIOSSMB; + } + + /** + * Gets the tcpip smb. + * + * @return the tcpip smb + */ + public TcpipSMBConfigBean getTcpipSMB() + { + return tcpipSMB; + } + + /** + * Sets the tcpip smb. + * + * @param tcpipSMB + * the new tcpip smb + */ + public void setTcpipSMB(TcpipSMBConfigBean tcpipSMB) + { + this.tcpipSMB = tcpipSMB; + } + + /** + * Gets the win32 net bios. + * + * @return the win32 net bios + */ + public Win32NetBIOSConfigBean getWin32NetBIOS() + { + return win32NetBIOS; + } + + /** + * Sets the win32 net bios. + * + * @param win32NetBIOS + * the new win32 net bios + */ + public void setWin32NetBIOS(Win32NetBIOSConfigBean win32NetBIOS) + { + this.win32NetBIOS = win32NetBIOS; + } + + /** + * Checks if is win32 host announcer enabled. + * + * @return true, if is win32 host announcer enabled + */ + public boolean getWin32HostAnnouncerEnabled() + { + return win32HostAnnouncerEnabled; + } + + /** + * Sets the win32 host announcer enabled. + * + * @param win32HostAnnouncerEnabled + * the new win32 host announcer enabled + */ + public void setWin32HostAnnouncerEnabled(boolean win32HostAnnouncerEnabled) + { + this.win32HostAnnouncerEnabled = win32HostAnnouncerEnabled; + } + + /** + * Gets the win32 host announce interval. + * + * @return the win32 host announce interval + */ + public Integer getWin32HostAnnounceInterval() + { + return win32HostAnnounceInterval; + } + + /** + * Sets the win32 host announce interval. + * + * @param win32HostAnnounceInterval + * the new win32 host announce interval + */ + public void setWin32HostAnnounceInterval(Integer win32HostAnnounceInterval) + { + this.win32HostAnnounceInterval = win32HostAnnounceInterval; + } + + /** + * Gets the wINS config. + * + * @return the wINS config + */ + public WINSConfigBean getWINSConfig() + { + return winsConfig; + } + + /** + * Sets the wINS config. + * + * @param config + * the new wINS config + */ + public void setWINSConfig(WINSConfigBean config) + { + winsConfig = config; + } + + /** + * Gets the session debug flags. + * + * @return the session debug flags + */ + public String getSessionDebugFlags() + { + return sessionDebugFlags; + } + + /** + * Sets the session debug flags. + * + * @param sessionDebugFlags + * the new session debug flags + */ + public void setSessionDebugFlags(String sessionDebugFlags) + { + this.sessionDebugFlags = sessionDebugFlags; + } + + /** + * Checks if is disable nio. + * + * @return true, if is disable nio + */ + public boolean getDisableNIO() + { + return disableNIO; + } + + /** + * Sets the disable nio. + * + * @param disableNIO + * the new disable nio + */ + public void setDisableNIO(boolean disableNIO) + { + this.disableNIO = disableNIO; + } + + /** + * Gets the session timeout. + * + * @return the session timeout + */ + protected Integer getSessionTimeout() + { + return sessionTimeout; + } + + /** + * Sets the session timeout. + * + * @param sessionTimeout + * the new session timeout + */ + protected void setSessionTimeout(Integer sessionTimeout) + { + this.sessionTimeout = sessionTimeout; + } + +} diff --git a/source/java/org/alfresco/filesys/config/CoreServerConfigBean.java b/source/java/org/alfresco/filesys/config/CoreServerConfigBean.java new file mode 100644 index 0000000000..859f51dccd --- /dev/null +++ b/source/java/org/alfresco/filesys/config/CoreServerConfigBean.java @@ -0,0 +1,132 @@ +/* + * 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.filesys.config; + +import java.util.List; + +// TODO: Auto-generated Javadoc +/** + * The Class CoreServerConfigBean. + * + * @author dward + */ +public class CoreServerConfigBean +{ + /** The thread pool init. */ + private Integer threadPoolInit; + + /** The thread pool max. */ + private Integer threadPoolMax; + + /** The thread pool debug. */ + private boolean threadPoolDebug; + + /** The memory packet sizes. */ + private List memoryPacketSizes; + + /** + * Gets the thread pool init. + * + * @return the thread pool init + */ + public Integer getThreadPoolInit() + { + return threadPoolInit; + } + + /** + * Sets the thread pool init. + * + * @param threadPoolInit + * the new thread pool init + */ + public void setThreadPoolInit(Integer threadPoolInit) + { + this.threadPoolInit = threadPoolInit; + } + + /** + * Gets the thread pool max. + * + * @return the thread pool max + */ + public Integer getThreadPoolMax() + { + return threadPoolMax; + } + + /** + * Sets the thread pool max. + * + * @param threadPoolMax + * the new thread pool max + */ + public void setThreadPoolMax(Integer threadPoolMax) + { + this.threadPoolMax = threadPoolMax; + } + + /** + * Checks if is thread pool debug. + * + * @return true, if is thread pool debug + */ + public boolean getThreadPoolDebug() + { + return threadPoolDebug; + } + + /** + * Sets the thread pool debug. + * + * @param threadPoolDebug + * the new thread pool debug + */ + public void setThreadPoolDebug(boolean threadPoolDebug) + { + this.threadPoolDebug = threadPoolDebug; + } + + /** + * Gets the memory packet sizes. + * + * @return the memory packet sizes + */ + public List getMemoryPacketSizes() + { + return memoryPacketSizes; + } + + /** + * Sets the memory packet sizes. + * + * @param memoryPacketSizes + * the new memory packet sizes + */ + public void setMemoryPacketSizes(List memoryPacketSizes) + { + this.memoryPacketSizes = memoryPacketSizes; + } +} diff --git a/source/java/org/alfresco/filesys/config/DomainMappingConfigBean.java b/source/java/org/alfresco/filesys/config/DomainMappingConfigBean.java new file mode 100644 index 0000000000..ef8f9d4f1f --- /dev/null +++ b/source/java/org/alfresco/filesys/config/DomainMappingConfigBean.java @@ -0,0 +1,155 @@ +/* + * 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.filesys.config; + +// TODO: Auto-generated Javadoc +/** + * The Class DomainMappingConfigBean. + * + * @author dward + */ +public class DomainMappingConfigBean +{ + + /** The name. */ + private String name; + + /** The subnet. */ + private String subnet; + + /** The mask. */ + private String mask; + + /** The range from. */ + private String rangeFrom; + + /** The range to. */ + private String rangeTo; + + /** + * Gets the name. + * + * @return the name + */ + public String getName() + { + return name; + } + + /** + * Sets the name. + * + * @param name + * the new name + */ + public void setName(String name) + { + this.name = name; + } + + /** + * Gets the subnet. + * + * @return the subnet + */ + public String getSubnet() + { + return subnet; + } + + /** + * Sets the subnet. + * + * @param subnet + * the new subnet + */ + public void setSubnet(String subnet) + { + this.subnet = subnet; + } + + /** + * Gets the mask. + * + * @return the mask + */ + public String getMask() + { + return mask; + } + + /** + * Sets the mask. + * + * @param mask + * the new mask + */ + public void setMask(String mask) + { + this.mask = mask; + } + + /** + * Gets the range from. + * + * @return the range from + */ + public String getRangeFrom() + { + return rangeFrom; + } + + /** + * Sets the range from. + * + * @param rangeFrom + * the new range from + */ + public void setRangeFrom(String rangeFrom) + { + this.rangeFrom = rangeFrom; + } + + /** + * Gets the range to. + * + * @return the range to + */ + public String getRangeTo() + { + return rangeTo; + } + + /** + * Sets the range to. + * + * @param rangeTo + * the new range to + */ + public void setRangeTo(String rangeTo) + { + this.rangeTo = rangeTo; + } +} diff --git a/source/java/org/alfresco/filesys/config/FTPConfigBean.java b/source/java/org/alfresco/filesys/config/FTPConfigBean.java new file mode 100644 index 0000000000..da0a4a3e6b --- /dev/null +++ b/source/java/org/alfresco/filesys/config/FTPConfigBean.java @@ -0,0 +1,253 @@ +/* + * 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.filesys.config; + +import org.alfresco.jlan.ftp.FTPAuthenticator; + +// TODO: Auto-generated Javadoc +/** + * The Class FTPConfigBean. + * + * @author dward + */ +public class FTPConfigBean +{ + + /** The server enabled. */ + private boolean serverEnabled; + + /** The bind to. */ + private String bindTo; + + /** The port. */ + private Integer port; + + /** The allow anonymous. */ + private boolean allowAnonymous; + + /** The anonymous account. */ + private String anonymousAccount; + + /** The root directory. */ + private String rootDirectory; + + /** The debug flags. */ + private String debugFlags; + + /** The char set. */ + private String charSet; + + /** The authenticator. */ + private FTPAuthenticator authenticator; + + /** + * Checks if is server enabled. + * + * @return true, if is server enabled + */ + public boolean getServerEnabled() + { + return serverEnabled; + } + + /** + * Sets the server enabled. + * + * @param serverEnabled + * the new server enabled + */ + public void setServerEnabled(boolean serverEnabled) + { + this.serverEnabled = serverEnabled; + } + + /** + * Gets the bind to. + * + * @return the bind to + */ + public String getBindTo() + { + return bindTo; + } + + /** + * Sets the bind to. + * + * @param bindTo + * the new bind to + */ + public void setBindTo(String bindTo) + { + this.bindTo = bindTo; + } + + /** + * Gets the port. + * + * @return the port + */ + public Integer getPort() + { + return port; + } + + /** + * Sets the port. + * + * @param port + * the new port + */ + public void setPort(Integer port) + { + this.port = port; + } + + /** + * Checks if is allow anonymous. + * + * @return true, if is allow anonymous + */ + public boolean getAllowAnonymous() + { + return allowAnonymous; + } + + /** + * Sets the allow anonymous. + * + * @param allowAnonymous + * the new allow anonymous + */ + public void setAllowAnonymous(boolean allowAnonymous) + { + this.allowAnonymous = allowAnonymous; + } + + /** + * Gets the anonymous account. + * + * @return the anonymous account + */ + public String getAnonymousAccount() + { + return anonymousAccount; + } + + /** + * Sets the anonymous account. + * + * @param anonymousAccount + * the new anonymous account + */ + public void setAnonymousAccount(String anonymousAccount) + { + this.anonymousAccount = anonymousAccount; + } + + /** + * Gets the root directory. + * + * @return the root directory + */ + public String getRootDirectory() + { + return rootDirectory; + } + + /** + * Sets the root directory. + * + * @param rootDirectory + * the new root directory + */ + public void setRootDirectory(String rootDirectory) + { + this.rootDirectory = rootDirectory; + } + + /** + * Gets the debug flags. + * + * @return the debug flags + */ + public String getDebugFlags() + { + return debugFlags; + } + + /** + * Sets the debug flags. + * + * @param debugFlags + * the new debug flags + */ + public void setDebugFlags(String debugFlags) + { + this.debugFlags = debugFlags; + } + + /** + * Gets the char set. + * + * @return the char set + */ + public String getCharSet() + { + return charSet; + } + + /** + * Sets the char set. + * + * @param charSet + * the new char set + */ + public void setCharSet(String charSet) + { + this.charSet = charSet; + } + + /** + * Gets the authenticator. + * + * @return the authenticator + */ + public FTPAuthenticator getAuthenticator() + { + return authenticator; + } + + /** + * Sets the authenticator. + * + * @param authenticator + * the new authenticator + */ + public void setAuthenticator(FTPAuthenticator authenticator) + { + this.authenticator = authenticator; + } +} diff --git a/source/java/org/alfresco/filesys/config/GlobalDesktopActionConfigBean.java b/source/java/org/alfresco/filesys/config/GlobalDesktopActionConfigBean.java new file mode 100644 index 0000000000..d7e44d92ce --- /dev/null +++ b/source/java/org/alfresco/filesys/config/GlobalDesktopActionConfigBean.java @@ -0,0 +1,132 @@ +/* + * 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.filesys.config; + +// TODO: Auto-generated Javadoc +/** + * The Class GlobalDesktopActionConfigBean. + * + * @author dward + */ +public class GlobalDesktopActionConfigBean +{ + + /** The no confirm. */ + private boolean noConfirm; + + /** The webpath. */ + private String webpath; + + /** The path. */ + private String path; + + /** The debug. */ + private boolean debug; + + /** + * Checks if is no confirm. + * + * @return true, if is no confirm + */ + public boolean getNoConfirm() + { + return noConfirm; + } + + /** + * Sets the no confirm. + * + * @param noConfirm + * the new no confirm + */ + public void setNoConfirm(boolean noConfirm) + { + this.noConfirm = noConfirm; + } + + /** + * Gets the webpath. + * + * @return the webpath + */ + public String getWebpath() + { + return webpath; + } + + /** + * Sets the webpath. + * + * @param webpath + * the new webpath + */ + public void setWebpath(String webpath) + { + this.webpath = webpath; + } + + /** + * Gets the path. + * + * @return the path + */ + public String getPath() + { + return path; + } + + /** + * Sets the path. + * + * @param path + * the new path + */ + public void setPath(String path) + { + this.path = path; + } + + /** + * Checks if is debug. + * + * @return true, if is debug + */ + public boolean getDebug() + { + return debug; + } + + /** + * Sets the debug. + * + * @param debug + * the new debug + */ + public void setDebug(boolean debug) + { + this.debug = debug; + } + +} diff --git a/source/java/org/alfresco/filesys/config/MemoryPacketConfigBean.java b/source/java/org/alfresco/filesys/config/MemoryPacketConfigBean.java new file mode 100644 index 0000000000..bf7b275356 --- /dev/null +++ b/source/java/org/alfresco/filesys/config/MemoryPacketConfigBean.java @@ -0,0 +1,108 @@ +/* + * 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.filesys.config; + +// TODO: Auto-generated Javadoc +/** + * The Class MemoryPacketConfigBean. + * + * @author dward + */ +public class MemoryPacketConfigBean +{ + + /** The size. */ + private Long size; + + /** The init. */ + private Integer init; + + /** The max. */ + private Integer max; + + /** + * Gets the size. + * + * @return the size + */ + public Long getSize() + { + return size; + } + + /** + * Sets the size. + * + * @param size + * the new size + */ + public void setSize(Long size) + { + this.size = size; + } + + /** + * Gets the inits the. + * + * @return the inits the + */ + public Integer getInit() + { + return init; + } + + /** + * Sets the inits the. + * + * @param init + * the new inits the + */ + public void setInit(Integer init) + { + this.init = init; + } + + /** + * Gets the max. + * + * @return the max + */ + public Integer getMax() + { + return max; + } + + /** + * Sets the max. + * + * @param max + * the new max + */ + public void setMax(Integer max) + { + this.max = max; + } + +} diff --git a/source/java/org/alfresco/filesys/config/NFSConfigBean.java b/source/java/org/alfresco/filesys/config/NFSConfigBean.java new file mode 100644 index 0000000000..f45fad5839 --- /dev/null +++ b/source/java/org/alfresco/filesys/config/NFSConfigBean.java @@ -0,0 +1,302 @@ +/* + * 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.filesys.config; + +import org.alfresco.jlan.oncrpc.RpcAuthenticator; + +// TODO: Auto-generated Javadoc +/** + * The Class NFSConfigBean. + * + * @author dward + */ +public class NFSConfigBean +{ + + /** The server enabled. */ + private boolean serverEnabled; + + /** The port mapper enabled. */ + private boolean portMapperEnabled; + + /** The thread pool. */ + private Integer threadPool; + + /** The packet pool. */ + private Integer packetPool; + + /** The port mapper port. */ + private Integer portMapperPort; + + /** The mount server port. */ + private Integer mountServerPort; + + /** The NFS server port. */ + private Integer NFSServerPort; + + /** The debug flags. */ + private String debugFlags; + + /** The mount server debug. */ + private boolean mountServerDebug; + + /** The port mapper debug. */ + private boolean portMapperDebug; + + /** The rpc authenticator. */ + private RpcAuthenticator rpcAuthenticator; + + /** + * Checks if is server enabled. + * + * @return true, if is server enabled + */ + public boolean getServerEnabled() + { + return serverEnabled; + } + + /** + * Sets the server enabled. + * + * @param serverEnabled + * the new server enabled + */ + public void setServerEnabled(boolean serverEnabled) + { + this.serverEnabled = serverEnabled; + } + + /** + * Checks if is port mapper enabled. + * + * @return true, if is port mapper enabled + */ + public boolean getPortMapperEnabled() + { + return portMapperEnabled; + } + + /** + * Sets the port mapper enabled. + * + * @param portMapperEnabled + * the new port mapper enabled + */ + public void setPortMapperEnabled(boolean portMapperEnabled) + { + this.portMapperEnabled = portMapperEnabled; + } + + /** + * Gets the thread pool. + * + * @return the thread pool + */ + public Integer getThreadPool() + { + return threadPool; + } + + /** + * Sets the thread pool. + * + * @param threadPool + * the new thread pool + */ + public void setThreadPool(Integer threadPool) + { + this.threadPool = threadPool; + } + + /** + * Gets the packet pool. + * + * @return the packet pool + */ + public Integer getPacketPool() + { + return packetPool; + } + + /** + * Sets the packet pool. + * + * @param packetPool + * the new packet pool + */ + public void setPacketPool(Integer packetPool) + { + this.packetPool = packetPool; + } + + /** + * Gets the port mapper port. + * + * @return the port mapper port + */ + public Integer getPortMapperPort() + { + return portMapperPort; + } + + /** + * Sets the port mapper port. + * + * @param portMapperPort + * the new port mapper port + */ + public void setPortMapperPort(Integer portMapperPort) + { + this.portMapperPort = portMapperPort; + } + + /** + * Gets the mount server port. + * + * @return the mount server port + */ + public Integer getMountServerPort() + { + return mountServerPort; + } + + /** + * Sets the mount server port. + * + * @param mountServerPort + * the new mount server port + */ + public void setMountServerPort(Integer mountServerPort) + { + this.mountServerPort = mountServerPort; + } + + /** + * Gets the nFS server port. + * + * @return the nFS server port + */ + public Integer getNFSServerPort() + { + return NFSServerPort; + } + + /** + * Sets the nFS server port. + * + * @param serverPort + * the new nFS server port + */ + public void setNFSServerPort(Integer serverPort) + { + NFSServerPort = serverPort; + } + + /** + * Gets the debug flags. + * + * @return the debug flags + */ + public String getDebugFlags() + { + return debugFlags; + } + + /** + * Sets the debug flags. + * + * @param debugFlags + * the new debug flags + */ + public void setDebugFlags(String debugFlags) + { + this.debugFlags = debugFlags; + } + + /** + * Checks if is mount server debug. + * + * @return true, if is mount server debug + */ + public boolean getMountServerDebug() + { + return mountServerDebug; + } + + /** + * Sets the mount server debug. + * + * @param mountServerDebug + * the new mount server debug + */ + public void setMountServerDebug(boolean mountServerDebug) + { + this.mountServerDebug = mountServerDebug; + } + + /** + * Checks if is port mapper debug. + * + * @return true, if is port mapper debug + */ + public boolean getPortMapperDebug() + { + return portMapperDebug; + } + + /** + * Sets the port mapper debug. + * + * @param portMapperDebug + * the new port mapper debug + */ + public void setPortMapperDebug(boolean portMapperDebug) + { + this.portMapperDebug = portMapperDebug; + } + + /** + * Gets the rpc authenticator. + * + * @return the rpc authenticator + */ + public RpcAuthenticator getRpcAuthenticator() + { + return rpcAuthenticator; + } + + /** + * Sets the rpc authenticator. + * + * @param rpcAuthenticator + * the new rpc authenticator + */ + public void setRpcAuthenticator(RpcAuthenticator rpcAuthenticator) + { + this.rpcAuthenticator = rpcAuthenticator; + } + +} diff --git a/source/java/org/alfresco/filesys/config/NetBIOSSMBConfigBean.java b/source/java/org/alfresco/filesys/config/NetBIOSSMBConfigBean.java new file mode 100644 index 0000000000..91d98fa585 --- /dev/null +++ b/source/java/org/alfresco/filesys/config/NetBIOSSMBConfigBean.java @@ -0,0 +1,180 @@ +/* + * 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.filesys.config; + +// TODO: Auto-generated Javadoc +/** + * The Class NetBIOSSMBConfigBean. + * + * @author dward + */ +public class NetBIOSSMBConfigBean +{ + + /** The platforms. */ + private String platforms; + + /** The bind to. */ + private String bindTo; + + /** The session port. */ + private Integer sessionPort; + + /** The name port. */ + private Integer namePort; + + /** The datagram port. */ + private Integer datagramPort; + + /** The adapter. */ + private String adapter; + + /** + * Gets the platforms. + * + * @return the platforms + */ + public String getPlatforms() + { + return platforms; + } + + /** + * Sets the platforms. + * + * @param platforms + * the new platforms + */ + public void setPlatforms(String platforms) + { + this.platforms = platforms; + } + + /** + * Gets the bind to. + * + * @return the bind to + */ + public String getBindTo() + { + return bindTo; + } + + /** + * Sets the bind to. + * + * @param bindTo + * the new bind to + */ + public void setBindTo(String bindTo) + { + this.bindTo = bindTo; + } + + /** + * Gets the session port. + * + * @return the session port + */ + public Integer getSessionPort() + { + return sessionPort; + } + + /** + * Sets the session port. + * + * @param sessionPort + * the new session port + */ + public void setSessionPort(Integer sessionPort) + { + this.sessionPort = sessionPort; + } + + /** + * Gets the name port. + * + * @return the name port + */ + public Integer getNamePort() + { + return namePort; + } + + /** + * Sets the name port. + * + * @param namePort + * the new name port + */ + public void setNamePort(Integer namePort) + { + this.namePort = namePort; + } + + /** + * Gets the datagram port. + * + * @return the datagram port + */ + public Integer getDatagramPort() + { + return datagramPort; + } + + /** + * Sets the datagram port. + * + * @param datagramPort + * the new datagram port + */ + public void setDatagramPort(Integer datagramPort) + { + this.datagramPort = datagramPort; + } + + /** + * Gets the adapter. + * + * @return the adapter + */ + public String getAdapter() + { + return adapter; + } + + /** + * Sets the adapter. + * + * @param adapter + * the new adapter + */ + public void setAdapter(String adapter) + { + this.adapter = adapter; + } + +} diff --git a/source/java/org/alfresco/filesys/config/SecurityConfigBean.java b/source/java/org/alfresco/filesys/config/SecurityConfigBean.java new file mode 100644 index 0000000000..04858e27b8 --- /dev/null +++ b/source/java/org/alfresco/filesys/config/SecurityConfigBean.java @@ -0,0 +1,161 @@ +/* + * 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.filesys.config; + +import java.util.List; + +import org.alfresco.jlan.server.auth.acl.AccessControl; +import org.alfresco.jlan.server.core.ShareMapper; + +// TODO: Auto-generated Javadoc +/** + * The Class SecurityConfigBean. + * + * @author dward + */ +public class SecurityConfigBean +{ + + /** The global default access level. */ + private String globalDefaultAccessLevel; + + /** The global access control. */ + private List globalAccessControl; + + /** The jce provider. */ + private String jceProvider; + + /** The share mapper. */ + private ShareMapper shareMapper; + + /** The domain mappings. */ + private List domainMappings; + + /** + * Gets the global default access level. + * + * @return the global default access level + */ + public String getGlobalDefaultAccessLevel() + { + return globalDefaultAccessLevel; + } + + /** + * Sets the global default access level. + * + * @param globalDefaultAccessLevel + * the new global default access level + */ + public void setGlobalDefaultAccessLevel(String globalDefaultAccessLevel) + { + this.globalDefaultAccessLevel = globalDefaultAccessLevel; + } + + /** + * Gets the global access control. + * + * @return the global access control + */ + public List getGlobalAccessControl() + { + return globalAccessControl; + } + + /** + * Sets the global access control. + * + * @param globalAccessControl + * the new global access control + */ + public void setGlobalAccessControl(List globalAccessControl) + { + this.globalAccessControl = globalAccessControl; + } + + /** + * Gets the jCE provider. + * + * @return the jCE provider + */ + public String getJCEProvider() + { + return jceProvider; + } + + /** + * Sets the jCE provider. + * + * @param provider + * the new jCE provider + */ + public void setJCEProvider(String provider) + { + jceProvider = provider; + } + + /** + * Gets the share mapper. + * + * @return the share mapper + */ + public ShareMapper getShareMapper() + { + return shareMapper; + } + + /** + * Sets the share mapper. + * + * @param shareMapper + * the new share mapper + */ + public void setShareMapper(ShareMapper shareMapper) + { + this.shareMapper = shareMapper; + } + + /** + * Gets the domain mappings. + * + * @return the domain mappings + */ + public List getDomainMappings() + { + return domainMappings; + } + + /** + * Sets the domain mappings. + * + * @param domainMappings + * the new domain mappings + */ + public void setDomainMappings(List domainMappings) + { + this.domainMappings = domainMappings; + } + +} diff --git a/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java b/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java new file mode 100644 index 0000000000..c68a3dacbe --- /dev/null +++ b/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java @@ -0,0 +1,2012 @@ +/* + * 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.filesys.config; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.NetworkInterface; +import java.net.Socket; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException; +import java.util.EnumSet; +import java.util.Enumeration; +import java.util.List; +import java.util.StringTokenizer; + +import org.alfresco.config.element.GenericConfigElement; +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.filesys.AbstractServerConfigurationBean; +import org.alfresco.filesys.alfresco.ExtendedDiskInterface; +import org.alfresco.filesys.avm.AVMContext; +import org.alfresco.filesys.avm.AVMDiskDriver; +import org.alfresco.filesys.repo.ContentContext; +import org.alfresco.jlan.ftp.FTPAuthenticator; +import org.alfresco.jlan.ftp.FTPConfigSection; +import org.alfresco.jlan.ftp.FTPPath; +import org.alfresco.jlan.ftp.InvalidPathException; +import org.alfresco.jlan.netbios.NetBIOSSession; +import org.alfresco.jlan.netbios.RFCNetBIOSProtocol; +import org.alfresco.jlan.netbios.win32.Win32NetBIOS; +import org.alfresco.jlan.oncrpc.RpcAuthenticator; +import org.alfresco.jlan.oncrpc.nfs.NFSConfigSection; +import org.alfresco.jlan.server.auth.ICifsAuthenticator; +import org.alfresco.jlan.server.auth.acl.ACLParseException; +import org.alfresco.jlan.server.auth.acl.AccessControl; +import org.alfresco.jlan.server.auth.acl.AccessControlList; +import org.alfresco.jlan.server.auth.acl.AccessControlParser; +import org.alfresco.jlan.server.auth.acl.InvalidACLTypeException; +import org.alfresco.jlan.server.auth.passthru.DomainMapping; +import org.alfresco.jlan.server.auth.passthru.RangeDomainMapping; +import org.alfresco.jlan.server.auth.passthru.SubnetDomainMapping; +import org.alfresco.jlan.server.config.CoreServerConfigSection; +import org.alfresco.jlan.server.config.InvalidConfigurationException; +import org.alfresco.jlan.server.config.SecurityConfigSection; +import org.alfresco.jlan.server.core.DeviceContext; +import org.alfresco.jlan.server.core.DeviceContextException; +import org.alfresco.jlan.server.core.ShareMapper; +import org.alfresco.jlan.server.core.ShareType; +import org.alfresco.jlan.server.filesys.DiskSharedDevice; +import org.alfresco.jlan.server.filesys.FilesystemsConfigSection; +import org.alfresco.jlan.server.thread.ThreadRequestPool; +import org.alfresco.jlan.smb.server.CIFSConfigSection; +import org.alfresco.jlan.util.IPAddress; +import org.alfresco.jlan.util.MemorySize; +import org.alfresco.jlan.util.Platform; +import org.alfresco.jlan.util.StringList; +import org.alfresco.jlan.util.X64; + +/** + * Alfresco File Server Configuration Bean Class + * + * @author gkspencer + * @author dward + */ +public class ServerConfigurationBean extends AbstractServerConfigurationBean +{ + + private CIFSConfigBean cifsConfigBean; + private FTPConfigBean ftpConfigBean; + private NFSConfigBean nfsConfigBean; + private List filesystemContexts; + private boolean avmAllStores; + private SecurityConfigBean securityConfigBean; + private CoreServerConfigBean coreServerConfigBean; + + /** + * Default constructor + */ + public ServerConfigurationBean() + { + super(""); + } + + /** + * Class constructor + * + * @param srvName + * String + */ + public ServerConfigurationBean(String srvName) + { + super(srvName); + } + + public void setCifsConfigBean(CIFSConfigBean cifsConfigBean) + { + this.cifsConfigBean = cifsConfigBean; + } + + public void setFtpConfigBean(FTPConfigBean ftpConfigBean) + { + this.ftpConfigBean = ftpConfigBean; + } + + public void setNfsConfigBean(NFSConfigBean nfsConfigBean) + { + this.nfsConfigBean = nfsConfigBean; + } + + public void setFilesystemContexts(List filesystemContexts) + { + this.filesystemContexts = filesystemContexts; + } + + public void setAvmAllStores(boolean avmAllStores) + { + this.avmAllStores = avmAllStores; + } + + public void setSecurityConfigBean(SecurityConfigBean securityConfigBean) + { + this.securityConfigBean = securityConfigBean; + } + + public void setCoreServerConfigBean(CoreServerConfigBean coreServerConfigBean) + { + this.coreServerConfigBean = coreServerConfigBean; + } + + /** + * Process the CIFS server configuration + */ + protected void processCIFSServerConfig() + { + // If the configuration section is not valid then CIFS is disabled + + if (cifsConfigBean == null) + { + removeConfigSection(CIFSConfigSection.SectionName); + return; + } + + // Check if the server has been disabled + if (!cifsConfigBean.getServerEnabled()) + { + removeConfigSection(CIFSConfigSection.SectionName); + return; + } + + // Create the CIFS server configuration section + + CIFSConfigSection cifsConfig = new CIFSConfigSection(this); + + try + { + // Check if native code calls should be disabled on Windows + if (cifsConfigBean.getDisableNativeCode()) + { + // Disable native code calls so that the JNI DLL is not required + + cifsConfig.setNativeCodeDisabled(true); + m_disableNativeCode = true; + + // Warning + + logger.warn("CIFS server native calls disabled, JNI code will not be used"); + } + + // Get the network broadcast address + // + // Note: We need to set this first as the call to getLocalDomainName() may use a NetBIOS + // name lookup, so the broadcast mask must be set before then. + + String broadcastAddess = cifsConfigBean.getBroadcastAddress(); + if (broadcastAddess != null && broadcastAddess.length() > 0) + { + + // Check if the broadcast mask is a valid numeric IP address + + if (IPAddress.isNumericAddress(broadcastAddess) == false) + throw new AlfrescoRuntimeException("Invalid broadcast mask, must be n.n.n.n format"); + + // Set the network broadcast mask + + cifsConfig.setBroadcastMask(broadcastAddess); + } + + // Get the host configuration + + String hostName = cifsConfigBean.getServerName(); + if (hostName == null || hostName.length() == 0) + throw new AlfrescoRuntimeException("Host name not specified or invalid"); + + // Check if the host name contains the local name token + + int pos = hostName.indexOf(TokenLocalName); + if (pos != -1) + { + + // Get the local server name + + String srvName = getLocalServerName(true); + + // Rebuild the host name substituting the token with the local server name + + StringBuilder hostStr = new StringBuilder(); + + hostStr.append(hostName.substring(0, pos)); + hostStr.append(srvName); + + pos += TokenLocalName.length(); + if (pos < hostName.length()) + hostStr.append(hostName.substring(pos)); + + hostName = hostStr.toString(); + + // Make sure the CIFS server name does not match the local server name + + if (hostName.equals(srvName) && getPlatformType() == Platform.Type.WINDOWS) + throw new AlfrescoRuntimeException("CIFS server name must be unique"); + } + + // Check if the host name is longer than 15 characters. NetBIOS only allows a maximum of 16 characters in + // the + // server name with the last character reserved for the service type. + + if (hostName.length() > 15) + { + // Truncate the CIFS server name + + hostName = hostName.substring(0, 15); + + // Output a warning + + logger.warn("CIFS server name is longer than 15 characters, truncated to " + hostName); + } + + // Set the CIFS server name + + cifsConfig.setServerName(hostName.toUpperCase()); + setServerName(hostName.toUpperCase()); + + // Get the domain/workgroup name + + String domain = cifsConfigBean.getDomainName(); + if (domain != null && domain.length() > 0) + { + // Set the domain/workgroup name + + cifsConfig.setDomainName(domain.toUpperCase()); + } + else + { + // Get the local domain/workgroup name + + String localDomain = getLocalDomainName(); + + if (localDomain == null && (getPlatformType() != Platform.Type.WINDOWS || isNativeCodeDisabled())) + { + // Use a default domain/workgroup name + + localDomain = "WORKGROUP"; + + // Output a warning + + logger.error("Failed to get local domain/workgroup name, using default of " + localDomain); + logger.error("(This may be due to firewall settings or incorrect setting)"); + } + + // Set the local domain/workgroup that the CIFS server belongs to + + cifsConfig.setDomainName(localDomain); + } + + // Check for a server comment + String comment = cifsConfigBean.getServerComment(); + if (comment != null && comment.length() > 0) + { + cifsConfig.setComment(comment); + } + + // Check for a bind address + + // Check if the network adapter name has been specified + String bindToAdapter = cifsConfigBean.getBindToAdapter(); + String bindTo; + + if (bindToAdapter != null && bindToAdapter.length() > 0) + { + + // Get the IP address for the adapter + + InetAddress bindAddr = parseAdapterName(bindToAdapter); + + // Set the bind address for the server + + cifsConfig.setSMBBindAddress(bindAddr); + } + else if ((bindTo = cifsConfigBean.getBindToAddress()) != null && !bindTo.equals(BIND_TO_IGNORE)) + { + + // Validate the bind address + try + { + // Check the bind address + + InetAddress bindAddr = InetAddress.getByName(bindTo); + + // Set the bind address for the server + + cifsConfig.setSMBBindAddress(bindAddr); + } + catch (UnknownHostException ex) + { + throw new AlfrescoRuntimeException("Invalid CIFS server bind address"); + } + } + + // Get the authenticator + + ICifsAuthenticator authenticator = cifsConfigBean.getAuthenticator(); + if (authenticator != null) + { + cifsConfig.setAuthenticator(authenticator); + } + else + throw new AlfrescoRuntimeException("CIFS authenticator not specified"); + + // Check if the host announcer has been disabled + + if (!cifsConfigBean.getHostAccouncerEnabled()) + { + // Switch off the host announcer + + cifsConfig.setHostAnnouncer( false); + + // Log that host announcements are not enabled + + logger.info("Host announcements not enabled"); + } + else + { + // Check for an announcement interval + + Integer interval = cifsConfigBean.getHostAccounceInterval(); + if (interval != null) + { + cifsConfig.setHostAnnounceInterval(interval); + } + + // Check if the domain name has been set, this is required if the + // host announcer is enabled + + if (cifsConfig.getDomainName() == null) + throw new AlfrescoRuntimeException("Domain name must be specified if host announcement is enabled"); + + // Enable host announcement + + cifsConfig.setHostAnnouncer(true); + } + + // Check if NetBIOS SMB is enabled + NetBIOSSMBConfigBean netBIOSSMBConfigBean = cifsConfigBean.getNetBIOSSMB(); + if (netBIOSSMBConfigBean != null) + { + // Check if NetBIOS over TCP/IP is enabled for the current platform + + String platformsStr = netBIOSSMBConfigBean.getPlatforms(); + boolean platformOK = false; + + if (platformsStr != null && platformsStr.length() > 0) + { + // Parse the list of platforms that NetBIOS over TCP/IP is to be enabled for and + // check if the current platform is included + + EnumSet enabledPlatforms = parsePlatformString(platformsStr); + if (enabledPlatforms.contains(getPlatformType())) + platformOK = true; + } + else + { + // No restriction on platforms + + platformOK = true; + } + + // Enable the NetBIOS SMB support, if enabled for this platform + + cifsConfig.setNetBIOSSMB(platformOK); + + // Parse/check NetBIOS settings, if enabled + + if (cifsConfig.hasNetBIOSSMB()) + { + // Check if the broadcast mask has been specified + + if (cifsConfig.getBroadcastMask() == null) + throw new AlfrescoRuntimeException("Network broadcast mask not specified"); + + // Check for a bind address + + String bindto = netBIOSSMBConfigBean.getBindTo(); + if (bindto != null && bindto.length() > 0 && !bindto.equals(BIND_TO_IGNORE)) + { + + // Validate the bind address + + try + { + + // Check the bind address + + InetAddress bindAddr = InetAddress.getByName(bindto); + + // Set the bind address for the NetBIOS name server + + cifsConfig.setNetBIOSBindAddress(bindAddr); + } + catch (UnknownHostException ex) + { + throw new AlfrescoRuntimeException("Invalid NetBIOS bind address"); + } + } + else if (cifsConfig.hasSMBBindAddress()) + { + + // Use the SMB bind address for the NetBIOS name server + + cifsConfig.setNetBIOSBindAddress(cifsConfig.getSMBBindAddress()); + } + else + { + // Get a list of all the local addresses + + InetAddress[] addrs = null; + + try + { + // Get the local server IP address list + + addrs = InetAddress.getAllByName(InetAddress.getLocalHost().getHostName()); + } + catch (UnknownHostException ex) + { + logger.error("Failed to get local address list", ex); + } + + // Check the address list for one or more valid local addresses filtering out the loopback + // address + + int addrCnt = 0; + + if (addrs != null) + { + for (int i = 0; i < addrs.length; i++) + { + + // Check for a valid address, filter out '127.0.0.1' and '0.0.0.0' addresses + + if (addrs[i].getHostAddress().equals("127.0.0.1") == false + && addrs[i].getHostAddress().equals("0.0.0.0") == false) + addrCnt++; + } + } + + // Check if any addresses were found + + if (addrCnt == 0) + { + // Enumerate the network adapter list + + Enumeration niEnum = null; + + try + { + niEnum = NetworkInterface.getNetworkInterfaces(); + } + catch (SocketException ex) + { + } + + if (niEnum != null) + { + while (niEnum.hasMoreElements()) + { + // Get the current network interface + + NetworkInterface ni = niEnum.nextElement(); + + // Enumerate the addresses for the network adapter + + Enumeration niAddrs = ni.getInetAddresses(); + if (niAddrs != null) + { + // Check for any valid addresses + + while (niAddrs.hasMoreElements()) + { + InetAddress curAddr = niAddrs.nextElement(); + + if (curAddr.getHostAddress().equals("127.0.0.1") == false + && curAddr.getHostAddress().equals("0.0.0.0") == false) + addrCnt++; + } + } + } + + // DEBUG + + if (addrCnt > 0 && logger.isDebugEnabled()) + logger.debug("Found valid IP address from interface list"); + } + + // Check if we found any valid network addresses + + if (addrCnt == 0) + { + // Log the available IP addresses + + if (logger.isDebugEnabled()) + { + logger.debug("Local address list dump :-"); + if (addrs != null) + { + for (int i = 0; i < addrs.length; i++) + logger.debug(" Address: " + addrs[i]); + } + else + logger.debug(" No addresses"); + } + + // Throw an exception to stop the CIFS/NetBIOS name server from starting + + throw new AlfrescoRuntimeException( + "Failed to get IP address(es) for the local server, check hosts file and/or DNS setup"); + } + } + } + + // Check if the session port has been specified + + Integer portNum = netBIOSSMBConfigBean.getSessionPort(); + if (portNum != null) + { + cifsConfig.setSessionPort(portNum); + if (cifsConfig.getSessionPort() <= 0 || cifsConfig.getSessionPort() >= 65535) + throw new AlfrescoRuntimeException("NetBIOS session port out of valid range"); + } + + // Check if the name port has been specified + + portNum = netBIOSSMBConfigBean.getNamePort(); + if (portNum != null) + { + cifsConfig.setNameServerPort(portNum); + if (cifsConfig.getNameServerPort() <= 0 || cifsConfig.getNameServerPort() >= 65535) + throw new AlfrescoRuntimeException("NetBIOS name port out of valid range"); + } + + // Check if the datagram port has been specified + + portNum = netBIOSSMBConfigBean.getDatagramPort(); + if (portNum != null) + { + cifsConfig.setDatagramPort(portNum); + if (cifsConfig.getDatagramPort() <= 0 || cifsConfig.getDatagramPort() >= 65535) + throw new AlfrescoRuntimeException("NetBIOS datagram port out of valid range"); + } + + // Check for a bind address + + String attr = netBIOSSMBConfigBean.getBindTo(); + if (attr != null && attr.length() > 0 && !attr.equals(BIND_TO_IGNORE)) + { + + // Validate the bind address + + try + { + + // Check the bind address + + InetAddress bindAddr = InetAddress.getByName(attr); + + // Set the bind address for the NetBIOS name server + + cifsConfig.setNetBIOSBindAddress(bindAddr); + } + catch (UnknownHostException ex) + { + throw new InvalidConfigurationException(ex.toString()); + } + } + + // Check for a bind address using the adapter name + + else if ((attr = netBIOSSMBConfigBean.getAdapter()) != null && attr.length() > 0) + { + + // Get the bind address via the network adapter name + + InetAddress bindAddr = parseAdapterName(attr); + cifsConfig.setNetBIOSBindAddress(bindAddr); + } + else if (cifsConfig.hasSMBBindAddress()) + { + + // Use the SMB bind address for the NetBIOS name server + + cifsConfig.setNetBIOSBindAddress(cifsConfig.getSMBBindAddress()); + } + + } + } + else + { + + // Disable NetBIOS SMB support + + cifsConfig.setNetBIOSSMB(false); + } + + // Check if TCP/IP SMB is enabled + + TcpipSMBConfigBean tcpipSMBConfigBean = cifsConfigBean.getTcpipSMB(); + if (tcpipSMBConfigBean != null) + { + + // Check if native SMB is enabled for the current platform + + String platformsStr = tcpipSMBConfigBean.getPlatforms(); + boolean platformOK = false; + + if (platformsStr != null) + { + // Parse the list of platforms that native SMB is to be enabled for and + // check if the current platform is included + + EnumSet enabledPlatforms = parsePlatformString(platformsStr); + if (enabledPlatforms.contains(getPlatformType())) + platformOK = true; + } + else + { + // No restriction on platforms + + platformOK = true; + } + + // Enable the TCP/IP SMB support, if enabled for this platform + + cifsConfig.setTcpipSMB(platformOK); + + // Check if the port has been specified + + Integer portNum = tcpipSMBConfigBean.getPort(); + if (portNum != null) + { + cifsConfig.setTcpipSMBPort(portNum); + if (cifsConfig.getTcpipSMBPort() <= 0 || cifsConfig.getTcpipSMBPort() >= 65535) + throw new AlfrescoRuntimeException("TCP/IP SMB port out of valid range"); + } + + // Check if IPv6 support should be enabled + + if ( tcpipSMBConfigBean.getIpv6Enabled()) + { + try + { + // Use the IPv6 bind all address + + cifsConfig.setSMBBindAddress( InetAddress.getByName( "::")); + + // DEBUG + + if ( logger.isInfoEnabled()) + logger.info("Enabled CIFS IPv6 bind address for native SMB"); + } + catch ( UnknownHostException ex) + { + throw new AlfrescoRuntimeException("Failed to enable IPv6 bind address, " + ex.getMessage()); + } + } + + } + else + { + + // Disable TCP/IP SMB support + + cifsConfig.setTcpipSMB(false); + } + + // Check if Win32 NetBIOS is enabled + + Win32NetBIOSConfigBean win32NetBIOSConfigBean = cifsConfigBean.getWin32NetBIOS(); + if (win32NetBIOSConfigBean != null) + { + + // Check if the Win32 NetBIOS server name has been specified + + String win32Name = win32NetBIOSConfigBean.getName(); + if (win32Name != null && win32Name.length() > 0) + { + + // Validate the name + + if (win32Name.length() > 16) + throw new AlfrescoRuntimeException("Invalid Win32 NetBIOS name, " + win32Name); + + // Set the Win32 NetBIOS file server name + + cifsConfig.setWin32NetBIOSName(win32Name); + } + + // Check if the Win32 NetBIOS LANA has been specified + + String lanaStr = win32NetBIOSConfigBean.getLana(); + if (lanaStr != null && lanaStr.length() > 0) + { + // Check if the LANA has been specified as an IP address or adapter name + + int lana = -1; + + if (IPAddress.isNumericAddress(lanaStr)) + { + + // Convert the IP address to a LANA id + + lana = Win32NetBIOS.getLANAForIPAddress(lanaStr); + if (lana == -1) + throw new AlfrescoRuntimeException("Failed to convert IP address " + lanaStr + " to a LANA"); + } + else if (lanaStr.length() > 1 && Character.isLetter(lanaStr.charAt(0))) + { + + // Convert the network adapter to a LANA id + + lana = Win32NetBIOS.getLANAForAdapterName(lanaStr); + if (lana == -1) + throw new AlfrescoRuntimeException("Failed to convert network adapter " + lanaStr + + " to a LANA"); + } + else + { + + try + { + lana = Integer.parseInt(lanaStr); + } + catch (NumberFormatException ex) + { + throw new AlfrescoRuntimeException("Invalid win32 NetBIOS LANA specified"); + } + } + + // LANA should be in the range 0-255 + + if (lana < 0 || lana > 255) + throw new AlfrescoRuntimeException("Invalid Win32 NetBIOS LANA number, " + lana); + + // Set the LANA number + + cifsConfig.setWin32LANA(lana); + } + + // Check if the native NetBIOS interface has been specified, either 'winsock' or 'netbios' + + String nativeAPI = win32NetBIOSConfigBean.getApi(); + if (nativeAPI != null && nativeAPI.length() > 0) + { + // Validate the API type + + boolean useWinsock = true; + + if (nativeAPI.equalsIgnoreCase("netbios")) + useWinsock = false; + else if (nativeAPI.equalsIgnoreCase("winsock") == false) + throw new AlfrescoRuntimeException("Invalid NetBIOS API type, spefify 'winsock' or 'netbios'"); + + // Set the NetBIOS API to use + + cifsConfig.setWin32WinsockNetBIOS(useWinsock); + } + + // Force the older NetBIOS API code to be used on 64Bit Windows + + if (cifsConfig.useWinsockNetBIOS() == true && X64.isWindows64()) + { + // Debug + + if (logger.isDebugEnabled()) + logger.debug("Using older Netbios() API code"); + + // Use the older NetBIOS API code + + cifsConfig.setWin32WinsockNetBIOS(false); + } + + // Check if the current operating system is supported by the Win32 + // NetBIOS handler + + String osName = System.getProperty("os.name"); + if (osName.startsWith("Windows") + && (osName.endsWith("95") == false && osName.endsWith("98") == false && osName.endsWith("ME") == false) + && isNativeCodeDisabled() == false) + { + + // Call the Win32NetBIOS native code to make sure it is initialized + + if (Win32NetBIOS.LanaEnumerate() != null) + { + // Enable Win32 NetBIOS + + cifsConfig.setWin32NetBIOS(true); + } + else + { + logger.warn("No NetBIOS LANAs available"); + } + } + else + { + + // Win32 NetBIOS not supported on the current operating system + + cifsConfig.setWin32NetBIOS(false); + } + } + else + { + + // Disable Win32 NetBIOS + + cifsConfig.setWin32NetBIOS(false); + } + + // Check if the Win32 host announcer has been disabled + + if ( !cifsConfigBean.getWin32HostAnnouncerEnabled()) + { + // Switch off the Win32 host announcer + + cifsConfig.setWin32HostAnnouncer( false); + + // Log that host announcements are not enabled + + logger.info("Win32 host announcements not enabled"); + } + else + { + // Check for an announcement interval + Integer interval = cifsConfigBean.getWin32HostAnnounceInterval(); + if (interval != null) + { + cifsConfig.setWin32HostAnnounceInterval(interval); + } + + // Check if the domain name has been set, this is required if the + // host announcer is enabled + + if (cifsConfig.getDomainName() == null) + throw new AlfrescoRuntimeException("Domain name must be specified if host announcement is enabled"); + + // Enable Win32 NetBIOS host announcement + + cifsConfig.setWin32HostAnnouncer(true); + } + + // Check if NetBIOS and/or TCP/IP SMB have been enabled + + if (cifsConfig.hasNetBIOSSMB() == false && cifsConfig.hasTcpipSMB() == false + && cifsConfig.hasWin32NetBIOS() == false) + throw new AlfrescoRuntimeException("NetBIOS SMB, TCP/IP SMB or Win32 NetBIOS must be enabled"); + + // Check if WINS servers are configured + + WINSConfigBean winsConfigBean = cifsConfigBean.getWINSConfig(); + + if (winsConfigBean != null && !winsConfigBean.isAutoDetectEnabled()) + { + + // Get the primary WINS server + + String priWins = winsConfigBean.getPrimary(); + + if (priWins == null || priWins.length() == 0) + throw new AlfrescoRuntimeException("No primary WINS server configured"); + + // Validate the WINS server address + + InetAddress primaryWINS = null; + + try + { + primaryWINS = InetAddress.getByName(priWins); + } + catch (UnknownHostException ex) + { + throw new AlfrescoRuntimeException("Invalid primary WINS server address, " + priWins); + } + + // Check if a secondary WINS server has been specified + + String secWins = winsConfigBean.getSecondary(); + InetAddress secondaryWINS = null; + + if (secWins != null && secWins.length() > 0) + { + + // Validate the secondary WINS server address + + try + { + secondaryWINS = InetAddress.getByName(secWins); + } + catch (UnknownHostException ex) + { + throw new AlfrescoRuntimeException("Invalid secondary WINS server address, " + secWins); + } + } + + // Set the WINS server address(es) + + cifsConfig.setPrimaryWINSServer(primaryWINS); + if (secondaryWINS != null) + cifsConfig.setSecondaryWINSServer(secondaryWINS); + + // Pass the setting to the NetBIOS session class + + NetBIOSSession.setDefaultWINSServer(primaryWINS); + } + + // Check if WINS is configured, if we are running on Windows and socket based NetBIOS is enabled + + else if (cifsConfig.hasNetBIOSSMB() && getPlatformType() == Platform.Type.WINDOWS && !isNativeCodeDisabled()) + { + // Get the WINS server list + + String winsServers = Win32NetBIOS.getWINSServerList(); + + if (winsServers != null) + { + // Use the first WINS server address for now + + StringTokenizer tokens = new StringTokenizer(winsServers, ","); + String addr = tokens.nextToken(); + + try + { + // Convert to a network address and check if the WINS server is accessible + + InetAddress winsAddr = InetAddress.getByName(addr); + + Socket winsSocket = new Socket(); + InetSocketAddress sockAddr = new InetSocketAddress(winsAddr, RFCNetBIOSProtocol.NAME_PORT); + + winsSocket.connect(sockAddr, 3000); + winsSocket.close(); + + // Set the primary WINS server address + + cifsConfig.setPrimaryWINSServer(winsAddr); + + // Debug + + if (logger.isDebugEnabled()) + logger.debug("Configuring to use WINS server " + addr); + } + catch (UnknownHostException ex) + { + throw new AlfrescoRuntimeException("Invalid auto WINS server address, " + addr); + } + catch (IOException ex) + { + if (logger.isDebugEnabled()) + logger.debug("Failed to connect to auto WINS server " + addr); + } + } + } + + // Check for session debug flags + + String flags = cifsConfigBean.getSessionDebugFlags(); + + int sessDbg = 0; + + if (flags != null && flags.length() > 0) + { + + // Parse the flags + + flags = flags.toUpperCase(); + StringTokenizer token = new StringTokenizer(flags, ","); + + while (token.hasMoreTokens()) + { + // Get the current debug flag token + + String dbg = token.nextToken().trim(); + + // Find the debug flag name + + int idx = 0; + + while (idx < m_sessDbgStr.length && m_sessDbgStr[idx].equalsIgnoreCase(dbg) == false) + idx++; + + if (idx > m_sessDbgStr.length) + throw new AlfrescoRuntimeException("Invalid session debug flag, " + dbg); + + // Set the debug flag + + sessDbg += 1 << idx; + } + } + + // Set the session debug flags + + cifsConfig.setSessionDebugFlags(sessDbg); + + // Check if NIO based socket code should be disabled + + if (cifsConfigBean.getDisableNIO()) + { + + // Disable NIO based code + + cifsConfig.setDisableNIOCode(true); + + // DEBUG + + if (logger.isDebugEnabled()) + logger.debug("NIO based code disabled for CIFS server"); + } + + + // Check if a session timeout is configured + + Integer tmo = cifsConfigBean.getSessionTimeout(); + if (tmo != null) + { + + // Validate the session timeout value + + if (tmo < 0 || tmo > MaxSessionTimeout) + throw new AlfrescoRuntimeException("Session timeout out of range (0 - " + MaxSessionTimeout + ")"); + + // Convert the session timeout to milliseconds + + cifsConfig.setSocketTimeout(tmo * 1000); + } + } + catch (InvalidConfigurationException ex) + { + throw new AlfrescoRuntimeException(ex.getMessage()); + } + } + + /** + * Process the FTP server configuration + */ + protected void processFTPServerConfig() + { + // If the configuration section is not valid then FTP is disabled + + if (ftpConfigBean == null) + { + removeConfigSection(FTPConfigSection.SectionName); + return; + } + + // Check if the server has been disabled + + if (!ftpConfigBean.getServerEnabled()) + { + removeConfigSection(FTPConfigSection.SectionName); + return; + } + + // Create the FTP configuration section + + FTPConfigSection ftpConfig = new FTPConfigSection(this); + + try + { + // Check for a bind address + + String bindText = ftpConfigBean.getBindTo(); + if (bindText != null && bindText.length() > 0 && !bindText.equals(BIND_TO_IGNORE)) + { + + // Validate the bind address + + try + { + + // Check the bind address + + InetAddress bindAddr = InetAddress.getByName(bindText); + + // Set the bind address for the FTP server + + ftpConfig.setFTPBindAddress(bindAddr); + } + catch (UnknownHostException ex) + { + throw new AlfrescoRuntimeException("Invalid FTP bindto address, " + bindText); + } + } + + // Check for an FTP server port + + Integer port = ftpConfigBean.getPort(); + if (port != null) + { + ftpConfig.setFTPPort(port); + if (ftpConfig.getFTPPort() <= 0 || ftpConfig.getFTPPort() >= 65535) + throw new AlfrescoRuntimeException("FTP server port out of valid range"); + } + else + { + + // Use the default FTP port + + ftpConfig.setFTPPort(DefaultFTPServerPort); + } + + // Check if anonymous login is allowed + + if (ftpConfigBean.getAllowAnonymous()) + { + + // Enable anonymous login to the FTP server + + ftpConfig.setAllowAnonymousFTP(true); + + // Check if an anonymous account has been specified + + String anonAcc = ftpConfigBean.getAnonymousAccount(); + if (anonAcc != null && anonAcc.length() > 0) + { + + // Set the anonymous account name + + ftpConfig.setAnonymousFTPAccount(anonAcc); + + // Check if the anonymous account name is valid + + if (ftpConfig.getAnonymousFTPAccount() == null || ftpConfig.getAnonymousFTPAccount().length() == 0) + throw new AlfrescoRuntimeException("Anonymous FTP account invalid"); + } + else + { + + // Use the default anonymous account name + + ftpConfig.setAnonymousFTPAccount(DefaultFTPAnonymousAccount); + } + } + else + { + + // Disable anonymous logins + + ftpConfig.setAllowAnonymousFTP(false); + } + + // Check if a root path has been specified + + String rootPath = ftpConfigBean.getRootDirectory(); + if (rootPath != null && rootPath.length() > 0) + { + try + { + + // Parse the path + + new FTPPath(rootPath); + + // Set the root path + + ftpConfig.setFTPRootPath(rootPath); + } + catch (InvalidPathException ex) + { + throw new AlfrescoRuntimeException("Invalid FTP root directory, " + rootPath); + } + } + + // Check for FTP debug flags + + String flags = ftpConfigBean.getDebugFlags(); + int ftpDbg = 0; + + if (flags != null) + { + + // Parse the flags + + flags = flags.toUpperCase(); + StringTokenizer token = new StringTokenizer(flags, ","); + + while (token.hasMoreTokens()) + { + + // Get the current debug flag token + + String dbg = token.nextToken().trim(); + + // Find the debug flag name + + int idx = 0; + + while (idx < m_ftpDebugStr.length && m_ftpDebugStr[idx].equalsIgnoreCase(dbg) == false) + idx++; + + if (idx >= m_ftpDebugStr.length) + throw new AlfrescoRuntimeException("Invalid FTP debug flag, " + dbg); + + // Set the debug flag + + ftpDbg += 1 << idx; + } + + // Set the FTP debug flags + + ftpConfig.setFTPDebug(ftpDbg); + } + + // Check if a character set has been specified + + String charSet = ftpConfigBean.getCharSet(); + if (charSet != null && charSet.length() > 0) + { + + try + { + + // Validate the character set name + + Charset.forName(charSet); + + // Set the FTP character set + + ftpConfig.setFTPCharacterSet(charSet); + } + catch (IllegalCharsetNameException ex) + { + throw new AlfrescoRuntimeException("Illegal character set name, " + charSet); + } + catch (UnsupportedCharsetException ex) + { + throw new AlfrescoRuntimeException("Unsupported character set name, " + charSet); + } + } + + // Check if an authenticator has been specified + + FTPAuthenticator auth = ftpConfigBean.getAuthenticator(); + if (auth != null) + { + + // Initialize and set the authenticator class + + ftpConfig.setAuthenticator(auth); + } + else + throw new AlfrescoRuntimeException("FTP authenticator not specified"); + + } + catch (InvalidConfigurationException ex) + { + throw new AlfrescoRuntimeException(ex.getMessage()); + } + + } + + /** + * Process the NFS server configuration + */ + protected void processNFSServerConfig() + { + // If the configuration section is not valid then NFS is disabled + + if (nfsConfigBean == null) + { + removeConfigSection(NFSConfigSection.SectionName); + return; + } + + // Check if the server has been disabled + + if (!nfsConfigBean.getServerEnabled()) + { + removeConfigSection(NFSConfigSection.SectionName); + return; + } + + // Create the NFS configuration section + + NFSConfigSection nfsConfig = new NFSConfigSection(this); + + try + { + // Check if the port mapper is enabled + + if (nfsConfigBean.getPortMapperEnabled()) + nfsConfig.setNFSPortMapper(true); + + // Check for the thread pool size + + Integer poolSize = nfsConfigBean.getThreadPool(); + + if (poolSize != null) + { + + // Range check the pool size value + + if (poolSize < 4) + throw new AlfrescoRuntimeException("NFS thread pool size is below minimum of 4"); + + // Set the thread pool size + + nfsConfig.setNFSThreadPoolSize(poolSize); + } + + // NFS packet pool size + + Integer pktPoolSize = nfsConfigBean.getPacketPool(); + + if (pktPoolSize != null) + { + // Range check the pool size value + + if (pktPoolSize < 10) + throw new AlfrescoRuntimeException("NFS packet pool size is below minimum of 10"); + + if (pktPoolSize < nfsConfig.getNFSThreadPoolSize() + 1) + throw new AlfrescoRuntimeException("NFS packet pool must be at least thread pool size plus one"); + + // Set the packet pool size + + nfsConfig.setNFSPacketPoolSize(pktPoolSize); + } + + // Check for a port mapper server port + + Integer portMapperPort = nfsConfigBean.getPortMapperPort(); + if (portMapperPort != null) + { + nfsConfig.setPortMapperPort(portMapperPort); + if (nfsConfig.getPortMapperPort() <= 0 || nfsConfig.getPortMapperPort() >= 65535) + throw new AlfrescoRuntimeException("Port mapper server port out of valid range"); + } + + // Check for a mount server port + + Integer mountServerPort = nfsConfigBean.getMountServerPort(); + if (mountServerPort != null) + { + nfsConfig.setMountServerPort(mountServerPort); + if (nfsConfig.getMountServerPort() <= 0 || nfsConfig.getMountServerPort() >= 65535) + throw new AlfrescoRuntimeException("Mount server port out of valid range"); + } + + // Check for an NFS server port + + Integer nfsServerPort = nfsConfigBean.getNFSServerPort(); + if (nfsServerPort != null) + { + nfsConfig.setNFSServerPort(nfsServerPort); + if (nfsConfig.getNFSServerPort() <= 0 || nfsConfig.getNFSServerPort() >= 65535) + throw new AlfrescoRuntimeException("NFS server port out of valid range"); + } + + // Check for NFS debug flags + + String flags = nfsConfigBean.getDebugFlags(); + int nfsDbg = 0; + + if (flags != null && flags.length() > 0) + { + + // Parse the flags + + flags = flags.toUpperCase(); + StringTokenizer token = new StringTokenizer(flags, ","); + + while (token.hasMoreTokens()) + { + + // Get the current debug flag token + + String dbg = token.nextToken().trim(); + + // Find the debug flag name + + int idx = 0; + + while (idx < m_nfsDebugStr.length && m_nfsDebugStr[idx].equalsIgnoreCase(dbg) == false) + idx++; + + if (idx >= m_nfsDebugStr.length) + throw new AlfrescoRuntimeException("Invalid NFS debug flag, " + dbg); + + // Set the debug flag + + nfsDbg += 1 << idx; + } + + // Set the NFS debug flags + + nfsConfig.setNFSDebug(nfsDbg); + } + + // Check if mount server debug output is enabled + + if (nfsConfigBean.getMountServerDebug()) + nfsConfig.setMountServerDebug(true); + + // Check if portmapper debug output is enabled + + if (nfsConfigBean.getPortMapperDebug()) + nfsConfig.setPortMapperDebug(true); + + // Create the RPC authenticator + RpcAuthenticator rpcAuthenticator = nfsConfigBean.getRpcAuthenticator(); + if (rpcAuthenticator != null) + { + nfsConfig.setRpcAuthenticator(rpcAuthenticator); + } + else + throw new AlfrescoRuntimeException("RPC authenticator configuration missing, require user mappings"); + } + catch (InvalidConfigurationException ex) + { + throw new AlfrescoRuntimeException(ex.getMessage()); + } + } + + /** + * Process the filesystems configuration + */ + protected void processFilesystemsConfig() + { + // Create the filesystems configuration section + + FilesystemsConfigSection fsysConfig = new FilesystemsConfigSection(this); + + // Access the security configuration section + + SecurityConfigSection secConfig = (SecurityConfigSection) getConfigSection(SecurityConfigSection.SectionName); + + // Process the filesystems list + + if (this.filesystemContexts != null) + { + + // Add the filesystems + + for (DeviceContext filesystem : this.filesystemContexts) + { + + // Get the current filesystem configuration + + try + { + // Check the filesystem type and use the appropriate driver + + DiskSharedDevice filesys = null; + + if (filesystem instanceof AVMContext) + { + // Create a new filesystem driver instance and register a context for + // the new filesystem + + ExtendedDiskInterface filesysDriver = getAvmDiskInterface(); + filesysDriver.registerContext(filesystem); + + // Create the shared filesystem + + filesys = new DiskSharedDevice(filesystem.getDeviceName(), filesysDriver, (AVMContext)filesystem); + + // Start the filesystem + + ((AVMContext)filesystem).startFilesystem(filesys); + } + else + { + // Create a new filesystem driver instance and register a context for + // the new filesystem + + ExtendedDiskInterface filesysDriver = getRepoDiskInterface(); + ContentContext filesysContext = (ContentContext) filesystem; + filesysDriver.registerContext(filesystem); + + // Check if an access control list has been specified + + AccessControlList acls = null; + String defaultAccessLevel = filesysContext.getDefaultAccessLevel(); + List accessControls = filesysContext.getAccessControl(); + + if ((defaultAccessLevel != null && defaultAccessLevel.length() > 0) || + (accessControls != null && !accessControls.isEmpty())) + { + // Parse the access control list + + acls = processAccessControlList(secConfig, defaultAccessLevel, accessControls); + } + else if (secConfig.hasGlobalAccessControls()) + { + + // Use the global access control list for this disk share + + acls = secConfig.getGlobalAccessControls(); + } + + // Create the shared filesystem + + filesys = new DiskSharedDevice(filesystem.getDeviceName(), filesysDriver, filesysContext); + + // Add any access controls to the share + + filesys.setAccessControlList(acls); + + // Start the filesystem + + filesysContext.startFilesystem(filesys); + } + + // Add the new filesystem + + fsysConfig.addShare(filesys); + } + catch (DeviceContextException ex) + { + throw new AlfrescoRuntimeException("Error creating filesystem " + filesystem.getDeviceName(), ex); + } + } + } + else + { + // No filesystems defined + + logger.warn("No filesystems defined"); + } + + // Check if shares should be added for all AVM stores + if (this.avmAllStores && getAvmDiskInterface() != null) + { + // Get the list of store names + + AVMDiskDriver avmDriver = (AVMDiskDriver) getAvmDiskInterface(); + StringList storeNames = avmDriver.getAVMStoreNames(); + + // Add shares for each of the store names, if the share name does not already exist + + if (storeNames != null && storeNames.numberOfStrings() > 0) + { + // Add a share for each store + + for (int i = 0; i < storeNames.numberOfStrings(); i++) + { + String storeName = storeNames.getStringAt(i); + + // Check if a share of the same name already exists + + if (fsysConfig.getShares().findShare(storeName, ShareType.DISK, true) == null) + { + // Create the new share for the store + + AVMContext avmContext = new AVMContext(storeName, storeName + ":/", AVMContext.VERSION_HEAD); + avmContext.enableStateTable(true, avmDriver.getStateReaper()); + + // Create the shared filesystem + + fsysConfig.addShare(new DiskSharedDevice(storeName, avmDriver, avmContext)); + + // DEBUG + + if (logger.isDebugEnabled()) + logger.debug("Added AVM share " + storeName); + } + } + } + } + + + // home folder share mapper could be declared in security config + } + + /** + * Process the security configuration + */ + protected void processSecurityConfig() + { + // Create the security configuration section + + SecurityConfigSection secConfig = new SecurityConfigSection(this); + + try + { + // Check if global access controls have been specified + + String defaultAccessLevel = securityConfigBean.getGlobalDefaultAccessLevel(); + List accessControls = securityConfigBean.getGlobalAccessControl(); + + if ((defaultAccessLevel != null && defaultAccessLevel.length() > 0) || + (accessControls != null && !accessControls.isEmpty())) + { + // Parse the access control list + + AccessControlList acls = processAccessControlList(secConfig, defaultAccessLevel, accessControls); + if (acls != null) + secConfig.setGlobalAccessControls(acls); + } + + + // Check if a JCE provider class has been specified + + String jceProvider = securityConfigBean.getJCEProvider(); + if (jceProvider != null && jceProvider.length() > 0) + { + + // Set the JCE provider + + secConfig.setJCEProvider(jceProvider); + } + else + { + // Use the default Bouncy Castle JCE provider + + secConfig.setJCEProvider("org.bouncycastle.jce.provider.BouncyCastleProvider"); + } + + // Check if a share mapper has been specified + + ShareMapper shareMapper = securityConfigBean.getShareMapper(); + if (shareMapper != null) + { + // Associate the share mapper + secConfig.setShareMapper(shareMapper); + } + else + { + // Check if the tenant service is enabled + + if (m_tenantService != null && m_tenantService.isEnabled()) + { + // Initialize the multi-tenancy share mapper + + secConfig.setShareMapper("org.alfresco.filesys.alfresco.MultiTenantShareMapper", + new GenericConfigElement("shareMapper")); + } + } + + // Check if any domain mappings have been specified + + List mappings = securityConfigBean.getDomainMappings(); + if (mappings != null) + { + DomainMapping mapping = null; + + for (DomainMappingConfigBean domainMap : mappings) + { + // Get the domain name + + String name = domainMap.getName(); + + // Check if the domain is specified by subnet or range + + String subnetStr = domainMap.getSubnet(); + String rangeFromStr; + if (subnetStr != null && subnetStr.length() > 0) + { + String maskStr = domainMap.getMask(); + + // Parse the subnet and mask, to validate and convert to int values + + int subnet = IPAddress.parseNumericAddress(subnetStr); + int mask = IPAddress.parseNumericAddress(maskStr); + + if (subnet == 0 || mask == 0) + throw new AlfrescoRuntimeException("Invalid subnet/mask for domain mapping " + name); + + // Create the subnet domain mapping + + mapping = new SubnetDomainMapping(name, subnet, mask); + } + else if ((rangeFromStr = domainMap.getRangeFrom()) != null && rangeFromStr.length() > 0) + { + String rangeToStr = domainMap.getRangeTo(); + + // Parse the range from/to values and convert to int values + + int rangeFrom = IPAddress.parseNumericAddress(rangeFromStr); + int rangeTo = IPAddress.parseNumericAddress(rangeToStr); + + if (rangeFrom == 0 || rangeTo == 0) + throw new AlfrescoRuntimeException("Invalid address range domain mapping " + name); + + // Create the subnet domain mapping + + mapping = new RangeDomainMapping(name, rangeFrom, rangeTo); + } + else + throw new AlfrescoRuntimeException("Invalid domain mapping specified"); + + // Add the domain mapping + + secConfig.addDomainMapping(mapping); + } + } + } + catch (InvalidConfigurationException ex) + { + throw new AlfrescoRuntimeException(ex.getMessage()); + } + } + + /** + * Process the core server configuration + * + * @exception InvalidConfigurationException + */ + protected void processCoreServerConfig() throws InvalidConfigurationException + { + // Create the core server configuration section + + CoreServerConfigSection coreConfig = new CoreServerConfigSection(this); + + // Check if the server core element has been specified + + if (coreServerConfigBean == null) + { + + // Configure a default memory pool + + coreConfig.setMemoryPool(DefaultMemoryPoolBufSizes, DefaultMemoryPoolInitAlloc, DefaultMemoryPoolMaxAlloc); + + // Configure a default thread pool size + + coreConfig.setThreadPool(DefaultThreadPoolInit, DefaultThreadPoolMax); + return; + } + + // Check if the thread pool size has been specified + + Integer initSize = coreServerConfigBean.getThreadPoolInit(); + if (initSize == null) + { + initSize = DefaultThreadPoolInit; + } + Integer maxSize = coreServerConfigBean.getThreadPoolMax(); + if (maxSize == null) + { + maxSize = DefaultThreadPoolMax; + } + + // Range check the thread pool size + + if (initSize < ThreadRequestPool.MinimumWorkerThreads) + throw new InvalidConfigurationException("Thread pool size below minimum allowed size"); + + if (initSize > ThreadRequestPool.MaximumWorkerThreads) + throw new InvalidConfigurationException("Thread pool size above maximum allowed size"); + + // Range check the maximum thread pool size + + if (maxSize < ThreadRequestPool.MinimumWorkerThreads) + throw new InvalidConfigurationException("Thread pool maximum size below minimum allowed size"); + + if (maxSize > ThreadRequestPool.MaximumWorkerThreads) + throw new InvalidConfigurationException("Thread pool maximum size above maximum allowed size"); + + if (maxSize < initSize) + throw new InvalidConfigurationException("Initial size is larger than maxmimum size"); + + // Configure the thread pool + + coreConfig.setThreadPool(initSize, maxSize); + + // Check if thread pool debug output is enabled + + if (coreServerConfigBean.getThreadPoolDebug()) + coreConfig.getThreadPool().setDebug(true); + + // Check if the packet sizes/allocations have been specified + + List packetSizes = coreServerConfigBean.getMemoryPacketSizes(); + if (packetSizes != null) + { + + // Calculate the array size for the packet size/allocation arrays + + int elemCnt = packetSizes.size(); + + // Create the packet size, initial allocation and maximum allocation arrays + + int[] pktSizes = new int[elemCnt]; + int[] initSizes = new int[elemCnt]; + int[] maxSizes = new int[elemCnt]; + + int elemIdx = 0; + + // Process the packet size elements + for (MemoryPacketConfigBean curChild : packetSizes) + { + + // Get the packet size + + int pktSize = -1; + + Long pktSizeLong = curChild.getSize(); + if (pktSizeLong == null) + throw new InvalidConfigurationException("Memory pool packet size not specified"); + + // Parse the packet size + + try + { + pktSize = MemorySize.getByteValueInt(pktSizeLong.toString()); + } + catch (NumberFormatException ex) + { + throw new InvalidConfigurationException("Memory pool packet size, invalid size value, " + + pktSizeLong); + } + + // Make sure the packet sizes have been specified in ascending order + + if (elemIdx > 0 && pktSizes[elemIdx - 1] >= pktSize) + throw new InvalidConfigurationException( + "Invalid packet size specified, less than/equal to previous packet size"); + + // Get the initial allocation for the current packet size + Integer initAlloc = curChild.getInit(); + if (initAlloc == null) + throw new InvalidConfigurationException("Memory pool initial allocation not specified"); + + // Range check the initial allocation + + if (initAlloc < MemoryPoolMinimumAllocation) + throw new InvalidConfigurationException("Initial memory pool allocation below minimum of " + + MemoryPoolMinimumAllocation); + + if (initAlloc > MemoryPoolMaximumAllocation) + throw new InvalidConfigurationException("Initial memory pool allocation above maximum of " + + MemoryPoolMaximumAllocation); + + // Get the maximum allocation for the current packet size + + Integer maxAlloc = curChild.getMax(); + if (maxAlloc == null) + throw new InvalidConfigurationException("Memory pool maximum allocation not specified"); + + // Range check the maximum allocation + + if (maxAlloc < MemoryPoolMinimumAllocation) + throw new InvalidConfigurationException("Maximum memory pool allocation below minimum of " + + MemoryPoolMinimumAllocation); + + if (initAlloc > MemoryPoolMaximumAllocation) + throw new InvalidConfigurationException("Maximum memory pool allocation above maximum of " + + MemoryPoolMaximumAllocation); + + // Set the current packet size elements + + pktSizes[elemIdx] = pktSize; + initSizes[elemIdx] = initAlloc; + maxSizes[elemIdx] = maxAlloc; + + elemIdx++; + } + + // Check if all elements were used in the packet size/allocation arrays + + if (elemIdx < pktSizes.length) + { + + // Re-allocate the packet size/allocation arrays + + int[] newPktSizes = new int[elemIdx]; + int[] newInitSizes = new int[elemIdx]; + int[] newMaxSizes = new int[elemIdx]; + + // Copy the values to the shorter arrays + + System.arraycopy(pktSizes, 0, newPktSizes, 0, elemIdx); + System.arraycopy(initSizes, 0, newInitSizes, 0, elemIdx); + System.arraycopy(maxSizes, 0, newMaxSizes, 0, elemIdx); + + // Move the new arrays into place + + pktSizes = newPktSizes; + initSizes = newInitSizes; + maxSizes = newMaxSizes; + } + + // Configure the memory pool + + coreConfig.setMemoryPool(pktSizes, initSizes, maxSizes); + } + else + { + + // Configure a default memory pool + + coreConfig.setMemoryPool(DefaultMemoryPoolBufSizes, DefaultMemoryPoolInitAlloc, DefaultMemoryPoolMaxAlloc); + } + } + + /** + * Process an access control sub-section and return the access control list + * + * @param secConfig + * SecurityConfigSection + * @param aclsElem + * ConfigElement + */ + protected AccessControlList processAccessControlList(SecurityConfigSection secConfig, String defaultAccessLevel, + List accessControls) + { + + // Check if there is an access control manager configured + + if (secConfig.getAccessControlManager() == null) + throw new AlfrescoRuntimeException("No access control manager configured"); + + // Create the access control list + + AccessControlList acls = new AccessControlList(); + + // Check if there is a default access level for the ACL group + + if (defaultAccessLevel != null && defaultAccessLevel.length() > 0) + { + + // Get the access level and validate + + try + { + + // Parse the access level name + + int access = AccessControlParser.parseAccessTypeString(defaultAccessLevel); + + // Set the default access level for the access control list + + acls.setDefaultAccessLevel(access); + } + catch (InvalidACLTypeException ex) + { + throw new AlfrescoRuntimeException("Default access level error", ex); + } + catch (ACLParseException ex) + { + throw new AlfrescoRuntimeException("Default access level error", ex); + } + } + + // Parse each access control element + if (accessControls != null && accessControls.size() > 0) + { + + // Create the access controls + + for (AccessControl accessControl : accessControls) + { + + acls.addControl(accessControl); + } + } + + // Check if there are no access control rules but the default access level is set to 'None', + // this is not allowed as the share would not be accessible or visible. + + if (acls.getDefaultAccessLevel() == AccessControl.NoAccess && acls.numberOfControls() == 0) + throw new AlfrescoRuntimeException("Empty access control list and default access 'None' not allowed"); + + // Return the access control list + + return acls; + } + +} diff --git a/source/java/org/alfresco/filesys/config/TcpipSMBConfigBean.java b/source/java/org/alfresco/filesys/config/TcpipSMBConfigBean.java new file mode 100644 index 0000000000..53c71342ed --- /dev/null +++ b/source/java/org/alfresco/filesys/config/TcpipSMBConfigBean.java @@ -0,0 +1,108 @@ +/* + * 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.filesys.config; + +// TODO: Auto-generated Javadoc +/** + * The Class TcpipSMBConfigBean. + * + * @author dward + */ +public class TcpipSMBConfigBean +{ + + /** The platforms. */ + private String platforms; + + /** The port. */ + private Integer port; + + /** The ipv6 enabled. */ + private boolean ipv6Enabled; + + /** + * Gets the platforms. + * + * @return the platforms + */ + public String getPlatforms() + { + return platforms; + } + + /** + * Sets the platforms. + * + * @param platforms + * the new platforms + */ + public void setPlatforms(String platforms) + { + this.platforms = platforms; + } + + /** + * Gets the port. + * + * @return the port + */ + public Integer getPort() + { + return port; + } + + /** + * Sets the port. + * + * @param port + * the new port + */ + public void setPort(Integer port) + { + this.port = port; + } + + /** + * Checks if is ipv6 enabled. + * + * @return true, if is ipv6 enabled + */ + public boolean getIpv6Enabled() + { + return ipv6Enabled; + } + + /** + * Sets the ipv6 enabled. + * + * @param ipv6Enabled + * the new ipv6 enabled + */ + public void setIpv6Enabled(boolean ipv6Enabled) + { + this.ipv6Enabled = ipv6Enabled; + } + +} diff --git a/source/java/org/alfresco/filesys/config/WINSConfigBean.java b/source/java/org/alfresco/filesys/config/WINSConfigBean.java new file mode 100644 index 0000000000..523946435a --- /dev/null +++ b/source/java/org/alfresco/filesys/config/WINSConfigBean.java @@ -0,0 +1,108 @@ +/* + * 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.filesys.config; + +// TODO: Auto-generated Javadoc +/** + * The Class WINSConfigBean. + * + * @author dward + */ +public class WINSConfigBean +{ + + /** The primary. */ + private String primary; + + /** The secondary. */ + private String secondary; + + /** The auto detect enabled. */ + private boolean autoDetectEnabled = true; + + /** + * Checks if is auto detect enabled. + * + * @return true, if is auto detect enabled + */ + public boolean isAutoDetectEnabled() + { + return autoDetectEnabled; + } + + /** + * Sets the auto detect enabled. + * + * @param autoDetectEnabled + * the new auto detect enabled + */ + public void setAutoDetectEnabled(boolean autoDetectEnabled) + { + this.autoDetectEnabled = autoDetectEnabled; + } + + /** + * Gets the primary. + * + * @return the primary + */ + public String getPrimary() + { + return primary; + } + + /** + * Sets the primary. + * + * @param primary + * the new primary + */ + public void setPrimary(String primary) + { + this.primary = primary; + } + + /** + * Gets the secondary. + * + * @return the secondary + */ + public String getSecondary() + { + return secondary; + } + + /** + * Sets the secondary. + * + * @param secondary + * the new secondary + */ + public void setSecondary(String secondary) + { + this.secondary = secondary; + } + +} diff --git a/source/java/org/alfresco/filesys/config/Win32NetBIOSConfigBean.java b/source/java/org/alfresco/filesys/config/Win32NetBIOSConfigBean.java new file mode 100644 index 0000000000..9a78cbe0a6 --- /dev/null +++ b/source/java/org/alfresco/filesys/config/Win32NetBIOSConfigBean.java @@ -0,0 +1,108 @@ +/* + * 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.filesys.config; + +// TODO: Auto-generated Javadoc +/** + * The Class Win32NetBIOSConfigBean. + * + * @author dward + */ +public class Win32NetBIOSConfigBean +{ + + /** The name. */ + private String name; + + /** The lana. */ + private String lana; + + /** The api. */ + private String api; + + /** + * Gets the name. + * + * @return the name + */ + public String getName() + { + return name; + } + + /** + * Sets the name. + * + * @param name + * the new name + */ + public void setName(String name) + { + this.name = name; + } + + /** + * Gets the lana. + * + * @return the lana + */ + public String getLana() + { + return lana; + } + + /** + * Sets the lana. + * + * @param lana + * the new lana + */ + public void setLana(String lana) + { + this.lana = lana; + } + + /** + * Gets the api. + * + * @return the api + */ + public String getApi() + { + return api; + } + + /** + * Sets the api. + * + * @param api + * the new api + */ + public void setApi(String api) + { + this.api = api; + } + +} diff --git a/source/java/org/alfresco/filesys/repo/ContentContext.java b/source/java/org/alfresco/filesys/repo/ContentContext.java index 9c2a79e5b3..7230004971 100644 --- a/source/java/org/alfresco/filesys/repo/ContentContext.java +++ b/source/java/org/alfresco/filesys/repo/ContentContext.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,20 +18,24 @@ * 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.filesys.repo; +import java.util.List; + +import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.filesys.alfresco.AlfrescoContext; import org.alfresco.filesys.alfresco.IOControlHandler; +import org.alfresco.jlan.server.auth.acl.AccessControl; import org.alfresco.jlan.server.core.DeviceContextException; import org.alfresco.jlan.server.filesys.DiskInterface; import org.alfresco.jlan.server.filesys.DiskSharedDevice; +import org.alfresco.jlan.server.filesys.FileName; import org.alfresco.jlan.server.filesys.FileSystem; -import org.alfresco.jlan.smb.server.notify.NotifyChangeHandler; -import org.alfresco.service.cmr.repository.*; +import org.alfresco.service.cmr.repository.NodeRef; /** * Content Filesystem Context Class @@ -51,32 +55,114 @@ public class ContentContext extends AlfrescoContext private NodeRef m_rootNodeRef; + private String m_relativePath; + + private boolean m_offlineFiles; + + private boolean m_disableNodeMonitor; + + private String m_defaultAccessLevel; + + private List m_accessControl; + // Node monitor private NodeMonitor m_nodeMonitor; - + /** - * Class constructor - * - *@param filesysName String - * @param storeName String - * @param rootPath String - * @param rootNodeRef NodeRef + * Default constructor allowing initialization by container. */ - public ContentContext(String filesysName, String storeName, String rootPath, NodeRef rootNodeRef) + public ContentContext() { - super(filesysName, rootNodeRef.toString()); - - m_storeName = storeName; - m_rootPath = rootPath; - - m_rootNodeRef = rootNodeRef; - // Create the I/O control handler setIOHandler( createIOHandler( null)); } + /** + * Class constructor + * + *@param filesysName + * String + * @param storeName + * String + * @param rootPath + * String + * @param rootNodeRef + * NodeRef + */ + public ContentContext(String filesysName, String storeName, String rootPath, NodeRef rootNodeRef) + { + this(); + + setDeviceName(filesysName); + + setStoreName(storeName); + setRootPath(rootPath); + setRootNodeRef(rootNodeRef); + + afterPropertiesSet(); + } + + public void setStoreName(String name) + { + m_storeName = name; + } + + public void setRootPath(String path) + { + m_rootPath = path; + } + + public void setRelativePath(String path) + { + // Make sure the path is in CIFS format + m_relativePath = path.replace( '/', FileName.DOS_SEPERATOR);; + } + + public void setOfflineFiles(boolean offlineFiles) + { + m_offlineFiles = offlineFiles; + } + + public void setDisableNodeMonitor(boolean disableNodeMonitor) + { + m_disableNodeMonitor = disableNodeMonitor; + } + + public void setDefaultAccessLevel(String defaultAccessLevel) + { + m_defaultAccessLevel = defaultAccessLevel; + } + + public void setAccessControl(List accessControl) + { + m_accessControl = accessControl; + } + + public void setRootNodeRef(NodeRef nodeRef) + { + m_rootNodeRef = nodeRef; + setShareName(nodeRef.toString()); + } + + + @Override + public void afterPropertiesSet() + { + super.afterPropertiesSet(); + + if (m_storeName == null || m_storeName.length() == 0) + { + throw new AlfrescoRuntimeException("Device missing storeName"); + } + + if (m_rootPath == null || m_rootPath.length() == 0) + { + throw new AlfrescoRuntimeException("Device missing rootPath"); + } + } + /** * Return the filesystem type, either FileSystem.TypeFAT or FileSystem.TypeNTFS. * @@ -107,6 +193,57 @@ public class ContentContext extends AlfrescoContext return m_rootPath; } + /** + * Return the relative path + * + * @return String + */ + public String getRelativePath() + { + return m_relativePath; + } + + + /** + * Determines whether locked files should be marked as offline. + * + * @return true if locked files should be marked as offline + */ + public boolean getOfflineFiles() + { + return m_offlineFiles; + } + + /** + * Determines whether a node monitor is required. + * + * @return true if a node monitor is required + */ + public boolean getDisableNodeMonitor() + { + return m_disableNodeMonitor; + } + + /** + * Return the default access level + * + * @return String + */ + public String getDefaultAccessLevel() + { + return m_defaultAccessLevel; + } + + /** + * Return the access control list + * + * @return List + */ + public List getAccessControl() + { + return m_accessControl; + } + /** * Return the root node * @@ -120,17 +257,17 @@ public class ContentContext extends AlfrescoContext /** * Close the filesystem context */ - public void CloseContext() { + public void CloseContext() { - // Stop the node monitor, if enabled - - if ( m_nodeMonitor != null) - m_nodeMonitor.shutdownRequest(); - - // Call the base class - - super.CloseContext(); - } + // Stop the node monitor, if enabled + + if ( m_nodeMonitor != null) + m_nodeMonitor.shutdownRequest(); + + // Call the base class + + super.CloseContext(); + } /** * Create the I/O control handler for this filesystem type @@ -140,7 +277,7 @@ public class ContentContext extends AlfrescoContext */ protected IOControlHandler createIOHandler( DiskInterface filesysDriver) { - return new ContentIOControlHandler(); + return new ContentIOControlHandler(); } /** @@ -149,25 +286,25 @@ public class ContentContext extends AlfrescoContext * @param filesysDriver ContentDiskDriver */ protected void setNodeMonitor( NodeMonitor nodeMonitor) { - m_nodeMonitor = nodeMonitor; + m_nodeMonitor = nodeMonitor; } - /** - * Start the filesystem - * - * @param share DiskSharedDevice - * @exception DeviceContextException - */ - public void startFilesystem(DiskSharedDevice share) - throws DeviceContextException { + /** + * Start the filesystem + * + * @param share DiskSharedDevice + * @exception DeviceContextException + */ + public void startFilesystem(DiskSharedDevice share) + throws DeviceContextException { - // Call the base class - - super.startFilesystem(share); - - // Start the node monitor, if enabled - - if ( m_nodeMonitor != null) - m_nodeMonitor.startMonitor(); - } + // Call the base class + + super.startFilesystem(share); + + // Start the node monitor, if enabled + + if ( m_nodeMonitor != null) + m_nodeMonitor.startMonitor(); + } } diff --git a/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java b/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java index 528e3ebbe0..5b1963a9df 100644 --- a/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java +++ b/source/java/org/alfresco/filesys/repo/ContentDiskDriver.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 @@ -105,10 +105,6 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa private static final String KEY_ROOT_PATH = "rootPath"; private static final String KEY_RELATIVE_PATH = "relativePath"; - // Token name to substitute current servers DNS name or TCP/IP address into the webapp URL - - private static final String TokenLocalName = "${localname}"; - // Services and helpers private CifsHelper cifsHelper; @@ -347,12 +343,115 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa */ public DeviceContext createContext(String shareName, ConfigElement cfg) throws DeviceContextException { + ContentContext context = null; + + try + { + + // Get the store + + ConfigElement storeElement = cfg.getChild(KEY_STORE); + if (storeElement == null || storeElement.getValue() == null || storeElement.getValue().length() == 0) + { + throw new DeviceContextException("Device missing init value: " + KEY_STORE); + } + String storeValue = storeElement.getValue(); + + // Get the root path + + ConfigElement rootPathElement = cfg.getChild(KEY_ROOT_PATH); + if (rootPathElement == null || rootPathElement.getValue() == null || rootPathElement.getValue().length() == 0) + { + throw new DeviceContextException("Device missing init value: " + KEY_ROOT_PATH); + } + String rootPath = rootPathElement.getValue(); + + + // Create the context + + context = new ContentContext(); + context.setDeviceName(shareName); + context.setStoreName(storeValue); + context.setRootPath(rootPath); + + // Check if a relative path has been specified + + ConfigElement relativePathElement = cfg.getChild(KEY_RELATIVE_PATH); + + if ( relativePathElement != null) + { + // Make sure the path is in CIFS format + + String relPath = relativePathElement.getValue().replace( '/', FileName.DOS_SEPERATOR); + context.setRelativePath(relPath); + } + + + } + catch (Exception ex) + { + logger.error("Error during create context", ex); + } + + // Check if URL link files are enabled + + ConfigElement urlFileElem = cfg.getChild( "urlFile"); + if ( urlFileElem != null) + { + // Get the pseudo file name and web prefix path + + ConfigElement pseudoName = urlFileElem.getChild( "filename"); + ConfigElement webPath = urlFileElem.getChild( "webpath"); + + if ( pseudoName != null && webPath != null) + { + context.setURLFileName(pseudoName.getValue()); + context.setURLPrefix(webPath.getValue()); + } + } + + // Check if locked files should be marked as offline + + ConfigElement offlineFiles = cfg.getChild( "offlineFiles"); + if ( offlineFiles != null) + { + context.setOfflineFiles(true); + } + + // Install the node service monitor + + if ( cfg.getChild("disableNodeMonitor") == null) { + + // Create the node monitor + context.setDisableNodeMonitor(true); + } + + context.afterPropertiesSet(); + + registerContext(context); + + // Return the context for this shared filesystem + + return context; + } + + + /** + * Registers a device context object for this instance + * of the shared device. The same DeviceInterface implementation may be used for multiple + * shares. + * + * @param ctx the context + * @exception DeviceContextException + */ + public void registerContext(DeviceContext ctx) throws DeviceContextException + { + ContentContext context = (ContentContext)ctx; + // Wrap the initialization in a transaction UserTransaction tx = getTransactionService().getUserTransaction(true); - ContentContext context = null; - try { // Use the system user as the authenticated context for the filesystem initialization @@ -366,13 +465,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa tx.begin(); // Get the store - - ConfigElement storeElement = cfg.getChild(KEY_STORE); - if (storeElement == null || storeElement.getValue() == null || storeElement.getValue().length() == 0) - { - throw new DeviceContextException("Device missing init value: " + KEY_STORE); - } - String storeValue = storeElement.getValue(); + String storeValue = context.getStoreName(); StoreRef storeRef = new StoreRef(storeValue); // Connect to the repo and ensure that the store exists @@ -384,13 +477,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef); // Get the root path - - ConfigElement rootPathElement = cfg.getChild(KEY_ROOT_PATH); - if (rootPathElement == null || rootPathElement.getValue() == null || rootPathElement.getValue().length() == 0) - { - throw new DeviceContextException("Device missing init value: " + KEY_ROOT_PATH); - } - String rootPath = rootPathElement.getValue(); + String rootPath = context.getRootPath(); // Find the root node for this device @@ -407,41 +494,37 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa else if (nodeRefs.size() == 0) { // Nothing found - + throw new DeviceContextException("No root found for device: \n" + " root path: " + rootPath); } else { // We found a node - + rootNodeRef = nodeRefs.get(0); } // Check if a relative path has been specified - ConfigElement relativePathElement = cfg.getChild(KEY_RELATIVE_PATH); + String relPath = context.getRelativePath(); - if ( relativePathElement != null) + if ( relPath != null && relPath.length() > 0) { - // Make sure the path is in CIFS format - - String relPath = relativePathElement.getValue().replace( '/', FileName.DOS_SEPERATOR); - // Find the node and validate that the relative path is to a folder NodeRef relPathNode = cifsHelper.getNodeRef( rootNodeRef, relPath); if ( cifsHelper.isDirectory( relPathNode) == false) - throw new DeviceContextException("Relative path is not a folder, " + relativePathElement.getValue()); + throw new DeviceContextException("Relative path is not a folder, " + relPath); // Use the relative path node as the root of the filesystem rootNodeRef = relPathNode; } else { - - // Make sure the default root node is a folder - + + // Make sure the default root node is a folder + if ( cifsHelper.isDirectory( rootNodeRef) == false) throw new DeviceContextException("Root node is not a folder type node"); } @@ -450,10 +533,9 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa tx.commit(); tx = null; - - // Create the context - - context = new ContentContext(shareName, storeValue, rootPath, rootNodeRef); + + // Record the root node ref + context.setRootNodeRef(rootNodeRef); } catch (Exception ex) { @@ -480,72 +562,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa } } - // Check if URL link files are enabled - - ConfigElement urlFileElem = cfg.getChild( "urlFile"); - if ( urlFileElem != null) - { - // Get the pseudo file name and web prefix path - - ConfigElement pseudoName = urlFileElem.getChild( "filename"); - ConfigElement webPath = urlFileElem.getChild( "webpath"); - - if ( pseudoName != null && webPath != null) - { - // Make sure the web prefix has a trailing slash - - String path = webPath.getValue(); - if ( path.endsWith("/") == false) - path = path + "/"; - - // URL file name must end with .url - - if ( pseudoName.getValue().endsWith(".url") == false) - throw new DeviceContextException("URL link file must end with .url, " + pseudoName.getValue()); - - // Check if the URL path name contains the local name token - - int pos = path.indexOf(TokenLocalName); - if (pos != -1) - { - - // Get the local server name - - String srvName = "localhost"; - - try - { - srvName = InetAddress.getLocalHost().getHostName(); - } - catch ( Exception ex) - { - } - - // Rebuild the host name substituting the token with the local server name - - StringBuilder hostStr = new StringBuilder(); - - hostStr.append( path.substring(0, pos)); - hostStr.append(srvName); - - pos += TokenLocalName.length(); - if (pos < path.length()) - hostStr.append( path.substring(pos)); - - path = hostStr.toString(); - } - - // Set the URL link file name and web path - - context.setURLFileName( pseudoName.getValue()); - context.setURLPrefix( path); - } - } - // Check if locked files should be marked as offline - - ConfigElement offlineFiles = cfg.getChild( "offlineFiles"); - if ( offlineFiles != null) + if ( context.getOfflineFiles() ) { // Enable marking locked files as offline @@ -563,21 +581,17 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Initialize the I/O control handler if ( context.hasIOHandler()) - context.getIOHandler().initialize( this, context); + context.getIOHandler().initialize( this, context); // Install the node service monitor - if ( cfg.getChild("disableNodeMonitor") == null && m_nodeMonitorFactory != null) { - - // Create the node monitor + if ( !context.getDisableNodeMonitor() && m_nodeMonitorFactory != null) { + + // Create the node monitor - NodeMonitor nodeMonitor = m_nodeMonitorFactory.createNodeMonitor( this, context); - context.setNodeMonitor( nodeMonitor); + NodeMonitor nodeMonitor = m_nodeMonitorFactory.createNodeMonitor( this, context); + context.setNodeMonitor( nodeMonitor); } - - // Return the context for this shared filesystem - - return context; } /** diff --git a/source/java/org/alfresco/filesys/repo/HomeShareMapper.java b/source/java/org/alfresco/filesys/repo/HomeShareMapper.java index a35a928435..59dee1e784 100644 --- a/source/java/org/alfresco/filesys/repo/HomeShareMapper.java +++ b/source/java/org/alfresco/filesys/repo/HomeShareMapper.java @@ -43,6 +43,7 @@ import org.alfresco.config.ConfigElement; import org.alfresco.filesys.alfresco.AlfrescoClientInfo; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.InitializingBean; /** * Home Share Mapper Class @@ -52,7 +53,7 @@ import org.apache.commons.logging.LogFactory; * * @author GKSpencer */ -public class HomeShareMapper implements ShareMapper +public class HomeShareMapper implements ShareMapper, InitializingBean { // Logging @@ -86,6 +87,22 @@ public class HomeShareMapper implements ShareMapper { } + + public void setServerConfiguration(ServerConfiguration config) + { + this.m_config = config; + } + + public void setName(String shareName) + { + m_homeShareName = shareName; + } + + public void setDebug(boolean debug) + { + this.m_debug = debug; + } + /** * Initialize the share mapper * @@ -97,19 +114,28 @@ public class HomeShareMapper implements ShareMapper { // Save the server configuration - m_config = config; - m_filesysConfig = (FilesystemsConfigSection) m_config.getConfigSection(FilesystemsConfigSection.SectionName); + setServerConfiguration(config); // Check if the home share name has been specified String homeName = params.getAttribute("name"); if ( homeName != null && homeName.length() > 0) - m_homeShareName = homeName; + setName(homeName); // Check if debug is enabled if (params != null && params.getChild("debug") != null) - m_debug = true; + setDebug(true); + + // Complete initialization + afterPropertiesSet(); + } + + + public void afterPropertiesSet() + { + // Save the server configuration + m_filesysConfig = (FilesystemsConfigSection) m_config.getConfigSection(FilesystemsConfigSection.SectionName); // Search for a filesystem that uses the content driver to use the driver when creating the home shares diff --git a/source/java/org/alfresco/filesys/repo/desk/JavaScriptDesktopAction.java b/source/java/org/alfresco/filesys/repo/desk/JavaScriptDesktopAction.java index 62556f5a42..0874e7d304 100644 --- a/source/java/org/alfresco/filesys/repo/desk/JavaScriptDesktopAction.java +++ b/source/java/org/alfresco/filesys/repo/desk/JavaScriptDesktopAction.java @@ -89,22 +89,20 @@ public class JavaScriptDesktopAction extends DesktopAction { return "Run Javascript action"; } - /** - * Initialize the action - * - * @param global ConfigElement - * @param config ConfigElement - * @param fileSys DiskSharedDevice - * @exception DesktopActionException - */ - @Override - public void initializeAction(ConfigElement global, ConfigElement config, DiskSharedDevice fileSys) - throws DesktopActionException - { - + /** + * Perform standard desktop action initialization + * + * @param global ConfigElement + * @param config ConfigElement + * @param fileSys DiskSharedDevice + * @exception DesktopActionException + */ + @Override + public void standardInitialize(ConfigElement global, ConfigElement config, DiskSharedDevice fileSys) + throws DesktopActionException + { // Perform standard initialization - - super.initializeAction(global, config, fileSys); + super.standardInitialize(global, config, fileSys); // Get the script file name and check that it exists @@ -112,46 +110,7 @@ public class JavaScriptDesktopAction extends DesktopAction { if ( elem != null && elem.getValue().length() > 0) { // Set the script name - setScriptName(elem.getValue()); - - // Check if the script exists on the classpath - - URL scriptURL = this.getClass().getClassLoader().getResource(getScriptName()); - if ( scriptURL == null) - throw new DesktopActionException("Failed to find script on classpath, " + getScriptName()); - - // Decode the URL path, it might contain escaped characters - - String scriptURLPath = null; - try - { - scriptURLPath = URLDecoder.decode( scriptURL.getFile(), "UTF-8"); - } - catch ( UnsupportedEncodingException ex) - { - throw new DesktopActionException("Failed to decode script path, " + ex.getMessage()); - } - - // Check that the script file exists - - File scriptFile = new File(scriptURLPath); - if ( scriptFile.exists() == false) - throw new DesktopActionException("Script file not found, " + elem.getValue()); - - m_scriptPath = scriptFile.getAbsolutePath(); - m_lastModified =scriptFile.lastModified(); - - // Load the script - - try - { - loadScript( scriptFile); - } - catch ( IOException ex) - { - throw new DesktopActionException( "Failed to load script, " + ex.getMessage()); - } } else throw new DesktopActionException("Script name not specified"); @@ -167,45 +126,7 @@ public class JavaScriptDesktopAction extends DesktopAction { throw new DesktopActionException("Empty desktop action attributes"); // Parse the attribute string - - int attr = 0; - StringTokenizer tokens = new StringTokenizer( elem.getValue(), ","); - - while ( tokens.hasMoreTokens()) - { - // Get the current attribute token and validate - - String token = tokens.nextToken().trim(); - - if ( token.equalsIgnoreCase( "targetFiles")) - attr |= AttrTargetFiles; - else if ( token.equalsIgnoreCase( "targetFolders")) - attr |= AttrTargetFolders; - else if ( token.equalsIgnoreCase( "clientFiles")) - attr |= AttrClientFiles; - else if ( token.equalsIgnoreCase( "clientFolders")) - attr |= AttrClientFolders; - else if ( token.equalsIgnoreCase( "alfrescoFiles")) - attr |= AttrAlfrescoFiles; - else if ( token.equalsIgnoreCase( "alfrescoFolders")) - attr |= AttrAlfrescoFolders; - else if ( token.equalsIgnoreCase( "multiplePaths")) - attr |= AttrMultiplePaths; - else if ( token.equalsIgnoreCase( "allowNoParams")) - attr |= AttrAllowNoParams; - else if ( token.equalsIgnoreCase( "anyFiles")) - attr |= AttrAnyFiles; - else if ( token.equalsIgnoreCase( "anyFolders")) - attr |= AttrAnyFolders; - else if ( token.equalsIgnoreCase( "anyFilesFolders")) - attr |= AttrAnyFilesFolders; - else - throw new DesktopActionException("Unknown attribute, " + token); - } - - // Set the action attributes - - setAttributes( attr); + setAttributes(elem.getValue()); } // Check if the desktop action pre-processing options have been specified @@ -213,40 +134,64 @@ public class JavaScriptDesktopAction extends DesktopAction { elem = config.getChild("preprocess"); if ( elem != null) { - // Check if the pre-process string is empty - - int pre = 0; - - if ( elem.getValue() != null && elem.getValue().length() > 0) - { - // Parse the pre-process string - - StringTokenizer tokens = new StringTokenizer( elem.getValue(), ","); - - while ( tokens.hasMoreTokens()) - { - // Get the current pre-process token and validate - - String token = tokens.nextToken().trim(); - - if ( token.equalsIgnoreCase( "copyToTarget")) - pre |= PreCopyToTarget; - else if ( token.equalsIgnoreCase( "confirm")) - pre |= PreConfirmAction; - else if ( token.equalsIgnoreCase( "localToWorkingCopy")) - pre |= PreLocalToWorkingCopy; - else - throw new DesktopActionException("Unknown pre-processing flag, " + token); - } - } - - // Set the action pre-processing flags - - setPreProcessActions( pre); + setPreProcessActions(elem.getValue()); } } - /** + @Override + public void afterPropertiesSet() throws DesktopActionException + { + // Perform standard initialization + + super.afterPropertiesSet(); + + // Get the script file name and check that it exists + + if ( m_scriptName == null || m_scriptName.length() == 0) + { + throw new DesktopActionException("Script name not specified"); + } + + // Check if the script exists on the classpath + + URL scriptURL = this.getClass().getClassLoader().getResource(m_scriptName); + if ( scriptURL == null) + throw new DesktopActionException("Failed to find script on classpath, " + getScriptName()); + + // Decode the URL path, it might contain escaped characters + + String scriptURLPath = null; + try + { + scriptURLPath = URLDecoder.decode( scriptURL.getFile(), "UTF-8"); + } + catch ( UnsupportedEncodingException ex) + { + throw new DesktopActionException("Failed to decode script path, " + ex.getMessage()); + } + + // Check that the script file exists + + File scriptFile = new File(scriptURLPath); + if ( scriptFile.exists() == false) + throw new DesktopActionException("Script file not found, " + m_scriptName); + + m_scriptPath = scriptFile.getAbsolutePath(); + m_lastModified =scriptFile.lastModified(); + + // Load the script + + try + { + loadScript( scriptFile); + } + catch ( IOException ex) + { + throw new DesktopActionException( "Failed to load script, " + ex.getMessage()); + } + } + + /** * Run the desktop action * * @param params DesktopParams @@ -428,7 +373,101 @@ public class JavaScriptDesktopAction extends DesktopAction { m_scriptName = name; } - /** + /** + * Set the action attributes + * + * @param attributes String + * @throws DesktopActionException + */ + protected void setAttributes(String attributes) throws DesktopActionException + { + // Check if the attribute string is empty + if ( attributes == null || attributes.length() == 0) + { + return; + } + // Parse the attribute string + + int attr = 0; + StringTokenizer tokens = new StringTokenizer( attributes, ","); + + while ( tokens.hasMoreTokens()) + { + // Get the current attribute token and validate + + String token = tokens.nextToken().trim(); + + if ( token.equalsIgnoreCase( "targetFiles")) + attr |= AttrTargetFiles; + else if ( token.equalsIgnoreCase( "targetFolders")) + attr |= AttrTargetFolders; + else if ( token.equalsIgnoreCase( "clientFiles")) + attr |= AttrClientFiles; + else if ( token.equalsIgnoreCase( "clientFolders")) + attr |= AttrClientFolders; + else if ( token.equalsIgnoreCase( "alfrescoFiles")) + attr |= AttrAlfrescoFiles; + else if ( token.equalsIgnoreCase( "alfrescoFolders")) + attr |= AttrAlfrescoFolders; + else if ( token.equalsIgnoreCase( "multiplePaths")) + attr |= AttrMultiplePaths; + else if ( token.equalsIgnoreCase( "allowNoParams")) + attr |= AttrAllowNoParams; + else if ( token.equalsIgnoreCase( "anyFiles")) + attr |= AttrAnyFiles; + else if ( token.equalsIgnoreCase( "anyFolders")) + attr |= AttrAnyFolders; + else if ( token.equalsIgnoreCase( "anyFilesFolders")) + attr |= AttrAnyFilesFolders; + else + throw new DesktopActionException("Unknown attribute, " + token); + } + setAttributes(attr); + } + + /** + * Set the client side pre-processing actions + * + * @param preProcessActions String + * @throws DesktopActionException + */ + protected void setPreProcessActions(String preProcessActions) throws DesktopActionException + { + // Check if the pre-process string is empty + + if ( preProcessActions == null || preProcessActions.length() == 0) + { + return; + } + + int pre = 0; + + // Parse the pre-process string + + StringTokenizer tokens = new StringTokenizer( preProcessActions, ","); + + while ( tokens.hasMoreTokens()) + { + // Get the current pre-process token and validate + + String token = tokens.nextToken().trim(); + + if ( token.equalsIgnoreCase( "copyToTarget")) + pre |= PreCopyToTarget; + else if ( token.equalsIgnoreCase( "confirm")) + pre |= PreConfirmAction; + else if ( token.equalsIgnoreCase( "localToWorkingCopy")) + pre |= PreLocalToWorkingCopy; + else + throw new DesktopActionException("Unknown pre-processing flag, " + token); + } + + // Set the action pre-processing flags + + setPreProcessActions( pre); + } + + /** * Load, or reload, the script * * @param scriptFile File diff --git a/source/java/org/alfresco/repo/management/DefaultManagedApplicationContextFactory.java b/source/java/org/alfresco/repo/management/DefaultManagedApplicationContextFactory.java index 911a36c801..3fc4f7f011 100644 --- a/source/java/org/alfresco/repo/management/DefaultManagedApplicationContextFactory.java +++ b/source/java/org/alfresco/repo/management/DefaultManagedApplicationContextFactory.java @@ -27,6 +27,7 @@ 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; @@ -35,6 +36,7 @@ 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; /** @@ -42,14 +44,15 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; * {@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 implements ManagedApplicationContextFactory, - InitializingBean, ApplicationContextAware, BeanNameAware +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) @@ -59,6 +62,7 @@ public class DefaultManagedApplicationContextFactory implements ManagedApplicati public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.parent = applicationContext; + super.setApplicationContext(applicationContext); } /* @@ -74,7 +78,7 @@ public class DefaultManagedApplicationContextFactory implements ManagedApplicati * @param properties * the properties to set */ - @Managed(category="management") + @Managed(category = "management") public void setProperties(Properties properties) { this.properties = properties; @@ -88,6 +92,15 @@ public class DefaultManagedApplicationContextFactory implements ManagedApplicati 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() @@ -152,11 +165,34 @@ public class DefaultManagedApplicationContextFactory implements ManagedApplicati } } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.alfresco.repo.management.ManagedApplicationContextFactory#getApplicationContext() */ public ApplicationContext getApplicationContext() { return this.applicationContext; } + + /* + * (non-Javadoc) + * @see org.alfresco.util.AbstractLifecycleBean#onBootstrap(org.springframework.context.ApplicationEvent) + */ + @Override + protected void onBootstrap(ApplicationEvent event) + { + if (this.autoStart) + { + onStart(); + } + } + + /* + * (non-Javadoc) + * @see org.alfresco.util.AbstractLifecycleBean#onShutdown(org.springframework.context.ApplicationEvent) + */ + @Override + protected void onShutdown(ApplicationEvent event) + { + } }