Commit ccd7f7a4 authored by justcoding121's avatar justcoding121

ntlm progress

parent dabcc1d6
......@@ -33,6 +33,7 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
......@@ -59,6 +60,7 @@
<Compile Include="CertificateManagerTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ProxyServerTests.cs" />
<Compile Include="WinAuthTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Titanium.Web.Proxy\Titanium.Web.Proxy.csproj">
......
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Titanium.Web.Proxy.Network.WinAuth;
namespace Titanium.Web.Proxy.UnitTests
{
[TestClass]
public class WinAuthTests
{
[TestMethod]
public void Test_Acquire_Client_Token()
{
var token = WinAuthHandler.GetInitialAuthToken("mylocalserver.com");
Assert.IsTrue(token.Length > 1);
}
}
}
namespace Titanium.Web.Proxy.Network.WinAuth.Security
{
using System;
internal struct BufferWrapper
{
internal byte[] Buffer;
internal Common.SecurityBufferType BufferType;
internal BufferWrapper(byte[] buffer, Common.SecurityBufferType bufferType)
{
if (buffer == null || buffer.Length == 0)
{
throw new ArgumentException("buffer cannot be null or 0 length");
}
Buffer = buffer;
BufferType = bufferType;
}
};
}
namespace Titanium.Web.Proxy.Network.WinAuth.Security
{
using System;
using System.Runtime.InteropServices;
internal class Common
{
#region Private constants
private const int ISC_REQ_REPLAY_DETECT = 0x00000004;
private const int ISC_REQ_SEQUENCE_DETECT = 0x00000008;
private const int ISC_REQ_CONFIDENTIALITY = 0x00000010;
private const int ISC_REQ_CONNECTION = 0x00000800;
#endregion
internal static uint NewContextAttributes = 0;
internal static Common.SecurityInteger NewLifeTime = new SecurityInteger(0);
#region internal constants
internal const int StandardContextAttributes = ISC_REQ_CONFIDENTIALITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_CONNECTION;
internal const int SecurityNativeDataRepresentation = 0x10;
internal const int MaximumTokenSize = 12288;
internal const int SecurityCredentialsOutbound = 2;
internal const int SuccessfulResult = 0;
internal const int IntermediateResult = 0x90312;
#endregion
#region internal enumerations
internal enum SecurityBufferType
{
SECBUFFER_VERSION = 0,
SECBUFFER_EMPTY = 0,
SECBUFFER_DATA = 1,
SECBUFFER_TOKEN = 2
}
[Flags]
internal enum NtlmFlags : int
{
// The client sets this flag to indicate that it supports Unicode strings.
NegotiateUnicode = 0x00000001,
// This is set to indicate that the client supports OEM strings.
NegotiateOem = 0x00000002,
// This requests that the server send the authentication target with the Type 2 reply.
RequestTarget = 0x00000004,
// Indicates that NTLM authentication is supported.
NegotiateNtlm = 0x00000200,
// When set, the client will send with the message the name of the domain in which the workstation has membership.
NegotiateDomainSupplied = 0x00001000,
// Indicates that the client is sending its workstation name with the message.
NegotiateWorkstationSupplied = 0x00002000,
// Indicates that communication between the client and server after authentication should carry a "dummy" signature.
NegotiateAlwaysSign = 0x00008000,
// Indicates that this client supports the NTLM2 signing and sealing scheme; if negotiated, this can also affect the response calculations.
NegotiateNtlm2Key = 0x00080000,
// Indicates that this client supports strong (128-bit) encryption.
Negotiate128 = 0x20000000,
// Indicates that this client supports medium (56-bit) encryption.
Negotiate56 = (unchecked((int)0x80000000))
}
internal enum NtlmAuthLevel
{
/* Use LM and NTLM, never use NTLMv2 session security. */
LM_and_NTLM,
/* Use NTLMv2 session security if the server supports it,
* otherwise fall back to LM and NTLM. */
LM_and_NTLM_and_try_NTLMv2_Session,
/* Use NTLMv2 session security if the server supports it,
* otherwise fall back to NTLM. Never use LM. */
NTLM_only,
/* Use NTLMv2 only. */
NTLMv2_only,
}
#endregion
#region internal structures
[StructLayout(LayoutKind.Sequential)]
internal struct SecurityHandle
{
internal IntPtr LowPart;
internal IntPtr HighPart;
internal SecurityHandle(int dummy)
{
LowPart = HighPart = IntPtr.Zero;
}
/// <summary>
/// Resets all internal pointers to default value
/// </summary>
internal void Reset()
{
LowPart = HighPart = IntPtr.Zero;
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct SecurityInteger
{
internal uint LowPart;
internal int HighPart;
internal SecurityInteger(int dummy)
{
LowPart = 0;
HighPart = 0;
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct SecurityBuffer : IDisposable
{
internal int cbBuffer;
internal int cbBufferType;
internal IntPtr pvBuffer;
internal SecurityBuffer(int bufferSize)
{
cbBuffer = bufferSize;
cbBufferType = (int)SecurityBufferType.SECBUFFER_TOKEN;
pvBuffer = Marshal.AllocHGlobal(bufferSize);
}
internal SecurityBuffer(byte[] secBufferBytes)
{
cbBuffer = secBufferBytes.Length;
cbBufferType = (int)SecurityBufferType.SECBUFFER_TOKEN;
pvBuffer = Marshal.AllocHGlobal(cbBuffer);
Marshal.Copy(secBufferBytes, 0, pvBuffer, cbBuffer);
}
internal SecurityBuffer(byte[] secBufferBytes, SecurityBufferType bufferType)
{
cbBuffer = secBufferBytes.Length;
cbBufferType = (int)bufferType;
pvBuffer = Marshal.AllocHGlobal(cbBuffer);
Marshal.Copy(secBufferBytes, 0, pvBuffer, cbBuffer);
}
public void Dispose()
{
if (pvBuffer != IntPtr.Zero)
{
Marshal.FreeHGlobal(pvBuffer);
pvBuffer = IntPtr.Zero;
}
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct SecurityBufferDesciption : IDisposable
{
internal int ulVersion;
internal int cBuffers;
internal IntPtr pBuffers; //Point to SecBuffer
internal SecurityBufferDesciption(int bufferSize)
{
ulVersion = (int)SecurityBufferType.SECBUFFER_VERSION;
cBuffers = 1;
Common.SecurityBuffer ThisSecBuffer = new Common.SecurityBuffer(bufferSize);
pBuffers = Marshal.AllocHGlobal(Marshal.SizeOf(ThisSecBuffer));
Marshal.StructureToPtr(ThisSecBuffer, pBuffers, false);
}
internal SecurityBufferDesciption(byte[] secBufferBytes)
{
ulVersion = (int)SecurityBufferType.SECBUFFER_VERSION;
cBuffers = 1;
Common.SecurityBuffer ThisSecBuffer = new Common.SecurityBuffer(secBufferBytes);
pBuffers = Marshal.AllocHGlobal(Marshal.SizeOf(ThisSecBuffer));
Marshal.StructureToPtr(ThisSecBuffer, pBuffers, false);
}
internal SecurityBufferDesciption(BufferWrapper[] secBufferBytesArray)
{
if (secBufferBytesArray == null || secBufferBytesArray.Length == 0)
{
throw new ArgumentException("secBufferBytesArray cannot be null or 0 length");
}
ulVersion = (int)SecurityBufferType.SECBUFFER_VERSION;
cBuffers = secBufferBytesArray.Length;
//Allocate memory for SecBuffer Array....
pBuffers = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Buffer)) * cBuffers);
for (int Index = 0; Index < secBufferBytesArray.Length; Index++)
{
//Super hack: Now allocate memory for the individual SecBuffers
//and just copy the bit values to the SecBuffer array!!!
Common.SecurityBuffer ThisSecBuffer = new Common.SecurityBuffer(secBufferBytesArray[Index].Buffer, secBufferBytesArray[Index].BufferType);
//We will write out bits in the following order:
//int cbBuffer;
//int BufferType;
//pvBuffer;
//Note that we won't be releasing the memory allocated by ThisSecBuffer until we
//are disposed...
int CurrentOffset = Index * Marshal.SizeOf(typeof(Buffer));
Marshal.WriteInt32(pBuffers, CurrentOffset, ThisSecBuffer.cbBuffer);
Marshal.WriteInt32(pBuffers, CurrentOffset + Marshal.SizeOf(ThisSecBuffer.cbBuffer), ThisSecBuffer.cbBufferType);
Marshal.WriteIntPtr(pBuffers, CurrentOffset + Marshal.SizeOf(ThisSecBuffer.cbBuffer) + Marshal.SizeOf(ThisSecBuffer.cbBufferType), ThisSecBuffer.pvBuffer);
}
}
public void Dispose()
{
if (pBuffers != IntPtr.Zero)
{
if (cBuffers == 1)
{
Common.SecurityBuffer ThisSecBuffer = (Common.SecurityBuffer)Marshal.PtrToStructure(pBuffers, typeof(Common.SecurityBuffer));
ThisSecBuffer.Dispose();
}
else
{
for (int Index = 0; Index < cBuffers; Index++)
{
//The bits were written out the following order:
//int cbBuffer;
//int BufferType;
//pvBuffer;
//What we need to do here is to grab a hold of the pvBuffer allocate by the individual
//SecBuffer and release it...
int CurrentOffset = Index * Marshal.SizeOf(typeof(Buffer));
IntPtr SecBufferpvBuffer = Marshal.ReadIntPtr(pBuffers, CurrentOffset + Marshal.SizeOf(typeof(int)) + Marshal.SizeOf(typeof(int)));
Marshal.FreeHGlobal(SecBufferpvBuffer);
}
}
Marshal.FreeHGlobal(pBuffers);
pBuffers = IntPtr.Zero;
}
}
internal byte[] GetBytes()
{
byte[] Buffer = null;
if (pBuffers == IntPtr.Zero)
{
throw new InvalidOperationException("Object has already been disposed!!!");
}
if (cBuffers == 1)
{
Common.SecurityBuffer ThisSecBuffer = (Common.SecurityBuffer)Marshal.PtrToStructure(pBuffers, typeof(Common.SecurityBuffer));
if (ThisSecBuffer.cbBuffer > 0)
{
Buffer = new byte[ThisSecBuffer.cbBuffer];
Marshal.Copy(ThisSecBuffer.pvBuffer, Buffer, 0, ThisSecBuffer.cbBuffer);
}
}
else
{
int BytesToAllocate = 0;
for (int Index = 0; Index < cBuffers; Index++)
{
//The bits were written out the following order:
//int cbBuffer;
//int BufferType;
//pvBuffer;
//What we need to do here calculate the total number of bytes we need to copy...
int CurrentOffset = Index * Marshal.SizeOf(typeof(Buffer));
BytesToAllocate += Marshal.ReadInt32(pBuffers, CurrentOffset);
}
Buffer = new byte[BytesToAllocate];
for (int Index = 0, BufferIndex = 0; Index < cBuffers; Index++)
{
//The bits were written out the following order:
//int cbBuffer;
//int BufferType;
//pvBuffer;
//Now iterate over the individual buffers and put them together into a
//byte array...
int CurrentOffset = Index * Marshal.SizeOf(typeof(Buffer));
int BytesToCopy = Marshal.ReadInt32(pBuffers, CurrentOffset);
IntPtr SecBufferpvBuffer = Marshal.ReadIntPtr(pBuffers, CurrentOffset + Marshal.SizeOf(typeof(int)) + Marshal.SizeOf(typeof(int)));
Marshal.Copy(SecBufferpvBuffer, Buffer, BufferIndex, BytesToCopy);
BufferIndex += BytesToCopy;
}
}
return (Buffer);
}
}
#endregion
}
}
// http://pinvoke.net/default.aspx/secur32/InitializeSecurityContext.html
namespace Titanium.Web.Proxy.Network.WinAuth.Security
{
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
using static Common;
internal class EndPoint
{
internal static byte[] AcquireInitialSecurityToken(string hostname)
{
byte[] token = null;
//null for initial call
SecurityBufferDesciption serverToken
= new SecurityBufferDesciption();
SecurityBufferDesciption clientToken
= new SecurityBufferDesciption(MaximumTokenSize);
try
{
int result;
var state = new State();
result = AcquireCredentialsHandle(
WindowsIdentity.GetCurrent().Name,
"NTLM",
Common.SecurityCredentialsOutbound,
IntPtr.Zero,
IntPtr.Zero,
0,
IntPtr.Zero,
ref state.Credentials,
ref NewLifeTime);
if (result != SuccessfulResult)
{
// Credentials acquire operation failed.
return null;
}
result = InitializeSecurityContext(ref state.Credentials,
IntPtr.Zero,
hostname,
StandardContextAttributes,
0,
SecurityNativeDataRepresentation,
ref serverToken,
0,
out state.Context,
out clientToken,
out NewContextAttributes,
out NewLifeTime);
if (result != IntermediateResult)
{
// Client challenge issue operation failed.
return null;
}
token = clientToken.GetBytes();
}
finally
{
clientToken.Dispose();
serverToken.Dispose();
}
return token;
}
/// <summary>
/// Acquire the final token to send
/// </summary>
/// <param name="hostname"></param>
/// <param name="serverChallenge"></param>
/// <returns></returns>
internal static byte[] AcquireFinalSecurityToken(string hostname, byte[] serverChallenge)
{
byte[] token = null;
//user server challenge
SecurityBufferDesciption serverToken
= new SecurityBufferDesciption(serverChallenge);
SecurityBufferDesciption clientToken
= new SecurityBufferDesciption(MaximumTokenSize);
try
{
int result;
var state = new State();
result = AcquireCredentialsHandle(
WindowsIdentity.GetCurrent().Name,
"NTLM",
SecurityCredentialsOutbound,
IntPtr.Zero,
IntPtr.Zero,
0,
IntPtr.Zero,
ref state.Credentials,
ref NewLifeTime);
if (result != SuccessfulResult)
{
// Credentials acquire operation failed.
return null;
}
result = InitializeSecurityContext(ref state.Credentials,
IntPtr.Zero,
hostname,
StandardContextAttributes,
0,
SecurityNativeDataRepresentation,
ref serverToken,
0,
out state.Context,
out clientToken,
out NewContextAttributes,
out NewLifeTime);
if (result != SuccessfulResult)
{
// Client challenge issue operation failed.
return null;
}
token = clientToken.GetBytes();
}
finally
{
clientToken.Dispose();
serverToken.Dispose();
}
return token;
}
#region Native calls to secur32.dll
[DllImport("secur32.dll", SetLastError = true)]
static extern int InitializeSecurityContext(ref SecurityHandle phCredential,//PCredHandle
IntPtr phContext, //PCtxtHandle
string pszTargetName,
int fContextReq,
int Reserved1,
int TargetDataRep,
ref SecurityBufferDesciption pInput, //PSecBufferDesc SecBufferDesc
int Reserved2,
out SecurityHandle phNewContext, //PCtxtHandle
out Common.SecurityBufferDesciption pOutput, //PSecBufferDesc SecBufferDesc
out uint pfContextAttr, //managed ulong == 64 bits!!!
out Common.SecurityInteger ptsExpiry); //PTimeStamp
[DllImport("secur32.dll", CharSet = CharSet.Auto, SetLastError = false)]
private static extern int AcquireCredentialsHandle(
string pszPrincipal, //SEC_CHAR*
string pszPackage, //SEC_CHAR* //"Kerberos","NTLM","Negotiative"
int fCredentialUse,
IntPtr PAuthenticationID, //_LUID AuthenticationID,//pvLogonID, //PLUID
IntPtr pAuthData, //PVOID
int pGetKeyFn, //SEC_GET_KEY_FN
IntPtr pvGetKeyArgument, //PVOID
ref Common.SecurityHandle phCredential, //SecHandle //PCtxtHandle ref
ref Common.SecurityInteger ptsExpiry); //PTimeStamp //TimeStamp ref
#endregion
}
}
//
// Mono.Security.BitConverterLE.cs
// Like System.BitConverter but always little endian
//
// Author:
// Bernie Solomon
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
namespace Titanium.Web.Proxy.Network.WinAuth.Security
{
using System;
internal sealed class LittleEndian
{
private LittleEndian ()
{
}
unsafe private static byte[] GetUShortBytes (byte *bytes)
{
if (BitConverter.IsLittleEndian)
{
return new byte[] { bytes[0], bytes[1] };
}
else
{
return new byte[] { bytes[1], bytes[0] };
}
}
unsafe private static byte[] GetUIntBytes (byte *bytes)
{
if (BitConverter.IsLittleEndian)
{
return new byte[] { bytes[0], bytes[1], bytes[2], bytes[3] };
}
else
{
return new byte[] { bytes[3], bytes[2], bytes[1], bytes[0] };
}
}
unsafe private static byte[] GetULongBytes (byte *bytes)
{
if (BitConverter.IsLittleEndian)
{
return new byte[] { bytes [0], bytes [1], bytes [2], bytes [3],
bytes [4], bytes [5], bytes [6], bytes [7] };
}
else
{
return new byte[] { bytes [7], bytes [6], bytes [5], bytes [4],
bytes [3], bytes [2], bytes [1], bytes [0] };
}
}
unsafe internal static byte[] GetBytes (bool value)
{
return new byte [] { value ? (byte)1 : (byte)0 };
}
unsafe internal static byte[] GetBytes (char value)
{
return GetUShortBytes ((byte *) &value);
}
unsafe internal static byte[] GetBytes (short value)
{
return GetUShortBytes ((byte *) &value);
}
unsafe internal static byte[] GetBytes (int value)
{
return GetUIntBytes ((byte *) &value);
}
unsafe internal static byte[] GetBytes (long value)
{
return GetULongBytes ((byte *) &value);
}
unsafe internal static byte[] GetBytes (ushort value)
{
return GetUShortBytes ((byte *) &value);
}
unsafe internal static byte[] GetBytes (uint value)
{
return GetUIntBytes ((byte *) &value);
}
unsafe internal static byte[] GetBytes (ulong value)
{
return GetULongBytes ((byte *) &value);
}
unsafe internal static byte[] GetBytes (float value)
{
return GetUIntBytes ((byte *) &value);
}
unsafe internal static byte[] GetBytes (double value)
{
return GetULongBytes ((byte *) &value);
}
unsafe private static void UShortFromBytes (byte *dst, byte[] src, int startIndex)
{
if (BitConverter.IsLittleEndian)
{
dst [0] = src [startIndex];
dst [1] = src [startIndex + 1];
}
else
{
dst [0] = src [startIndex + 1];
dst [1] = src [startIndex];
}
}
unsafe private static void UIntFromBytes (byte *dst, byte[] src, int startIndex)
{
if (BitConverter.IsLittleEndian)
{
dst [0] = src [startIndex];
dst [1] = src [startIndex + 1];
dst [2] = src [startIndex + 2];
dst [3] = src [startIndex + 3];
}
else
{
dst [0] = src [startIndex + 3];
dst [1] = src [startIndex + 2];
dst [2] = src [startIndex + 1];
dst [3] = src [startIndex];
}
}
unsafe private static void ULongFromBytes (byte *dst, byte[] src, int startIndex)
{
if (BitConverter.IsLittleEndian) {
for (int i = 0; i < 8; ++i)
dst [i] = src [startIndex + i];
} else {
for (int i = 0; i < 8; ++i)
dst [i] = src [startIndex + (7 - i)];
}
}
unsafe internal static bool ToBoolean (byte[] value, int startIndex)
{
return value [startIndex] != 0;
}
unsafe internal static char ToChar (byte[] value, int startIndex)
{
char ret;
UShortFromBytes ((byte *) &ret, value, startIndex);
return ret;
}
unsafe internal static short ToInt16 (byte[] value, int startIndex)
{
short ret;
UShortFromBytes ((byte *) &ret, value, startIndex);
return ret;
}
unsafe internal static int ToInt32 (byte[] value, int startIndex)
{
int ret;
UIntFromBytes ((byte *) &ret, value, startIndex);
return ret;
}
unsafe internal static long ToInt64 (byte[] value, int startIndex)
{
long ret;
ULongFromBytes ((byte *) &ret, value, startIndex);
return ret;
}
unsafe internal static ushort ToUInt16 (byte[] value, int startIndex)
{
ushort ret;
UShortFromBytes ((byte *) &ret, value, startIndex);
return ret;
}
unsafe internal static uint ToUInt32 (byte[] value, int startIndex)
{
uint ret;
UIntFromBytes ((byte *) &ret, value, startIndex);
return ret;
}
unsafe internal static ulong ToUInt64 (byte[] value, int startIndex)
{
ulong ret;
ULongFromBytes ((byte *) &ret, value, startIndex);
return ret;
}
unsafe internal static float ToSingle (byte[] value, int startIndex)
{
float ret;
UIntFromBytes ((byte *) &ret, value, startIndex);
return ret;
}
unsafe internal static double ToDouble (byte[] value, int startIndex)
{
double ret;
ULongFromBytes ((byte *) &ret, value, startIndex);
return ret;
}
}
}
//
// Nancy.Authentication.Ntlm.Protocol.Type3Message - Authentication
//
// Author:
// Sebastien Pouliot <sebastien@ximian.com>
//
// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
//
// References
// a. NTLM Authentication Scheme for HTTP, Ronald Tschalär
// http://www.innovation.ch/java/ntlm.html
// b. The NTLM Authentication Protocol, Copyright © 2003 Eric Glass
// http://davenport.sourceforge.net/ntlm.html
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
namespace Titanium.Web.Proxy.Network.WinAuth.Security
{
using System;
using System.Text;
internal class Message
{
static private byte[] header = { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00 };
internal Message (byte[] message)
{
_type = 3;
Decode (message);
}
/// <summary>
/// Domain name
/// </summary>
internal string Domain
{
get;
private set;
}
/// <summary>
/// Username
/// </summary>
internal string Username
{
get;
private set;
}
private int _type;
private Common.NtlmFlags _flags;
internal Common.NtlmFlags Flags
{
get { return _flags; }
set { _flags = value; }
}
// methods
private void Decode (byte[] message)
{
//base.Decode (message);
if (message == null)
throw new ArgumentNullException("message");
if (message.Length < 12)
{
string msg = "Minimum Type3 message length is 12 bytes.";
throw new ArgumentOutOfRangeException("message", message.Length, msg);
}
if (!CheckHeader(message))
{
string msg = "Invalid Type3 message header.";
throw new ArgumentException(msg, "message");
}
if (LittleEndian.ToUInt16 (message, 56) != message.Length)
{
string msg = "Invalid Type3 message length.";
throw new ArgumentException (msg, "message");
}
if (message.Length >= 64)
{
Flags = (Common.NtlmFlags)LittleEndian.ToUInt32(message, 60);
}
else
{
Flags = (Common.NtlmFlags)0x8201;
}
int dom_len = LittleEndian.ToUInt16 (message, 28);
int dom_off = LittleEndian.ToUInt16 (message, 32);
this.Domain = DecodeString (message, dom_off, dom_len);
int user_len = LittleEndian.ToUInt16 (message, 36);
int user_off = LittleEndian.ToUInt16 (message, 40);
this.Username = DecodeString (message, user_off, user_len);
}
string DecodeString (byte[] buffer, int offset, int len)
{
if ((Flags & Common.NtlmFlags.NegotiateUnicode) != 0)
{
return Encoding.Unicode.GetString(buffer, offset, len);
}
else
{
return Encoding.ASCII.GetString(buffer, offset, len);
}
}
protected bool CheckHeader(byte[] message)
{
for (int i = 0; i < header.Length; i++)
{
if (message[i] != header[i])
return false;
}
return (LittleEndian.ToUInt32(message, 8) == _type);
}
}
}
namespace Titanium.Web.Proxy.Network.WinAuth.Security
{
using System;
/// <summary>
/// Status of authenticated session
/// </summary>
internal class State
{
internal State()
{
this.Credentials = new Common.SecurityHandle(0);
this.Context = new Common.SecurityHandle(0);
this.LastSeen = DateTime.MinValue;
}
/// <summary>
/// Credentials used to validate NTLM hashes
/// </summary>
internal Common.SecurityHandle Credentials;
/// <summary>
/// Context will be used to validate HTLM hashes
/// </summary>
internal Common.SecurityHandle Context;
/// <summary>
/// Timestamp needed to calculate validity of the authenticated session
/// </summary>
internal DateTime LastSeen;
internal bool isOlder(int seconds)
{
return (this.LastSeen.AddSeconds(seconds) < DateTime.UtcNow) ? true : false;
}
internal void ResetHandles()
{
this.Credentials.Reset();
this.Context.Reset();
}
internal void UpdatePresence()
{
this.LastSeen = DateTime.UtcNow;
}
}
}
using Titanium.Web.Proxy.Network.WinAuth.Security;
using System;
namespace Titanium.Web.Proxy.Network.WinAuth
{
/// <summary>
/// A handler for NTLM/Kerberos windows authentication challenge from server
/// NTLM process details below
/// https://blogs.msdn.microsoft.com/chiranth/2013/09/20/ntlm-want-to-know-how-it-works/
/// </summary>
public static class WinAuthHandler
{
/// <summary>
/// Get the initial client token for server
/// using credentials of user running the proxy server process
/// </summary>
/// <param name="serverHostname"></param>
/// <returns></returns>
public static string GetInitialAuthToken(string serverHostname)
{
var tokenBytes = EndPoint.AcquireInitialSecurityToken(serverHostname);
return string.Concat(" ", Convert.ToBase64String(tokenBytes));
}
/// <summary>
/// Get the final token given the server challenge token
/// </summary>
/// <param name="serverHostname"></param>
/// <param name="serverToken"></param>
/// <returns></returns>
public static string GetFinalAuthToken(string serverHostname, string serverToken)
{
var tokenBytes = EndPoint.AcquireFinalSecurityToken(serverHostname, Convert.FromBase64String(serverToken));
return string.Concat(" ", Convert.ToBase64String(tokenBytes));
}
}
}
......@@ -37,6 +37,7 @@
<DocumentationFile>bin\Release\Titanium.Web.Proxy.XML</DocumentationFile>
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
......@@ -105,6 +106,13 @@
<Compile Include="Network\Tcp\TcpConnectionFactory.cs" />
<Compile Include="Models\HttpHeader.cs" />
<Compile Include="Http\HttpWebClient.cs" />
<Compile Include="Network\WinAuth\Security\BufferWrapper.cs" />
<Compile Include="Network\WinAuth\Security\Common.cs" />
<Compile Include="Network\WinAuth\Security\EndPoint.cs" />
<Compile Include="Network\WinAuth\Security\LittleEndian.cs" />
<Compile Include="Network\WinAuth\Security\Message.cs" />
<Compile Include="Network\WinAuth\Security\State.cs" />
<Compile Include="Network\WinAuth\WinAuthHandler.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ProxyAuthorizationHandler.cs" />
<Compile Include="RequestHandler.cs" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment