mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
NTLMv2
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@14811 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
package org.alfresco.web.sharepoint.auth.ntlm;
|
package org.alfresco.web.sharepoint.auth.ntlm;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -42,6 +43,7 @@ import org.alfresco.jlan.server.auth.PasswordEncryptor;
|
|||||||
import org.alfresco.jlan.server.auth.ntlm.NTLM;
|
import org.alfresco.jlan.server.auth.ntlm.NTLM;
|
||||||
import org.alfresco.jlan.server.auth.ntlm.NTLMLogonDetails;
|
import org.alfresco.jlan.server.auth.ntlm.NTLMLogonDetails;
|
||||||
import org.alfresco.jlan.server.auth.ntlm.NTLMMessage;
|
import org.alfresco.jlan.server.auth.ntlm.NTLMMessage;
|
||||||
|
import org.alfresco.jlan.server.auth.ntlm.NTLMv2Blob;
|
||||||
import org.alfresco.jlan.server.auth.ntlm.TargetInfo;
|
import org.alfresco.jlan.server.auth.ntlm.TargetInfo;
|
||||||
import org.alfresco.jlan.server.auth.ntlm.Type1NTLMMessage;
|
import org.alfresco.jlan.server.auth.ntlm.Type1NTLMMessage;
|
||||||
import org.alfresco.jlan.server.auth.ntlm.Type2NTLMMessage;
|
import org.alfresco.jlan.server.auth.ntlm.Type2NTLMMessage;
|
||||||
@@ -81,8 +83,13 @@ public class NtlmAuthenticationHandler extends AbstractAuthenticationHandler
|
|||||||
private NLTMAuthenticator authenticationComponent;
|
private NLTMAuthenticator authenticationComponent;
|
||||||
private TransactionService transactionService;
|
private TransactionService transactionService;
|
||||||
private NodeService nodeService;
|
private NodeService nodeService;
|
||||||
private static final int ntlmFlags = NTLM.Flag56Bit + NTLM.FlagLanManKey + NTLM.FlagNegotiateNTLM
|
|
||||||
+ NTLM.FlagNegotiateOEM + NTLM.FlagNegotiateUnicode;
|
private static final int ntlmFlags = NTLM.Flag56Bit +
|
||||||
|
NTLM.Flag128Bit +
|
||||||
|
NTLM.FlagLanManKey +
|
||||||
|
NTLM.FlagNegotiateNTLM +
|
||||||
|
NTLM.FlagNTLM2Key +
|
||||||
|
NTLM.FlagNegotiateUnicode;
|
||||||
|
|
||||||
public void setAuthenticationComponent(NLTMAuthenticator authenticationComponent)
|
public void setAuthenticationComponent(NLTMAuthenticator authenticationComponent)
|
||||||
{
|
{
|
||||||
@@ -503,7 +510,44 @@ public class NtlmAuthenticationHandler extends AbstractAuthenticationHandler
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
authenticated = checkNTLMv1(md4hash, ntlmDetails.getChallengeKey(), type3Msg, false);
|
if (type3Msg.hasFlag(NTLM.FlagNTLM2Key))
|
||||||
|
{
|
||||||
|
// Determine if the client sent us an NTLMv2 blob or an NTLMv2 session key
|
||||||
|
if (type3Msg.getNTLMHashLength() > 24)
|
||||||
|
{
|
||||||
|
// Looks like an NTLMv2 blob
|
||||||
|
authenticated = checkNTLMv2(md4hash, ntlmDetails.getChallengeKey(), type3Msg);
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug((authenticated ? "Logged on" : "Logon failed") + " using NTLMSSP/NTLMv2");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( authenticated == false && type3Msg.hasFlag(NTLM.Flag56Bit) && type3Msg.getLMHashLength() == 24)
|
||||||
|
{
|
||||||
|
authenticated = checkNTLMv1(md4hash, ntlmDetails.getChallengeKey(), type3Msg, true);
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug((authenticated ? "Logged on" : "Logon failed") + " using NTLMSSP/NTLMv1 (via fallback)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
authenticated = checkNTLMv2SessionKey(md4hash, ntlmDetails.getChallengeKey(), type3Msg);
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug((authenticated ? "Logged on" : "Logon failed") + " using NTLMSSP/NTLMv2SessKey");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
authenticated = checkNTLMv1(md4hash, ntlmDetails.getChallengeKey(), type3Msg, false);
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug((authenticated ? "Logged on" : "Logon failed") + " using NTLMSSP/NTLMv1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return authenticated;
|
return authenticated;
|
||||||
}
|
}
|
||||||
@@ -549,6 +593,143 @@ public class NtlmAuthenticationHandler extends AbstractAuthenticationHandler
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final boolean checkNTLMv2(String md4hash, byte[] challenge, Type3NTLMMessage type3Msg)
|
||||||
|
{
|
||||||
|
boolean ntlmv2OK = false;
|
||||||
|
boolean lmv2OK = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
byte[] v2hash = encryptor.doNTLM2Encryption(md4Encoder.decodeHash(md4hash), type3Msg.getUserName(), type3Msg.getDomain());
|
||||||
|
|
||||||
|
NTLMv2Blob v2blob = new NTLMv2Blob(type3Msg.getNTLMHash());
|
||||||
|
|
||||||
|
byte[] srvHmac = v2blob.calculateHMAC(challenge, v2hash);
|
||||||
|
byte[] clientHmac = v2blob.getHMAC();
|
||||||
|
|
||||||
|
if (clientHmac != null && srvHmac != null && clientHmac.length == srvHmac.length)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (i < clientHmac.length && clientHmac[i] == srvHmac[i])
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (i == clientHmac.length)
|
||||||
|
{
|
||||||
|
ntlmv2OK = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ntlmv2OK == false)
|
||||||
|
{
|
||||||
|
byte[] lmv2 = type3Msg.getLMHash();
|
||||||
|
byte[] clChallenge = v2blob.getClientChallenge();
|
||||||
|
|
||||||
|
if ( lmv2 != null && lmv2.length == 24 && clChallenge != null && clChallenge.length == 8)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while ( i < clChallenge.length && lmv2[ i + 16] == clChallenge[ i])
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if ( i == clChallenge.length)
|
||||||
|
{
|
||||||
|
|
||||||
|
byte[] lmv2Hmac = v2blob.calculateLMv2HMAC(v2hash, challenge, clChallenge);
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
while (i < lmv2Hmac.length && lmv2[i] == lmv2Hmac[i])
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (i == lmv2Hmac.length)
|
||||||
|
{
|
||||||
|
lmv2OK = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( ntlmv2OK || lmv2OK)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final boolean checkNTLMv2SessionKey(String md4hash, byte[] challenge, Type3NTLMMessage type3Msg)
|
||||||
|
{
|
||||||
|
// Create the value to be encrypted by appending the server challenge and client challenge
|
||||||
|
// and applying an MD5 digest
|
||||||
|
byte[] nonce = new byte[16];
|
||||||
|
System.arraycopy(challenge, 0, nonce, 0, 8);
|
||||||
|
System.arraycopy(type3Msg.getLMHash(), 0, nonce, 8, 8);
|
||||||
|
|
||||||
|
MessageDigest md5 = null;
|
||||||
|
byte[] v2challenge = new byte[8];
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
md5 = MessageDigest.getInstance("MD5");
|
||||||
|
// Apply the MD5 digest to the nonce
|
||||||
|
md5.update(nonce);
|
||||||
|
byte[] md5nonce = md5.digest();
|
||||||
|
|
||||||
|
// We only want the first 8 bytes
|
||||||
|
System.arraycopy(md5nonce, 0, v2challenge, 0, 8);
|
||||||
|
}
|
||||||
|
catch (NoSuchAlgorithmException ex)
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug(ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the local encrypted password using the MD5 generated challenge
|
||||||
|
byte[] p21 = new byte[21];
|
||||||
|
byte[] md4byts = md4Encoder.decodeHash(md4hash);
|
||||||
|
System.arraycopy(md4byts, 0, p21, 0, 16);
|
||||||
|
|
||||||
|
// Generate the local hash of the password
|
||||||
|
byte[] localHash = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
localHash = encryptor.doNTLM1Encryption(p21, v2challenge);
|
||||||
|
}
|
||||||
|
catch (NoSuchAlgorithmException ex)
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug(ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
byte[] clientHash = type3Msg.getNTLMHash();
|
||||||
|
|
||||||
|
if (clientHash != null && localHash != null && clientHash.length == localHash.length)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (i < clientHash.length && clientHash[i] == localHash[i])
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == clientHash.length)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private void putNtlmLogonDetailsToSession(HttpServletRequest request, NTLMLogonDetails details)
|
private void putNtlmLogonDetailsToSession(HttpServletRequest request, NTLMLogonDetails details)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user