httpwebrequest 401 response - vb.net

I have a program written in VB.net that interacts with a data services hosted on IIS. Authentication is handled through the users Active Directory credentials. At one of my customer sites, on exactly one (out of about 100) of the customer's workstations, requests to the data service fail with status of 401.
Some additional relevant information: the production IIS installation is split into two nodes. A load balancer directs traffic to the nodes. Also, the exact same request made with Internet Explorer from workstation in question does not fail.
I suspect that something is stripping the user's credentials out of the requests when I make the request through the VB code, but I am stumped as to what that could be.
Here is the VB code that I use to make the request:
Dim httpRequest As HttpWebRequest = Nothing
Dim httpResponse As HttpWebResponse = Nothing
httpRequest = WebRequest.Create("http://server/xyzportal/portal.php")
httpRequest.KeepAlive = False
httpRequest.UseDefaultCredentials = True
httpRequest.Method = "GET"
httpRequest.ContentLength = 0
httpRequest.Accept = "text/xml"
httpRequest.Timeout = 3000000
httpResponse = httpRequest.GetResponse
Any thoughts would be appreciated.
Additional information: here are the IIS log entries for a request that fails. Notice the 2nd entry does not include the Windows user name:
2014-11-11 22:20:42 199.99.51.58 GET /xyzportal/portal.php - 80 - 199.99.50.128 - 401 2 5 0
2014-11-11 22:20:42 199.99.51.58 GET /xyzportal/portal.php - 80 - 199.99.50.128 - 401 1 2148074248 0
Contrast that to the IIS entries for a request from a working machine. Notice the 2nd entry does include the Windows user name:
2014-11-11 22:56:40 199.99.51.58 GET /xyzportal/portal.php - 80 - 199.99.50.128 - 401 2 5 0
2014-11-11 22:56:40 199.99.51.58 GET /xyzportal/portal.php - 80 MYDOMAIN\jreichert 199.99.50.128 - 200 0 0 93
The machine with the IP Address 199.99.50.128 is the load balancer.
I am logged in on the exact same domain and user on both machines.

You haven't said but if you are using a proxy then you haven't told the HttpRequest to use the AD user credentials for the proxy and so you are getting a 401 Unauthorised error, i.e. you are being refused access via the proxy. If so try this to explicitly tell it to...
HttpRequest.Proxy.Credentials = System.Net.CredentialCache.DefaultCredentials
I had exactly the same problem and it's solved it.

keepalive must be set to true. Setting keepalive = true fixes my problem. The following page explains the role of keepalive in the authentication handshake:
http://www.innovation.ch/personal/ronald/ntlm.html
I am still not sure why the request does not work on <1% of the workstations in my customer base when keepalive = false. All I know is setting keepalive = true makes the request work on 100% of the workstations.
More info: keepalive must be set to true when the authentication protocol is Kerebos. The request works if the authentication protocol is NTLM. I don't know why Kerebos gets used on only the two workstations where the request does not work.

Related

Webdav Lock request return "405 Method Not allowed" in asp .net core 6 hosted in IIS

I actually a migrate an old asp .net framework 4 web app to asp .net core 6.
This webapp was serving docx et xlsx files through IIS and webdav to allow end users edit directly files on the server
On the old app, the config was like that
a virtual directory on IIS to associate a virtual Path Webdav to a physical path
an IHttpModule which allow me to intercept all request on the server and add some authentication when the request point out /webdav (webdav don't support anonymous authentication)
HttpContext.Request.Headers.Remove("Authorization");
HttpContext.Request.Headers.Add("Authorization", "Basic " + base64string);
On the new app
the virtual directory is manage directly on the code (Startup)
var lOptions = new FileServerOptions
{
FileProvider = new PhysicalFileProvider(Sys.Web.AppliIs.Path_Webdav),
RequestPath = new PathString("/" + Sys.Web.AppliIs.WEBDAV_FOLDER),
EnableDirectoryBrowsing = false,
};
app.UseFileServer(lOptions);
i intercept the request to add my authentication in a custom middleware (called before the code above)
app.Use(async (context, next) =>
{
AppliGeckosSL.WriteLogDebug($"intercept {context.Request.Path}, Method : {context.Request.Method}", null);//just to log everything which arrived
var lFileInfo = lHostEnv.ContentRootFileProvider.GetFileInfo(context.Request.Path);
if (lFileInfo != null)
{
WebdavFileManager.HandleRequest(context, lFileInfo.PhysicalPath);
}
// Call the next delegate/middleware in the pipeline.
await next(context);
});
Whe i test the new code (opening a file stored in the server with word), it failed.
Whe i inspect the logs, i notice thow things :
On the IIS logs, i see my different request called by word
2022-03-23 11:20:31 ::1 OPTIONS /Webdav/ - 7520 - ::1 Microsoft+Office+Protocol+Discovery 200 0 0 47
2022-03-23 11:20:31 ::1 HEAD /Webdav/BeWise.docx - 7520 - ::1 Microsoft+Office+Existence+Discovery 200 0 0 4
2022-03-23 11:20:31 ::1 OPTIONS /Webdav/ - 7520 - ::1 Microsoft+Office+Existence+Discovery 200 0 0 5
2022-03-23 11:20:31 ::1 LOCK /Webdav/BeWise.docx - 7520 - ::1 Microsoft+Office+Core+Storage+Infrastructure/1.0 405 0 0 4
2022-03-23 11:20:31 ::1 GET /Webdav/BeWise.docx - 7520 - ::1 Microsoft+Office+Core+Storage+Infrastructure/1.0 404 0 3 2
we can see the Lock method finished in 405
We can also see the get finishing in 404 which i can't understand because the HEAD finished on 200 on the same file
The log of my middleware give me only this
23/03 12:20:32:023 [FW] intercept /Webdav/BeWise.docx, Method : HEAD
23/03 12:20:32:055 [FW] intercept /Webdav/, Method : OPTIONS
so we see the LOCK and the GET are not handle by my server
I see many solutions on this problem on this forum and others which recommand to disable webdav, solution which dont fit me because i want to use webdav
There is not a lot of documentations about .net core and webdav, im not even sure its supported.
I try to remove the virtual directory by code and set a virtual directory through IIS like the old app but still not working, in this case the lock not finish in 405 but in 401. I notice my middleware in not called, so i cant add my authentication. I suppose with this option we don't go through the asp .net core pipeline.
What do you think ? any suggestion on that ?
Thanks for your help !
I had some answers from microsoft, the IIS webdav module is no longer supported with .net core (they will update the docs for that because it was not clearly said). So there is no way i will be able to achieve what i want.
My solutions now :
implement myself the webdav protocol
buy a licence to IT HIT WEBDAV Server Engine
thanks anyway for your answers, the subject is closed

Apache web server sending 400 response

We have configured NTLM authentication using SSPI on apache due to which the authentication is three steps, where there are two 401 responses followed by 201/200 response.
Now in IE browser, this breaks because of - Why "Content-Length: 0" in POST requests?
Apache web server sends a 400 bad request response due to empty post request due to which POST on the server breaks.
How can I configure Apache to not treat this as 400 BAD request and process it normally?

PingAccess issues with proxying target sites with HTTP/HTTPS mix

I'm trying to get PingAccess set up as a proxy (let's call the PA host
pagateway) for a couple of applications that share a Web Session. I want all access to come via the PA pagateway and use HTTPS, but the back end systems are not HTTPS.
I have two sites defined, app1:8080 and app2:8080. Both are set to "secure" = no and "use target host header" = yes.
I have listeners defined on ports 5000 and 5001 that are both set to "secure" = yes.
The first problem I found is that when I access either app in this way (e.g. going to https://pagateway:5000), after successfully authenticating with PingFederate I end up getting redirected to the actual underlying host name (e.g. http://app1:8080), meaning any subsequent interactions with the app are not via PingAccess. For users outside the network they wouldn't even be able to do that because the app1 host wouldn't even be visible or accessible.
I thought maybe I needed to turn off "Use target host header" to false but Chrome prompts me to download a file that contains NAK, ETX, ETX, NUL, STX, STX codes, and in the PA logs I get an SSL error:
2015-11-20 11:13:33,718 DEBUG [6a5KYac2dnnY0ZpIl-3GNA] com.pingidentity.pa.core.transport.http.HttpServerHandler:180 - IOException reading sourceSocket
javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
at sun.security.ssl.InputRecord.handleUnknownRecord(InputRecord.java:710)
...
I'm unsure exactly which part of the process the SSL error is coming from (between browser and pagateway, or pagateway and app1). I'm guessing maybe app1 is having trouble with the unexpected host header...
In another variation I turned off SSL on the PA listener (I also had to change the PingAccess call-back URL in the PingFederate client settings to be http). But when I accessed it via http://pagateway:5000 I got a generic PingFederate error message in the browser and a different error in the PA logs:
2015-11-20 11:37:25,764 DEBUG [DBxHnFjViCgLYgYb-IrfqQ] com.pingidentity.pa.core.interceptor.flow.InterceptorFlowController:148 - Invoking request handler: Scheme Validation for Request to [pagateway:5000] [/]
2015-11-20 11:37:25,764 DEBUG [DBxHnFjViCgLYgYb-IrfqQ] com.pingidentity.pa.core.interceptor.flow.InterceptorFlowController:200 - Exception caught. Invoking abort handlers
com.pingidentity.pa.sdk.policy.AccessException: Invalid request protocol.
at com.pingidentity.pa.core.interceptor.SchemeValidationInterceptor.handleRequest(SchemeValidationInterceptor.java:61)
Does anyone have any idea what I'm doing wrong? I'm kind of surprised about the redirection to the actual server name, to be honest, but after that I'm stumped about where to go from here.
Any help would be appreciated.
Have you contacted our support on this? It's sounding like something that will need to be dug into a bit deeper - but some high level suggestions I can make:
Take a look at a browser trace to determine when the redirect is happening to the backend site. Usually this is because there's a Location header in a redirect from the backend web server that (by nature) is an absolute URL but pointing to it instead of the externally facing hostname.
A common solution to this is setting Target Host Header to False - so it will receive the request unmodified from the browser, and the backend server should know to represent itself as that (if it behaves nicely behind a proxy).
If the backend server can't do that (which it sounds like it can't) - you should look at assigning rewriting rules to that application. More details on them are available here: https://support.pingidentity.com/s/document-item?bundleId=pingaccess-52&topicId=reference%2Fui%2Fpa_c_Rewrite_Rules_Overview.html. The "Rewrite Response Header Rule" in particular will rewrite Location headers in HTTP redirects.
FYI - The "Invalid request protocol." error you're seeing at bottom of your description could be due to a "Require HTTPS" flag on your defined Application.
Do you have the same issue if you add a trailing slash at the end (https://pagateway:5000/webapp/)? Your application server will rewrite the URL based on what it thinks is the true host. This is to get around some security related issues around directory listing.
Which application server are you using? All app servers are unique, but I'll provide instructions on how to resolve this with Tomcat.
Add a global rule that forces the application server to use the external facing host name. Here is a sample Groovy script:
def header = exc?.request?.header;
header?.setHost("pf.pingdemo.com:443");
anything();
In Tomcat's server.xml, add scheme="https" to the connection:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="443" scheme="https" />
Cheers,
Tam

How to handle https traffic using libmproxy?

I want to implement a proxy server that intercepts both http and https requests. I came across libmproxy (http://mitmproxy.org/doc/scripting/libmproxy.html) that it is SSL-capable. I start with this simplest proxy that just prints the headers of all requests and responses, and forwards them to clients and servers normally.
#!/usr/bin/env python
from libmproxy import controller, proxy
import os
class Master(controller.Master):
def __init__(self, server):
controller.Master.__init__(self, server)
self.stickyhosts = {}
def run(self):
try:
return controller.Master.run(self)
except KeyboardInterrupt:
self.shutdown()
def handle_request(self, msg):
print "handle request.................................................."
print msg.headers
msg.reply()
def handle_response(self, msg):
print "handle response................................................."
print msg.headers
msg.reply()
config = proxy.ProxyConfig(
cacert = os.path.expanduser("~/.mitmproxy/mitmproxy-ca.pem")
)
server = proxy.ProxyServer(config, 1234)
m = Master(server)
m.run()
Then I configure http and ssl proxy in firefox to 127.0.0.1 port 1234. http seems to work fine as I can see all the headers are printed out. However, when the browser sends https requests, the proxy server does not print anything at all, and the browser displays "the connect was interrupted" error.
Further investigation reveals that the https requests go though the proxy server but not controller.Master. I see that proxy.ProxyHandler.establish_ssl() is being called when there is an https request, but the request does not go though controller.Master.handle_request(). Despite that establish_ssl() is called, the browser does not seem to get any response back. I test this with https://www.google.com.
First, how can I make proxy.ProxyHandler works properly with https requests/responses? Second, how can I modify controller.Master so that it can intercept https requests? I'm also open to other tools that I can build a custom http/https proxy server on top of.
You need to install the mitmproxy CA in the browser you are testing with.
Please see details here ("Installing the mitmproxy CA" section):
http://mitmproxy.org/doc/ssl.html
This solved the problem for me.

NTLM-authenticaion fails but Basic authentication works

Here's what happens on the local server when application invokes HTTP request on local IIS.
request.Credentials = CredentialCache.DefaultNetworkCredentials;
request.PreAuthenticate = true;
request.KeepAlive = true;
When I execute the request, I can see the following series of HTTP calls in Fiddler:
Request without authorization header, results in 401 with WWW-Authenticate NTLM+Negotiate
Request with Authorization: Negotiate (Base64 string 1), results in 401 with WWW-Authenticate: Negotiate (Base64 string 2)
Request with Authorization: Negotiate (Base64 string 3), results in 401 with WWW-Authenticate: Negotiate (Base64 string 4)
Request with Authorization: Negotiate (Base64 string 3), results in 401 with WWW-Authenticate NTLM+Negotiate
Apparently the client and the server (both running on the same machine) are trying to handshake, but in the end authorization fails.
What is strange is that if I disable Windows authentication of the site and enable Basic authentication and send user/pwd explicitly, it all works. It also works if I use NTLM authentication and try to access the site from the browser specifying my credentials.
Well, after several hours of struggling I figured what the problem was. In order to be able to inspect network traffic in Fiddler I defined a Fiddler rule:
if (oSession.HostnameIs("MYAPP")) { oSession.host = "127.0.0.1"; }
Then I used "MYAPP" instead of "localhost" in the Web app reference, and Fiddler happily displayed all session information.
But server security was far less happy, so this alias basically broke challenge-response authentication on the local server. Once I replaced the alias with "localhost", it all worked.