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
e041a288
Commit
e041a288
authored
Mar 28, 2018
by
Björn Weström
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
State handling of WinAuth, fixes issue with failed authentication
parent
b0379905
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
123 additions
and
3 deletions
+123
-3
State.cs
Titanium.Web.Proxy/Network/WinAuth/Security/State.cs
+18
-0
WinAuthEndPoint.cs
...ium.Web.Proxy/Network/WinAuth/Security/WinAuthEndPoint.cs
+47
-1
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+10
-2
WinAuthHandler.cs
Titanium.Web.Proxy/WinAuthHandler.cs
+48
-0
No files found.
Titanium.Web.Proxy/Network/WinAuth/Security/State.cs
View file @
e041a288
...
...
@@ -7,12 +7,24 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
/// </summary>
internal
class
State
{
/// <summary>
/// States during Windows Authentication
/// </summary>
public
enum
WinAuthState
{
UNAUTHORIZED
,
INITIAL_TOKEN
,
FINAL_TOKEN
,
AUTHORIZED
};
internal
State
()
{
Credentials
=
new
Common
.
SecurityHandle
(
0
);
Context
=
new
Common
.
SecurityHandle
(
0
);
LastSeen
=
DateTime
.
Now
;
AuthState
=
WinAuthState
.
UNAUTHORIZED
;
}
/// <summary>
...
...
@@ -30,10 +42,16 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
/// </summary>
internal
DateTime
LastSeen
;
/// <summary>
/// Current state of the authentication process
/// </summary>
internal
WinAuthState
AuthState
;
internal
void
ResetHandles
()
{
Credentials
.
Reset
();
Context
.
Reset
();
AuthState
=
WinAuthState
.
UNAUTHORIZED
;
}
internal
void
UpdatePresence
()
...
...
Titanium.Web.Proxy/Network/WinAuth/Security/WinAuthEndPoint.cs
View file @
e041a288
...
...
@@ -79,6 +79,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
return
null
;
}
state
.
AuthState
=
State
.
WinAuthState
.
INITIAL_TOKEN
;
token
=
clientToken
.
GetBytes
();
authStates
.
Add
(
requestId
,
state
);
}
...
...
@@ -135,7 +136,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
return
null
;
}
authStates
.
Remove
(
requestId
)
;
state
.
AuthState
=
State
.
WinAuthState
.
FINAL_TOKEN
;
token
=
clientToken
.
GetBytes
();
}
finally
...
...
@@ -166,6 +167,51 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
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
)
{
State
state
;
var
stateExists
=
authStates
.
TryGetValue
(
requestId
,
out
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
)
{
State
state
;
if
(
authStates
.
TryGetValue
(
requestId
,
out
state
))
{
state
.
AuthState
=
State
.
WinAuthState
.
AUTHORIZED
;
state
.
UpdatePresence
();
}
}
#
region
Native
calls
to
secur32
.
dll
[
DllImport
(
"secur32.dll"
,
SetLastError
=
true
)]
...
...
Titanium.Web.Proxy/ResponseHandler.cs
View file @
e041a288
...
...
@@ -7,6 +7,7 @@ using Titanium.Web.Proxy.Compression;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Exceptions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Network.WinAuth.Security
;
namespace
Titanium.Web.Proxy
{
...
...
@@ -31,9 +32,16 @@ namespace Titanium.Web.Proxy
args
.
ReRequest
=
false
;
//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
;
...
...
Titanium.Web.Proxy/WinAuthHandler.cs
View file @
e041a288
...
...
@@ -6,6 +6,7 @@ using Titanium.Web.Proxy.EventArguments;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Network.WinAuth
;
using
Titanium.Web.Proxy.Network.WinAuth.Security
;
namespace
Titanium.Web.Proxy
{
...
...
@@ -84,6 +85,14 @@ namespace Titanium.Web.Proxy
{
string
scheme
=
authSchemes
.
FirstOrDefault
(
x
=>
authHeader
.
Value
.
Equals
(
x
,
StringComparison
.
OrdinalIgnoreCase
));
if
((
scheme
!=
null
&&
!
WinAuthEndPoint
.
ValidateWinAuthState
(
args
.
WebSession
.
RequestId
,
State
.
WinAuthState
.
UNAUTHORIZED
))
||
(
scheme
==
null
&&
!
WinAuthEndPoint
.
ValidateWinAuthState
(
args
.
WebSession
.
RequestId
,
State
.
WinAuthState
.
INITIAL_TOKEN
)))
{
// Invalid state, create proper error message to client
await
RewriteUnauthorizedResponse
(
args
);
return
;
}
var
request
=
args
.
WebSession
.
Request
;
//clear any existing headers to avoid confusing bad servers
...
...
@@ -134,5 +143,44 @@ namespace Titanium.Web.Proxy
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
();
if
(
body
.
ToLower
().
Contains
(
"<body>"
))
{
var
bodyPos
=
body
.
ToLower
().
IndexOf
(
"<body>"
)
+
(
"<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