mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Redesign of the CIFS authentication code to support NTLMv1/NTLMv2, SPNEGO and NTLMSSP
authentication methods via the session setup. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2760 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
@@ -19,7 +19,7 @@ package org.alfresco.filesys.server;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.alfresco.filesys.server.auth.SrvAuthenticator;
|
||||
import org.alfresco.filesys.server.auth.CifsAuthenticator;
|
||||
import org.alfresco.filesys.server.auth.acl.AccessControlManager;
|
||||
import org.alfresco.filesys.server.config.ServerConfiguration;
|
||||
import org.alfresco.filesys.server.core.ShareMapper;
|
||||
@@ -99,9 +99,9 @@ public abstract class NetworkServer
|
||||
/**
|
||||
* Return the authenticator for this server
|
||||
*
|
||||
* @return SrvAuthenticator
|
||||
* @return CifsAuthenticator
|
||||
*/
|
||||
public final SrvAuthenticator getAuthenticator()
|
||||
public final CifsAuthenticator getAuthenticator()
|
||||
{
|
||||
return getConfiguration().getAuthenticator();
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
@@ -23,6 +23,7 @@ import javax.transaction.SystemException;
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.filesys.server.auth.AuthContext;
|
||||
import org.alfresco.filesys.server.auth.ClientInfo;
|
||||
import org.alfresco.filesys.server.core.SharedDevice;
|
||||
import org.alfresco.filesys.server.core.SharedDeviceList;
|
||||
@@ -60,10 +61,6 @@ public abstract class SrvSession
|
||||
|
||||
private ClientInfo m_clientInfo;
|
||||
|
||||
// Challenge key used for this session
|
||||
|
||||
private byte[] m_challenge;
|
||||
|
||||
// Debug flags for this session
|
||||
|
||||
private int m_debug;
|
||||
@@ -85,6 +82,10 @@ public abstract class SrvSession
|
||||
|
||||
private Object m_authToken;
|
||||
|
||||
// Authentication context, used during the initial session setup phase
|
||||
|
||||
private AuthContext m_authContext;
|
||||
|
||||
// List of dynamic/temporary shares created for this session
|
||||
|
||||
private SharedDeviceList m_dynamicShares;
|
||||
@@ -154,26 +155,6 @@ public abstract class SrvSession
|
||||
return m_authToken != null ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the session challenge key
|
||||
*
|
||||
* @return byte[]
|
||||
*/
|
||||
public final byte[] getChallengeKey()
|
||||
{
|
||||
return m_challenge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the challenge key has been set for this session
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasChallengeKey()
|
||||
{
|
||||
return m_challenge != null ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the process id
|
||||
*
|
||||
@@ -231,6 +212,26 @@ public abstract class SrvSession
|
||||
return m_clientInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the session has an authentication context
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasAuthenticationContext()
|
||||
{
|
||||
return m_authContext != null ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the authentication context for this sesion
|
||||
*
|
||||
* @return AuthContext
|
||||
*/
|
||||
public final AuthContext getAuthenticationContext()
|
||||
{
|
||||
return m_authContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the session has any dynamic shares
|
||||
*
|
||||
@@ -342,6 +343,16 @@ public abstract class SrvSession
|
||||
m_authToken = authToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the authentication context, used during the initial session setup phase
|
||||
*
|
||||
* @param ctx AuthContext
|
||||
*/
|
||||
public final void setAuthenticationContext( AuthContext ctx)
|
||||
{
|
||||
m_authContext = ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the client information
|
||||
*
|
||||
@@ -352,16 +363,6 @@ public abstract class SrvSession
|
||||
m_clientInfo = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the session challenge key
|
||||
*
|
||||
* @param key byte[]
|
||||
*/
|
||||
public final void setChallengeKey(byte[] key)
|
||||
{
|
||||
m_challenge = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the debug output interface.
|
||||
*
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
@@ -20,7 +20,6 @@ import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import org.alfresco.filesys.server.SrvSession;
|
||||
import org.alfresco.filesys.smb.server.SMBSrvSession;
|
||||
import org.alfresco.filesys.util.DataPacker;
|
||||
import org.alfresco.repo.security.authentication.NTLMMode;
|
||||
|
||||
/**
|
||||
@@ -34,7 +33,7 @@ import org.alfresco.repo.security.authentication.NTLMMode;
|
||||
*
|
||||
* @author GKSpencer
|
||||
*/
|
||||
public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
public class AlfrescoAuthenticator extends CifsAuthenticator
|
||||
{
|
||||
/**
|
||||
* Default Constructor
|
||||
@@ -43,8 +42,6 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
*/
|
||||
public AlfrescoAuthenticator()
|
||||
{
|
||||
setAccessMode(SrvAuthenticator.USER_MODE);
|
||||
setEncryptedPasswords(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,7 +79,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
if ( logger.isDebugEnabled())
|
||||
logger.debug("Null CIFS logon allowed");
|
||||
|
||||
return SrvAuthenticator.AUTH_ALLOW;
|
||||
return CifsAuthenticator.AUTH_ALLOW;
|
||||
}
|
||||
|
||||
// Check if the client is already authenticated, and it is not a null logon
|
||||
@@ -175,46 +172,6 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
return authSts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a challenge key
|
||||
*
|
||||
* @param sess SrvSession
|
||||
* @return byte[]
|
||||
*/
|
||||
public byte[] getChallengeKey(SrvSession sess)
|
||||
{
|
||||
// In MD4 mode we generate the challenge locally
|
||||
|
||||
byte[] key = null;
|
||||
|
||||
// Check if the client is already authenticated, and it is not a null logon
|
||||
|
||||
if ( sess.hasClientInformation() && sess.getClientInformation().getAuthenticationToken() != null &&
|
||||
sess.getClientInformation().getLogonType() != ClientInfo.LogonNull)
|
||||
{
|
||||
// Return the previous challenge, user is already authenticated
|
||||
|
||||
key = sess.getChallengeKey();
|
||||
|
||||
// DEBUG
|
||||
|
||||
if ( logger.isDebugEnabled())
|
||||
logger.debug("Re-using existing challenge, already authenticated");
|
||||
}
|
||||
else if ( m_authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER)
|
||||
{
|
||||
// Generate a new challenge key, pack the key and return
|
||||
|
||||
key = new byte[8];
|
||||
|
||||
DataPacker.putIntelLong(m_random.nextLong(), key, 0);
|
||||
}
|
||||
|
||||
// Return the challenge
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform MD4 user authentication
|
||||
*
|
||||
@@ -234,7 +191,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
// Check if the client has supplied an NTLM hashed password, if not then do not allow access
|
||||
|
||||
if ( client.getPassword() == null)
|
||||
return SrvAuthenticator.AUTH_BADPASSWORD;
|
||||
return CifsAuthenticator.AUTH_BADPASSWORD;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -244,21 +201,30 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
byte[] md4byts = m_md4Encoder.decodeHash(md4hash);
|
||||
System.arraycopy(md4byts, 0, p21, 0, 16);
|
||||
|
||||
// Get the challenge that was sent to the client
|
||||
|
||||
NTLanManAuthContext authCtx = null;
|
||||
|
||||
if ( sess.hasAuthenticationContext() && sess.getAuthenticationContext() instanceof NTLanManAuthContext)
|
||||
authCtx = (NTLanManAuthContext) sess.getAuthenticationContext();
|
||||
else
|
||||
return CifsAuthenticator.AUTH_DISALLOW;
|
||||
|
||||
// Generate the local hash of the password using the same challenge
|
||||
|
||||
byte[] localHash = getEncryptor().doNTLM1Encryption(p21, sess.getChallengeKey());
|
||||
byte[] localHash = getEncryptor().doNTLM1Encryption(p21, authCtx.getChallenge());
|
||||
|
||||
// Validate the password
|
||||
|
||||
byte[] clientHash = client.getPassword();
|
||||
|
||||
if ( clientHash == null || clientHash.length != localHash.length)
|
||||
return SrvAuthenticator.AUTH_BADPASSWORD;
|
||||
return CifsAuthenticator.AUTH_BADPASSWORD;
|
||||
|
||||
for ( int i = 0; i < clientHash.length; i++)
|
||||
{
|
||||
if ( clientHash[i] != localHash[i])
|
||||
return SrvAuthenticator.AUTH_BADPASSWORD;
|
||||
return CifsAuthenticator.AUTH_BADPASSWORD;
|
||||
}
|
||||
|
||||
// Set the current user to be authenticated, save the authentication token
|
||||
@@ -271,7 +237,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
|
||||
// Passwords match, grant access
|
||||
|
||||
return SrvAuthenticator.AUTH_ALLOW;
|
||||
return CifsAuthenticator.AUTH_ALLOW;
|
||||
}
|
||||
catch (NoSuchAlgorithmException ex)
|
||||
{
|
||||
@@ -279,7 +245,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
|
||||
// Error during password check, do not allow access
|
||||
|
||||
return SrvAuthenticator.AUTH_DISALLOW;
|
||||
return CifsAuthenticator.AUTH_DISALLOW;
|
||||
}
|
||||
|
||||
// Check if this is an SMB/CIFS null session logon.
|
||||
@@ -287,10 +253,10 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
// The null session will only be allowed to connect to the IPC$ named pipe share.
|
||||
|
||||
if (client.isNullSession() && sess instanceof SMBSrvSession)
|
||||
return SrvAuthenticator.AUTH_ALLOW;
|
||||
return CifsAuthenticator.AUTH_ALLOW;
|
||||
|
||||
// User does not exist, check if guest access is allowed
|
||||
|
||||
return allowGuest() ? SrvAuthenticator.AUTH_GUEST : SrvAuthenticator.AUTH_DISALLOW;
|
||||
return allowGuest() ? CifsAuthenticator.AUTH_GUEST : CifsAuthenticator.AUTH_DISALLOW;
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.auth;
|
||||
|
||||
/**
|
||||
* CIFS Authentication Context Class
|
||||
*
|
||||
* <p>Holds authentication specific information for the negotiate/session setup phase of a new CIFS session.
|
||||
*
|
||||
* @author gkspencer
|
||||
*/
|
||||
public class AuthContext
|
||||
{
|
||||
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.auth;
|
||||
|
||||
/**
|
||||
* Authenticator Exception Class
|
||||
*
|
||||
* @author gkspencer
|
||||
*/
|
||||
public class AuthenticatorException extends Exception
|
||||
{
|
||||
private static final long serialVersionUID = 7816213724352083486L;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public AuthenticatorException()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param s String
|
||||
*/
|
||||
public AuthenticatorException(String s)
|
||||
{
|
||||
super(s);
|
||||
}
|
||||
}
|
@@ -0,0 +1,893 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.auth;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
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.Capability;
|
||||
import org.alfresco.filesys.smb.Dialect;
|
||||
import org.alfresco.filesys.smb.DialectSelector;
|
||||
import org.alfresco.filesys.smb.SMBStatus;
|
||||
import org.alfresco.filesys.smb.server.SMBSrvException;
|
||||
import org.alfresco.filesys.smb.server.SMBSrvPacket;
|
||||
import org.alfresco.filesys.smb.server.SMBSrvSession;
|
||||
import org.alfresco.filesys.smb.server.SecurityMode;
|
||||
import org.alfresco.filesys.smb.server.repo.ContentContext;
|
||||
import org.alfresco.filesys.util.DataPacker;
|
||||
import org.alfresco.filesys.util.HexDump;
|
||||
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.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;
|
||||
|
||||
/**
|
||||
* CIFS Authenticator Class
|
||||
*
|
||||
* <p>
|
||||
* An authenticator is used by the CIFS server to authenticate users when in user level access mode
|
||||
* and authenticate requests to connect to a share when in share level access.
|
||||
*/
|
||||
public abstract class CifsAuthenticator
|
||||
{
|
||||
// Logging
|
||||
|
||||
protected static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol.auth");
|
||||
|
||||
// Encryption algorithm types
|
||||
|
||||
public static final int LANMAN = PasswordEncryptor.LANMAN;
|
||||
public static final int NTLM1 = PasswordEncryptor.NTLM1;
|
||||
public static final int NTLM2 = PasswordEncryptor.NTLM2;
|
||||
|
||||
// Authentication status values
|
||||
|
||||
public static final int AUTH_ALLOW = 0;
|
||||
public static final int AUTH_GUEST = 0x10000000;
|
||||
public static final int AUTH_DISALLOW = -1;
|
||||
public static final int AUTH_BADPASSWORD = -2;
|
||||
public static final int AUTH_BADUSER = -3;
|
||||
|
||||
// Share access permissions, returned by authenticateShareConnect()
|
||||
|
||||
public static final int NoAccess = 0;
|
||||
public static final int ReadOnly = 1;
|
||||
public static final int Writeable = 2;
|
||||
|
||||
// Standard encrypted password and challenge length
|
||||
|
||||
public static final int STANDARD_PASSWORD_LEN = 24;
|
||||
public static final int STANDARD_CHALLENGE_LEN = 8;
|
||||
|
||||
// Default guest user name
|
||||
|
||||
protected static final String GUEST_USERNAME = "guest";
|
||||
|
||||
// Default SMB dialects to enable
|
||||
|
||||
private DialectSelector m_dialects;
|
||||
|
||||
// Security mode flags
|
||||
|
||||
private int m_securityMode = SecurityMode.UserMode + SecurityMode.EncryptedPasswords;
|
||||
|
||||
// Password encryption algorithms
|
||||
|
||||
private PasswordEncryptor m_encryptor = new PasswordEncryptor();
|
||||
|
||||
// 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.
|
||||
*
|
||||
* @param client User/client details from the tree connect request.
|
||||
* @param share Shared device the client wants to connect to.
|
||||
* @param pwd Share password.
|
||||
* @param sess Server session.
|
||||
* @return int Granted file permission level or disallow status if negative. See the
|
||||
* FilePermission class.
|
||||
*/
|
||||
public int authenticateShareConnect(ClientInfo client, SharedDevice share, String sharePwd, SrvSession sess)
|
||||
{
|
||||
// Allow write access
|
||||
//
|
||||
// Main authentication is handled by authenticateUser()
|
||||
|
||||
return CifsAuthenticator.Writeable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate a user. A user may be granted full access, guest access or no access.
|
||||
*
|
||||
* @param client User/client details from the session setup request.
|
||||
* @param sess Server session
|
||||
* @param alg Encryption algorithm
|
||||
* @return int Access level or disallow status.
|
||||
*/
|
||||
public int authenticateUser(ClientInfo client, SrvSession sess, int alg)
|
||||
{
|
||||
return CifsAuthenticator.AUTH_DISALLOW;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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");
|
||||
|
||||
// Allocate the SMB dialect selector, and initialize using the default list of dialects
|
||||
|
||||
m_dialects = new DialectSelector();
|
||||
|
||||
m_dialects.AddDialect(Dialect.DOSLanMan1);
|
||||
m_dialects.AddDialect(Dialect.DOSLanMan2);
|
||||
m_dialects.AddDialect(Dialect.LanMan1);
|
||||
m_dialects.AddDialect(Dialect.LanMan2);
|
||||
m_dialects.AddDialect(Dialect.LanMan2_1);
|
||||
m_dialects.AddDialect(Dialect.NT);
|
||||
|
||||
// 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());
|
||||
|
||||
// Check that the authentication component is the required type for this authenticator
|
||||
|
||||
if ( validateAuthenticationMode() == false)
|
||||
throw new InvalidConfigurationException("Required authentication mode not available");
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the authentication component supports the required mode
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected boolean validateAuthenticationMode()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt the plain text password with the specified encryption key using the specified
|
||||
* encryption algorithm.
|
||||
*
|
||||
* @param plainPwd String
|
||||
* @param encryptKey byte[]
|
||||
* @param alg int
|
||||
* @param userName String
|
||||
* @param domain String
|
||||
* @return byte[]
|
||||
*/
|
||||
protected final byte[] generateEncryptedPassword(String plainPwd, byte[] encryptKey, int alg, String userName, String domain)
|
||||
{
|
||||
|
||||
// Use the password encryptor
|
||||
|
||||
byte[] encPwd = null;
|
||||
|
||||
try
|
||||
{
|
||||
// Encrypt the password
|
||||
|
||||
encPwd = m_encryptor.generateEncryptedPassword(plainPwd, encryptKey, alg, userName, domain);
|
||||
}
|
||||
catch (NoSuchAlgorithmException ex)
|
||||
{
|
||||
}
|
||||
catch (InvalidKeyException ex)
|
||||
{
|
||||
}
|
||||
|
||||
// Return the encrypted password
|
||||
|
||||
return encPwd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an authentication context for the new session
|
||||
*
|
||||
* @return AuthContext
|
||||
*/
|
||||
public AuthContext getAuthContext( SMBSrvSession sess)
|
||||
{
|
||||
AuthContext authCtx = null;
|
||||
|
||||
if ( sess.hasAuthenticationContext() && sess.getAuthenticationContext() instanceof NTLanManAuthContext)
|
||||
{
|
||||
// Use the existing authentication context
|
||||
|
||||
authCtx = (NTLanManAuthContext) sess.getAuthenticationContext();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a new authentication context for the session
|
||||
|
||||
authCtx = new NTLanManAuthContext();
|
||||
sess.setAuthenticationContext( authCtx);
|
||||
}
|
||||
|
||||
// Return the authentication context
|
||||
|
||||
return authCtx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the enabled SMB dialects that the server will use when negotiating sessions.
|
||||
*
|
||||
* @return DialectSelector
|
||||
*/
|
||||
public final DialectSelector getEnabledDialects()
|
||||
{
|
||||
return m_dialects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the security mode flags
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int getSecurityMode()
|
||||
{
|
||||
return m_securityMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the CIFS negotiate response packet, the authenticator should add authentication specific fields
|
||||
* to the response.
|
||||
*
|
||||
* @param sess SMBSrvSession
|
||||
* @param respPkt SMBSrvPacket
|
||||
* @param extendedSecurity boolean
|
||||
* @exception AuthenticatorException
|
||||
*/
|
||||
public void generateNegotiateResponse(SMBSrvSession sess, SMBSrvPacket respPkt, boolean extendedSecurity)
|
||||
throws AuthenticatorException
|
||||
{
|
||||
// Pack the negotiate response for NT/LanMan challenge/response authentication
|
||||
|
||||
NTLanManAuthContext authCtx = (NTLanManAuthContext) getAuthContext( sess);
|
||||
|
||||
// Encryption key and primary domain string should be returned in the byte area
|
||||
|
||||
int pos = respPkt.getByteOffset();
|
||||
byte[] buf = respPkt.getBuffer();
|
||||
|
||||
if ( authCtx.getChallenge() == null)
|
||||
{
|
||||
|
||||
// Return a dummy encryption key
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
buf[pos++] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Store the encryption key
|
||||
|
||||
byte[] key = authCtx.getChallenge();
|
||||
for (int i = 0; i < key.length; i++)
|
||||
buf[pos++] = key[i];
|
||||
}
|
||||
|
||||
// Pack the local domain name
|
||||
|
||||
String domain = sess.getServer().getConfiguration().getDomainName();
|
||||
if (domain != null)
|
||||
pos = DataPacker.putString(domain, buf, pos, true, true);
|
||||
|
||||
// Pack the local server name
|
||||
|
||||
pos = DataPacker.putString( sess.getServer().getServerName(), buf, pos, true, true);
|
||||
|
||||
// Set the packet length
|
||||
|
||||
respPkt.setByteCount(pos - respPkt.getByteOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the CIFS session setup request packet and build the session setup response
|
||||
*
|
||||
* @param sess SMBSrvSession
|
||||
* @param reqPkt SMBSrvPacket
|
||||
* @param respPkt SMBSrvPacket
|
||||
* @exception SMBSrvException
|
||||
*/
|
||||
public void processSessionSetup(SMBSrvSession sess, SMBSrvPacket reqPkt, SMBSrvPacket respPkt)
|
||||
throws SMBSrvException
|
||||
{
|
||||
|
||||
// Check that the received packet looks like a valid NT session setup andX request
|
||||
|
||||
if (reqPkt.checkPacketIsValid(13, 0) == false)
|
||||
{
|
||||
throw new SMBSrvException(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
|
||||
}
|
||||
|
||||
// Extract the session details
|
||||
|
||||
int maxBufSize = reqPkt.getParameter(2);
|
||||
int maxMpx = reqPkt.getParameter(3);
|
||||
int vcNum = reqPkt.getParameter(4);
|
||||
int ascPwdLen = reqPkt.getParameter(7);
|
||||
int uniPwdLen = reqPkt.getParameter(8);
|
||||
int capabs = reqPkt.getParameterLong(11);
|
||||
|
||||
// Extract the client details from the session setup request
|
||||
|
||||
byte[] buf = reqPkt.getBuffer();
|
||||
|
||||
// Determine if ASCII or unicode strings are being used
|
||||
|
||||
boolean isUni = reqPkt.isUnicode();
|
||||
|
||||
// Extract the password strings
|
||||
|
||||
byte[] ascPwd = reqPkt.unpackBytes(ascPwdLen);
|
||||
byte[] uniPwd = reqPkt.unpackBytes(uniPwdLen);
|
||||
|
||||
// Extract the user name string
|
||||
|
||||
String user = reqPkt.unpackString(isUni);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
throw new SMBSrvException(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
|
||||
}
|
||||
|
||||
// Extract the clients primary domain name string
|
||||
|
||||
String domain = "";
|
||||
|
||||
if (reqPkt.hasMoreData())
|
||||
{
|
||||
|
||||
// Extract the callers domain name
|
||||
|
||||
domain = reqPkt.unpackString(isUni);
|
||||
|
||||
if (domain == null)
|
||||
{
|
||||
throw new SMBSrvException(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the clients native operating system
|
||||
|
||||
String clientOS = "";
|
||||
|
||||
if (reqPkt.hasMoreData())
|
||||
{
|
||||
|
||||
// Extract the callers operating system name
|
||||
|
||||
clientOS = reqPkt.unpackString(isUni);
|
||||
|
||||
if (clientOS == null)
|
||||
{
|
||||
throw new SMBSrvException(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG
|
||||
|
||||
if (logger.isDebugEnabled() && sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE))
|
||||
{
|
||||
logger.debug("NT Session setup from user=" + user + ", password="
|
||||
+ (uniPwd != null ? HexDump.hexString(uniPwd) : "none") + ", ANSIpwd="
|
||||
+ (ascPwd != null ? HexDump.hexString(ascPwd) : "none") + ", domain=" + domain + ", os=" + clientOS
|
||||
+ ", VC=" + vcNum + ", maxBuf=" + maxBufSize + ", maxMpx=" + maxMpx
|
||||
+ ", authCtx=" + sess.getAuthenticationContext());
|
||||
logger.debug(" MID=" + reqPkt.getMultiplexId() + ", UID=" + reqPkt.getUserId() + ", PID="
|
||||
+ reqPkt.getProcessId());
|
||||
}
|
||||
|
||||
// Store the client maximum buffer size, maximum multiplexed requests count and client
|
||||
// capability flags
|
||||
|
||||
sess.setClientMaximumBufferSize(maxBufSize);
|
||||
sess.setClientMaximumMultiplex(maxMpx);
|
||||
sess.setClientCapabilities(capabs);
|
||||
|
||||
// Create the client information and store in the session
|
||||
|
||||
ClientInfo client = new ClientInfo(user, uniPwd);
|
||||
client.setANSIPassword(ascPwd);
|
||||
client.setDomain(domain);
|
||||
client.setOperatingSystem(clientOS);
|
||||
|
||||
if (sess.hasRemoteAddress())
|
||||
client.setClientAddress(sess.getRemoteAddress().getHostAddress());
|
||||
|
||||
// Check if this is a null session logon
|
||||
|
||||
if (user.length() == 0 && domain.length() == 0 && uniPwdLen == 0 && ascPwdLen == 1)
|
||||
client.setLogonType(ClientInfo.LogonNull);
|
||||
|
||||
// Authenticate the user
|
||||
|
||||
boolean isGuest = false;
|
||||
|
||||
int sts = authenticateUser(client, sess, CifsAuthenticator.NTLM1);
|
||||
|
||||
if (sts > 0 && (sts & CifsAuthenticator.AUTH_GUEST) != 0)
|
||||
{
|
||||
|
||||
// Guest logon
|
||||
|
||||
isGuest = true;
|
||||
|
||||
// DEBUG
|
||||
|
||||
if (logger.isDebugEnabled() && sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE))
|
||||
logger.debug("User " + user + ", logged on as guest");
|
||||
}
|
||||
else if (sts != CifsAuthenticator.AUTH_ALLOW)
|
||||
{
|
||||
|
||||
// Check if the session already has valid client details and the new client details
|
||||
// have null username/password values
|
||||
|
||||
if (sess.getClientInformation() != null && client.getUserName().length() == 0)
|
||||
{
|
||||
|
||||
// Use the existing client information details
|
||||
|
||||
client = sess.getClientInformation();
|
||||
|
||||
// DEBUG
|
||||
|
||||
if (logger.isDebugEnabled() && sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE))
|
||||
logger.debug("Null client information, reusing existing client=" + client);
|
||||
}
|
||||
else
|
||||
{
|
||||
// DEBUG
|
||||
|
||||
if (logger.isDebugEnabled() && sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE))
|
||||
logger.debug("User " + user + ", access denied");
|
||||
|
||||
// Invalid user, reject the session setup request
|
||||
|
||||
throw new SMBSrvException(SMBStatus.NTLogonFailure, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
|
||||
}
|
||||
}
|
||||
else if (logger.isDebugEnabled() && sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE))
|
||||
{
|
||||
|
||||
// DEBUG
|
||||
|
||||
logger.debug("User " + user + " logged on "
|
||||
+ (client != null ? " (type " + client.getLogonTypeString() + ")" : ""));
|
||||
}
|
||||
|
||||
// Update the client information if not already set
|
||||
|
||||
if (sess.getClientInformation() == null
|
||||
|| sess.getClientInformation().getUserName().length() == 0)
|
||||
{
|
||||
|
||||
// Set the client details for the session
|
||||
|
||||
sess.setClientInformation(client);
|
||||
}
|
||||
|
||||
// Set the guest flag for the client, indicate that the session is logged on
|
||||
|
||||
client.setGuest(isGuest);
|
||||
sess.setLoggedOn(true);
|
||||
|
||||
// Build the session setup response SMB
|
||||
|
||||
respPkt.setParameterCount(3);
|
||||
respPkt.setParameter(0, 0); // No chained response
|
||||
respPkt.setParameter(1, 0); // Offset to chained response
|
||||
respPkt.setParameter(2, isGuest ? 1 : 0);
|
||||
respPkt.setByteCount(0);
|
||||
|
||||
respPkt.setTreeId(0);
|
||||
respPkt.setUserId(0);
|
||||
|
||||
// Set the various flags
|
||||
|
||||
int flags = respPkt.getFlags();
|
||||
flags &= ~SMBSrvPacket.FLG_CASELESS;
|
||||
respPkt.setFlags(flags);
|
||||
|
||||
int flags2 = SMBSrvPacket.FLG2_LONGFILENAMES;
|
||||
if (isUni)
|
||||
flags2 += SMBSrvPacket.FLG2_UNICODE;
|
||||
respPkt.setFlags2(flags2);
|
||||
|
||||
// Pack the OS, dialect and domain name strings.
|
||||
|
||||
int pos = respPkt.getByteOffset();
|
||||
buf = respPkt.getBuffer();
|
||||
|
||||
if (isUni)
|
||||
pos = DataPacker.wordAlign(pos);
|
||||
|
||||
pos = DataPacker.putString("Java", buf, pos, true, isUni);
|
||||
pos = DataPacker.putString("Alfresco CIFS Server " + sess.getServer().isVersion(), buf, pos, true, isUni);
|
||||
pos = DataPacker.putString(sess.getServer().getConfiguration().getDomainName(), buf, pos, true, isUni);
|
||||
|
||||
respPkt.setByteCount(pos - respPkt.getByteOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the encryption key/challenge length
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public int getEncryptionKeyLength()
|
||||
{
|
||||
return STANDARD_CHALLENGE_LEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the server capability flags
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public int getServerCapabilities()
|
||||
{
|
||||
return Capability.Unicode + Capability.RemoteAPIs + Capability.NTSMBs + Capability.NTFind +
|
||||
Capability.NTStatus + Capability.LargeFiles + Capability.LargeRead + Capability.LargeWrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if guest access is allowed
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean allowGuest()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable the guest account
|
||||
*
|
||||
* @param ena Enable the guest account if true, only allow defined user accounts access if false
|
||||
*/
|
||||
public final void setAllowGuest(boolean ena)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the security mode flags
|
||||
*
|
||||
* @param flg int
|
||||
*/
|
||||
protected final void setSecurityMode(int flg)
|
||||
{
|
||||
m_securityMode = flg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the authenticator, perform any cleanup
|
||||
*/
|
||||
public void closeAuthenticator()
|
||||
{
|
||||
// Override if cleanup required
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a password by encrypting the plain text password using the specified encryption key
|
||||
* and encryption algorithm.
|
||||
*
|
||||
* @param plainPwd String
|
||||
* @param encryptedPwd String
|
||||
* @param encryptKey byte[]
|
||||
* @param alg int
|
||||
* @param userName String
|
||||
* @param domain String
|
||||
* @return boolean
|
||||
*/
|
||||
protected final boolean validatePassword(String plainPwd, byte[] encryptedPwd, byte[] encryptKey, int alg, String userName, String domain)
|
||||
{
|
||||
|
||||
// Generate an encrypted version of the plain text password
|
||||
|
||||
byte[] encPwd = generateEncryptedPassword(plainPwd != null ? plainPwd : "", encryptKey, alg, userName, domain);
|
||||
|
||||
// Compare the generated password with the received password
|
||||
|
||||
if (encPwd != null && encryptedPwd != null && encPwd.length == STANDARD_PASSWORD_LEN
|
||||
&& encryptedPwd.length == STANDARD_PASSWORD_LEN)
|
||||
{
|
||||
|
||||
// Compare the password arrays
|
||||
|
||||
for (int i = 0; i < STANDARD_PASSWORD_LEN; i++)
|
||||
if (encPwd[i] != encryptedPwd[i])
|
||||
return false;
|
||||
|
||||
// Password is valid
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// User or password is invalid
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the password string to a byte array
|
||||
*
|
||||
* @param pwd String
|
||||
* @return byte[]
|
||||
*/
|
||||
|
||||
protected final byte[] convertPassword(String pwd)
|
||||
{
|
||||
|
||||
// Create a padded/truncated 14 character string
|
||||
|
||||
StringBuffer p14str = new StringBuffer();
|
||||
p14str.append(pwd);
|
||||
if (p14str.length() > 14)
|
||||
p14str.setLength(14);
|
||||
else
|
||||
{
|
||||
while (p14str.length() < 14)
|
||||
p14str.append((char) 0x00);
|
||||
}
|
||||
|
||||
// Convert the P14 string to an array of bytes. Allocate the return 16 byte array.
|
||||
|
||||
return p14str.toString().getBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the password encryptor
|
||||
*
|
||||
* @return PasswordEncryptor
|
||||
*/
|
||||
protected final PasswordEncryptor getEncryptor()
|
||||
{
|
||||
return m_encryptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the authentication status as a string
|
||||
*
|
||||
* @param sts int
|
||||
* @return String
|
||||
*/
|
||||
protected final String getStatusAsString(int sts)
|
||||
{
|
||||
String str = null;
|
||||
|
||||
switch ( sts)
|
||||
{
|
||||
case AUTH_ALLOW:
|
||||
str = "Allow";
|
||||
break;
|
||||
case AUTH_DISALLOW:
|
||||
str = "Disallow";
|
||||
break;
|
||||
case AUTH_GUEST:
|
||||
str = "Guest";
|
||||
break;
|
||||
case AUTH_BADPASSWORD:
|
||||
str = "BadPassword";
|
||||
break;
|
||||
case AUTH_BADUSER:
|
||||
str = "BadUser";
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
@@ -74,6 +74,14 @@ public class ClientInfo
|
||||
// Home folder node
|
||||
|
||||
private NodeRef m_homeNode;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public ClientInfo()
|
||||
{
|
||||
setUserName("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
|
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.auth;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Default authenticator class.
|
||||
* <p>
|
||||
* The default authenticator implementation enables user level security mode and allows any user to
|
||||
* connect to the server.
|
||||
*/
|
||||
public class DefaultAuthenticator extends SrvAuthenticator
|
||||
{
|
||||
|
||||
// Server configuration
|
||||
|
||||
private ServerConfiguration m_config;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*/
|
||||
public DefaultAuthenticator()
|
||||
{
|
||||
setAccessMode(USER_MODE);
|
||||
setEncryptedPasswords(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow any user to access the server
|
||||
*
|
||||
* @param client Client details.
|
||||
* @param share Shared device the user is connecting to.
|
||||
* @param pwd Share level password.
|
||||
* @param sess Server session
|
||||
* @return int
|
||||
*/
|
||||
public int authenticateShareConnect(ClientInfo client, SharedDevice share, String pwd, SrvSession sess)
|
||||
{
|
||||
return Writeable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow any user to access the server.
|
||||
*
|
||||
* @param client Client details.
|
||||
* @param sess Server session
|
||||
* @param alg Encryption algorithm
|
||||
* @return int
|
||||
*/
|
||||
public int authenticateUser(ClientInfo client, SrvSession sess, int alg)
|
||||
{
|
||||
return AUTH_ALLOW;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default authenticator does not use encrypted passwords.
|
||||
*
|
||||
* @param sess SrvSession
|
||||
* @return byte[]
|
||||
*/
|
||||
public byte[] getChallengeKey(SrvSession sess)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the requried user account details in the defined user list
|
||||
*
|
||||
* @param user String
|
||||
* @return UserAccount
|
||||
*/
|
||||
public UserAccount getUserDetails(String user)
|
||||
{
|
||||
|
||||
// Get the user account list from the configuration
|
||||
|
||||
UserAccountList userList = m_config.getUserAccounts();
|
||||
if (userList == null || userList.numberOfUsers() == 0)
|
||||
return null;
|
||||
|
||||
// Search for the required user account record
|
||||
|
||||
return userList.findUser(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialzie 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 defined user list
|
||||
|
||||
m_config = config;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -1,216 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.auth;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
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.ShareType;
|
||||
import org.alfresco.filesys.server.core.SharedDevice;
|
||||
import org.alfresco.filesys.smb.server.SMBSrvSession;
|
||||
import org.alfresco.filesys.util.DataPacker;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Local Authenticator Class.
|
||||
* <p>
|
||||
* The local authenticator implementation enables user level security mode and uses the user account
|
||||
* list that is part of the server configuration to determine if a user is allowed to access the
|
||||
* server/share.
|
||||
* <p>
|
||||
* Note: Switching off encrypted password support will cause later NT4 service pack releases and
|
||||
* Win2000 to refuse to connect to the server without a registry update on the client.
|
||||
*/
|
||||
public class LocalAuthenticator extends SrvAuthenticator
|
||||
{
|
||||
|
||||
// Random number generator used to generate challenge keys
|
||||
|
||||
private Random m_random = new Random(System.currentTimeMillis());
|
||||
|
||||
// Server configuration
|
||||
|
||||
private ServerConfiguration m_config;
|
||||
|
||||
/**
|
||||
* Local Authenticator Constructor
|
||||
* <p>
|
||||
* Default to user mode security with encrypted password support.
|
||||
*/
|
||||
public LocalAuthenticator()
|
||||
{
|
||||
setAccessMode(SrvAuthenticator.USER_MODE);
|
||||
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)
|
||||
{
|
||||
|
||||
// If the server is in share mode security allow the user access
|
||||
|
||||
if (this.getAccessMode() == SHARE_MODE)
|
||||
return SrvAuthenticator.Writeable;
|
||||
|
||||
// Check if the IPC$ share is being accessed
|
||||
|
||||
if (share.getType() == ShareType.ADMINPIPE)
|
||||
return SrvAuthenticator.Writeable;
|
||||
|
||||
// Check if the user is allowed to access the specified shared device
|
||||
//
|
||||
// If a user does not have access to the requested share the connection will still be
|
||||
// allowed
|
||||
// but any attempts to access files or search directories will result in a 'no access
|
||||
// rights'
|
||||
// error being returned to the client.
|
||||
|
||||
UserAccount user = null;
|
||||
if (client != null)
|
||||
user = getUserDetails(client.getUserName());
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
|
||||
// Check if the guest account is enabled
|
||||
|
||||
return allowGuest() ? SrvAuthenticator.Writeable : SrvAuthenticator.NoAccess;
|
||||
}
|
||||
else if (user.hasShare(share.getName()) == false)
|
||||
return SrvAuthenticator.NoAccess;
|
||||
|
||||
// Allow user to access this share
|
||||
|
||||
return SrvAuthenticator.Writeable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate a user
|
||||
*
|
||||
* @param client Client information
|
||||
* @param sess Server session
|
||||
* @param alg Encryption algorithm
|
||||
*/
|
||||
public int authenticateUser(ClientInfo client, SrvSession sess, int alg)
|
||||
{
|
||||
|
||||
// Check if the user exists in the user list
|
||||
|
||||
UserAccount userAcc = getUserDetails(client.getUserName());
|
||||
if (userAcc != null)
|
||||
{
|
||||
|
||||
// Validate the password
|
||||
|
||||
boolean authSts = false;
|
||||
|
||||
if (client.getPassword() != null)
|
||||
{
|
||||
|
||||
// Validate using the Unicode password
|
||||
|
||||
authSts = validatePassword(userAcc.getPassword(), client.getPassword(), sess.getChallengeKey(), alg);
|
||||
}
|
||||
else if (client.hasANSIPassword())
|
||||
{
|
||||
|
||||
// Validate using the ANSI password with the LanMan encryption
|
||||
|
||||
authSts = validatePassword(userAcc.getPassword(), client.getANSIPassword(), sess.getChallengeKey(),
|
||||
SrvAuthenticator.LANMAN);
|
||||
}
|
||||
|
||||
// Return the authentication status
|
||||
|
||||
return authSts == true ? SrvAuthenticator.AUTH_ALLOW : SrvAuthenticator.AUTH_BADPASSWORD;
|
||||
}
|
||||
|
||||
// Check if this is an SMB/CIFS null session logon.
|
||||
//
|
||||
// The null session will only be allowed to connect to the IPC$ named pipe share.
|
||||
|
||||
if (client.isNullSession() && sess instanceof SMBSrvSession)
|
||||
return SrvAuthenticator.AUTH_ALLOW;
|
||||
|
||||
// Unknown user
|
||||
|
||||
return allowGuest() ? SrvAuthenticator.AUTH_GUEST : SrvAuthenticator.AUTH_DISALLOW;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a challenge key
|
||||
*
|
||||
* @param sess SrvSession
|
||||
* @return byte[]
|
||||
*/
|
||||
public byte[] getChallengeKey(SrvSession sess)
|
||||
{
|
||||
|
||||
// Generate a new challenge key, pack the key and return
|
||||
|
||||
byte[] key = new byte[8];
|
||||
|
||||
DataPacker.putIntelLong(m_random.nextLong(), key, 0);
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the requried user account details in the defined user list
|
||||
*
|
||||
* @param user String
|
||||
* @return UserAccount
|
||||
*/
|
||||
public UserAccount getUserDetails(String user)
|
||||
{
|
||||
|
||||
// Get the user account list from the configuration
|
||||
|
||||
UserAccountList userList = m_config.getUserAccounts();
|
||||
if (userList == null || userList.numberOfUsers() == 0)
|
||||
return null;
|
||||
|
||||
// Search for the required user account record
|
||||
|
||||
return userList.findUser(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 defined user list
|
||||
|
||||
m_config = config;
|
||||
}
|
||||
}
|
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.auth;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.alfresco.filesys.util.DataPacker;
|
||||
import org.alfresco.filesys.util.HexDump;
|
||||
|
||||
/**
|
||||
* NTLM1/LanMan CIFS Authentication Context Class
|
||||
*
|
||||
* <p>Holds the challenge sent to the client during the negotiate phase that is used to verify the hashed password
|
||||
* in the session setup phase.
|
||||
*
|
||||
* @author gkspencer
|
||||
*/
|
||||
public class NTLanManAuthContext extends AuthContext
|
||||
{
|
||||
// Random number generator used to generate challenge
|
||||
|
||||
private static Random m_random = new Random(System.currentTimeMillis());
|
||||
|
||||
// Challenge sent to client
|
||||
|
||||
private byte[] m_challenge;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*/
|
||||
public NTLanManAuthContext()
|
||||
{
|
||||
// Generate a new challenge key, pack the key and return
|
||||
|
||||
m_challenge = new byte[8];
|
||||
DataPacker.putIntelLong(m_random.nextLong(), m_challenge, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param challenge byte[]
|
||||
*/
|
||||
public NTLanManAuthContext( byte[] challenge)
|
||||
{
|
||||
m_challenge = challenge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the challenge
|
||||
*
|
||||
* return byte[]
|
||||
*/
|
||||
public final byte[] getChallenge()
|
||||
{
|
||||
return m_challenge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CIFS authentication context as a string
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder str = new StringBuilder();
|
||||
|
||||
str.append("[NTLM,Challenge=");
|
||||
str.append(HexDump.hexString(m_challenge));
|
||||
str.append("]");
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
@@ -24,6 +24,7 @@ import java.security.NoSuchAlgorithmException;
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
@@ -75,6 +76,14 @@ public class PasswordEncryptor
|
||||
// Check if DES is available
|
||||
|
||||
Cipher.getInstance("DES");
|
||||
|
||||
// Check if HMAC-MD5 is available
|
||||
|
||||
Mac.getInstance("HMACMD5");
|
||||
|
||||
// Indicate required algorithms are available
|
||||
|
||||
algOK = true;
|
||||
}
|
||||
catch (NoSuchAlgorithmException ex)
|
||||
{
|
||||
@@ -95,13 +104,15 @@ public class PasswordEncryptor
|
||||
* @param plainPwd Plaintext password string
|
||||
* @param encryptKey byte[] Encryption key
|
||||
* @param alg int Encryption algorithm
|
||||
* @param userName String
|
||||
* @param domain String
|
||||
* @return byte[] Encrypted password
|
||||
* @exception NoSuchAlgorithmException If a required encryption algorithm is not available
|
||||
* @exception InvalidKeyException Key is invalid
|
||||
*/
|
||||
public byte[] generateEncryptedPassword(String plainPwd, byte[] encryptKey, int alg)
|
||||
throws NoSuchAlgorithmException
|
||||
public byte[] generateEncryptedPassword(String plainPwd, byte[] encryptKey, int alg, String userName, String domain)
|
||||
throws NoSuchAlgorithmException, InvalidKeyException
|
||||
{
|
||||
|
||||
// Get the password
|
||||
|
||||
String pwd = plainPwd;
|
||||
@@ -150,6 +161,41 @@ public class PasswordEncryptor
|
||||
// NTLM v2 encryption
|
||||
|
||||
case NTLM2:
|
||||
|
||||
// Get the MD4 hash of the plaintext password
|
||||
|
||||
byte[] md4Hash = generateEncryptedPassword( plainPwd, encryptKey, MD4, null, null);
|
||||
|
||||
// HMAC-MD5 the username + domain string using the MD4 hash as the key
|
||||
|
||||
Mac hmacMd5 = Mac.getInstance("HMACMD5");
|
||||
SecretKeySpec key = new SecretKeySpec( md4Hash, 0, md4Hash.length, "MD5");
|
||||
|
||||
hmacMd5.init(key);
|
||||
|
||||
// Build the username + domain string and convert to bytes
|
||||
|
||||
StringBuilder str = new StringBuilder();
|
||||
|
||||
str.append( userName.toUpperCase());
|
||||
str.append( domain.toUpperCase());
|
||||
|
||||
byte[] dataByts = null;
|
||||
|
||||
try
|
||||
{
|
||||
// Convert the string to a byte array
|
||||
|
||||
String dataStr = str.toString();
|
||||
dataByts = dataStr.getBytes("UnicodeLittleUnmarked");
|
||||
}
|
||||
catch ( UnsupportedEncodingException ex)
|
||||
{
|
||||
}
|
||||
|
||||
// Encrypt the username+domain bytes to generate the NTLMv2 hash
|
||||
|
||||
encPwd = hmacMd5.doFinal( dataByts);
|
||||
break;
|
||||
|
||||
// MD4 encryption
|
||||
@@ -414,4 +460,46 @@ public class PasswordEncryptor
|
||||
{
|
||||
return P24(p21, c8);
|
||||
}
|
||||
|
||||
/**
|
||||
* NTLM2 encryption of the MD4 hashed password
|
||||
*
|
||||
* @param md4Hash byte[]
|
||||
* @param userName String
|
||||
* @param domain String
|
||||
* @return byte[]
|
||||
* @exception NoSuchAlgorithmException
|
||||
*/
|
||||
public final byte[] doNTLM2Encryption(byte[] md4Hash, String userName, String domain)
|
||||
throws NoSuchAlgorithmException, InvalidKeyException
|
||||
{
|
||||
// Use the MD4 hashed password as the key for HMAC-MD5
|
||||
|
||||
Mac hmacMd5 = Mac.getInstance("HMACMD5");
|
||||
SecretKeySpec key = new SecretKeySpec(md4Hash, 0, md4Hash.length, "MD5");
|
||||
|
||||
hmacMd5.init( key);
|
||||
|
||||
// Build the data to be encrypted
|
||||
|
||||
StringBuilder str = new StringBuilder();
|
||||
|
||||
str.append(userName.toUpperCase());
|
||||
str.append(domain.toUpperCase());
|
||||
|
||||
String dataStr = str.toString();
|
||||
byte[] dataByts = null;
|
||||
|
||||
try
|
||||
{
|
||||
dataByts = dataStr.getBytes("UnicodeLittleUnmarked");
|
||||
}
|
||||
catch ( UnsupportedEncodingException ex)
|
||||
{
|
||||
}
|
||||
|
||||
// Encrypt the data
|
||||
|
||||
return hmacMd5.doFinal( dataByts);
|
||||
}
|
||||
}
|
||||
|
@@ -1,596 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* An authenticator is used by the SMB server to authenticate users when in user level access mode
|
||||
* and authenticate requests to connect to a share when in share level access.
|
||||
*/
|
||||
public abstract class SrvAuthenticator
|
||||
{
|
||||
// Logging
|
||||
|
||||
protected static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol.auth");
|
||||
|
||||
// Encryption algorithm types
|
||||
|
||||
public static final int LANMAN = PasswordEncryptor.LANMAN;
|
||||
public static final int NTLM1 = PasswordEncryptor.NTLM1;
|
||||
public static final int NTLM2 = PasswordEncryptor.NTLM2;
|
||||
|
||||
// Authentication status values
|
||||
|
||||
public static final int AUTH_ALLOW = 0;
|
||||
public static final int AUTH_GUEST = 0x10000000;
|
||||
public static final int AUTH_DISALLOW = -1;
|
||||
public static final int AUTH_BADPASSWORD = -2;
|
||||
public static final int AUTH_BADUSER = -3;
|
||||
|
||||
// Share access permissions, returned by authenticateShareConnect()
|
||||
|
||||
public static final int NoAccess = 0;
|
||||
public static final int ReadOnly = 1;
|
||||
public static final int Writeable = 2;
|
||||
|
||||
// Server access mode
|
||||
|
||||
public static final int SHARE_MODE = 0;
|
||||
public static final int USER_MODE = 1;
|
||||
|
||||
// Standard encrypted password length
|
||||
|
||||
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;
|
||||
|
||||
// Use encrypted password
|
||||
|
||||
private boolean m_encryptPwd = false;
|
||||
|
||||
// Password encryption algorithms
|
||||
|
||||
private PasswordEncryptor m_encryptor = new PasswordEncryptor();
|
||||
|
||||
// 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.
|
||||
*
|
||||
* @param client User/client details from the tree connect request.
|
||||
* @param share Shared device the client wants to connect to.
|
||||
* @param pwd Share password.
|
||||
* @param sess Server session.
|
||||
* @return int Granted file permission level or disallow status if negative. See the
|
||||
* FilePermission class.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param client User/client details from the session setup request.
|
||||
* @param sess Server session
|
||||
* @param alg Encryption algorithm
|
||||
* @return int Access level or disallow status.
|
||||
*/
|
||||
public abstract int authenticateUser(ClientInfo client, SrvSession sess, int alg);
|
||||
|
||||
/**
|
||||
* Return the user account details for the specified user
|
||||
*
|
||||
* @param user String
|
||||
* @return UserAccount
|
||||
*/
|
||||
public UserAccount getUserDetails(String user)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate a user using a plain text password.
|
||||
*
|
||||
* @param client User/client details from the session setup request.
|
||||
* @param sess Server session
|
||||
* @return int Access level or disallow status.
|
||||
* @throws InvalidConfigurationException
|
||||
*/
|
||||
public final int authenticateUserPlainText(ClientInfo client, SrvSession sess)
|
||||
{
|
||||
|
||||
// Get a challenge key
|
||||
|
||||
sess.setChallengeKey(getChallengeKey(sess));
|
||||
|
||||
if (sess.hasChallengeKey() == false)
|
||||
return SrvAuthenticator.AUTH_DISALLOW;
|
||||
|
||||
// Get the plain text password
|
||||
|
||||
String textPwd = client.getPasswordAsString();
|
||||
if (textPwd == null)
|
||||
textPwd = client.getANSIPasswordAsString();
|
||||
|
||||
// Encrypt the password
|
||||
|
||||
byte[] encPwd = generateEncryptedPassword(textPwd, sess.getChallengeKey(), SrvAuthenticator.NTLM1);
|
||||
client.setPassword(encPwd);
|
||||
|
||||
// Authenticate the user
|
||||
|
||||
return authenticateUser(client, sess, SrvAuthenticator.NTLM1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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");
|
||||
|
||||
// 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());
|
||||
|
||||
// Check that the authentication component is the required type for this authenticator
|
||||
|
||||
if ( validateAuthenticationMode() == false)
|
||||
throw new InvalidConfigurationException("Required authentication mode not available");
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the authentication component supports the required mode
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected boolean validateAuthenticationMode()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt the plain text password with the specified encryption key using the specified
|
||||
* encryption algorithm.
|
||||
*
|
||||
* @return byte[]
|
||||
* @param plainPwd java.lang.String
|
||||
* @param encryptKey byte[]
|
||||
* @param alg int
|
||||
*/
|
||||
protected final byte[] generateEncryptedPassword(String plainPwd, byte[] encryptKey, int alg)
|
||||
{
|
||||
|
||||
// Use the password encryptor
|
||||
|
||||
byte[] encPwd = null;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
// Encrypt the password
|
||||
|
||||
encPwd = m_encryptor.generateEncryptedPassword(plainPwd, encryptKey, alg);
|
||||
}
|
||||
catch (NoSuchAlgorithmException ex)
|
||||
{
|
||||
}
|
||||
|
||||
// Return the encrypted password
|
||||
|
||||
return encPwd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the access mode of the server, either SHARE_MODE or USER_MODE.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int getAccessMode()
|
||||
{
|
||||
return m_accessMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a challenge encryption key, when encrypted passwords are enabled.
|
||||
*
|
||||
* @param sess SrvSession
|
||||
* @return byte[]
|
||||
*/
|
||||
public abstract byte[] getChallengeKey(SrvSession sess);
|
||||
|
||||
/**
|
||||
* Determine if encrypted passwords should be used.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasEncryptPasswords()
|
||||
{
|
||||
return m_encryptPwd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if guest access is allowed
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean allowGuest()
|
||||
{
|
||||
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.
|
||||
*
|
||||
* @param mode Either SHARE_MODE or USER_MODE.
|
||||
*/
|
||||
public final void setAccessMode(int mode)
|
||||
{
|
||||
m_accessMode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set/clear the encrypted passwords flag.
|
||||
*
|
||||
* @param encFlag Encrypt passwords if true, use plain text passwords if false.
|
||||
*/
|
||||
public final void setEncryptedPasswords(boolean encFlag)
|
||||
{
|
||||
m_encryptPwd = encFlag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable the guest account
|
||||
*
|
||||
* @param ena Enable the guest account if true, only allow defined user accounts access if false
|
||||
*/
|
||||
public final void setAllowGuest(boolean ena)
|
||||
{
|
||||
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
|
||||
*/
|
||||
public void closeAuthenticator()
|
||||
{
|
||||
// Override if cleanup required
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a password by encrypting the plain text password using the specified encryption key
|
||||
* and encryption algorithm.
|
||||
*
|
||||
* @return boolean
|
||||
* @param plainPwd java.lang.String
|
||||
* @param encryptedPwd java.lang.String
|
||||
* @param encryptKey byte[]
|
||||
* @param alg int
|
||||
*/
|
||||
protected final boolean validatePassword(String plainPwd, byte[] encryptedPwd, byte[] encryptKey, int alg)
|
||||
{
|
||||
|
||||
// Generate an encrypted version of the plain text password
|
||||
|
||||
byte[] encPwd = generateEncryptedPassword(plainPwd != null ? plainPwd : "", encryptKey, alg);
|
||||
|
||||
// Compare the generated password with the received password
|
||||
|
||||
if (encPwd != null && encryptedPwd != null && encPwd.length == STANDARD_PASSWORD_LEN
|
||||
&& encryptedPwd.length == STANDARD_PASSWORD_LEN)
|
||||
{
|
||||
|
||||
// Compare the password arrays
|
||||
|
||||
for (int i = 0; i < STANDARD_PASSWORD_LEN; i++)
|
||||
if (encPwd[i] != encryptedPwd[i])
|
||||
return false;
|
||||
|
||||
// Password is valid
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// User or password is invalid
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the password string to a byte array
|
||||
*
|
||||
* @param pwd String
|
||||
* @return byte[]
|
||||
*/
|
||||
|
||||
protected final byte[] convertPassword(String pwd)
|
||||
{
|
||||
|
||||
// Create a padded/truncated 14 character string
|
||||
|
||||
StringBuffer p14str = new StringBuffer();
|
||||
p14str.append(pwd);
|
||||
if (p14str.length() > 14)
|
||||
p14str.setLength(14);
|
||||
else
|
||||
{
|
||||
while (p14str.length() < 14)
|
||||
p14str.append((char) 0x00);
|
||||
}
|
||||
|
||||
// Convert the P14 string to an array of bytes. Allocate the return 16 byte array.
|
||||
|
||||
return p14str.toString().getBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the password encryptor
|
||||
*
|
||||
* @return PasswordEncryptor
|
||||
*/
|
||||
protected final PasswordEncryptor getEncryptor()
|
||||
{
|
||||
return m_encryptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the authentication status as a string
|
||||
*
|
||||
* @param sts int
|
||||
* @return String
|
||||
*/
|
||||
protected final String getStatusAsString(int sts)
|
||||
{
|
||||
String str = null;
|
||||
|
||||
switch ( sts)
|
||||
{
|
||||
case AUTH_ALLOW:
|
||||
str = "Allow";
|
||||
break;
|
||||
case AUTH_DISALLOW:
|
||||
str = "Disallow";
|
||||
break;
|
||||
case AUTH_GUEST:
|
||||
str = "Guest";
|
||||
break;
|
||||
case AUTH_BADPASSWORD:
|
||||
str = "BadPassword";
|
||||
break;
|
||||
case AUTH_BADUSER:
|
||||
str = "BadUser";
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,331 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.auth;
|
||||
|
||||
import org.alfresco.filesys.util.StringList;
|
||||
|
||||
/**
|
||||
* User Account Class
|
||||
* <p>
|
||||
* Holds the details of a user account on the server.
|
||||
*/
|
||||
public class UserAccount
|
||||
{
|
||||
|
||||
// User name and password
|
||||
|
||||
private String m_userName;
|
||||
private String m_password;
|
||||
|
||||
// Real user name and comment
|
||||
|
||||
private String m_realName;
|
||||
private String m_comment;
|
||||
|
||||
// List of shares this user is allowed to use
|
||||
|
||||
private StringList m_shares;
|
||||
|
||||
// Administrator flag
|
||||
|
||||
private boolean m_admin;
|
||||
|
||||
// Home directory
|
||||
|
||||
private String m_homeDir;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public UserAccount()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a user with the specified name and password.
|
||||
*
|
||||
* @param user String
|
||||
* @param pwd String
|
||||
*/
|
||||
public UserAccount(String user, String pwd)
|
||||
{
|
||||
setUserName(user);
|
||||
setPassword(pwd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the specified share to the list of allowed shares for this user.
|
||||
*
|
||||
* @param shr java.lang.String
|
||||
*/
|
||||
public final void addShare(String shr)
|
||||
{
|
||||
if (m_shares == null)
|
||||
m_shares = new StringList();
|
||||
m_shares.addString(shr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this user is allowed to access the specified share.
|
||||
*
|
||||
* @return boolean
|
||||
* @param shr java.lang.String
|
||||
*/
|
||||
public final boolean allowsShare(String shr)
|
||||
{
|
||||
if (m_shares == null)
|
||||
return true;
|
||||
else if (m_shares.containsString(shr))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user has a home direectory configured
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasHomeDirectory()
|
||||
{
|
||||
return m_homeDir != null ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the home directory for this user
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public final String getHomeDirectory()
|
||||
{
|
||||
return m_homeDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the password
|
||||
*
|
||||
* @return java.lang.String
|
||||
*/
|
||||
public final String getPassword()
|
||||
{
|
||||
return m_password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the user name.
|
||||
*
|
||||
* @return java.lang.String
|
||||
*/
|
||||
public final String getUserName()
|
||||
{
|
||||
return m_userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the real user name
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public final String getRealName()
|
||||
{
|
||||
return m_realName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the user comment
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public final String getComment()
|
||||
{
|
||||
return m_comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the specified share is listed in the users allowed list.
|
||||
*
|
||||
* @return boolean
|
||||
* @param shr java.lang.String
|
||||
*/
|
||||
public final boolean hasShare(String shr)
|
||||
{
|
||||
if (m_shares != null && m_shares.containsString(shr) == false)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detemrine if this account is restricted to using certain shares only.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasShareRestrictions()
|
||||
{
|
||||
return m_shares == null ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of shares
|
||||
*
|
||||
* @return StringList
|
||||
*/
|
||||
public final StringList getShareList()
|
||||
{
|
||||
return m_shares;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this user in an administrator.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean isAdministrator()
|
||||
{
|
||||
return m_admin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all shares from the list of restricted shares.
|
||||
*/
|
||||
public final void removeAllShares()
|
||||
{
|
||||
m_shares = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified share from the list of shares this user is allowed to access.
|
||||
*
|
||||
* @param shr java.lang.String
|
||||
*/
|
||||
public final void removeShare(String shr)
|
||||
{
|
||||
|
||||
// Check if the share list has been allocated
|
||||
|
||||
if (m_shares != null)
|
||||
{
|
||||
|
||||
// Remove the share from the list
|
||||
|
||||
m_shares.removeString(shr);
|
||||
|
||||
// Check if the list is empty
|
||||
|
||||
if (m_shares.numberOfStrings() == 0)
|
||||
m_shares = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the administrator flag.
|
||||
*
|
||||
* @param admin boolean
|
||||
*/
|
||||
public final void setAdministrator(boolean admin)
|
||||
{
|
||||
m_admin = admin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user home directory
|
||||
*
|
||||
* @param home String
|
||||
*/
|
||||
public final void setHomeDirectory(String home)
|
||||
{
|
||||
m_homeDir = home;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the password for this account.
|
||||
*
|
||||
* @param pwd java.lang.String
|
||||
*/
|
||||
public final void setPassword(String pwd)
|
||||
{
|
||||
m_password = pwd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user name.
|
||||
*
|
||||
* @param user java.lang.String
|
||||
*/
|
||||
public final void setUserName(String user)
|
||||
{
|
||||
m_userName = user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the real user name
|
||||
*
|
||||
* @param name String
|
||||
*/
|
||||
public final void setRealName(String name)
|
||||
{
|
||||
m_realName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the comment
|
||||
*
|
||||
* @param comment String
|
||||
*/
|
||||
public final void setComment(String comment)
|
||||
{
|
||||
m_comment = comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the user account as a string.
|
||||
*
|
||||
* @return java.lang.String
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer str = new StringBuffer();
|
||||
|
||||
str.append("[");
|
||||
str.append(getUserName());
|
||||
str.append(":");
|
||||
str.append(getPassword());
|
||||
|
||||
if (isAdministrator())
|
||||
str.append("(ADMIN)");
|
||||
|
||||
str.append(",Real=");
|
||||
|
||||
str.append(getRealName());
|
||||
str.append(",Comment=");
|
||||
str.append(getComment());
|
||||
str.append(",Allow=");
|
||||
|
||||
if (m_shares == null)
|
||||
str.append("<ALL>");
|
||||
else
|
||||
str.append(m_shares);
|
||||
str.append("]");
|
||||
|
||||
str.append(",Home=");
|
||||
if (hasHomeDirectory())
|
||||
str.append(getHomeDirectory());
|
||||
else
|
||||
str.append("None");
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
}
|
@@ -1,195 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.auth;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* User Account List Class
|
||||
*/
|
||||
public class UserAccountList
|
||||
{
|
||||
|
||||
// User account list
|
||||
|
||||
private Vector<UserAccount> m_users;
|
||||
|
||||
/**
|
||||
* Create a user account list.
|
||||
*/
|
||||
public UserAccountList()
|
||||
{
|
||||
m_users = new Vector<UserAccount>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a user to the list of accounts.
|
||||
*
|
||||
* @param user UserAccount
|
||||
*/
|
||||
public final void addUser(UserAccount user)
|
||||
{
|
||||
|
||||
// Check if the user exists on the list
|
||||
|
||||
removeUser(user);
|
||||
m_users.add(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the required user account details.
|
||||
*
|
||||
* @param user java.lang.String
|
||||
* @return UserAccount
|
||||
*/
|
||||
public final UserAccount findUser(String user)
|
||||
{
|
||||
|
||||
// Search for the specified user account
|
||||
|
||||
for (int i = 0; i < m_users.size(); i++)
|
||||
{
|
||||
UserAccount acc = m_users.get(i);
|
||||
if (acc.getUserName().equalsIgnoreCase(user))
|
||||
return acc;
|
||||
}
|
||||
|
||||
// User not found
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the specified user account exists in the list.
|
||||
*
|
||||
* @return boolean
|
||||
* @param user java.lang.String
|
||||
*/
|
||||
public final boolean hasUser(String user)
|
||||
{
|
||||
|
||||
// Search for the specified user account
|
||||
|
||||
for (int i = 0; i < m_users.size(); i++)
|
||||
{
|
||||
UserAccount acc = m_users.get(i);
|
||||
if (acc.getUserName().compareTo(user) == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
// User not found
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the specified user account details
|
||||
*
|
||||
* @param idx int
|
||||
* @return UserAccount
|
||||
*/
|
||||
public final UserAccount getUserAt(int idx)
|
||||
{
|
||||
if (idx >= m_users.size())
|
||||
return null;
|
||||
return m_users.get(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of defined user accounts.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int numberOfUsers()
|
||||
{
|
||||
return m_users.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all user accounts from the list.
|
||||
*/
|
||||
public final void removeAllUsers()
|
||||
{
|
||||
m_users.removeAllElements();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remvoe the specified user account from the list.
|
||||
*
|
||||
* @param userAcc UserAccount
|
||||
*/
|
||||
public final void removeUser(UserAccount userAcc)
|
||||
{
|
||||
|
||||
// Search for the specified user account
|
||||
|
||||
for (int i = 0; i < m_users.size(); i++)
|
||||
{
|
||||
UserAccount acc = m_users.get(i);
|
||||
if (acc.getUserName().compareTo(userAcc.getUserName()) == 0)
|
||||
{
|
||||
m_users.remove(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remvoe the specified user account from the list.
|
||||
*
|
||||
* @param user java.lang.String
|
||||
*/
|
||||
public final void removeUser(String user)
|
||||
{
|
||||
|
||||
// Search for the specified user account
|
||||
|
||||
for (int i = 0; i < m_users.size(); i++)
|
||||
{
|
||||
UserAccount acc = m_users.get(i);
|
||||
if (acc.getUserName().compareTo(user) == 0)
|
||||
{
|
||||
m_users.remove(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the user account list as a string.
|
||||
*
|
||||
* @return java.lang.String
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer str = new StringBuffer();
|
||||
|
||||
str.append("[");
|
||||
str.append(m_users.size());
|
||||
str.append(":");
|
||||
|
||||
for (int i = 0; i < m_users.size(); i++)
|
||||
{
|
||||
UserAccount acc = m_users.get(i);
|
||||
str.append(acc.getUserName());
|
||||
str.append(",");
|
||||
}
|
||||
str.append("]");
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.auth.kerberos;
|
||||
|
||||
import org.ietf.jgss.GSSName;
|
||||
|
||||
/**
|
||||
* Kerberos Details Class
|
||||
*
|
||||
* <p>Holds the Kerberos response token and session details about the user.
|
||||
*
|
||||
* @author gkspencer
|
||||
*/
|
||||
public class KerberosDetails
|
||||
{
|
||||
// Source and target details
|
||||
|
||||
private String m_krbSource;
|
||||
private String m_krbTarget;
|
||||
|
||||
// Kerberos response token
|
||||
|
||||
private byte[] m_krbResponse;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param source GSSName
|
||||
* @param target GSSName
|
||||
* @param response byte[]
|
||||
*/
|
||||
public KerberosDetails(GSSName source, GSSName target, byte[] response)
|
||||
{
|
||||
m_krbSource = source.toString();
|
||||
m_krbTarget = target.toString();
|
||||
|
||||
m_krbResponse = response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the context initiator for the Kerberos authentication
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public final String getSourceName()
|
||||
{
|
||||
return m_krbSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the context acceptor for the Kerberos authentication
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public final String getTargetName()
|
||||
{
|
||||
return m_krbTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Kerberos response token
|
||||
*
|
||||
* @return byte[]
|
||||
*/
|
||||
public final byte[] getResponseToken()
|
||||
{
|
||||
return m_krbResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the source name to return the user name part only
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public final String getUserName()
|
||||
{
|
||||
String userName = m_krbSource;
|
||||
|
||||
if ( m_krbSource != null)
|
||||
{
|
||||
int pos = m_krbSource.indexOf( '@');
|
||||
if ( pos != -1)
|
||||
{
|
||||
userName = m_krbSource.substring(0, pos);
|
||||
}
|
||||
}
|
||||
|
||||
return userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the response token length
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int getResponseLength()
|
||||
{
|
||||
return m_krbResponse != null ? m_krbResponse.length : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Kerberos authentication details as a string
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder str = new StringBuilder();
|
||||
|
||||
str.append("[Source=");
|
||||
str.append(getSourceName());
|
||||
str.append(",Target=");
|
||||
str.append(getTargetName());
|
||||
str.append(":Response=");
|
||||
str.append(getResponseLength());
|
||||
str.append(" bytes]");
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.auth.kerberos;
|
||||
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
import org.alfresco.filesys.server.auth.spnego.OID;
|
||||
import org.ietf.jgss.GSSContext;
|
||||
import org.ietf.jgss.GSSCredential;
|
||||
import org.ietf.jgss.GSSException;
|
||||
import org.ietf.jgss.GSSManager;
|
||||
import org.ietf.jgss.GSSName;
|
||||
|
||||
/**
|
||||
* Session Setup Privileged Action Class
|
||||
*
|
||||
* <p>Handle the processing of a received SPNEGO packet in the context of the CIFS server.
|
||||
*
|
||||
* @author gkspencer
|
||||
*/
|
||||
public class SessionSetupPrivilegedAction implements PrivilegedAction
|
||||
{
|
||||
// Received security blob details
|
||||
|
||||
private byte[] m_secBlob;
|
||||
private int m_secOffset;
|
||||
private int m_secLen;
|
||||
|
||||
// CIFS server account name
|
||||
|
||||
private String m_accountName;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param accountName String
|
||||
* @param secBlob byte[]
|
||||
*/
|
||||
public SessionSetupPrivilegedAction ( String accountName, byte[] secBlob)
|
||||
{
|
||||
m_accountName = accountName;
|
||||
|
||||
m_secBlob = secBlob;
|
||||
m_secOffset = 0;
|
||||
m_secLen = secBlob.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param accountName String
|
||||
* @param secBlob byte[]
|
||||
* @param secOffset int
|
||||
* @param secLen int
|
||||
*/
|
||||
public SessionSetupPrivilegedAction ( String accountName, byte[] secBlob, int secOffset, int secLen)
|
||||
{
|
||||
m_accountName = accountName;
|
||||
|
||||
m_secBlob = secBlob;
|
||||
m_secOffset = secOffset;
|
||||
m_secLen = secLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the privileged action
|
||||
*/
|
||||
public Object run()
|
||||
{
|
||||
KerberosDetails krbDetails = null;
|
||||
|
||||
try
|
||||
{
|
||||
GSSManager gssManager = GSSManager.getInstance();
|
||||
GSSName serverGSSName = gssManager.createName(m_accountName, GSSName.NT_USER_NAME);
|
||||
GSSCredential serverGSSCreds = gssManager.createCredential( serverGSSName, GSSCredential.INDEFINITE_LIFETIME,
|
||||
OID.KERBEROS5, GSSCredential.ACCEPT_ONLY);
|
||||
|
||||
GSSContext serverGSSContext = gssManager.createContext( serverGSSCreds);
|
||||
|
||||
// Accept the incoming security blob and generate the response blob
|
||||
|
||||
byte[] respBlob = serverGSSContext.acceptSecContext( m_secBlob, m_secOffset, m_secLen);
|
||||
|
||||
// Create the Kerberos response details
|
||||
|
||||
krbDetails = new KerberosDetails( serverGSSContext.getSrcName(), serverGSSContext.getTargName(), respBlob);
|
||||
}
|
||||
catch (GSSException ex)
|
||||
{
|
||||
System.out.println("GSSException: " + ex.getMajorString());
|
||||
System.out.println(" " + ex.getMessage());
|
||||
}
|
||||
|
||||
// Return the Kerberos response
|
||||
|
||||
return krbDetails;
|
||||
}
|
||||
}
|
@@ -20,8 +20,9 @@ import java.security.NoSuchAlgorithmException;
|
||||
import net.sf.acegisecurity.Authentication;
|
||||
|
||||
import org.alfresco.filesys.server.SrvSession;
|
||||
import org.alfresco.filesys.server.auth.CifsAuthenticator;
|
||||
import org.alfresco.filesys.server.auth.ClientInfo;
|
||||
import org.alfresco.filesys.server.auth.SrvAuthenticator;
|
||||
import org.alfresco.filesys.server.auth.NTLanManAuthContext;
|
||||
import org.alfresco.filesys.smb.server.SMBSrvSession;
|
||||
import org.alfresco.filesys.util.DataPacker;
|
||||
import org.alfresco.repo.security.authentication.NTLMMode;
|
||||
@@ -38,7 +39,7 @@ import org.alfresco.repo.security.authentication.ntlm.NTLMPassthruToken;
|
||||
*
|
||||
* @author GKSpencer
|
||||
*/
|
||||
public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
public class AlfrescoAuthenticator extends CifsAuthenticator
|
||||
{
|
||||
/**
|
||||
* Default Constructor
|
||||
@@ -47,8 +48,6 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
*/
|
||||
public AlfrescoAuthenticator()
|
||||
{
|
||||
setAccessMode(SrvAuthenticator.USER_MODE);
|
||||
setEncryptedPasswords(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,7 +85,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
if ( logger.isDebugEnabled())
|
||||
logger.debug("Null CIFS logon allowed");
|
||||
|
||||
return SrvAuthenticator.AUTH_ALLOW;
|
||||
return CifsAuthenticator.AUTH_ALLOW;
|
||||
}
|
||||
|
||||
// Check if the client is already authenticated, and it is not a null logon
|
||||
@@ -196,12 +195,13 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
|
||||
// Check if the client is already authenticated, and it is not a null logon
|
||||
|
||||
if ( sess.hasClientInformation() && sess.getClientInformation().getAuthenticationToken() != null &&
|
||||
if ( sess.hasAuthenticationContext() && sess.hasAuthenticationToken() &&
|
||||
sess.getClientInformation().getLogonType() != ClientInfo.LogonNull)
|
||||
{
|
||||
// Return the previous challenge, user is already authenticated
|
||||
|
||||
key = sess.getChallengeKey();
|
||||
|
||||
NTLanManAuthContext authCtx = (NTLanManAuthContext) sess.getAuthenticationContext();
|
||||
key = authCtx.getChallenge();
|
||||
|
||||
// DEBUG
|
||||
|
||||
@@ -260,7 +260,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
// Check if the client has supplied an NTLM hashed password, if not then do not allow access
|
||||
|
||||
if ( client.getPassword() == null)
|
||||
return SrvAuthenticator.AUTH_BADPASSWORD;
|
||||
return CifsAuthenticator.AUTH_BADPASSWORD;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -270,21 +270,30 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
byte[] md4byts = m_md4Encoder.decodeHash(md4hash);
|
||||
System.arraycopy(md4byts, 0, p21, 0, 16);
|
||||
|
||||
// Get the challenge that was sent to the client
|
||||
|
||||
NTLanManAuthContext authCtx = null;
|
||||
|
||||
if ( sess.hasAuthenticationContext() && sess.getAuthenticationContext() instanceof NTLanManAuthContext)
|
||||
authCtx = (NTLanManAuthContext) sess.getAuthenticationContext();
|
||||
else
|
||||
return CifsAuthenticator.AUTH_DISALLOW;
|
||||
|
||||
// Generate the local hash of the password using the same challenge
|
||||
|
||||
byte[] localHash = getEncryptor().doNTLM1Encryption(p21, sess.getChallengeKey());
|
||||
byte[] localHash = getEncryptor().doNTLM1Encryption(p21, authCtx.getChallenge());
|
||||
|
||||
// Validate the password
|
||||
|
||||
byte[] clientHash = client.getPassword();
|
||||
|
||||
if ( clientHash == null || clientHash.length != localHash.length)
|
||||
return SrvAuthenticator.AUTH_BADPASSWORD;
|
||||
return CifsAuthenticator.AUTH_BADPASSWORD;
|
||||
|
||||
for ( int i = 0; i < clientHash.length; i++)
|
||||
{
|
||||
if ( clientHash[i] != localHash[i])
|
||||
return SrvAuthenticator.AUTH_BADPASSWORD;
|
||||
return CifsAuthenticator.AUTH_BADPASSWORD;
|
||||
}
|
||||
|
||||
// Set the current user to be authenticated, save the authentication token
|
||||
@@ -297,7 +306,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
|
||||
// Passwords match, grant access
|
||||
|
||||
return SrvAuthenticator.AUTH_ALLOW;
|
||||
return CifsAuthenticator.AUTH_ALLOW;
|
||||
}
|
||||
catch (NoSuchAlgorithmException ex)
|
||||
{
|
||||
@@ -305,7 +314,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
|
||||
// Error during password check, do not allow access
|
||||
|
||||
return SrvAuthenticator.AUTH_DISALLOW;
|
||||
return CifsAuthenticator.AUTH_DISALLOW;
|
||||
}
|
||||
|
||||
// Check if this is an SMB/CIFS null session logon.
|
||||
@@ -313,11 +322,11 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
// The null session will only be allowed to connect to the IPC$ named pipe share.
|
||||
|
||||
if (client.isNullSession() && sess instanceof SMBSrvSession)
|
||||
return SrvAuthenticator.AUTH_ALLOW;
|
||||
return CifsAuthenticator.AUTH_ALLOW;
|
||||
|
||||
// User does not exist, check if guest access is allowed
|
||||
|
||||
return allowGuest() ? SrvAuthenticator.AUTH_GUEST : SrvAuthenticator.AUTH_DISALLOW;
|
||||
return allowGuest() ? CifsAuthenticator.AUTH_GUEST : CifsAuthenticator.AUTH_DISALLOW;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -335,11 +344,11 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
NTLMPassthruToken authToken = (NTLMPassthruToken) sess.getAuthenticationToken();
|
||||
|
||||
if ( authToken == null)
|
||||
return SrvAuthenticator.AUTH_DISALLOW;
|
||||
return CifsAuthenticator.AUTH_DISALLOW;
|
||||
|
||||
// Get the appropriate hashed password for the algorithm
|
||||
|
||||
int authSts = SrvAuthenticator.AUTH_DISALLOW;
|
||||
int authSts = CifsAuthenticator.AUTH_DISALLOW;
|
||||
byte[] hashedPassword = null;
|
||||
|
||||
if ( alg == NTLM1)
|
||||
@@ -350,7 +359,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
{
|
||||
// Invalid/unsupported algorithm specified
|
||||
|
||||
return SrvAuthenticator.AUTH_DISALLOW;
|
||||
return CifsAuthenticator.AUTH_DISALLOW;
|
||||
}
|
||||
|
||||
// Set the username and hashed password in the authentication token
|
||||
@@ -379,7 +388,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
|
||||
// Allow the user access as a guest
|
||||
|
||||
authSts = SrvAuthenticator.AUTH_GUEST;
|
||||
authSts = CifsAuthenticator.AUTH_GUEST;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -387,7 +396,7 @@ public class AlfrescoAuthenticator extends SrvAuthenticator
|
||||
|
||||
// Allow the user full access to the server
|
||||
|
||||
authSts = SrvAuthenticator.AUTH_ALLOW;
|
||||
authSts = CifsAuthenticator.AUTH_ALLOW;
|
||||
}
|
||||
|
||||
// Set the current user to be authenticated, save the authentication token
|
||||
|
@@ -42,14 +42,15 @@ public class NTLM
|
||||
public static final int FlagNegotiateSeal = 0x00000020;
|
||||
public static final int FlagDatagramStyle = 0x00000040;
|
||||
public static final int FlagLanManKey = 0x00000080;
|
||||
public static final int FlagNegotiateNetware = 0x00000100;
|
||||
public static final int FlagNegotiateNTLM = 0x00000200;
|
||||
public static final int FlagDomainSupplied = 0x00001000;
|
||||
public static final int FlagWorkstationSupplied = 0x00002000;
|
||||
public static final int FlagLocalCall = 0x00004000;
|
||||
public static final int FlagAlwaysSign = 0x00008000;
|
||||
public static final int FlagTypeDomain = 0x00010000;
|
||||
public static final int FlagTypeServer = 0x00020000;
|
||||
public static final int FlagTypeShare = 0x00040000;
|
||||
public static final int FlagChallengeInit = 0x00010000;
|
||||
public static final int FlagChallengeAccept = 0x00020000;
|
||||
public static final int FlagChallengeNonNT = 0x00040000;
|
||||
public static final int FlagNTLM2Key = 0x00080000;
|
||||
public static final int FlagTargetInfo = 0x00800000;
|
||||
public static final int Flag128Bit = 0x20000000;
|
||||
|
@@ -204,7 +204,7 @@ public abstract class NTLMMessage
|
||||
*/
|
||||
protected final int getByteOffset(int offset)
|
||||
{
|
||||
return getIntValue(m_offset + offset + 4);
|
||||
return getIntValue(offset + 4);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,11 +217,11 @@ public abstract class NTLMMessage
|
||||
{
|
||||
// Get the byte block length
|
||||
|
||||
int bLen = getShortValue(m_offset + offset);
|
||||
int bLen = getShortValue(offset);
|
||||
if ( bLen == 0)
|
||||
return null;
|
||||
|
||||
int bOff = getIntValue(m_offset + offset + 4);
|
||||
int bOff = getIntValue(offset + 4);
|
||||
return getRawBytes(bOff, bLen);
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.auth.ntlm;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.alfresco.filesys.smb.NTTime;
|
||||
import org.alfresco.filesys.util.DataPacker;
|
||||
import org.alfresco.filesys.util.HexDump;
|
||||
|
||||
/**
|
||||
* NTLMv2 Blob Class
|
||||
*
|
||||
* <P>Contains methods to pack/unpack and calculate the hash of an NTLMv2 blob.
|
||||
*
|
||||
* @author gkspencer
|
||||
*/
|
||||
public class NTLMv2Blob
|
||||
{
|
||||
// Constants
|
||||
|
||||
public static final int HMAC_LEN = 16;
|
||||
public static final int CHALLENGE_LEN = 8;
|
||||
|
||||
// Offsets
|
||||
|
||||
public static final int OFFSET_HMAC = 0;
|
||||
public static final int OFFSET_HEADER = 16;
|
||||
public static final int OFFSET_RESERVED = 20;
|
||||
public static final int OFFSET_TIMESTAMP = 24;
|
||||
public static final int OFFSET_CHALLENGE = 32;
|
||||
public static final int OFFSET_UNKNOWN = 36;
|
||||
public static final int OFFSET_TARGETINFO = 40;
|
||||
|
||||
// NTLMv2 blob
|
||||
|
||||
private byte[] m_blob;
|
||||
private int m_offset;
|
||||
private int m_len;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param buf byte[]
|
||||
*/
|
||||
public NTLMv2Blob(byte[] buf)
|
||||
{
|
||||
m_blob = buf;
|
||||
m_offset = 0;
|
||||
m_len = m_blob.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param buf byte[]
|
||||
* @param offset int
|
||||
* @param len int
|
||||
*/
|
||||
public NTLMv2Blob(byte[] buf, int offset, int len)
|
||||
{
|
||||
m_blob = buf;
|
||||
m_offset = offset;
|
||||
m_len = len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer
|
||||
*
|
||||
* @return byte[]
|
||||
*/
|
||||
public final byte[] getBuffer()
|
||||
{
|
||||
return m_blob;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the offset
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int getOffset()
|
||||
{
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the blob length
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int getLength()
|
||||
{
|
||||
return m_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the HMAC from the buffer
|
||||
*
|
||||
* @return byte[]
|
||||
*/
|
||||
public final byte[] getHMAC()
|
||||
{
|
||||
byte[] hmac = new byte[HMAC_LEN];
|
||||
System.arraycopy(m_blob, m_offset, hmac, 0, HMAC_LEN);
|
||||
|
||||
return hmac;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the timestamp from the buffer, in NT 64bit time format
|
||||
*
|
||||
* @return long
|
||||
*/
|
||||
public final long getTimeStamp()
|
||||
{
|
||||
return DataPacker.getIntelLong(m_blob, m_offset + OFFSET_TIMESTAMP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the client challenge
|
||||
*
|
||||
* @return byte[]
|
||||
*/
|
||||
public final byte[] getClientChallenge()
|
||||
{
|
||||
byte[] challenge = new byte[CHALLENGE_LEN];
|
||||
System.arraycopy( m_blob, m_offset + OFFSET_CHALLENGE, challenge, 0, CHALLENGE_LEN);
|
||||
|
||||
return challenge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the HMAC of the blob using the specified NTLMv2 hash and challenge
|
||||
*
|
||||
* @param challenge byte[]
|
||||
* @param v2hash byte[]
|
||||
* @return byte[]
|
||||
* @exception Exception
|
||||
*/
|
||||
public final byte[] calculateHMAC( byte[] challenge, byte[] v2hash)
|
||||
throws Exception
|
||||
{
|
||||
// Create a copy of the NTLMv2 blob with room for the challenge
|
||||
|
||||
byte[] blob = new byte[(m_len - HMAC_LEN) + CHALLENGE_LEN];
|
||||
System.arraycopy( challenge, 0, blob, 0, CHALLENGE_LEN);
|
||||
System.arraycopy( m_blob, m_offset + OFFSET_HEADER, blob, CHALLENGE_LEN, m_len - HMAC_LEN);
|
||||
|
||||
// Generate the HMAC of the blob using the v2 hash as the key
|
||||
|
||||
Mac hmacMd5 = Mac.getInstance( "HMACMD5");
|
||||
SecretKeySpec blobKey = new SecretKeySpec( v2hash, 0, v2hash.length, "MD5");
|
||||
|
||||
hmacMd5.init( blobKey);
|
||||
return hmacMd5.doFinal( blob);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the NTLMv2 blob details
|
||||
*/
|
||||
public final void Dump()
|
||||
{
|
||||
System.out.println("NTLMv2 blob :");
|
||||
System.out.println(" HMAC : " + HexDump.hexString( getHMAC()));
|
||||
System.out.println(" Header : 0x" + Integer.toHexString(DataPacker.getIntelInt( m_blob, m_offset + OFFSET_HEADER)));
|
||||
System.out.println(" Timestamp : " + new Date(NTTime.toJavaDate( getTimeStamp())));
|
||||
System.out.println(" Challenge : " + HexDump.hexString( getClientChallenge()));
|
||||
}
|
||||
}
|
@@ -92,6 +92,16 @@ public class Type3NTLMMessage extends NTLMMessage
|
||||
return getIntValue(OffsetFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the length of the LM hash
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int getLMHashLength()
|
||||
{
|
||||
return getShortValue(OffsetLMResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the LM password hash
|
||||
*
|
||||
@@ -102,6 +112,16 @@ public class Type3NTLMMessage extends NTLMMessage
|
||||
return getByteValue(OffsetLMResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the length of the NTLM hash
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int getNTLMHashLength()
|
||||
{
|
||||
return getShortValue(OffsetNTLMResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the NTLM password hash
|
||||
*
|
||||
|
@@ -1,289 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.auth.passthru;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.sf.acegisecurity.AuthenticationManager;
|
||||
import net.sf.acegisecurity.providers.ProviderManager;
|
||||
|
||||
import org.alfresco.config.ConfigElement;
|
||||
import org.alfresco.filesys.server.SrvSession;
|
||||
import org.alfresco.filesys.server.auth.ClientInfo;
|
||||
import org.alfresco.filesys.server.auth.SrvAuthenticator;
|
||||
import org.alfresco.filesys.server.auth.UserAccount;
|
||||
import org.alfresco.filesys.server.config.InvalidConfigurationException;
|
||||
import org.alfresco.filesys.server.config.ServerConfiguration;
|
||||
import org.alfresco.filesys.server.core.SharedDevice;
|
||||
import org.alfresco.repo.security.authentication.ntlm.NTLMAuthenticationProvider;
|
||||
import org.alfresco.repo.security.authentication.ntlm.NTLMPassthruToken;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* <p>Passthru authenticator implementation that uses the Acegi NTLM passthru authentication provider
|
||||
*
|
||||
* @author GKSpencer
|
||||
*/
|
||||
public class AcegiPassthruAuthenticator extends SrvAuthenticator
|
||||
{
|
||||
// Debug logging
|
||||
|
||||
private static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol.auth");
|
||||
|
||||
// Constants
|
||||
//
|
||||
// Default authentication manager bean name
|
||||
|
||||
private static final String DefaultAuthManagerName = "authenticationManager";
|
||||
|
||||
// Acegi authentication manager
|
||||
|
||||
private AuthenticationManager m_authMgr;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public AcegiPassthruAuthenticator()
|
||||
{
|
||||
setAccessMode(SrvAuthenticator.USER_MODE);
|
||||
setEncryptedPasswords(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate the connection to a particular share, called when the SMB server is in share
|
||||
* security mode
|
||||
*
|
||||
* @param client ClientInfo
|
||||
* @param share SharedDevice
|
||||
* @param sharePwd String
|
||||
* @param sess SrvSession
|
||||
* @return int
|
||||
*/
|
||||
public int authenticateShareConnect(ClientInfo client, SharedDevice share, String sharePwd, SrvSession sess)
|
||||
{
|
||||
return SrvAuthenticator.Writeable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate a session setup by a user
|
||||
*
|
||||
* @param client ClientInfo
|
||||
* @param sess SrvSession
|
||||
* @param alg int
|
||||
* @return int
|
||||
*/
|
||||
public int authenticateUser(ClientInfo client, SrvSession sess, int alg)
|
||||
{
|
||||
// Get the authentication token for the session
|
||||
|
||||
NTLMPassthruToken authToken = (NTLMPassthruToken) sess.getAuthenticationToken();
|
||||
|
||||
if ( authToken == null)
|
||||
return SrvAuthenticator.AUTH_DISALLOW;
|
||||
|
||||
// Get the appropriate hashed password for the algorithm
|
||||
|
||||
int authSts = SrvAuthenticator.AUTH_DISALLOW;
|
||||
byte[] hashedPassword = null;
|
||||
|
||||
if ( alg == NTLM1)
|
||||
hashedPassword = client.getPassword();
|
||||
else if ( alg == LANMAN)
|
||||
hashedPassword = client.getANSIPassword();
|
||||
else
|
||||
{
|
||||
// Debug
|
||||
|
||||
if ( logger.isDebugEnabled())
|
||||
logger.debug("Invalid algorithm specified for user authentication (" + alg + ")");
|
||||
|
||||
// Invalid/unsupported algorithm specified
|
||||
|
||||
return SrvAuthenticator.AUTH_DISALLOW;
|
||||
}
|
||||
|
||||
// Set the username and hashed password in the authentication token
|
||||
|
||||
authToken.setUserAndPassword( client.getUserName(), hashedPassword, alg);
|
||||
|
||||
// Authenticate the user
|
||||
|
||||
try
|
||||
{
|
||||
// Run the second stage of the passthru authentication
|
||||
|
||||
m_authMgr.authenticate( authToken);
|
||||
|
||||
// Check if the user has been logged on as a guest
|
||||
|
||||
if (authToken.isGuestLogon())
|
||||
{
|
||||
|
||||
// Check if the local server allows guest access
|
||||
|
||||
if (allowGuest() == true)
|
||||
{
|
||||
|
||||
// Allow the user access as a guest
|
||||
|
||||
authSts = SrvAuthenticator.AUTH_GUEST;
|
||||
|
||||
// Debug
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Acegi passthru authenticate user=" + client.getUserName() + ", GUEST");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Allow the user full access to the server
|
||||
|
||||
authSts = SrvAuthenticator.AUTH_ALLOW;
|
||||
|
||||
// Debug
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Acegi passthru authenticate user=" + client.getUserName() + ", FULL");
|
||||
}
|
||||
}
|
||||
catch ( Exception ex)
|
||||
{
|
||||
// Log the error
|
||||
|
||||
if ( logger.isErrorEnabled())
|
||||
logger.error("Logon failure, " + ex.getMessage());
|
||||
}
|
||||
|
||||
// Clear the authentication token
|
||||
|
||||
sess.setAuthenticationToken(null);
|
||||
|
||||
// Return the authentication status
|
||||
|
||||
return authSts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user account details for the specified user
|
||||
*
|
||||
* @param user String
|
||||
* @return UserAccount
|
||||
*/
|
||||
public UserAccount getUserDetails(String user)
|
||||
{
|
||||
// No user details to return
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a challenge key for a new session
|
||||
*
|
||||
* @param sess SrvSession
|
||||
* @return byte[]
|
||||
*/
|
||||
public byte[] getChallengeKey(SrvSession sess)
|
||||
{
|
||||
// Create an authentication token for the session
|
||||
|
||||
NTLMPassthruToken authToken = new NTLMPassthruToken();
|
||||
|
||||
// Run the first stage of the passthru authentication to get the challenge
|
||||
|
||||
m_authMgr.authenticate( authToken);
|
||||
|
||||
// Save the authentication token for the second stage of the authentication
|
||||
|
||||
sess.setAuthenticationToken(authToken);
|
||||
|
||||
// Debug
|
||||
|
||||
if ( logger.isDebugEnabled())
|
||||
logger.debug("Created new passthru token " + authToken);
|
||||
|
||||
// Get the challenge from the token
|
||||
|
||||
if ( authToken.getChallenge() != null)
|
||||
return authToken.getChallenge().getBytes();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialzie the authenticator
|
||||
*
|
||||
* @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 configuration has an associated bean factory, if not it looks like we are
|
||||
// not running inside Spring
|
||||
|
||||
if ( config.getAuthenticationManager() == null)
|
||||
throw new InvalidConfigurationException("Acegi authentication manager not available");
|
||||
|
||||
// Passthru authenticator only works in user mode
|
||||
|
||||
if ( getAccessMode() != USER_MODE)
|
||||
throw new InvalidConfigurationException("Acegi authenticator only works in user mode");
|
||||
|
||||
// Check if authentication manager is the required type and that the NTLM authentication provider
|
||||
// is available.
|
||||
|
||||
Object authMgrObj = config.getAuthenticationManager();
|
||||
|
||||
if ( authMgrObj instanceof ProviderManager)
|
||||
{
|
||||
// The required authentication manager is configured, now check if the NTLM provider is configured
|
||||
|
||||
ProviderManager providerManager = (ProviderManager) authMgrObj;
|
||||
List providerList = providerManager.getProviders();
|
||||
|
||||
if ( providerList != null)
|
||||
{
|
||||
// Check for the NTLM authentication provider
|
||||
|
||||
int i = 0;
|
||||
boolean foundProvider = false;
|
||||
|
||||
while ( i < providerList.size() && foundProvider == false)
|
||||
{
|
||||
if ( providerList.get(i++) instanceof NTLMAuthenticationProvider)
|
||||
foundProvider = true;
|
||||
}
|
||||
|
||||
if (foundProvider == false)
|
||||
throw new InvalidConfigurationException("NTLM authentication provider is not available");
|
||||
|
||||
// Save the authentication manager
|
||||
|
||||
m_authMgr = (AuthenticationManager) authMgrObj;
|
||||
}
|
||||
else
|
||||
throw new InvalidConfigurationException("No authentication providers available");
|
||||
}
|
||||
else
|
||||
throw new InvalidConfigurationException("Required authentication manager is not configured");
|
||||
}
|
||||
}
|
@@ -24,15 +24,15 @@ import org.alfresco.config.ConfigElement;
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.filesys.server.SessionListener;
|
||||
import org.alfresco.filesys.server.SrvSession;
|
||||
import org.alfresco.filesys.server.auth.AuthContext;
|
||||
import org.alfresco.filesys.server.auth.ClientInfo;
|
||||
import org.alfresco.filesys.server.auth.SrvAuthenticator;
|
||||
import org.alfresco.filesys.server.auth.UserAccount;
|
||||
import org.alfresco.filesys.server.auth.CifsAuthenticator;
|
||||
import org.alfresco.filesys.server.auth.NTLanManAuthContext;
|
||||
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.SMBServer;
|
||||
import org.alfresco.filesys.smb.server.SMBSrvSession;
|
||||
import org.alfresco.filesys.util.HexDump;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -46,7 +46,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
*
|
||||
* @author GKSpencer
|
||||
*/
|
||||
public class PassthruAuthenticator extends SrvAuthenticator implements SessionListener
|
||||
public class PassthruAuthenticator extends CifsAuthenticator implements SessionListener
|
||||
{
|
||||
// Debug logging
|
||||
|
||||
@@ -77,9 +77,6 @@ public class PassthruAuthenticator extends SrvAuthenticator implements SessionLi
|
||||
*/
|
||||
public PassthruAuthenticator()
|
||||
{
|
||||
setAccessMode(SrvAuthenticator.USER_MODE);
|
||||
setEncryptedPasswords(true);
|
||||
|
||||
// Allocate the session table
|
||||
|
||||
m_sessions = new Hashtable<String, PassthruDetails>();
|
||||
@@ -97,7 +94,7 @@ public class PassthruAuthenticator extends SrvAuthenticator implements SessionLi
|
||||
*/
|
||||
public int authenticateShareConnect(ClientInfo client, SharedDevice share, String sharePwd, SrvSession sess)
|
||||
{
|
||||
return SrvAuthenticator.Writeable;
|
||||
return CifsAuthenticator.Writeable;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,18 +107,16 @@ public class PassthruAuthenticator extends SrvAuthenticator implements SessionLi
|
||||
*/
|
||||
public int authenticateUser(ClientInfo client, SrvSession sess, int alg)
|
||||
{
|
||||
// Check if this is an SMB/CIFS null session logon.
|
||||
//
|
||||
// The null session will only be allowed to connect to the IPC$ named pipe share.
|
||||
|
||||
if (client.isNullSession() && sess instanceof SMBSrvSession)
|
||||
if (client.isNullSession())
|
||||
{
|
||||
// Debug
|
||||
|
||||
if ( logger.isDebugEnabled())
|
||||
logger.debug("Null CIFS logon allowed");
|
||||
|
||||
return SrvAuthenticator.AUTH_ALLOW;
|
||||
return CifsAuthenticator.AUTH_ALLOW;
|
||||
}
|
||||
|
||||
// Check if the client is already authenticated, and it is not a null logon
|
||||
@@ -202,7 +197,7 @@ public class PassthruAuthenticator extends SrvAuthenticator implements SessionLi
|
||||
|
||||
// Allow the user access as a guest
|
||||
|
||||
authSts = SrvAuthenticator.AUTH_GUEST;
|
||||
authSts = CifsAuthenticator.AUTH_GUEST;
|
||||
|
||||
// Debug
|
||||
|
||||
@@ -255,7 +250,7 @@ public class PassthruAuthenticator extends SrvAuthenticator implements SessionLi
|
||||
|
||||
// Allow the user full access to the server
|
||||
|
||||
authSts = SrvAuthenticator.AUTH_ALLOW;
|
||||
authSts = CifsAuthenticator.AUTH_ALLOW;
|
||||
|
||||
// Debug
|
||||
|
||||
@@ -336,35 +331,21 @@ public class PassthruAuthenticator extends SrvAuthenticator implements SessionLi
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user account details for the specified user
|
||||
* Return an authentication context for the new session
|
||||
*
|
||||
* @param user String
|
||||
* @return UserAccount
|
||||
* @return AuthContext
|
||||
*/
|
||||
public UserAccount getUserDetails(String user)
|
||||
{
|
||||
|
||||
// No user details to return
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a challenge key for a new session
|
||||
*
|
||||
* @param sess SrvSession
|
||||
* @return byte[]
|
||||
*/
|
||||
public byte[] getChallengeKey(SrvSession sess)
|
||||
public AuthContext getAuthContext( SMBSrvSession sess)
|
||||
{
|
||||
|
||||
// Check for an SMB session
|
||||
|
||||
byte[] chKey = null;
|
||||
AuthContext authCtx = null;
|
||||
|
||||
// Check if the client is already authenticated, and it is not a null logon
|
||||
|
||||
if ( sess.hasClientInformation() && sess.getClientInformation().getAuthenticationToken() != null &&
|
||||
if ( sess.hasAuthenticationContext() && sess.hasClientInformation() &&
|
||||
sess.getClientInformation().getAuthenticationToken() != null &&
|
||||
sess.getClientInformation().getLogonType() != ClientInfo.LogonNull)
|
||||
{
|
||||
// DEBUG
|
||||
@@ -374,24 +355,7 @@ public class PassthruAuthenticator extends SrvAuthenticator implements SessionLi
|
||||
|
||||
// Return the previous challenge, user is already authenticated
|
||||
|
||||
return sess.getChallengeKey();
|
||||
}
|
||||
else if (sess instanceof SMBSrvSession)
|
||||
{
|
||||
|
||||
// Check if the SMB server listener has been initialized
|
||||
|
||||
if (m_server == null)
|
||||
{
|
||||
|
||||
// Initialize the SMB server session listener so we receive callbacks when sessions
|
||||
// are opened/closed on the SMB server
|
||||
|
||||
SMBSrvSession smbSess = (SMBSrvSession) sess;
|
||||
m_server = smbSess.getSMBServer();
|
||||
|
||||
m_server.addSessionListener(this);
|
||||
}
|
||||
return sess.getAuthenticationContext();
|
||||
}
|
||||
|
||||
try
|
||||
@@ -410,13 +374,13 @@ public class PassthruAuthenticator extends SrvAuthenticator implements SessionLi
|
||||
|
||||
// Use the challenge key returned from the authentication server
|
||||
|
||||
chKey = authSess.getEncryptionKey();
|
||||
authCtx = new NTLanManAuthContext( authSess.getEncryptionKey());
|
||||
sess.setAuthenticationContext( authCtx);
|
||||
|
||||
// DEBUG
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Passthru sessId=" + authSess.getSessionId() + ", negotiate key=["
|
||||
+ HexDump.hexString(chKey) + "]");
|
||||
logger.debug("Passthru sessId=" + authSess.getSessionId() + ", auth ctx=" + authCtx);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -427,9 +391,9 @@ public class PassthruAuthenticator extends SrvAuthenticator implements SessionLi
|
||||
logger.error("Passthru error getting challenge", ex);
|
||||
}
|
||||
|
||||
// Return the challenge key
|
||||
// Return the authentication context
|
||||
|
||||
return chKey;
|
||||
return authCtx;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -563,6 +527,13 @@ public class PassthruAuthenticator extends SrvAuthenticator implements SessionLi
|
||||
|
||||
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
|
||||
|
||||
SMBServer smbServer = (SMBServer) config.findServer( "SMB");
|
||||
if ( smbServer != null)
|
||||
smbServer.addSessionListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -639,8 +610,7 @@ public class PassthruAuthenticator extends SrvAuthenticator implements SessionLi
|
||||
{
|
||||
|
||||
// Check if the client information has an empty user name, if so then do not close the
|
||||
// authentication
|
||||
// session
|
||||
// authentication session
|
||||
|
||||
if (sess.hasClientInformation() && sess.getClientInformation().getUserName() != null
|
||||
&& sess.getClientInformation().getUserName().length() > 0)
|
||||
|
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.auth.spnego;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1EncodableVector;
|
||||
import org.bouncycastle.asn1.ASN1InputStream;
|
||||
import org.bouncycastle.asn1.DERApplicationSpecific;
|
||||
import org.bouncycastle.asn1.DERBitString;
|
||||
import org.bouncycastle.asn1.DERGeneralString;
|
||||
import org.bouncycastle.asn1.DERObject;
|
||||
import org.bouncycastle.asn1.DERObjectIdentifier;
|
||||
import org.bouncycastle.asn1.DEROctetString;
|
||||
import org.bouncycastle.asn1.DEROutputStream;
|
||||
import org.bouncycastle.asn1.DERSequence;
|
||||
import org.bouncycastle.asn1.DERTaggedObject;
|
||||
import org.bouncycastle.asn1.DERTags;
|
||||
import org.bouncycastle.asn1.DERUnknownTag;
|
||||
import org.ietf.jgss.GSSException;
|
||||
import org.ietf.jgss.Oid;
|
||||
|
||||
/**
|
||||
* NegTokenInit Class
|
||||
*
|
||||
* <p>Contains the details of an SPNEGO NegTokenInit blob for use with CIFS.
|
||||
*
|
||||
* @author gkspencer
|
||||
*/
|
||||
public class NegTokenInit
|
||||
{
|
||||
// Mechtypes list
|
||||
|
||||
private Oid[] m_mechTypes;
|
||||
|
||||
// Context flags
|
||||
|
||||
private int m_contextFlags = -1;
|
||||
|
||||
// Mechtoken
|
||||
|
||||
private byte[] m_mechToken;
|
||||
|
||||
// MectListMIC principal
|
||||
|
||||
private String m_mecListMICPrincipal;
|
||||
|
||||
/**
|
||||
* Class constructor for decoding
|
||||
*/
|
||||
public NegTokenInit()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Class constructor for encoding
|
||||
*
|
||||
* @param mechTypes Oid[]
|
||||
* @param mechPrinciple String
|
||||
*/
|
||||
public NegTokenInit( Oid[] mechTypes, String mechPrinciple)
|
||||
{
|
||||
m_mechTypes = mechTypes;
|
||||
m_mecListMICPrincipal = mechPrinciple;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class constructor for encoding
|
||||
*
|
||||
* @param mechTypes Vector<Oid>
|
||||
* @param mechPrinciple String
|
||||
*/
|
||||
public NegTokenInit( Vector<Oid> mechTypes, String mechPrinciple)
|
||||
{
|
||||
// Create the mechTypes array
|
||||
|
||||
m_mechTypes = new Oid[ mechTypes.size()];
|
||||
for ( int i = 0; i < mechTypes.size(); i++)
|
||||
m_mechTypes[i] = mechTypes.get(i);
|
||||
|
||||
m_mecListMICPrincipal = mechPrinciple;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mechTypes OID list
|
||||
*
|
||||
* @return Oid[]
|
||||
*/
|
||||
public final Oid[] getOids()
|
||||
{
|
||||
return m_mechTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the context flags
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int getContextFlags()
|
||||
{
|
||||
return m_contextFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mechToken
|
||||
*
|
||||
* @return byte[]
|
||||
*/
|
||||
public final byte[] getMechtoken()
|
||||
{
|
||||
return m_mechToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mechListMIC principal
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public final String getPrincipal()
|
||||
{
|
||||
return m_mecListMICPrincipal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the OID list contains the specified OID
|
||||
*
|
||||
* @param oid Oid
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasOid( Oid oid)
|
||||
{
|
||||
boolean foundOid = false;
|
||||
|
||||
if ( m_mechTypes != null)
|
||||
{
|
||||
foundOid = oid.containedIn( m_mechTypes);
|
||||
}
|
||||
|
||||
return foundOid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of OIDs
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int numberOfOids()
|
||||
{
|
||||
return m_mechTypes != null ? m_mechTypes.length : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the specified OID
|
||||
*
|
||||
* @param idx int
|
||||
* @return OID
|
||||
*/
|
||||
public final Oid getOidAt(int idx)
|
||||
{
|
||||
if ( m_mechTypes != null && idx >= 0 && idx < m_mechTypes.length)
|
||||
return m_mechTypes[idx];
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an SPNEGO NegTokenInit blob
|
||||
*
|
||||
* @param buf byte[]
|
||||
* @param off int
|
||||
* @param len int
|
||||
* @exception IOException
|
||||
*/
|
||||
public void decode(byte[] buf, int off, int len) throws IOException
|
||||
{
|
||||
// Create a stream around the security blob
|
||||
|
||||
ByteArrayInputStream bytStream = new ByteArrayInputStream( buf, off, len);
|
||||
ASN1InputStream asnStream = new ASN1InputStream( bytStream);
|
||||
|
||||
// Read the top level object from the security blob
|
||||
|
||||
DERObject derObj = asnStream.readObject();
|
||||
|
||||
if ( derObj instanceof DERApplicationSpecific == false)
|
||||
throw new IOException("Bad blob format (AppSpec)");
|
||||
|
||||
// Access the application specific contents
|
||||
|
||||
DERApplicationSpecific derApp = (DERApplicationSpecific) derObj;
|
||||
|
||||
ByteArrayInputStream appStream = new ByteArrayInputStream( derApp.getContents());
|
||||
ASN1InputStream asnAppStream = new ASN1InputStream( appStream);
|
||||
|
||||
// First object should be an OID, make sure it is the SPNEGO OID
|
||||
|
||||
derObj = asnAppStream.readObject();
|
||||
if ( derObj instanceof DERObjectIdentifier == false)
|
||||
throw new IOException("Bad blob format (SPNEGO OID)");
|
||||
|
||||
DERObjectIdentifier derOid = (DERObjectIdentifier) derObj;
|
||||
if ( derOid.getId().equals( OID.ID_SPNEGO) == false)
|
||||
throw new IOException("Not an SPNEGO blob");
|
||||
|
||||
// Next object should be a tagged object with a sequence
|
||||
|
||||
derObj = asnAppStream.readObject();
|
||||
if ( derObj instanceof DERTaggedObject == false)
|
||||
throw new IOException("Bad blob format, tagged object missing");
|
||||
|
||||
DERTaggedObject derTagSeq = (DERTaggedObject) derObj;
|
||||
if ( derTagSeq.getTagNo() != 0 || derTagSeq.getObject() instanceof DERSequence == false)
|
||||
throw new IOException("Bad blob format, sequence missing");
|
||||
|
||||
// Enumerate the main NegTokenInit sequence
|
||||
|
||||
DERSequence negTokInitSeq = (DERSequence) derTagSeq.getObject();
|
||||
Enumeration seqEnum = negTokInitSeq.getObjects();
|
||||
|
||||
while ( seqEnum.hasMoreElements())
|
||||
{
|
||||
// Read an object from the sequence
|
||||
|
||||
derObj = (DERObject) seqEnum.nextElement();
|
||||
if ( derObj instanceof DERTaggedObject)
|
||||
{
|
||||
// Tag 0 should be a sequence of object identifiers
|
||||
|
||||
DERTaggedObject derTag = (DERTaggedObject) derObj;
|
||||
if ( derTag.getTagNo() == 0 && derTag.getObject() instanceof DERSequence)
|
||||
{
|
||||
DERSequence derSeq = (DERSequence) derTag.getObject();
|
||||
Enumeration typesEnum = derSeq.getObjects();
|
||||
|
||||
// Allocate the OID list
|
||||
|
||||
m_mechTypes = new Oid[derSeq.size()];
|
||||
int idx = 0;
|
||||
|
||||
while( typesEnum.hasMoreElements())
|
||||
{
|
||||
derObj = (DERObject) typesEnum.nextElement();
|
||||
if ( derObj instanceof DERObjectIdentifier)
|
||||
{
|
||||
derOid = (DERObjectIdentifier) derObj;
|
||||
try
|
||||
{
|
||||
m_mechTypes[idx++] = new Oid( derOid.getId());
|
||||
}
|
||||
catch (GSSException ex)
|
||||
{
|
||||
throw new IOException("Bad mechType OID");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( derTag.getTagNo() == 1 && derTag.getObject() instanceof DERBitString)
|
||||
{
|
||||
// Context flags
|
||||
|
||||
}
|
||||
else if ( derTag.getTagNo() == 2 && derTag.getObject() instanceof DEROctetString)
|
||||
{
|
||||
// Unpack the mechToken
|
||||
|
||||
DEROctetString derStr = (DEROctetString) derTag.getObject();
|
||||
m_mechToken = derStr.getOctets();
|
||||
}
|
||||
else if ( derTag.getTagNo() == 3 &&derTag.getObject() instanceof DEROctetString)
|
||||
{
|
||||
// mechListMIC
|
||||
|
||||
}
|
||||
else if ( derTag.getTagNo() == 3 && derTag.getObject() instanceof DERSequence)
|
||||
{
|
||||
// mechListMIC (Microsoft)
|
||||
|
||||
DERSequence derSeq = (DERSequence) derTag.getObject();
|
||||
|
||||
Enumeration subEnum = derSeq.getObjects();
|
||||
while( subEnum.hasMoreElements())
|
||||
{
|
||||
derObj = (DERObject) subEnum.nextElement();
|
||||
System.out.println("mechListMIC Seq: " + derObj);
|
||||
}
|
||||
}
|
||||
else
|
||||
throw new IOException("Bad format, unexpected type");
|
||||
}
|
||||
else
|
||||
throw new IOException("Bad format, untagged type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode an SPNEGO NegTokenInit blob
|
||||
*
|
||||
* @return byte[]
|
||||
* @exception IOException
|
||||
*/
|
||||
public byte[] encode() throws IOException
|
||||
{
|
||||
ByteArrayOutputStream tokStream = new ByteArrayOutputStream();
|
||||
|
||||
// Create an SPNEGO NegTokenInit token
|
||||
|
||||
DEROutputStream derOut = new DEROutputStream( tokStream);
|
||||
|
||||
derOut.writeObject( new DERObjectIdentifier( OID.ID_SPNEGO));
|
||||
ASN1EncodableVector asnList = new ASN1EncodableVector();
|
||||
|
||||
// Build the mechTypes sequence
|
||||
|
||||
ASN1EncodableVector mechTypesList = new ASN1EncodableVector();
|
||||
|
||||
for ( Oid mechType : m_mechTypes)
|
||||
{
|
||||
mechTypesList.add( new DERObjectIdentifier( mechType.toString()));
|
||||
}
|
||||
|
||||
asnList.add( new DERTaggedObject( true, 0, new DERSequence( mechTypesList)));
|
||||
|
||||
// Build the mechListMIC
|
||||
//
|
||||
// Note: This field is not as specified
|
||||
|
||||
if ( m_mecListMICPrincipal != null)
|
||||
{
|
||||
ASN1EncodableVector micList = new ASN1EncodableVector();
|
||||
|
||||
micList.add( new DERTaggedObject( true, 0, new DERGeneralString( m_mecListMICPrincipal)));
|
||||
asnList.add( new DERTaggedObject( true, 3, new DERSequence( micList)));
|
||||
}
|
||||
|
||||
// Generate the SPNEGO NegTokenInit blob
|
||||
|
||||
derOut.writeObject( new DERTaggedObject( true, 0, new DERSequence( asnList)));
|
||||
DERObject token = new DERUnknownTag( DERTags.CONSTRUCTED | DERTags.APPLICATION, tokStream.toByteArray());
|
||||
|
||||
tokStream = new ByteArrayOutputStream();
|
||||
derOut = new DEROutputStream( tokStream);
|
||||
derOut.writeObject( token);
|
||||
|
||||
return tokStream.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the NegTokenInit object as a string
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder str = new StringBuilder();
|
||||
|
||||
str.append("[NegTokenInit ");
|
||||
|
||||
if ( m_mechTypes != null)
|
||||
{
|
||||
str.append("mechTypes=");
|
||||
for ( Oid oid : m_mechTypes)
|
||||
{
|
||||
str.append(oid.toString());
|
||||
str.append(",");
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_contextFlags != -1)
|
||||
{
|
||||
str.append(" context=0x");
|
||||
str.append(Integer.toHexString(m_contextFlags));
|
||||
}
|
||||
|
||||
if ( m_mechToken != null)
|
||||
{
|
||||
str.append(" token=");
|
||||
str.append(m_mechToken.length);
|
||||
str.append(" bytes");
|
||||
}
|
||||
|
||||
if ( m_mecListMICPrincipal != null)
|
||||
{
|
||||
str.append(" principal=");
|
||||
str.append(m_mecListMICPrincipal);
|
||||
}
|
||||
str.append("]");
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.auth.spnego;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1EncodableVector;
|
||||
import org.bouncycastle.asn1.ASN1InputStream;
|
||||
import org.bouncycastle.asn1.DEREnumerated;
|
||||
import org.bouncycastle.asn1.DERObject;
|
||||
import org.bouncycastle.asn1.DERObjectIdentifier;
|
||||
import org.bouncycastle.asn1.DEROctetString;
|
||||
import org.bouncycastle.asn1.DEROutputStream;
|
||||
import org.bouncycastle.asn1.DERSequence;
|
||||
import org.bouncycastle.asn1.DERTaggedObject;
|
||||
import org.ietf.jgss.GSSException;
|
||||
import org.ietf.jgss.Oid;
|
||||
|
||||
/**
|
||||
* NegTokenTarg Class
|
||||
*
|
||||
* <p>Contains the details of an SPNEGO NegTokenTarg blob for use with CIFS.
|
||||
*
|
||||
* @author gkspencer
|
||||
*/
|
||||
public class NegTokenTarg
|
||||
{
|
||||
// Result code
|
||||
|
||||
private int m_result;
|
||||
|
||||
// Supported mechanism
|
||||
|
||||
private Oid m_supportedMech;
|
||||
|
||||
// Response token
|
||||
|
||||
private byte[] m_responseToken;
|
||||
|
||||
/**
|
||||
* Class constructor for decoding
|
||||
*/
|
||||
public NegTokenTarg()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param result int
|
||||
* @param mech Oid
|
||||
* @param response byte[]
|
||||
*/
|
||||
public NegTokenTarg(int result, Oid mech, byte[] response)
|
||||
{
|
||||
m_result = result;
|
||||
m_supportedMech = mech;
|
||||
m_responseToken = response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the result
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int getResult()
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the supported mech type Oid
|
||||
*
|
||||
* @return Oid
|
||||
*/
|
||||
public final Oid getSupportedMech()
|
||||
{
|
||||
return m_supportedMech;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if there is a valid response token
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasResponseToken()
|
||||
{
|
||||
return m_responseToken != null ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the response token
|
||||
*
|
||||
* @return byte[]
|
||||
*/
|
||||
public final byte[] getResponseToken()
|
||||
{
|
||||
return m_responseToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an SPNEGO NegTokenTarg blob
|
||||
*
|
||||
* @param buf byte[]
|
||||
* @param off int
|
||||
* @param len int
|
||||
* @exception IOException
|
||||
*/
|
||||
public void decode(byte[] buf, int off, int len) throws IOException
|
||||
{
|
||||
// Create a stream around the security blob
|
||||
|
||||
ByteArrayInputStream bytStream = new ByteArrayInputStream( buf, off, len);
|
||||
ASN1InputStream asnStream = new ASN1InputStream( bytStream);
|
||||
|
||||
// Read the top level object from the security blob
|
||||
|
||||
DERObject derObj = asnStream.readObject();
|
||||
|
||||
if ( derObj instanceof DERTaggedObject == false)
|
||||
throw new IOException("Bad blob format (Tagged)");
|
||||
|
||||
// Access the sequence
|
||||
|
||||
DERTaggedObject derTag = (DERTaggedObject) derObj;
|
||||
if ( derTag.getObject() instanceof DERSequence == false)
|
||||
throw new IOException("Bad blob format (Seq)");
|
||||
|
||||
DERSequence derSeq = (DERSequence) derTag.getObject();
|
||||
Enumeration seqEnum = derSeq.getObjects();
|
||||
|
||||
while ( seqEnum.hasMoreElements())
|
||||
{
|
||||
// Read an object from the sequence
|
||||
|
||||
derObj = (DERObject) seqEnum.nextElement();
|
||||
if ( derObj instanceof DERTaggedObject)
|
||||
{
|
||||
// Tag 0 should be a status
|
||||
|
||||
derTag = (DERTaggedObject) derObj;
|
||||
if ( derTag.getTagNo() == 0 && derTag.getObject() instanceof DEREnumerated)
|
||||
{
|
||||
// Result code
|
||||
|
||||
DEREnumerated derEnum = (DEREnumerated) derTag.getObject();
|
||||
m_result = derEnum.getValue().intValue();
|
||||
}
|
||||
else if ( derTag.getTagNo() == 1 && derTag.getObject() instanceof DERObjectIdentifier)
|
||||
{
|
||||
// Mech type
|
||||
|
||||
DERObjectIdentifier derOid = (DERObjectIdentifier) derTag.getObject();
|
||||
try
|
||||
{
|
||||
m_supportedMech = new Oid(derOid.getId());
|
||||
}
|
||||
catch (GSSException ex)
|
||||
{
|
||||
}
|
||||
}
|
||||
else if ( derTag.getTagNo() == 2 && derTag.getObject() instanceof DEROctetString)
|
||||
{
|
||||
// Unpack the response token
|
||||
|
||||
DEROctetString derStr = (DEROctetString) derTag.getObject();
|
||||
m_responseToken = derStr.getOctets();
|
||||
}
|
||||
else if ( derTag.getTagNo() == 3 &&derTag.getObject() instanceof DEROctetString)
|
||||
{
|
||||
// mechListMIC
|
||||
|
||||
}
|
||||
else
|
||||
throw new IOException("Bad format, unexpected type");
|
||||
}
|
||||
else
|
||||
throw new IOException("Bad format, untagged type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode an SPNEGO NegTokenTarg blob
|
||||
*
|
||||
* @return byte[]
|
||||
* @exception IOException
|
||||
*/
|
||||
public byte[] encode() throws IOException
|
||||
{
|
||||
ByteArrayOutputStream tokStream = new ByteArrayOutputStream();
|
||||
|
||||
// Create an SPNEGO NegTokenTarg token
|
||||
|
||||
DEROutputStream derOut = new DEROutputStream( tokStream);
|
||||
|
||||
ASN1EncodableVector asnList = new ASN1EncodableVector();
|
||||
|
||||
// Pack the result code
|
||||
|
||||
asnList.add( new DERTaggedObject( true, 0, new DEREnumerated(m_result)));
|
||||
|
||||
// Pack the supportedMech field
|
||||
|
||||
if ( m_supportedMech != null)
|
||||
asnList.add( new DERTaggedObject( true, 1, new DERObjectIdentifier( m_supportedMech.toString())));
|
||||
|
||||
// Pack the response token
|
||||
|
||||
if ( m_responseToken != null)
|
||||
asnList.add( new DERTaggedObject( true, 2, new DEROctetString(m_responseToken)));
|
||||
|
||||
// Generate the SPNEGO NegTokenTarg blob
|
||||
|
||||
derOut.writeObject( new DERTaggedObject( true, SPNEGO.NegTokenTarg, new DERSequence( asnList)));
|
||||
return tokStream.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the NegtokenTarg object as a string
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder str = new StringBuilder();
|
||||
|
||||
str.append("[NegtokenTarg result=");
|
||||
str.append( SPNEGO.asResultString( getResult()));
|
||||
|
||||
str.append(" oid=");
|
||||
str.append( getSupportedMech());
|
||||
|
||||
str.append(" response=");
|
||||
if ( hasResponseToken())
|
||||
{
|
||||
str.append(getResponseToken().length);
|
||||
str.append(" bytes");
|
||||
}
|
||||
else
|
||||
str.append("null");
|
||||
str.append("]");
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
}
|
74
source/java/org/alfresco/filesys/server/auth/spnego/OID.java
Normal file
74
source/java/org/alfresco/filesys/server/auth/spnego/OID.java
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.auth.spnego;
|
||||
|
||||
import org.ietf.jgss.GSSException;
|
||||
import org.ietf.jgss.Oid;
|
||||
|
||||
/**
|
||||
* OID Class
|
||||
*
|
||||
* <p>Contains Oids used by SPNEGO
|
||||
*
|
||||
* @author gkspencer
|
||||
*/
|
||||
public class OID
|
||||
{
|
||||
// IDs
|
||||
|
||||
public static final String ID_SPNEGO = "1.3.6.1.5.5.2";
|
||||
|
||||
// Kerberos providers
|
||||
|
||||
public static final String ID_KERBEROS5 = "1.2.840.113554.1.2.2";
|
||||
public static final String ID_MSKERBEROS5 = "1.2.840.48018.1.2.2";
|
||||
|
||||
// Microsoft NTLM security support provider
|
||||
|
||||
public static final String ID_NTLMSSP = "1.3.6.1.4.1.311.2.2.10";
|
||||
|
||||
// OIDs
|
||||
|
||||
public static Oid SPNEGO;
|
||||
|
||||
public static Oid KERBEROS5;
|
||||
public static Oid MSKERBEROS5;
|
||||
|
||||
public static Oid NTLMSSP;
|
||||
|
||||
/**
|
||||
* Static initializer
|
||||
*/
|
||||
|
||||
static {
|
||||
|
||||
// Create the OIDs
|
||||
|
||||
try
|
||||
{
|
||||
SPNEGO = new Oid(ID_SPNEGO);
|
||||
|
||||
KERBEROS5 = new Oid(ID_KERBEROS5);
|
||||
MSKERBEROS5 = new Oid( ID_MSKERBEROS5);
|
||||
|
||||
NTLMSSP = new Oid(ID_NTLMSSP);
|
||||
}
|
||||
catch ( GSSException ex)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
132
source/java/org/alfresco/filesys/server/auth/spnego/SPNEGO.java
Normal file
132
source/java/org/alfresco/filesys/server/auth/spnego/SPNEGO.java
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.auth.spnego;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1InputStream;
|
||||
import org.bouncycastle.asn1.DERApplicationSpecific;
|
||||
import org.bouncycastle.asn1.DERObject;
|
||||
import org.bouncycastle.asn1.DERTaggedObject;
|
||||
|
||||
/**
|
||||
* SPNEGO Class
|
||||
*
|
||||
* <p>Contains SPNEGO constants
|
||||
*
|
||||
* @author gkspencer
|
||||
*/
|
||||
public class SPNEGO
|
||||
{
|
||||
// Message types
|
||||
|
||||
public static final int NegTokenInit = 0;
|
||||
public static final int NegTokenTarg = 1;
|
||||
|
||||
// NegTokenInit context flags
|
||||
|
||||
public static final int ContextDelete = 0;
|
||||
public static final int ContextMutual = 1;
|
||||
public static final int ContextReplay = 2;
|
||||
public static final int ContextSequence = 3;
|
||||
public static final int ContextAnon = 4;
|
||||
public static final int ContextConf = 5;
|
||||
public static final int ContextInteg = 6;
|
||||
|
||||
// NegTokenTarg result codes
|
||||
|
||||
public static final int AcceptCompleted = 0;
|
||||
public static final int AcceptIncomplete = 1;
|
||||
public static final int Reject = 2;
|
||||
|
||||
/**
|
||||
* Return a result code as a string
|
||||
*
|
||||
* @param res int
|
||||
* @return String
|
||||
*/
|
||||
public static String asResultString(int res)
|
||||
{
|
||||
String resStr = null;
|
||||
|
||||
switch ( res)
|
||||
{
|
||||
case AcceptCompleted:
|
||||
resStr = "AcceptCompleted";
|
||||
break;
|
||||
case AcceptIncomplete:
|
||||
resStr = "AcceptIncomplete";
|
||||
break;
|
||||
case Reject:
|
||||
resStr = "Reject";
|
||||
break;
|
||||
default:
|
||||
resStr = "" + res;
|
||||
break;
|
||||
}
|
||||
|
||||
return resStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the SPNEGO token type
|
||||
*
|
||||
* @param buf byte[]
|
||||
* @param off int
|
||||
* @param len int
|
||||
* @return int
|
||||
* @exception IOException
|
||||
*/
|
||||
public static int checkTokenType( byte[] buf, int off, int len)
|
||||
throws IOException
|
||||
{
|
||||
// Create a stream around the security blob
|
||||
|
||||
ByteArrayInputStream bytStream = new ByteArrayInputStream( buf, off, len);
|
||||
ASN1InputStream asnStream = new ASN1InputStream( bytStream);
|
||||
|
||||
// Read the top level object from the security blob
|
||||
|
||||
DERObject derObj = asnStream.readObject();
|
||||
int tokType = -1;
|
||||
|
||||
if ( derObj instanceof DERApplicationSpecific)
|
||||
{
|
||||
// Looks like a NegTokenInit token
|
||||
|
||||
tokType = NegTokenInit;
|
||||
}
|
||||
else if ( derObj instanceof DERTaggedObject)
|
||||
{
|
||||
// Check the tag number
|
||||
|
||||
DERTaggedObject derTag = (DERTaggedObject) derObj;
|
||||
if ( derTag.getTagNo() == 1)
|
||||
tokType = NegTokenTarg;
|
||||
}
|
||||
|
||||
// Close the streams
|
||||
|
||||
asnStream.close();
|
||||
bytStream.close();
|
||||
|
||||
// Return the token type
|
||||
|
||||
return tokType;
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
@@ -20,7 +20,6 @@ import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
@@ -46,10 +45,7 @@ import org.alfresco.filesys.netbios.RFCNetBIOSProtocol;
|
||||
import org.alfresco.filesys.netbios.win32.Win32NetBIOS;
|
||||
import org.alfresco.filesys.server.NetworkServer;
|
||||
import org.alfresco.filesys.server.NetworkServerList;
|
||||
import org.alfresco.filesys.server.auth.LocalAuthenticator;
|
||||
import org.alfresco.filesys.server.auth.SrvAuthenticator;
|
||||
import org.alfresco.filesys.server.auth.UserAccount;
|
||||
import org.alfresco.filesys.server.auth.UserAccountList;
|
||||
import org.alfresco.filesys.server.auth.CifsAuthenticator;
|
||||
import org.alfresco.filesys.server.auth.acl.ACLParseException;
|
||||
import org.alfresco.filesys.server.auth.acl.AccessControl;
|
||||
import org.alfresco.filesys.server.auth.acl.AccessControlList;
|
||||
@@ -68,8 +64,6 @@ 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.HomeShareMapper;
|
||||
import org.alfresco.filesys.smb.Dialect;
|
||||
import org.alfresco.filesys.smb.DialectSelector;
|
||||
import org.alfresco.filesys.smb.ServerType;
|
||||
import org.alfresco.filesys.util.IPAddress;
|
||||
import org.alfresco.filesys.util.X64;
|
||||
@@ -138,15 +132,19 @@ public class ServerConfiguration implements ApplicationListener
|
||||
};
|
||||
|
||||
// Token name to substitute current server name into the CIFS server name
|
||||
|
||||
private static final String TokenLocalName = "${localname}";
|
||||
|
||||
// Acegi authentication manager
|
||||
// Authentication manager
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
// Configuration service
|
||||
|
||||
private ConfigService configService;
|
||||
|
||||
/** the device to connect use */
|
||||
// Disk interface to use for shared filesystems
|
||||
|
||||
private DiskInterface diskInterface;
|
||||
|
||||
// Runtime platform type
|
||||
@@ -159,46 +157,53 @@ public class ServerConfiguration implements ApplicationListener
|
||||
private boolean m_ftpEnable = true;
|
||||
|
||||
// Server name
|
||||
|
||||
private String m_name;
|
||||
|
||||
// Server type, used by the host announcer
|
||||
|
||||
private int m_srvType = ServerType.WorkStation + ServerType.Server + ServerType.NTServer;
|
||||
|
||||
// Active server list
|
||||
|
||||
private NetworkServerList m_serverList;
|
||||
|
||||
// Server comment
|
||||
|
||||
private String m_comment;
|
||||
|
||||
// Server domain
|
||||
|
||||
private String m_domain;
|
||||
|
||||
// Network broadcast mask string
|
||||
|
||||
private String m_broadcast;
|
||||
|
||||
// Announce the server to network neighborhood, announcement interval in
|
||||
// minutes
|
||||
private boolean m_announce;
|
||||
|
||||
private boolean m_announce;
|
||||
private int m_announceInterval;
|
||||
|
||||
// Default SMB dialects to enable
|
||||
private DialectSelector m_dialects;
|
||||
|
||||
// List of shared devices
|
||||
|
||||
private SharedDeviceList m_shareList;
|
||||
|
||||
// Authenticator, used to authenticate users and share connections.
|
||||
private SrvAuthenticator m_authenticator;
|
||||
|
||||
private CifsAuthenticator m_authenticator;
|
||||
|
||||
// Share mapper
|
||||
|
||||
private ShareMapper m_shareMapper;
|
||||
|
||||
// Access control manager
|
||||
|
||||
private AccessControlManager m_aclManager;
|
||||
|
||||
// Global access control list, applied to all shares that do not have access
|
||||
// controls
|
||||
// Global access control list, applied to all shares that do not have access controls
|
||||
|
||||
private AccessControlList m_globalACLs;
|
||||
|
||||
private boolean m_nbDebug = false;
|
||||
@@ -206,31 +211,31 @@ public class ServerConfiguration implements ApplicationListener
|
||||
private boolean m_announceDebug = false;
|
||||
|
||||
// Default session debugging setting
|
||||
|
||||
private int m_sessDebug;
|
||||
|
||||
// Flags to indicate if NetBIOS, native TCP/IP SMB and/or Win32 NetBIOS
|
||||
// should be enabled
|
||||
|
||||
private boolean m_netBIOSEnable = true;
|
||||
|
||||
private boolean m_tcpSMBEnable = false;
|
||||
|
||||
private boolean m_win32NBEnable = false;
|
||||
|
||||
// Address to bind the SMB server to, if null all local addresses are used
|
||||
|
||||
private InetAddress m_smbBindAddress;
|
||||
|
||||
// Address to bind the NetBIOS name server to, if null all addresses are
|
||||
// used
|
||||
// Address to bind the NetBIOS name server to, if null all addresses are used
|
||||
|
||||
private InetAddress m_nbBindAddress;
|
||||
|
||||
// WINS servers
|
||||
|
||||
private InetAddress m_winsPrimary;
|
||||
private InetAddress m_winsSecondary;
|
||||
|
||||
// User account list
|
||||
private UserAccountList m_userList;
|
||||
|
||||
// Enable/disable Macintosh extension SMBs
|
||||
|
||||
private boolean m_macExtensions;
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
@@ -238,13 +243,16 @@ public class ServerConfiguration implements ApplicationListener
|
||||
//
|
||||
// Server name to register under Win32 NetBIOS, if not set the main server
|
||||
// name is used
|
||||
|
||||
private String m_win32NBName;
|
||||
|
||||
// LANA to be used for Win32 NetBIOS, if not specified the first available
|
||||
// is used
|
||||
|
||||
private int m_win32NBLANA = -1;
|
||||
|
||||
// Send out host announcements via the Win32 NetBIOS interface
|
||||
|
||||
private boolean m_win32NBAnnounce = false;
|
||||
private int m_win32NBAnnounceInterval;
|
||||
|
||||
@@ -277,10 +285,12 @@ public class ServerConfiguration implements ApplicationListener
|
||||
// Global server configuration
|
||||
//
|
||||
// Timezone name and offset from UTC in minutes
|
||||
|
||||
private String m_timeZone;
|
||||
private int m_tzOffset;
|
||||
|
||||
// JCE provider class name
|
||||
|
||||
private String m_jceProviderClass;
|
||||
|
||||
// Local server name and domain/workgroup name
|
||||
@@ -288,7 +298,8 @@ public class ServerConfiguration implements ApplicationListener
|
||||
private String m_localName;
|
||||
private String m_localDomain;
|
||||
|
||||
/** flag indicating successful initialisation */
|
||||
// flag to indicate successful initialization
|
||||
|
||||
private boolean initialised;
|
||||
|
||||
// Main authentication service, public API
|
||||
@@ -314,23 +325,6 @@ public class ServerConfiguration implements ApplicationListener
|
||||
|
||||
m_shareList = new SharedDeviceList();
|
||||
|
||||
// Allocate the SMB dialect selector, and initialize using the default
|
||||
// list of dialects
|
||||
|
||||
m_dialects = new DialectSelector();
|
||||
|
||||
m_dialects.AddDialect(Dialect.DOSLanMan1);
|
||||
m_dialects.AddDialect(Dialect.DOSLanMan2);
|
||||
m_dialects.AddDialect(Dialect.LanMan1);
|
||||
m_dialects.AddDialect(Dialect.LanMan2);
|
||||
m_dialects.AddDialect(Dialect.LanMan2_1);
|
||||
m_dialects.AddDialect(Dialect.NT);
|
||||
|
||||
// Use the local authenticator, that allows locally defined users to connect to the
|
||||
// server
|
||||
|
||||
setAuthenticator(new LocalAuthenticator(), null, true);
|
||||
|
||||
// Use the default share mapper
|
||||
|
||||
m_shareMapper = new DefaultShareMapper();
|
||||
@@ -1328,7 +1322,7 @@ public class ServerConfiguration implements ApplicationListener
|
||||
|
||||
// Parse the path
|
||||
|
||||
FTPPath ftpPath = new FTPPath(rootPath);
|
||||
new FTPPath(rootPath);
|
||||
|
||||
// Set the root path
|
||||
|
||||
@@ -1419,10 +1413,32 @@ public class ServerConfiguration implements ApplicationListener
|
||||
}
|
||||
}
|
||||
|
||||
// Get the top level filesystems confgiruation element
|
||||
|
||||
ConfigElement filesystems = config.getConfigElement("filesystems");
|
||||
|
||||
// Get the filesystem configuration elements
|
||||
|
||||
List<ConfigElement> filesysElems = config.getConfigElementList("filesystem");
|
||||
List<ConfigElement> filesysElems = null;
|
||||
if ( filesystems != null)
|
||||
{
|
||||
// Get the list of filesystems
|
||||
|
||||
filesysElems = filesystems.getChildren();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check for the old style configuration
|
||||
|
||||
filesysElems = config.getConfigElementList( "filesystem");
|
||||
|
||||
// Warn that the configuration is using the old format
|
||||
|
||||
logger.warn("Old style file-servers.xml configuration being used");
|
||||
}
|
||||
|
||||
// Process the filesystems list
|
||||
|
||||
if (filesysElems != null)
|
||||
{
|
||||
|
||||
@@ -1494,6 +1510,12 @@ public class ServerConfiguration implements ApplicationListener
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No filesystems defined
|
||||
|
||||
logger.warn("No filesystems defined");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1544,7 +1566,7 @@ public class ServerConfiguration implements ApplicationListener
|
||||
|
||||
String authType = authElem.getAttribute("type");
|
||||
if (authType == null)
|
||||
throw new AlfrescoRuntimeException("Authenticator type not specified");
|
||||
authType = "alfresco";
|
||||
|
||||
// Get the authentication component type
|
||||
|
||||
@@ -1552,10 +1574,9 @@ public class ServerConfiguration implements ApplicationListener
|
||||
|
||||
// Set the authenticator class to use
|
||||
|
||||
SrvAuthenticator auth = null;
|
||||
if (authType.equalsIgnoreCase("local"))
|
||||
auth = new LocalAuthenticator();
|
||||
else if (authType.equalsIgnoreCase("passthru"))
|
||||
CifsAuthenticator auth = null;
|
||||
|
||||
if (authType.equalsIgnoreCase("passthru"))
|
||||
{
|
||||
// Check if the appropriate authentication component type is configured
|
||||
|
||||
@@ -1568,14 +1589,6 @@ public class ServerConfiguration implements ApplicationListener
|
||||
if ( auth == null)
|
||||
throw new AlfrescoRuntimeException("Failed to load passthru authenticator");
|
||||
}
|
||||
else if (authType.equalsIgnoreCase("acegi"))
|
||||
{
|
||||
// Load the Acegi authenticator dynamically
|
||||
|
||||
auth = loadAuthenticatorClass("org.alfresco.filesys.server.auth.passthru.AcegiPassthruAuthenticator");
|
||||
if ( auth == null)
|
||||
throw new AlfrescoRuntimeException("Failed to load Acegi passthru authenticator");
|
||||
}
|
||||
else if (authType.equalsIgnoreCase("alfresco"))
|
||||
{
|
||||
// Standard authenticator requires MD4 or passthru based authentication
|
||||
@@ -1592,6 +1605,15 @@ public class ServerConfiguration implements ApplicationListener
|
||||
if ( auth == null)
|
||||
throw new AlfrescoRuntimeException("Failed to load Alfresco authenticator");
|
||||
}
|
||||
else if( authType.equalsIgnoreCase("enterprise"))
|
||||
{
|
||||
// Load the Enterprise authenticator dynamically
|
||||
|
||||
auth = loadAuthenticatorClass("org.alfresco.filesys.server.auth.EnterpriseCifsAuthenticator");
|
||||
|
||||
if ( auth == null)
|
||||
throw new AlfrescoRuntimeException("Failed to load Enterprise authenticator");
|
||||
}
|
||||
else
|
||||
throw new AlfrescoRuntimeException("Invalid authenticator type, " + authType);
|
||||
|
||||
@@ -1605,31 +1627,6 @@ public class ServerConfiguration implements ApplicationListener
|
||||
setAuthenticator(auth, authElem, allowGuest);
|
||||
auth.setMapToGuest( mapGuest);
|
||||
}
|
||||
|
||||
// Add the users
|
||||
|
||||
ConfigElement usersElem = config.getConfigElement("users");
|
||||
if (usersElem != null)
|
||||
{
|
||||
|
||||
// Get the list of user elements
|
||||
|
||||
List<ConfigElement> userElemList = usersElem.getChildren();
|
||||
|
||||
for (int i = 0; i < userElemList.size(); i++)
|
||||
{
|
||||
|
||||
// Get the current user element
|
||||
|
||||
ConfigElement curUserElem = userElemList.get(i);
|
||||
|
||||
if (curUserElem.getName().equals("localuser"))
|
||||
{
|
||||
processUser(curUserElem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1723,62 +1720,6 @@ public class ServerConfiguration implements ApplicationListener
|
||||
return acls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a user account
|
||||
*
|
||||
* @param user ConfigElement
|
||||
*/
|
||||
private final void processUser(ConfigElement user)
|
||||
{
|
||||
|
||||
// Get the username
|
||||
|
||||
String attr = user.getAttribute("name");
|
||||
if (attr == null || attr.length() == 0)
|
||||
throw new AlfrescoRuntimeException("User name not specified, or zero length");
|
||||
|
||||
// Check if the user already exists
|
||||
|
||||
String userName = attr;
|
||||
|
||||
if (hasUserAccounts() && getUserAccounts().findUser(userName) != null)
|
||||
throw new AlfrescoRuntimeException("User " + userName + " already defined");
|
||||
|
||||
// Get the password for the account
|
||||
|
||||
ConfigElement elem = user.getChild("password");
|
||||
if (elem == null)
|
||||
throw new AlfrescoRuntimeException("No password specified for user " + userName);
|
||||
|
||||
String password = elem.getValue();
|
||||
|
||||
// Create the user account
|
||||
|
||||
UserAccount userAcc = new UserAccount(userName, password);
|
||||
|
||||
// Check if the user in an administrator
|
||||
|
||||
if (user.getChild("administrator") != null)
|
||||
userAcc.setAdministrator(true);
|
||||
|
||||
// Get the real user name and comment
|
||||
|
||||
elem = user.getChild("realname");
|
||||
if (elem != null)
|
||||
userAcc.setRealName(elem.getValue());
|
||||
|
||||
elem = user.getChild("comment");
|
||||
if (elem != null)
|
||||
userAcc.setComment(elem.getValue());
|
||||
|
||||
// Add the user account
|
||||
|
||||
UserAccountList accList = getUserAccounts();
|
||||
if (accList == null)
|
||||
setUserAccounts(new UserAccountList());
|
||||
getUserAccounts().addUser(userAcc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the platforms attribute returning the set of platform ids
|
||||
*
|
||||
@@ -1938,11 +1879,11 @@ public class ServerConfiguration implements ApplicationListener
|
||||
|
||||
/**
|
||||
* Get the authenticator object that is used to provide user and share connection
|
||||
* authentication.
|
||||
* authentication for CIFS.
|
||||
*
|
||||
* @return Authenticator
|
||||
* @return CifsAuthenticator
|
||||
*/
|
||||
public final SrvAuthenticator getAuthenticator()
|
||||
public final CifsAuthenticator getAuthenticator()
|
||||
{
|
||||
return m_authenticator;
|
||||
}
|
||||
@@ -2057,16 +1998,6 @@ public class ServerConfiguration implements ApplicationListener
|
||||
return m_domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the enabled SMB dialects that the server will use when negotiating sessions.
|
||||
*
|
||||
* @return DialectSelector
|
||||
*/
|
||||
public final DialectSelector getEnabledDialects()
|
||||
{
|
||||
return m_dialects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the server name.
|
||||
*
|
||||
@@ -2117,16 +2048,6 @@ public class ServerConfiguration implements ApplicationListener
|
||||
return m_shareMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the user account list.
|
||||
*
|
||||
* @return UserAccountList
|
||||
*/
|
||||
public final UserAccountList getUserAccounts()
|
||||
{
|
||||
return m_userList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Win32 NetBIOS server name, if null the default server name will be used
|
||||
*
|
||||
@@ -2470,18 +2391,6 @@ public class ServerConfiguration implements ApplicationListener
|
||||
return m_macExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if there are any user accounts defined.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasUserAccounts()
|
||||
{
|
||||
if (m_userList != null && m_userList.numberOfUsers() > 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if NetBIOS SMB is enabled
|
||||
*
|
||||
@@ -2543,18 +2452,17 @@ public class ServerConfiguration implements ApplicationListener
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the authenticator to be used to authenticate users and share connections.
|
||||
* Set the authenticator to be used to authenticate users and share connections for CIFS.
|
||||
*
|
||||
* @param auth SrvAuthenticator
|
||||
* @param auth CifsAuthenticator
|
||||
* @param params ConfigElement
|
||||
* @param allowGuest boolean
|
||||
*/
|
||||
public final void setAuthenticator(SrvAuthenticator auth, ConfigElement params, boolean allowGuest)
|
||||
public final void setAuthenticator(CifsAuthenticator auth, ConfigElement params, boolean allowGuest)
|
||||
{
|
||||
|
||||
// Set the server authenticator mode and guest access
|
||||
|
||||
auth.setAccessMode(SrvAuthenticator.USER_MODE);
|
||||
auth.setAllowGuest(allowGuest);
|
||||
|
||||
// Initialize the authenticator using the parameter values
|
||||
@@ -2733,16 +2641,6 @@ public class ServerConfiguration implements ApplicationListener
|
||||
m_sessDebug = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user account list.
|
||||
*
|
||||
* @param users UserAccountList
|
||||
*/
|
||||
public final void setUserAccounts(UserAccountList users)
|
||||
{
|
||||
m_userList = users;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the global access control list
|
||||
*
|
||||
@@ -3061,14 +2959,14 @@ public class ServerConfiguration implements ApplicationListener
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an authenticator using dyanmic loading
|
||||
* Load a CIFS authenticator using dyanmic loading
|
||||
*
|
||||
* @param className String
|
||||
* @return SrvAuthenticator
|
||||
* @return CifsAuthenticator
|
||||
*/
|
||||
private final SrvAuthenticator loadAuthenticatorClass(String className)
|
||||
private final CifsAuthenticator loadAuthenticatorClass(String className)
|
||||
{
|
||||
SrvAuthenticator srvAuth = null;
|
||||
CifsAuthenticator srvAuth = null;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -3078,8 +2976,8 @@ public class ServerConfiguration implements ApplicationListener
|
||||
|
||||
// Verify that the class is an authenticator
|
||||
|
||||
if ( authObj instanceof SrvAuthenticator)
|
||||
srvAuth = (SrvAuthenticator) authObj;
|
||||
if ( authObj instanceof CifsAuthenticator)
|
||||
srvAuth = (CifsAuthenticator) authObj;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
Reference in New Issue
Block a user