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:
Gary Spencer
2006-05-04 15:29:26 +00:00
parent fe5257a3a2
commit d021b46d07
29 changed files with 4719 additions and 2124 deletions

View File

@@ -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();
}

View File

@@ -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.
*

View File

@@ -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;
}
}

View File

@@ -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
{
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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()));
}
}

View File

@@ -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
*

View File

@@ -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");
}
}

View File

@@ -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)

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View 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)
{
}
}
}

View 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;
}
}

View File

@@ -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)
{