We use a custom HTTP module in IIS as a reverse proxy for web applications. Generally this works well and has done for some time, but we've come across an issue with Windows Authentication (WA). We're using IE 11, IIS 10 and Server 2016.
When accessing the target site directly, WA works fine - we get a browser login dialog when the initial HTML page is requested and the subsequent requests (CSS, JS, etc) go through fine.
When accessing via our proxy, the same (correct behaviour) happens for the initial html page, the first CSS/JS request authenticates ok too, but the subsequent ones cause a browser login to popup.
What seems to happen on the 'bad' requests (i,.e. those that cause the login dialog) is:
1) Browser decides it needs to authenticate, so sends an Authorization header (Negotiate, with an NTLM token)
2) Server responds (401) with a WWW-Authenticate: Negotiate response with a full NTLM token
3) Browser re-requests with an Authorization header (Negotiate, with a full NTLM token)
4) Server responds (401) with a WWW-Authenticate: Negotiate (with no token), which causes the browser to show the login dialog
5) With login credentials entered, Browser sends the same request as in (1) - identical NTLM token, server responds as in (2), Browser re-requests as in (3), but this time it works!
We've set up a test web site with one html page, requesting 3 JS and 2 CSS files to replicate this. On our test server we've got two sites, one using our reverse proxy and one using ARR. The ARR site works fine. Also, since step (5) above works, we believe that the proxy pass-through is fundamentally working, i.e. NTLM tokens are not being messed up by dodgy encoding, etc.
One thing that does work, is that if we use Fiddler and put breakpoints on each request, we're able to hold back on the 5 sub-requests (JS & CSS files), letting one go through at a time. If we let each sequence (i.e. NTLM token exchange for each URL/file, through to the 200 response), then it works. This made us think that there is some inter-leaving effect (e.g. shared memory corruption) in our proxy, this is still a possibility.
So, we put code at the start of BeginRequest and end of EndRequest with a Synclock and a shared var to store the Path (AppRelativeCurrentExecutionFilePath). This was for our code to 'Single Thread' each of these request/exchanges. This does what we expected, i.e. only allowing one auth exchange to happen and resulting in a 200 before allowing the next. However, we still have the same problem of the server rejecting the first exchange. So, does this indicate something happening in/before BeginRequest, where if we hold the requests back in Fiddler then they work, but not if we do it in our http module?
Or is there some sort of timing issue where the manual breakpoints in Fiddler also mean we’re doing it at ‘human’ speed and therefore allowing things to work better?
One difference we can see is the ‘Connection: Keep-Alive’. That header is in the request from the browser to our proxy site, but not passed from our proxy to the base site, yet the ARR site does pass that through... It’s all using HTTP 1.1. and so we can't find a way to set Keep-Alive on our outgoing request - could this be it?
Regarding 'things to try', we think we've eliminated things like having the site in the Intranet Zone for IE by having the ARR site work ok, and having the same IE settings for that site. Clearly, something is not right, so we could have missed something here!
In short, we've been working on this for days, and have tried most of what we can find on SO and elsewhere, but can't figure out what the heck is going on.
Any suggestions - let me know if you want any further info. All help will be very gratefully received!
Related
I have a PWA site which is working fine on Firefox, Chrome and Edge on Windows, and all of those on Android, Edge (EdgeA).
The problem
This much I know from looking at my Azure server logs:
(1) The login POST is hits a Core 2.2 controller which does the authentication and returns 302 along with a standard Core 2.2 cookie set including the authentication token for the user.
(2) The EdgeAndroid browser receives that, and immediately GETs the location specified.... except this GET doesn't include the cookies from (1), so the Core 2.2 system responds with a 302 back to the login page.
It's a redirect loop.
-> EdgeA is eating my cookies!
I can run this perfectly on the above browsers, and the logs show Edge/Windows for example has the (1)(2) sequence exactly as you'd expect, with the cookie credentials in the second request.
The only thing different is Edge Android. I stripped out all the caching from my service worker for that browser and it's still broken - I think I may need to just not run the service worker for it at all.
... and my questions are:
Does anyone have a PWA which actually works in EdgeA?
Does anyone have any idea what I may have missed? Note it's just this one browser which is broken, hence it may be them not me.
In case it is them not me, is there a place I have not yet googled where I can report defects in this possibly minor-interest browser?
This sounds similar, although that's cross-domain, and my 302 is not cross domain.
I think this was caused by the Edge Android Browser interpreting the display:standalone directive and consequently opening a "stand alone" window, which does not carry over the cookies from the original browser.
The server logs show that the EdgeA client "drops the cookies" when handling a "login successful" 302 response from the standard Core 2.2 login stuff.
My work around is to serve a specific manifest.json to the EdgeA browser, so that it reads display:browser.
At the same time I fixed this MS released a new version of EdgeA, so I can't be 100% sure if my change fixed this or if they actually listened to my whining.
I want to use an Apache proxy server (mod_proxy) to intercept all requests and responses to a web server. However I want to change requests and responses before redirecting them. Simply rewriting URLs is easy and documented, but the changes I want to make are more sophisticated, namely they need to inspect the request for user credentials as well as conditionally make redirects.
Is this possible in Apache's mod_rewrite, possibly in combination with other modules?
While the main goal is to implement this in Apache, I would also be happy with an alternative solution which doesn't necessarily use Apache.
Here is a more precise explanation of what I want to achieve, to give a little more context:
Check each incoming request for user credentials. If credentials are present, they are replaced by the user information which the web server can use to identify the user (Ideally in the Authorization header)
For example, let's assume a request contains a cookie which authenticates the request as beeing sent from the user "John", this cookie is removed, and the Authorization header is changed to Authorization Authenticated_by_proxy {"id":12345,"name":"John"}
Check each answer to see if it's an Error 403. If this is the case and the user is not logged in, redirect the user to a login page instead of forwarding the error
I'm investigating a problem a user is having with a web application that is built using Yii.
The user is not seeing the Yii 'flash' session-based user-feedback messages. These messages are shown once to a user and then destroyed (so they're not shown on subsequent page loads).
I took a look at the server access logs and I noticed something weird.
When this user requests a page there is a second identical request but from a different IP and with a different User Agent string. The second request is often at the same time or is sometimes (at most) a couple of minutes later. A bit of googling leads me to the conclusion that the user is browsing the web using a HTTP Proxy.
So, is this likely to be a HTTP Proxy? Or could it be something more suspicious? And if it is a HTTP Proxy, does this explain why they're not seeing the flash session messages? Could it be that the messages are being 'shown' to the Proxy and then destroyed?
I have a test plan that runs fine under http, and the Cookie Manager is correctly keeping my sessions in place. It is also capable of talking to the same server when switched to ssl, and even thinks everything is working correctly because it gets a 200 response with our custom message about not being logged in.
All I need to do to reproduce the behavior is switch from http to https. The test is still able to talk to the server, but I can see in the "View Results in Table" log that cookies has a JSESSIONID under http, and is empty under https. And each request under ssl is answered with a Set-Cookie for JSESSIONID.
Interesting scenario. Does the Jmeter log file offer any clues?
Could it be that Jmeter needs a copy of the certificate to properly store the SSL cookie? The console would display a handshake problem, which can be resolved by adding the certificate into the key store:
http://www.java-samples.com/showtutorial.php?tutorialid=210
You might be able to do some further debug by writing out the cookie value to a variable and logging its value:
Received Cookies can be stored as JMeter thread variables (versions of JMeter after 2.3.2 no longer do this by default). To save cookies as variables, define the property "CookieManager.save.cookies=true". Also, cookies names are prefixed with "COOKIE_" before they are stored (this avoids accidental corruption of local variables) To revert to the original behaviour, define the property "CookieManager.name.prefix= " (one or more spaces). If enabled, the value of a cookie with the name TEST can be referred to as ${COOKIE_TEST}.
Source: http://jmeter.apache.org/usermanual/component_reference.html#HTTP_Cookie_Manager
Edit: Somebody asked how my specific problem was solved. It turned out not to have anything to do with ssl specifically, but that other unrelated headers changed very slightly in their format, so the regex we were using to match on them started failing. So I'd start there with looking at your headers and comparing the difference between when you post http vs https
Sorry for posting basic question but please give me your advise.
I have to write iOS application which communicates with web application deployed on Tomcat server.
The web application requires client-app to call the "logon" servlet with username and password to get JSESSIONID. Once client get JSESSIONID, the web application allows to invoke other servlets.
But I couldn't figure out how to manage the session to invoke these servlets.
Would you please introduce me the examples/tutorials to learn how to invoke these kind of servlets?
Thank you in advance.
Here's a decent example of making an http request from iOS:
iOS: How to make a secure HTTPS connection to pass credentials?
There's nothing magic about making the call to a j2ee tomcat server - it's just an HTTP request, so any way you can make an HTTP request will work for you.
Maybe this one too:
Can I make POST or GET requests from an iphone application?
edit: ahh, looks like this is the one you want:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html
The JSESSIONID is nothing special. If your application is set up to handle cookies coming back from your HTTP request then the JSESSIONID will come back as a cookie in the header. Otherwise you will be issued a redirect to a URL with the JSESSIONID in it. From there, if you handle cookies, the JSESSIONID will be passed automatically with each request with all of the other cookies. Otherwise you'll have to put it into the URL of each request manually.
Download the liveheaders plugin for Firefox and try hitting your servlet with the webbrowser and you can see how the JSESSIONID gets passed around. Next, turn off cookies in Firefox and you can see how it's passed around in the URL and you can see the redirect that Tomcat issues if you watch the headers in liveheaders.