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
96d9775f
Unverified
Commit
96d9775f
authored
Mar 28, 2018
by
honfika
Committed by
GitHub
Mar 28, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #399 from justcoding121/develop
merge to beta
parents
ad784227
9fb2b18f
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
133 additions
and
10 deletions
+133
-10
StringExtensions.cs
Titanium.Web.Proxy/Extensions/StringExtensions.cs
+5
-0
State.cs
Titanium.Web.Proxy/Network/WinAuth/Security/State.cs
+18
-0
WinAuthEndPoint.cs
...ium.Web.Proxy/Network/WinAuth/Security/WinAuthEndPoint.cs
+47
-7
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+10
-2
WinAuthHandler.cs
Titanium.Web.Proxy/WinAuthHandler.cs
+53
-1
No files found.
Titanium.Web.Proxy/Extensions/StringExtensions.cs
View file @
96d9775f
...
@@ -14,5 +14,10 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -14,5 +14,10 @@ namespace Titanium.Web.Proxy.Extensions
{
{
return
CultureInfo
.
CurrentCulture
.
CompareInfo
.
IndexOf
(
str
,
value
,
CompareOptions
.
IgnoreCase
)
>=
0
;
return
CultureInfo
.
CurrentCulture
.
CompareInfo
.
IndexOf
(
str
,
value
,
CompareOptions
.
IgnoreCase
)
>=
0
;
}
}
internal
static
int
IndexOfIgnoreCase
(
this
string
str
,
string
value
)
{
return
CultureInfo
.
CurrentCulture
.
CompareInfo
.
IndexOf
(
str
,
value
,
CompareOptions
.
IgnoreCase
);
}
}
}
}
}
Titanium.Web.Proxy/Network/WinAuth/Security/State.cs
View file @
96d9775f
...
@@ -7,12 +7,24 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
...
@@ -7,12 +7,24 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
/// </summary>
/// </summary>
internal
class
State
internal
class
State
{
{
/// <summary>
/// States during Windows Authentication
/// </summary>
public
enum
WinAuthState
{
UNAUTHORIZED
,
INITIAL_TOKEN
,
FINAL_TOKEN
,
AUTHORIZED
};
internal
State
()
internal
State
()
{
{
Credentials
=
new
Common
.
SecurityHandle
(
0
);
Credentials
=
new
Common
.
SecurityHandle
(
0
);
Context
=
new
Common
.
SecurityHandle
(
0
);
Context
=
new
Common
.
SecurityHandle
(
0
);
LastSeen
=
DateTime
.
Now
;
LastSeen
=
DateTime
.
Now
;
AuthState
=
WinAuthState
.
UNAUTHORIZED
;
}
}
/// <summary>
/// <summary>
...
@@ -30,10 +42,16 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
...
@@ -30,10 +42,16 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
/// </summary>
/// </summary>
internal
DateTime
LastSeen
;
internal
DateTime
LastSeen
;
/// <summary>
/// Current state of the authentication process
/// </summary>
internal
WinAuthState
AuthState
;
internal
void
ResetHandles
()
internal
void
ResetHandles
()
{
{
Credentials
.
Reset
();
Credentials
.
Reset
();
Context
.
Reset
();
Context
.
Reset
();
AuthState
=
WinAuthState
.
UNAUTHORIZED
;
}
}
internal
void
UpdatePresence
()
internal
void
UpdatePresence
()
...
...
Titanium.Web.Proxy/Network/WinAuth/Security/WinAuthEndPoint.cs
View file @
96d9775f
...
@@ -38,11 +38,9 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
...
@@ -38,11 +38,9 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
try
try
{
{
int
result
;
var
state
=
new
State
();
var
state
=
new
State
();
result
=
AcquireCredentialsHandle
(
int
result
=
AcquireCredentialsHandle
(
WindowsIdentity
.
GetCurrent
().
Name
,
WindowsIdentity
.
GetCurrent
().
Name
,
authScheme
,
authScheme
,
SecurityCredentialsOutbound
,
SecurityCredentialsOutbound
,
...
@@ -79,6 +77,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
...
@@ -79,6 +77,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
return
null
;
return
null
;
}
}
state
.
AuthState
=
State
.
WinAuthState
.
INITIAL_TOKEN
;
token
=
clientToken
.
GetBytes
();
token
=
clientToken
.
GetBytes
();
authStates
.
Add
(
requestId
,
state
);
authStates
.
Add
(
requestId
,
state
);
}
}
...
@@ -109,13 +108,11 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
...
@@ -109,13 +108,11 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
try
try
{
{
int
result
;
var
state
=
authStates
[
requestId
];
var
state
=
authStates
[
requestId
];
state
.
UpdatePresence
();
state
.
UpdatePresence
();
result
=
InitializeSecurityContext
(
ref
state
.
Credentials
,
int
result
=
InitializeSecurityContext
(
ref
state
.
Credentials
,
ref
state
.
Context
,
ref
state
.
Context
,
hostname
,
hostname
,
StandardContextAttributes
,
StandardContextAttributes
,
...
@@ -135,7 +132,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
...
@@ -135,7 +132,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
return
null
;
return
null
;
}
}
authStates
.
Remove
(
requestId
)
;
state
.
AuthState
=
State
.
WinAuthState
.
FINAL_TOKEN
;
token
=
clientToken
.
GetBytes
();
token
=
clientToken
.
GetBytes
();
}
}
finally
finally
...
@@ -166,6 +163,49 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
...
@@ -166,6 +163,49 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
await
Task
.
Delay
(
1000
*
60
);
await
Task
.
Delay
(
1000
*
60
);
}
}
/// <summary>
/// Validates that the current WinAuth state of the connection matches the
/// expectation, used to detect failed authentication
/// </summary>
/// <param name="requestId"></param>
/// <param name="expectedAuthState"></param>
/// <returns></returns>
internal
static
bool
ValidateWinAuthState
(
Guid
requestId
,
State
.
WinAuthState
expectedAuthState
)
{
var
stateExists
=
authStates
.
TryGetValue
(
requestId
,
out
var
state
);
if
(
expectedAuthState
==
State
.
WinAuthState
.
UNAUTHORIZED
)
{
// Validation before initial token
return
stateExists
==
false
||
state
.
AuthState
==
State
.
WinAuthState
.
UNAUTHORIZED
||
state
.
AuthState
==
State
.
WinAuthState
.
AUTHORIZED
;
// Server may require re-authentication on an open connection
}
if
(
expectedAuthState
==
State
.
WinAuthState
.
INITIAL_TOKEN
)
{
// Validation before final token
return
stateExists
&&
(
state
.
AuthState
==
State
.
WinAuthState
.
INITIAL_TOKEN
||
state
.
AuthState
==
State
.
WinAuthState
.
AUTHORIZED
);
// Server may require re-authentication on an open connection
}
throw
new
Exception
(
"Unsupported validation of WinAuthState"
);
}
/// <summary>
/// Set the AuthState to authorized and update the connection state lifetime
/// </summary>
/// <param name="requestId"></param>
internal
static
void
AuthenticatedResponse
(
Guid
requestId
)
{
if
(
authStates
.
TryGetValue
(
requestId
,
out
var
state
))
{
state
.
AuthState
=
State
.
WinAuthState
.
AUTHORIZED
;
state
.
UpdatePresence
();
}
}
#
region
Native
calls
to
secur32
.
dll
#
region
Native
calls
to
secur32
.
dll
[
DllImport
(
"secur32.dll"
,
SetLastError
=
true
)]
[
DllImport
(
"secur32.dll"
,
SetLastError
=
true
)]
...
...
Titanium.Web.Proxy/ResponseHandler.cs
View file @
96d9775f
...
@@ -7,6 +7,7 @@ using Titanium.Web.Proxy.Compression;
...
@@ -7,6 +7,7 @@ using Titanium.Web.Proxy.Compression;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Exceptions
;
using
Titanium.Web.Proxy.Exceptions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Network.WinAuth.Security
;
namespace
Titanium.Web.Proxy
namespace
Titanium.Web.Proxy
{
{
...
@@ -31,9 +32,16 @@ namespace Titanium.Web.Proxy
...
@@ -31,9 +32,16 @@ namespace Titanium.Web.Proxy
args
.
ReRequest
=
false
;
args
.
ReRequest
=
false
;
//check for windows authentication
//check for windows authentication
if
(
isWindowsAuthenticationEnabledAndSupported
&&
response
.
StatusCode
==
(
int
)
HttpStatusCode
.
Unauthorized
)
if
(
isWindowsAuthenticationEnabledAndSupported
)
{
{
await
Handle401UnAuthorized
(
args
);
if
(
response
.
StatusCode
==
(
int
)
HttpStatusCode
.
Unauthorized
)
{
await
Handle401UnAuthorized
(
args
);
}
else
{
WinAuthEndPoint
.
AuthenticatedResponse
(
args
.
WebSession
.
RequestId
);
}
}
}
response
.
OriginalHasBody
=
response
.
HasBody
;
response
.
OriginalHasBody
=
response
.
HasBody
;
...
...
Titanium.Web.Proxy/WinAuthHandler.cs
View file @
96d9775f
...
@@ -3,9 +3,11 @@ using System.Collections.Generic;
...
@@ -3,9 +3,11 @@ using System.Collections.Generic;
using
System.Linq
;
using
System.Linq
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Network.WinAuth
;
using
Titanium.Web.Proxy.Network.WinAuth
;
using
Titanium.Web.Proxy.Network.WinAuth.Security
;
namespace
Titanium.Web.Proxy
namespace
Titanium.Web.Proxy
{
{
...
@@ -84,6 +86,15 @@ namespace Titanium.Web.Proxy
...
@@ -84,6 +86,15 @@ namespace Titanium.Web.Proxy
{
{
string
scheme
=
authSchemes
.
FirstOrDefault
(
x
=>
authHeader
.
Value
.
Equals
(
x
,
StringComparison
.
OrdinalIgnoreCase
));
string
scheme
=
authSchemes
.
FirstOrDefault
(
x
=>
authHeader
.
Value
.
Equals
(
x
,
StringComparison
.
OrdinalIgnoreCase
));
var
expectedAuthState
=
scheme
==
null
?
State
.
WinAuthState
.
INITIAL_TOKEN
:
State
.
WinAuthState
.
UNAUTHORIZED
;
if
(!
WinAuthEndPoint
.
ValidateWinAuthState
(
args
.
WebSession
.
RequestId
,
expectedAuthState
))
{
// Invalid state, create proper error message to client
await
RewriteUnauthorizedResponse
(
args
);
return
;
}
var
request
=
args
.
WebSession
.
Request
;
var
request
=
args
.
WebSession
.
Request
;
//clear any existing headers to avoid confusing bad servers
//clear any existing headers to avoid confusing bad servers
...
@@ -108,7 +119,7 @@ namespace Titanium.Web.Proxy
...
@@ -108,7 +119,7 @@ namespace Titanium.Web.Proxy
//challenge value will start with any of the scheme selected
//challenge value will start with any of the scheme selected
else
else
{
{
scheme
=
authSchemes
.
First
OrDefault
(
x
=>
authHeader
.
Value
.
StartsWith
(
x
,
StringComparison
.
OrdinalIgnoreCase
)
&&
scheme
=
authSchemes
.
First
(
x
=>
authHeader
.
Value
.
StartsWith
(
x
,
StringComparison
.
OrdinalIgnoreCase
)
&&
authHeader
.
Value
.
Length
>
x
.
Length
+
1
);
authHeader
.
Value
.
Length
>
x
.
Length
+
1
);
string
serverToken
=
authHeader
.
Value
.
Substring
(
scheme
.
Length
+
1
);
string
serverToken
=
authHeader
.
Value
.
Substring
(
scheme
.
Length
+
1
);
...
@@ -134,5 +145,46 @@ namespace Titanium.Web.Proxy
...
@@ -134,5 +145,46 @@ namespace Titanium.Web.Proxy
args
.
ReRequest
=
true
;
args
.
ReRequest
=
true
;
}
}
}
}
/// <summary>
/// Rewrites the response body for failed authentication
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
internal
async
Task
RewriteUnauthorizedResponse
(
SessionEventArgs
args
)
{
var
response
=
args
.
WebSession
.
Response
;
// Strip authentication headers to avoid credentials prompt in client web browser
foreach
(
var
authHeaderName
in
authHeaderNames
)
{
response
.
Headers
.
RemoveHeader
(
authHeaderName
);
}
// Add custom div to body to clarify that the proxy (not the client browser) failed authentication
string
authErrorMessage
=
"<div class=\"inserted-by-proxy\"><h2>NTLM authentication through Titanium.Web.Proxy ("
+
args
.
ProxyClient
.
TcpClient
.
Client
.
LocalEndPoint
+
") failed. Please check credentials.</h2></div>"
;
string
originalErrorMessage
=
"<div class=\"inserted-by-proxy\"><h3>Response from remote web server below.</h3></div><br/>"
;
string
body
=
await
args
.
GetResponseBodyAsString
();
int
idx
=
body
.
IndexOfIgnoreCase
(
"<body>"
);
if
(
idx
>=
0
)
{
var
bodyPos
=
idx
+
"<body>"
.
Length
;
body
=
body
.
Insert
(
bodyPos
,
authErrorMessage
+
originalErrorMessage
);
}
else
{
// Cannot parse response body, replace it
body
=
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"
+
"<html xmlns=\"http://www.w3.org/1999/xhtml\">"
+
"<body>"
+
authErrorMessage
+
"</body>"
+
"</html>"
;
}
args
.
SetResponseBodyString
(
body
);
}
}
}
}
}
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