Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
T
Titanium-Web-Proxy
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Titanium-Web-Proxy
Commits
b0a96db5
Commit
b0a96db5
authored
May 23, 2017
by
justcoding121
Committed by
justcoding121
May 23, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #248 from justcoding121/dev-ntlm-kerberos
ntlm kerberos
parents
b8f7b8c5
8ecbc88b
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
1234 additions
and
13 deletions
+1234
-13
README.md
README.md
+1
-1
Titanium.Web.Proxy.UnitTests.csproj
...m.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj
+2
-0
WinAuthTests.cs
Tests/Titanium.Web.Proxy.UnitTests/WinAuthTests.cs
+17
-0
SessionEventArgs.cs
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+15
-3
RunTime.cs
Titanium.Web.Proxy/Helpers/RunTime.cs
+3
-1
BufferWrapper.cs
Titanium.Web.Proxy/Network/WinAuth/Security/BufferWrapper.cs
+21
-0
Common.cs
Titanium.Web.Proxy/Network/WinAuth/Security/Common.cs
+297
-0
LittleEndian.cs
Titanium.Web.Proxy/Network/WinAuth/Security/LittleEndian.cs
+257
-0
Message.cs
Titanium.Web.Proxy/Network/WinAuth/Security/Message.cs
+147
-0
State.cs
Titanium.Web.Proxy/Network/WinAuth/Security/State.cs
+44
-0
WinAuthEndPoint.cs
...ium.Web.Proxy/Network/WinAuth/Security/WinAuthEndPoint.cs
+222
-0
WinAuthHandler.cs
Titanium.Web.Proxy/Network/WinAuth/WinAuthHandler.cs
+46
-0
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+15
-0
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+18
-8
Titanium.Web.Proxy.csproj
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
+9
-0
WinAuthHandler.cs
Titanium.Web.Proxy/WinAuthHandler.cs
+120
-0
No files found.
README.md
View file @
b0a96db5
...
@@ -18,6 +18,7 @@ Features
...
@@ -18,6 +18,7 @@ Features
*
Support mutual SSL authentication
*
Support mutual SSL authentication
*
Fully asynchronous proxy
*
Fully asynchronous proxy
*
Supports proxy authentication & automatic proxy detection
*
Supports proxy authentication & automatic proxy detection
*
Kerberos/NTLM authentication over HTTP protocols for windows domain
Usage
Usage
=====
=====
...
@@ -203,7 +204,6 @@ public Task OnCertificateSelection(object sender, CertificateSelectionEventArgs
...
@@ -203,7 +204,6 @@ public Task OnCertificateSelection(object sender, CertificateSelectionEventArgs
```
```
Future road map (Pull requests are welcome!)
Future road map (Pull requests are welcome!)
============
============
*
Implement Kerberos/NTLM authentication over HTTP protocols for windows domain
*
Support Server Name Indication (SNI) for transparent endpoints
*
Support Server Name Indication (SNI) for transparent endpoints
*
Support HTTP 2.0
*
Support HTTP 2.0
*
Support SOCKS protocol
*
Support SOCKS protocol
...
...
Tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj
View file @
b0a96db5
...
@@ -33,6 +33,7 @@
...
@@ -33,6 +33,7 @@
<DefineConstants>
TRACE
</DefineConstants>
<DefineConstants>
TRACE
</DefineConstants>
<ErrorReport>
prompt
</ErrorReport>
<ErrorReport>
prompt
</ErrorReport>
<WarningLevel>
4
</WarningLevel>
<WarningLevel>
4
</WarningLevel>
<AllowUnsafeBlocks>
true
</AllowUnsafeBlocks>
</PropertyGroup>
</PropertyGroup>
<PropertyGroup>
<PropertyGroup>
<SignAssembly>
true
</SignAssembly>
<SignAssembly>
true
</SignAssembly>
...
@@ -59,6 +60,7 @@
...
@@ -59,6 +60,7 @@
<Compile
Include=
"CertificateManagerTests.cs"
/>
<Compile
Include=
"CertificateManagerTests.cs"
/>
<Compile
Include=
"Properties\AssemblyInfo.cs"
/>
<Compile
Include=
"Properties\AssemblyInfo.cs"
/>
<Compile
Include=
"ProxyServerTests.cs"
/>
<Compile
Include=
"ProxyServerTests.cs"
/>
<Compile
Include=
"WinAuthTests.cs"
/>
</ItemGroup>
</ItemGroup>
<ItemGroup>
<ItemGroup>
<ProjectReference
Include=
"..\..\Titanium.Web.Proxy\Titanium.Web.Proxy.csproj"
>
<ProjectReference
Include=
"..\..\Titanium.Web.Proxy\Titanium.Web.Proxy.csproj"
>
...
...
Tests/Titanium.Web.Proxy.UnitTests/WinAuthTests.cs
0 → 100644
View file @
b0a96db5
using
Microsoft.VisualStudio.TestTools.UnitTesting
;
using
System
;
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"
,
"NTLM"
,
Guid
.
NewGuid
());
Assert
.
IsTrue
(
token
.
Length
>
1
);
}
}
}
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
b0a96db5
...
@@ -44,7 +44,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -44,7 +44,7 @@ namespace Titanium.Web.Proxy.EventArguments
public
Guid
Id
=>
WebSession
.
RequestId
;
public
Guid
Id
=>
WebSession
.
RequestId
;
/// <summary>
/// <summary>
/// Should we send
a rerequest
/// Should we send
the request again
/// </summary>
/// </summary>
public
bool
ReRequest
{
get
;
set
;
}
public
bool
ReRequest
{
get
;
set
;
}
...
@@ -136,9 +136,21 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -136,9 +136,21 @@ namespace Titanium.Web.Proxy.EventArguments
}
}
/// <summary>
/// <summary>
///
Read response body as byte[] for current response
///
reinit response object
/// </summary>
/// </summary>
private
async
Task
ReadResponseBody
()
internal
async
Task
ClearResponse
()
{
//siphon out the body
await
ReadResponseBody
();
WebSession
.
Response
.
Dispose
();
WebSession
.
Response
=
new
Response
();
}
/// <summary>
/// Read response body as byte[] for current response
/// </summary>
private
async
Task
ReadResponseBody
()
{
{
//If not already read (not cached yet)
//If not already read (not cached yet)
if
(
WebSession
.
Response
.
ResponseBody
==
null
)
if
(
WebSession
.
Response
.
ResponseBody
==
null
)
...
...
Titanium.Web.Proxy/Helpers/RunTime.cs
View file @
b0a96db5
...
@@ -7,13 +7,15 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -7,13 +7,15 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
/// </summary>
internal
class
RunTime
internal
class
RunTime
{
{
private
static
Lazy
<
bool
>
isMonoRuntime
=
new
Lazy
<
bool
>(()=>
Type
.
GetType
(
"Mono.Runtime"
)
!=
null
);
/// <summary>
/// <summary>
/// Checks if current run time is Mono
/// Checks if current run time is Mono
/// </summary>
/// </summary>
/// <returns></returns>
/// <returns></returns>
internal
static
bool
IsRunningOnMono
()
internal
static
bool
IsRunningOnMono
()
{
{
return
Type
.
GetType
(
"Mono.Runtime"
)
!=
null
;
return
isMonoRuntime
.
Value
;
}
}
}
}
}
}
Titanium.Web.Proxy/Network/WinAuth/Security/BufferWrapper.cs
0 → 100644
View file @
b0a96db5
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
;
}
};
}
Titanium.Web.Proxy/Network/WinAuth/Security/Common.cs
0 → 100644
View file @
b0a96db5
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
}
}
Titanium.Web.Proxy/Network/WinAuth/Security/LittleEndian.cs
0 → 100644
View file @
b0a96db5
//
// 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
;
}
}
}
Titanium.Web.Proxy/Network/WinAuth/Security/Message.cs
0 → 100644
View file @
b0a96db5
//
// 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
);
}
}
}
Titanium.Web.Proxy/Network/WinAuth/Security/State.cs
0 → 100644
View file @
b0a96db5
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
.
Now
;
}
/// <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
void
ResetHandles
()
{
this
.
Credentials
.
Reset
();
this
.
Context
.
Reset
();
}
internal
void
UpdatePresence
()
{
this
.
LastSeen
=
DateTime
.
Now
;
}
}
}
Titanium.Web.Proxy/Network/WinAuth/Security/WinAuthEndPoint.cs
0 → 100644
View file @
b0a96db5
// http://pinvoke.net/default.aspx/secur32/InitializeSecurityContext.html
namespace
Titanium.Web.Proxy.Network.WinAuth.Security
{
using
System
;
using
System.Linq
;
using
System.Collections.Concurrent
;
using
System.Collections.Generic
;
using
System.Runtime.InteropServices
;
using
System.Security.Principal
;
using
static
Common
;
using
System.Threading.Tasks
;
internal
class
WinAuthEndPoint
{
/// <summary>
/// Keep track of auth states for reuse in final challenge response
/// </summary>
private
static
IDictionary
<
Guid
,
State
>
authStates
=
new
ConcurrentDictionary
<
Guid
,
State
>();
/// <summary>
/// Acquire the intial client token to send
/// </summary>
/// <param name="hostname"></param>
/// <param name="authScheme"></param>
/// <param name="requestId"></param>
/// <returns></returns>
internal
static
byte
[]
AcquireInitialSecurityToken
(
string
hostname
,
string
authScheme
,
Guid
requestId
)
{
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
,
authScheme
,
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
();
authStates
.
Add
(
requestId
,
state
);
}
finally
{
clientToken
.
Dispose
();
serverToken
.
Dispose
();
}
return
token
;
}
/// <summary>
/// Acquire the final token to send
/// </summary>
/// <param name="hostname"></param>
/// <param name="serverChallenge"></param>
/// <param name="requestId"></param>
/// <returns></returns>
internal
static
byte
[]
AcquireFinalSecurityToken
(
string
hostname
,
byte
[]
serverChallenge
,
Guid
requestId
)
{
byte
[]
token
=
null
;
//user server challenge
SecurityBufferDesciption
serverToken
=
new
SecurityBufferDesciption
(
serverChallenge
);
SecurityBufferDesciption
clientToken
=
new
SecurityBufferDesciption
(
MaximumTokenSize
);
try
{
int
result
;
var
state
=
authStates
[
requestId
];
state
.
UpdatePresence
();
result
=
InitializeSecurityContext
(
ref
state
.
Credentials
,
ref
state
.
Context
,
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
;
}
authStates
.
Remove
(
requestId
);
token
=
clientToken
.
GetBytes
();
}
finally
{
clientToken
.
Dispose
();
serverToken
.
Dispose
();
}
return
token
;
}
/// <summary>
/// Clear any hanging states
/// </summary>
/// <param name="stateCacheTimeOutMinutes"></param>
internal
static
async
void
ClearIdleStates
(
int
stateCacheTimeOutMinutes
)
{
var
cutOff
=
DateTime
.
Now
.
AddMinutes
(-
1
*
stateCacheTimeOutMinutes
);
var
outdated
=
authStates
.
Where
(
x
=>
x
.
Value
.
LastSeen
<
cutOff
)
.
ToList
();
foreach
(
var
cache
in
outdated
)
{
authStates
.
Remove
(
cache
.
Key
);
}
//after a minute come back to check for outdated certificates in cache
await
Task
.
Delay
(
1000
*
60
);
}
#
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
SecurityBufferDesciption
pOutput
,
//PSecBufferDesc SecBufferDesc
out
uint
pfContextAttr
,
//managed ulong == 64 bits!!!
out
SecurityInteger
ptsExpiry
);
//PTimeStamp
[
DllImport
(
"secur32"
,
CharSet
=
CharSet
.
Auto
,
SetLastError
=
true
)]
static
extern
int
InitializeSecurityContext
(
ref
SecurityHandle
phCredential
,
//PCredHandle
ref
SecurityHandle
phContext
,
//PCtxtHandle
string
pszTargetName
,
int
fContextReq
,
int
Reserved1
,
int
TargetDataRep
,
ref
SecurityBufferDesciption
SecBufferDesc
,
//PSecBufferDesc SecBufferDesc
int
Reserved2
,
out
SecurityHandle
phNewContext
,
//PCtxtHandle
out
SecurityBufferDesciption
pOutput
,
//PSecBufferDesc SecBufferDesc
out
uint
pfContextAttr
,
//managed ulong == 64 bits!!!
out
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
}
}
Titanium.Web.Proxy/Network/WinAuth/WinAuthHandler.cs
0 → 100644
View file @
b0a96db5
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>
/// <param name="authScheme"></param>
/// <param name="requestId"></param>
/// <returns></returns>
public
static
string
GetInitialAuthToken
(
string
serverHostname
,
string
authScheme
,
Guid
requestId
)
{
var
tokenBytes
=
WinAuthEndPoint
.
AcquireInitialSecurityToken
(
serverHostname
,
authScheme
,
requestId
);
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>
/// <param name="requestId"></param>
/// <returns></returns>
public
static
string
GetFinalAuthToken
(
string
serverHostname
,
string
serverToken
,
Guid
requestId
)
{
var
tokenBytes
=
WinAuthEndPoint
.
AcquireFinalSecurityToken
(
serverHostname
,
Convert
.
FromBase64String
(
serverToken
),
requestId
);
return
string
.
Concat
(
" "
,
Convert
.
ToBase64String
(
tokenBytes
));
}
}
}
Titanium.Web.Proxy/ProxyServer.cs
View file @
b0a96db5
...
@@ -12,6 +12,7 @@ using Titanium.Web.Proxy.Helpers;
...
@@ -12,6 +12,7 @@ using Titanium.Web.Proxy.Helpers;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Network
;
using
Titanium.Web.Proxy.Network
;
using
Titanium.Web.Proxy.Network.Tcp
;
using
Titanium.Web.Proxy.Network.Tcp
;
using
Titanium.Web.Proxy.Network.WinAuth.Security
;
namespace
Titanium.Web.Proxy
namespace
Titanium.Web.Proxy
{
{
...
@@ -196,6 +197,15 @@ namespace Titanium.Web.Proxy
...
@@ -196,6 +197,15 @@ namespace Titanium.Web.Proxy
/// </summary>
/// </summary>
public
bool
ForwardToUpstreamGateway
{
get
;
set
;
}
public
bool
ForwardToUpstreamGateway
{
get
;
set
;
}
/// <summary>
/// Enable disable Windows Authentication (NTLM/Kerberos)
/// Note: NTLM/Kerberos will always send local credentials of current user
/// who is running the proxy process. This is because a man
/// in middle attack is not currently supported
/// (which would require windows delegation enabled for this server process)
/// </summary>
public
bool
EnableWinAuth
{
get
;
set
;
}
=
true
;
/// <summary>
/// <summary>
/// Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication
/// Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication
/// </summary>
/// </summary>
...
@@ -466,6 +476,11 @@ namespace Titanium.Web.Proxy
...
@@ -466,6 +476,11 @@ namespace Titanium.Web.Proxy
CertificateManager
.
ClearIdleCertificates
(
CertificateCacheTimeOutMinutes
);
CertificateManager
.
ClearIdleCertificates
(
CertificateCacheTimeOutMinutes
);
if
(!
RunTime
.
IsRunningOnMono
())
{
WinAuthEndPoint
.
ClearIdleStates
(
2
);
}
proxyRunning
=
true
;
proxyRunning
=
true
;
}
}
...
...
Titanium.Web.Proxy/ResponseHandler.cs
View file @
b0a96db5
...
@@ -36,6 +36,19 @@ namespace Titanium.Web.Proxy
...
@@ -36,6 +36,19 @@ namespace Titanium.Web.Proxy
args
.
WebSession
.
Response
.
ResponseStream
=
args
.
WebSession
.
ServerConnection
.
Stream
;
args
.
WebSession
.
Response
.
ResponseStream
=
args
.
WebSession
.
ServerConnection
.
Stream
;
}
}
//check for windows authentication
if
(
EnableWinAuth
&&
args
.
WebSession
.
Response
.
ResponseStatusCode
==
"401"
&&
!
RunTime
.
IsRunningOnMono
())
{
var
disposed
=
await
Handle401UnAuthorized
(
args
);
if
(
disposed
)
{
return
true
;
}
}
args
.
ReRequest
=
false
;
args
.
ReRequest
=
false
;
//If user requested call back then do it
//If user requested call back then do it
...
@@ -44,16 +57,13 @@ namespace Titanium.Web.Proxy
...
@@ -44,16 +57,13 @@ namespace Titanium.Web.Proxy
await
BeforeResponse
.
InvokeParallelAsync
(
this
,
args
);
await
BeforeResponse
.
InvokeParallelAsync
(
this
,
args
);
}
}
//if user requested to send request again
//likely after making modifications from User Response Handler
if
(
args
.
ReRequest
)
if
(
args
.
ReRequest
)
{
{
if
(
args
.
WebSession
.
ServerConnection
!=
null
)
//clear current response
{
await
args
.
ClearResponse
();
args
.
WebSession
.
ServerConnection
.
Dispose
();
var
disposed
=
await
HandleHttpSessionRequestInternal
(
args
.
WebSession
.
ServerConnection
,
args
,
false
);
Interlocked
.
Decrement
(
ref
serverConnectionCount
);
}
var
connection
=
await
GetServerConnection
(
args
);
var
disposed
=
await
HandleHttpSessionRequestInternal
(
null
,
args
,
true
);
return
disposed
;
return
disposed
;
}
}
...
...
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
View file @
b0a96db5
...
@@ -37,6 +37,7 @@
...
@@ -37,6 +37,7 @@
<DocumentationFile>
bin\Release\Titanium.Web.Proxy.XML
</DocumentationFile>
<DocumentationFile>
bin\Release\Titanium.Web.Proxy.XML
</DocumentationFile>
<DebugType>
none
</DebugType>
<DebugType>
none
</DebugType>
<DebugSymbols>
false
</DebugSymbols>
<DebugSymbols>
false
</DebugSymbols>
<AllowUnsafeBlocks>
true
</AllowUnsafeBlocks>
</PropertyGroup>
</PropertyGroup>
<PropertyGroup>
<PropertyGroup>
<SignAssembly>
true
</SignAssembly>
<SignAssembly>
true
</SignAssembly>
...
@@ -105,6 +106,13 @@
...
@@ -105,6 +106,13 @@
<Compile
Include=
"Network\Tcp\TcpConnectionFactory.cs"
/>
<Compile
Include=
"Network\Tcp\TcpConnectionFactory.cs"
/>
<Compile
Include=
"Models\HttpHeader.cs"
/>
<Compile
Include=
"Models\HttpHeader.cs"
/>
<Compile
Include=
"Http\HttpWebClient.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\WinAuthEndPoint.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=
"Properties\AssemblyInfo.cs"
/>
<Compile
Include=
"ProxyAuthorizationHandler.cs"
/>
<Compile
Include=
"ProxyAuthorizationHandler.cs"
/>
<Compile
Include=
"RequestHandler.cs"
/>
<Compile
Include=
"RequestHandler.cs"
/>
...
@@ -119,6 +127,7 @@
...
@@ -119,6 +127,7 @@
<Compile
Include=
"Shared\ProxyConstants.cs"
/>
<Compile
Include=
"Shared\ProxyConstants.cs"
/>
<Compile
Include=
"Network\Tcp\TcpRow.cs"
/>
<Compile
Include=
"Network\Tcp\TcpRow.cs"
/>
<Compile
Include=
"Network\Tcp\TcpTable.cs"
/>
<Compile
Include=
"Network\Tcp\TcpTable.cs"
/>
<Compile
Include=
"WinAuthHandler.cs"
/>
</ItemGroup>
</ItemGroup>
<ItemGroup>
<ItemGroup>
<COMReference
Include=
"CERTENROLLLib"
>
<COMReference
Include=
"CERTENROLLLib"
>
...
...
Titanium.Web.Proxy/WinAuthHandler.cs
0 → 100644
View file @
b0a96db5
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Network.WinAuth
;
using
Titanium.Web.Proxy.Extensions
;
namespace
Titanium.Web.Proxy
{
public
partial
class
ProxyServer
{
//possible header names
private
static
List
<
string
>
authHeaderNames
=
new
List
<
string
>()
{
"WWW-Authenticate"
,
//IIS 6.0 messed up names below
"WWWAuthenticate"
,
"NTLMAuthorization"
,
"NegotiateAuthorization"
,
"KerberosAuthorization"
};
private
static
List
<
string
>
authSchemes
=
new
List
<
string
>()
{
"NTLM"
,
"Negotiate"
,
"Kerberos"
};
/// <summary>
/// Handle windows NTLM authentication
/// Can expand this for Kerberos in future
/// Note: NTLM/Kerberos cannot do a man in middle operation
/// we do for HTTPS requests.
/// As such we will be sending local credentials of current
/// User to server to authenticate requests.
/// To disable this set ProxyServer.EnableWinAuth to false
/// </summary>
internal
async
Task
<
bool
>
Handle401UnAuthorized
(
SessionEventArgs
args
)
{
string
headerName
=
null
;
HttpHeader
authHeader
=
null
;
//check in non-unique headers first
var
header
=
args
.
WebSession
.
Response
.
NonUniqueResponseHeaders
.
FirstOrDefault
(
x
=>
authHeaderNames
.
Any
(
y
=>
x
.
Key
.
Equals
(
y
,
StringComparison
.
OrdinalIgnoreCase
)));
if
(!
header
.
Equals
(
new
KeyValuePair
<
string
,
List
<
HttpHeader
>>()))
{
headerName
=
header
.
Key
;
}
if
(
headerName
!=
null
)
{
authHeader
=
args
.
WebSession
.
Response
.
NonUniqueResponseHeaders
[
headerName
]
.
Where
(
x
=>
authSchemes
.
Any
(
y
=>
x
.
Value
.
ContainsIgnoreCase
(
y
)))
.
FirstOrDefault
();
}
//check in unique headers
if
(
authHeader
==
null
)
{
//check in non-unique headers first
var
uHeader
=
args
.
WebSession
.
Response
.
ResponseHeaders
.
FirstOrDefault
(
x
=>
authHeaderNames
.
Any
(
y
=>
x
.
Key
.
Equals
(
y
,
StringComparison
.
OrdinalIgnoreCase
)));
if
(!
uHeader
.
Equals
(
new
KeyValuePair
<
string
,
HttpHeader
>()))
{
headerName
=
uHeader
.
Key
;
}
if
(
headerName
!=
null
)
{
authHeader
=
authSchemes
.
Any
(
x
=>
args
.
WebSession
.
Response
.
ResponseHeaders
[
headerName
].
Value
.
ContainsIgnoreCase
(
x
))
?
args
.
WebSession
.
Response
.
ResponseHeaders
[
headerName
]
:
null
;
}
}
if
(
authHeader
!=
null
)
{
var
scheme
=
authSchemes
.
FirstOrDefault
(
x
=>
authHeader
.
Value
.
Equals
(
x
,
StringComparison
.
OrdinalIgnoreCase
));
//initial value will match exactly any of the schemes
if
(
scheme
!=
null
)
{
var
clientToken
=
WinAuthHandler
.
GetInitialAuthToken
(
args
.
WebSession
.
Request
.
Host
,
scheme
,
args
.
Id
);
args
.
WebSession
.
Request
.
RequestHeaders
.
Add
(
"Authorization"
,
new
HttpHeader
(
"Authorization"
,
string
.
Concat
(
scheme
,
clientToken
)));
}
//challenge value will start with any of the scheme selected
else
{
scheme
=
authSchemes
.
FirstOrDefault
(
x
=>
authHeader
.
Value
.
StartsWith
(
x
,
StringComparison
.
OrdinalIgnoreCase
));
var
serverToken
=
authHeader
.
Value
.
Substring
(
scheme
.
Length
+
1
);
var
clientToken
=
WinAuthHandler
.
GetFinalAuthToken
(
args
.
WebSession
.
Request
.
Host
,
serverToken
,
args
.
Id
);
args
.
WebSession
.
Request
.
RequestHeaders
[
"Authorization"
]
=
new
HttpHeader
(
"Authorization"
,
string
.
Concat
(
scheme
,
clientToken
));
}
//clear current response
await
args
.
ClearResponse
();
var
disposed
=
await
HandleHttpSessionRequestInternal
(
args
.
WebSession
.
ServerConnection
,
args
,
false
);
return
disposed
;
}
return
false
;
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment