diff --git a/source/java/org/alfresco/filesys/server/auth/AlfrescoAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/AlfrescoAuthenticator.java index 24c6d92ff5..5dd802c000 100644 --- a/source/java/org/alfresco/filesys/server/auth/AlfrescoAuthenticator.java +++ b/source/java/org/alfresco/filesys/server/auth/AlfrescoAuthenticator.java @@ -17,32 +17,11 @@ package org.alfresco.filesys.server.auth; import java.security.NoSuchAlgorithmException; -import java.util.Random; -import javax.transaction.UserTransaction; - -import net.sf.acegisecurity.Authentication; - -import org.alfresco.config.ConfigElement; import org.alfresco.filesys.server.SrvSession; -import org.alfresco.filesys.server.config.InvalidConfigurationException; -import org.alfresco.filesys.server.config.ServerConfiguration; -import org.alfresco.filesys.server.core.SharedDevice; import org.alfresco.filesys.smb.server.SMBSrvSession; import org.alfresco.filesys.util.DataPacker; -import org.alfresco.model.ContentModel; -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.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.service.transaction.TransactionService; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import com.sun.star.uno.RuntimeException; /** * Alfresco Authenticator Class @@ -57,32 +36,6 @@ import com.sun.star.uno.RuntimeException; */ public class AlfrescoAuthenticator extends SrvAuthenticator { - // Logging - - private static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol.auth"); - - // Random number generator used to generate challenge keys - - private Random m_random = new Random(System.currentTimeMillis()); - - // Server configuration - - private ServerConfiguration m_config; - - // Authentication component, used to access internal authentication functions - - private AuthenticationComponent m_authComponent; - - // MD4 hash decoder - - private MD4PasswordEncoder m_md4Encoder = new MD4PasswordEncoderImpl(); - - // Various services required to get user information - - private NodeService m_nodeService; - private PersonService m_personService; - private TransactionService m_transactionService; - /** * Default Constructor * @@ -94,24 +47,6 @@ public class AlfrescoAuthenticator extends SrvAuthenticator setEncryptedPasswords(true); } - /** - * Authenticate the connection to a share - * - * @param client ClienInfo - * @param share SharedDevice - * @param pwd Share level password. - * @param sess Server session - * @return Authentication status. - */ - public int authenticateShareConnect(ClientInfo client, SharedDevice share, String pwd, SrvSession sess) - { - // Allow write access - // - // Main authentication is handled by authenticateUser() - - return SrvAuthenticator.Writeable; - } - /** * Authenticate a user * @@ -160,7 +95,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator int authSts = AUTH_DISALLOW; - if ( client.isGuest()) + if ( client.isGuest() || client.getUserName().equalsIgnoreCase(GUEST_USERNAME)) { // Check if guest logons are allowed @@ -169,18 +104,20 @@ public class AlfrescoAuthenticator extends SrvAuthenticator // Get a guest authentication token - m_authComponent.setGuestUserAsCurrentUser(); - Authentication authToken = m_authComponent.getCurrentAuthentication(); - - client.setAuthenticationToken( authToken); - - // Set the home folder for the guest user - - getHomeFolderForUser( client); + doGuestLogon( client, sess); // Indicate logged on as guest authSts = AUTH_GUEST; + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Authenticated user " + client.getUserName() + " sts=" + getStatusAsString(authSts)); + + // Return the guest status + + return authSts; } // Check if MD4 or passthru mode is configured @@ -191,6 +128,26 @@ public class AlfrescoAuthenticator extends SrvAuthenticator authSts = doMD4UserAuthentication(client, sess, alg); } + + // Check if the logon status indicates a guest logon + + if ( authSts == AUTH_GUEST) + { + // Only allow the guest logon if user mapping is enabled + + if ( mapUnknownUserToGuest()) + { + // Logon as guest, setup the security context + + doGuestLogon( client, sess); + } + else + { + // Do not allow the guest logon + + authSts = AUTH_DISALLOW; + } + } // DEBUG @@ -243,47 +200,6 @@ public class AlfrescoAuthenticator extends SrvAuthenticator return key; } - /** - * Search for the required user account details in the defined user list - * - * @param user String - * @return UserAccount - */ - public UserAccount getUserDetails(String user) - { - return null; - } - - /** - * Initialize the authenticator - * - * @param config ServerConfiguration - * @param params ConfigElement - * @exception InvalidConfigurationException - */ - public void initialize(ServerConfiguration config, ConfigElement params) throws InvalidConfigurationException - { - // Save the server configuration so we can access the authentication component - - m_config = config; - - // Check that the required authentication classes are available - - m_authComponent = m_config.getAuthenticationComponent(); - - if ( m_authComponent == null) - throw new InvalidConfigurationException("Authentication component not available"); - - if ( m_authComponent.getNTLMMode() != NTLMMode.MD4_PROVIDER) - throw new InvalidConfigurationException("Required authentication mode not available"); - - // Get hold of various services - - m_nodeService = config.getNodeService(); - m_personService = config.getPersonService(); - m_transactionService = config.getTransactionService(); - } - /** * Perform MD4 user authentication * @@ -362,46 +278,4 @@ public class AlfrescoAuthenticator extends SrvAuthenticator return allowGuest() ? SrvAuthenticator.AUTH_GUEST : SrvAuthenticator.AUTH_DISALLOW; } - - /** - * Get the home folder for the user - * - * @param client ClientInfo - */ - private final void getHomeFolderForUser(ClientInfo client) - { - // Get the home folder for the user - - UserTransaction tx = m_transactionService.getUserTransaction(); - NodeRef homeSpaceRef = null; - - try - { - tx.begin(); - homeSpaceRef = (NodeRef) m_nodeService.getProperty(m_personService.getPerson(client.getUserName()), - ContentModel.PROP_HOMEFOLDER); - client.setHomeFolder( homeSpaceRef); - tx.commit(); - } - catch (Throwable ex) - { - try - { - tx.rollback(); - } - catch (Exception ex2) - { - logger.error("Failed to rollback transaction", ex2); - } - - if(ex instanceof RuntimeException) - { - throw (RuntimeException)ex; - } - else - { - throw new RuntimeException("Failed to get home folder", ex); - } - } - } } \ No newline at end of file diff --git a/source/java/org/alfresco/filesys/server/auth/SrvAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/SrvAuthenticator.java index bbb209a10e..bcee3d2d56 100644 --- a/source/java/org/alfresco/filesys/server/auth/SrvAuthenticator.java +++ b/source/java/org/alfresco/filesys/server/auth/SrvAuthenticator.java @@ -17,12 +17,34 @@ package org.alfresco.filesys.server.auth; import java.security.NoSuchAlgorithmException; +import java.util.Random; + +import javax.transaction.UserTransaction; + +import net.sf.acegisecurity.Authentication; import org.alfresco.config.ConfigElement; import org.alfresco.filesys.server.SrvSession; import org.alfresco.filesys.server.config.InvalidConfigurationException; import org.alfresco.filesys.server.config.ServerConfiguration; import org.alfresco.filesys.server.core.SharedDevice; +import org.alfresco.filesys.server.filesys.DiskDeviceContext; +import org.alfresco.filesys.server.filesys.DiskInterface; +import org.alfresco.filesys.server.filesys.DiskSharedDevice; +import org.alfresco.filesys.server.filesys.SrvDiskInfo; +import org.alfresco.filesys.smb.server.repo.ContentContext; +import org.alfresco.model.ContentModel; +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.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.transaction.TransactionService; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; /** *

@@ -31,6 +53,9 @@ import org.alfresco.filesys.server.core.SharedDevice; */ public abstract class SrvAuthenticator { + // Logging + + protected static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol.auth"); // Encryption algorithm types @@ -61,6 +86,10 @@ public abstract class SrvAuthenticator public static final int STANDARD_PASSWORD_LEN = 24; + // Default guest user name + + protected static final String GUEST_USERNAME = "guest"; + // Server access mode private int m_accessMode = SHARE_MODE; @@ -73,10 +102,38 @@ public abstract class SrvAuthenticator private PasswordEncryptor m_encryptor = new PasswordEncryptor(); - // Flag to enable/disable the guest account + // Flag to enable/disable the guest account, and control mapping of unknown users to the guest account private boolean m_allowGuest; + private boolean m_mapToGuest; + // Default guest user name + + private String m_guestUserName = GUEST_USERNAME; + + // Random number generator used to generate challenge keys + + protected Random m_random = new Random(System.currentTimeMillis()); + + // Server configuration + + protected ServerConfiguration m_config; + + // Authentication component, used to access internal authentication functions + + protected AuthenticationComponent m_authComponent; + + // MD4 hash decoder + + protected MD4PasswordEncoder m_md4Encoder = new MD4PasswordEncoderImpl(); + + // Various services required to get user information + + protected NodeService m_nodeService; + protected PersonService m_personService; + protected TransactionService m_transactionService; + protected AuthenticationService m_authenticationService; + /** * Authenticate a connection to a share. * @@ -87,7 +144,14 @@ public abstract class SrvAuthenticator * @return int Granted file permission level or disallow status if negative. See the * FilePermission class. */ - public abstract int authenticateShareConnect(ClientInfo client, SharedDevice share, String sharePwd, SrvSession sess); + public int authenticateShareConnect(ClientInfo client, SharedDevice share, String sharePwd, SrvSession sess) + { + // Allow write access + // + // Main authentication is handled by authenticateUser() + + return SrvAuthenticator.Writeable; + } /** * Authenticate a user. A user may be granted full access, guest access or no access. @@ -105,7 +169,10 @@ public abstract class SrvAuthenticator * @param user String * @return UserAccount */ - public abstract UserAccount getUserDetails(String user); + public UserAccount getUserDetails(String user) + { + return null; + } /** * Authenticate a user using a plain text password. @@ -150,6 +217,31 @@ public abstract class SrvAuthenticator */ public void initialize(ServerConfiguration config, ConfigElement params) throws InvalidConfigurationException { + // Save the server configuration so we can access the authentication component + + m_config = config; + + // Check that the required authentication classes are available + + m_authComponent = m_config.getAuthenticationComponent(); + + if ( m_authComponent == null) + throw new InvalidConfigurationException("Authentication component not available"); + + if ( m_authComponent.getNTLMMode() != NTLMMode.MD4_PROVIDER && + m_authComponent.getNTLMMode() != NTLMMode.PASS_THROUGH) + throw new InvalidConfigurationException("Required authentication mode not available"); + + // Get hold of various services + + m_nodeService = config.getNodeService(); + m_personService = config.getPersonService(); + m_transactionService = config.getTransactionService(); + m_authenticationService = config.getAuthenticationService(); + + // Set the guest user name + + setGuestUserName( m_authComponent.getGuestUserName()); } /** @@ -222,6 +314,26 @@ public abstract class SrvAuthenticator return m_allowGuest; } + /** + * Return the guest user name + * + * @return String + */ + public final String getGuestUserName() + { + return m_guestUserName; + } + + /** + * Determine if unknown users should be mapped to the guest account + * + * @return boolean + */ + public final boolean mapUnknownUserToGuest() + { + return m_mapToGuest; + } + /** * Set the access mode of the server. * @@ -252,6 +364,26 @@ public abstract class SrvAuthenticator m_allowGuest = ena; } + /** + * Set the guest user name + * + * @param guest String + */ + public final void setGuestUserName( String guest) + { + m_guestUserName = guest; + } + + /** + * Enable/disable mapping of unknown users to the guest account + * + * @param ena Enable mapping of unknown users to the guest if true + */ + public final void setMapToGuest( boolean ena) + { + m_mapToGuest = ena; + } + /** * Close the authenticator, perform any cleanup */ @@ -367,4 +499,87 @@ public abstract class SrvAuthenticator return str; } + + /** + * Logon using the guest user account + * + * @param client ClientInfo + * @param sess SrvSession + */ + protected final void doGuestLogon( ClientInfo client, SrvSession sess) + { + // Get a guest authentication token + + m_authenticationService.authenticateAsGuest(); + Authentication authToken = m_authComponent.getCurrentAuthentication(); + + client.setAuthenticationToken( authToken); + + // Set the home folder for the guest user + + client.setUserName( getGuestUserName()); + getHomeFolderForUser( client); + + // Mark the client as being a guest logon + + client.setGuest( true); + + // Create a dynamic share for the guest user + // Create the disk driver and context + + DiskInterface diskDrv = m_config.getDiskInterface(); + DiskDeviceContext diskCtx = new ContentContext("", "", client.getHomeFolder()); + + // Default the filesystem to look like an 80Gb sized disk with 90% free space + + diskCtx.setDiskInformation(new SrvDiskInfo(2560, 64, 512, 2304)); + + // Create a temporary shared device for the users home directory + + sess.addDynamicShare( new DiskSharedDevice( client.getUserName(), diskDrv, diskCtx, SharedDevice.Temporary)); + } + + /** + * Get the home folder for the user + * + * @param client ClientInfo + */ + protected final void getHomeFolderForUser(ClientInfo client) + { + // Get the home folder for the user + + UserTransaction tx = m_transactionService.getUserTransaction(); + NodeRef homeSpaceRef = null; + + try + { + tx.begin(); + homeSpaceRef = (NodeRef) m_nodeService.getProperty(m_personService.getPerson(client.getUserName()), + ContentModel.PROP_HOMEFOLDER); + client.setHomeFolder( homeSpaceRef); + tx.commit(); + } + catch (Throwable ex) + { + try + { + tx.rollback(); + } + catch (Throwable ex2) + { + logger.error("Failed to rollback transaction", ex2); + } + + // Re-throw the exception + if (ex instanceof RuntimeException) + { + throw (RuntimeException) ex; + } + else + { + throw new RuntimeException("Error during execution of transaction.", ex); + } + } + } + } \ No newline at end of file diff --git a/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java b/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java index 5b1e1d0195..cf5416443c 100644 --- a/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java +++ b/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java @@ -1451,13 +1451,15 @@ public class ServerConfiguration else throw new AlfrescoRuntimeException("Invalid authenticator type, " + authType); - // Get the allow guest setting + // Get the allow guest and map unknown user to guest settings boolean allowGuest = authElem.getChild("allowGuest") != null ? true : false; + boolean mapGuest = authElem.getChild("mapUnknownUserToGuest") != null ? true : false; // Initialize and set the authenticator class setAuthenticator(auth, authElem, allowGuest); + auth.setMapToGuest( mapGuest); } // Add the users diff --git a/source/java/org/alfresco/filesys/server/filesys/DefaultShareMapper.java b/source/java/org/alfresco/filesys/server/filesys/DefaultShareMapper.java index 82a70a24b6..7b5a1d9543 100644 --- a/source/java/org/alfresco/filesys/server/filesys/DefaultShareMapper.java +++ b/source/java/org/alfresco/filesys/server/filesys/DefaultShareMapper.java @@ -16,6 +16,8 @@ */ package org.alfresco.filesys.server.filesys; +import java.util.Enumeration; + import org.alfresco.config.ConfigElement; import org.alfresco.filesys.server.SrvSession; import org.alfresco.filesys.server.auth.InvalidUserException; @@ -99,20 +101,33 @@ public class DefaultShareMapper implements ShareMapper SharedDevice share = null; - // Find the required share by name/type. Use a case sensitive search first, if that fails - // use a case - // insensitive search. + // Search the sessions dynamic share list first - share = m_config.getShares().findShare(name, typ, false); - - if (share == null) - { - - // Try a case insensitive search for the required share - - share = m_config.getShares().findShare(name, typ, true); + if ( sess.hasDynamicShares()) { + + // Check if the required share exists in the sessions dynamic share list + + share = sess.getDynamicShareList().findShare(name, typ, true); } + // If we did not find a share then search the global share list + + if ( share == null) + { + // Find the required share by name/type. Use a case sensitive search first, if that fails + // use a case insensitive search. + + share = m_config.getShares().findShare(name, typ, false); + + if (share == null) + { + + // Try a case insensitive search for the required share + + share = m_config.getShares().findShare(name, typ, true); + } + } + // Check if the share is available if (share != null && share.getContext() != null && share.getContext().isAvailable() == false) @@ -130,6 +145,30 @@ public class DefaultShareMapper implements ShareMapper */ public void deleteShares(SrvSession sess) { + // Check if the session has any dynamic shares + + if ( sess.hasDynamicShares() == false) + return; + + // Delete the dynamic shares + + SharedDeviceList shares = sess.getDynamicShareList(); + Enumeration enm = shares.enumerateShares(); + + while ( enm.hasMoreElements()) { + + // Get the current share from the list + + SharedDevice shr = (SharedDevice) enm.nextElement(); + + // Close the shared device + + shr.getContext().CloseContext(); + } + + // Clear the dynamic share list + + shares.removeAllShares(); } /** @@ -149,6 +188,13 @@ public class DefaultShareMapper implements ShareMapper SharedDeviceList shrList = new SharedDeviceList(m_config.getShares()); + if ( sess != null && sess.hasDynamicShares()) { + + // Add the per session dynamic shares + + shrList.addShares(sess.getDynamicShareList()); + } + // Remove unavailable shares from the list and return the list if (allShares == false) diff --git a/source/java/org/alfresco/filesys/smb/server/NTProtocolHandler.java b/source/java/org/alfresco/filesys/smb/server/NTProtocolHandler.java index caf0ba50d3..8efde51ca3 100644 --- a/source/java/org/alfresco/filesys/smb/server/NTProtocolHandler.java +++ b/source/java/org/alfresco/filesys/smb/server/NTProtocolHandler.java @@ -4241,6 +4241,14 @@ public class NTProtocolHandler extends CoreProtocolHandler m_sess.sendResponseSMB(outPkt); } + catch (AccessDeniedException ex) + { + + // Not allowed to access the file/folder + + m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); + return; + } catch (FileNotFoundException ex) { @@ -4439,6 +4447,14 @@ public class NTProtocolHandler extends CoreProtocolHandler m_sess.sendResponseSMB(outPkt); } + catch (AccessDeniedException ex) + { + + // Not allowed to access the file/folder + + m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); + return; + } catch (FileNotFoundException ex) {