1. The problem I’m having:
NTLM based application repeatedly keeps asking for authentication (401).
2. Error messages and/or full log output:
As you can see, after I enter the credentials couple of requests go through but then 401 response along with Www-Authenticate: Negotiate
is back. As far as the client is concerned login doesn’t work
3. Caddy version:
v2.7.6
4. How I installed and ran Caddy:
a. System environment:
Ubuntu 22
b. Command:
- Start Caddy
- Make API calls to the endpoint
c. Service/unit/compose file:
I am using it directly for now;
d. My complete Caddy config:
{
"apps": {
"http": {
"servers": {
"srv0": {
"listen": [
":443"
],
"routes": [
{
"@id": "6617dfefa69a11bcada86df9",
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"encodings": {
"gzip": {},
"zstd": {}
},
"handler": "encode"
},
{
"handler": "reverse_proxy",
"headers": {
"request": {
"set": {
"Host": [
"{http.reverse_proxy.upstream.hostport}"
],
"X-Forwarded-For": [
"{http.request.remote.host}"
],
"X-Real-IP": [
"{http.request.remote.host}"
],
"X-Forwarded-Port": [
"{http.request.remote.port}"
]
},
"add": {
"X-Forwarded-Proto": [
"{http.request.scheme}"
]
}
},
"response": {
"replace": {
"Location": [
{
"replace": "6617dfefa69a11bcada86df9.SLUG-38.gw.DOMAIN.io",
"search": "{http.reverse_proxy.upstream.host}"
}
],
"Set-Cookie": [
{
"search": "secure;",
"replace": ""
},
{
"search": "SameSite=None",
"replace": "SameSite=Lax"
}
]
},
"set": {
"Content-Security-Policy": [
"frame-ancestors *"
]
}
}
},
"transport": {
"protocol": "http_ntlm",
"tls": {
"insecure_skip_verify": true
}
},
"upstreams": [
{
"dial": "etest.DOMAIN.com:443"
}
]
}
]
}
]
}
],
"match": [
{
"host": [
"6617dfefa69a11bcada86df9.SLUG-38.gw.DOMAIN.io"
]
}
],
"terminal": true
}
],
"tls_connection_policies": [
{
"match": {
"sni": [
"*.SLUG-38.gw.DOMAIN.io"
]
}
},
{}
]
}
}
},
"tls": {
"certificates": {
"load_files": [
{
"certificate": "/opt/DOMAIN/sdpgw/letsencrypt/fullchain.pem",
"key": "/opt/DOMAIN/sdpgw/letsencrypt/privatekey.pem"
}
]
}
}
},
"logging": {
"logs": {
"Empty": {
"writer": {
"filename": "/opt/myapp/caddy.logs",
"output": "file"
},
"level": "DEBUG"
}
},
"sink": {
"writer": {
"filename": "/opt/myapp/caddy.logs",
"output": "file"
},
"level": "DEBUG"
}
}
}
This is a combination of translating the haproxy config (given below) and surfing through the Caddy Community for any NTLM related article. I am not sure what else to change
5. Links to relevant resources:
But the same NTLM app works perfectly in haproxy. But when I moved to Caddy it doesn’t work anymore.
This is the haproxy config that was being used
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
default-server init-addr last,libc,none no-tls-tickets
frontend ourwebsitefrontend
mode http
bind *:80
bind *:443 ssl crt /etc/haproxy/certs/
#6617dfefa69a11bcada86df9_START_FRONTEND
acl host6617dfefa69a11bcada86df9 hdr_dom(host) -i 6617dfefa69a11bcada86df9.SLUG-54.gw.app.DOMAIN.io
use_backend 6617dfefa69a11bcada86df9_backend if xtoken_present jwtverify host6617dfefa69a11bcada86df9
#6617dfefa69a11bcada86df9_END_FRONTEND
#6617dfefa69a11bcada86df9_START_BACKEND
backend 6617dfefa69a11bcada86df9_backend
mode http
option forwardfor
http-request set-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto https if { ssl_fc }
#option httpchk HEAD / HTTP/1.1\r\nHost:localhost
http-send-name-header Host
server etest.wns.com etest.wns.com:443 ssl verify none
http-response replace-header Location (http|https)://(.+?(?=/))/(.*) \1://%[lua.get_redirection_location()]/\3
#6617dfefa69a11bcada86df9_END_BACKEND
What am I missing here?
Addition Logs
Here are two entries (from caddy debug logs) where the first log is after authentication is successful but immediately follows with 401. Its like as if the backend server suddenly decides this is not the same user as before
{"level":"debug","ts":1712981254.1765645,"logger":"http.handlers.reverse_proxy","msg":"upstream roundtrip","upstream":"etest.wns.com:443","duration":0.020057676,"request":{"remote_ip":"X.X.X.X","remote_port":"54236","client_ip":"X.X.X.X","proto":"HTTP/3.0","method":"GET","host":"etest.wns.com:443","uri":"/Resources/bootstrap/css/bootstrap.min.css","headers":{"Accept":["text/css,*/*;q=0.1"],"Sec-Fetch-Mode":["no-cors"],"X-Real-Ip":["X.X.X.X"],"Accept-Encoding":["gzip, deflate, br, zstd"],"X-Forwarded-For":["X.X.X.X"],"Referer":["https://6617dfefa69a11bcada86df9.SLUG-38.gw.DOMAIN.io/"],"Sec-Ch-Ua-Mobile":["?0"],"Cookie":[],"User-Agent":["Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"],"Sec-Fetch-Site":["same-origin"],"Sec-Ch-Ua":["\"Google Chrome\";v=\"123\", \"Not:A-Brand\";v=\"8\", \"Chromium\";v=\"123\""],"Sec-Fetch-Dest":["style"],"Dnt":["1"],"Pragma":["no-cache"],"X-Forwarded-Proto":["https"],"X-Forwarded-Host":["6617dfefa69a11bcada86df9.SLUG-38.gw.DOMAIN.io"],"Accept-Language":["en-US,en;q=0.9"],"Cache-Control":["no-cache"],"Sec-Ch-Ua-Platform":["\"macOS\""]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h3","server_name":"6617dfefa69a11bcada86df9.SLUG-38.gw.DOMAIN.io"}},"headers":{"Cache-Control":["no-cache, no-store"],"Persistent-Auth":["true"],"Date":["Sat, 13 Apr 2024 04:07:33 GMT"],"Content-Length":["32182"],"Content-Encoding":["gzip"],"Expires":["0"],"Vary":["Accept-Encoding"],"X-Frame-Options":["SAMEORIGIN"],"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],"Pragma":["no-cache"],"Content-Type":["text/css"],"Last-Modified":["Fri, 22 Dec 2023 15:29:02 GMT"],"Accept-Ranges":["bytes"],"Etag":["\"c93c8c97eb34da1:0\""],"X-Xss-Protection":["1; mode=block"],"X-Content-Type-Options":["nosniff"]},"status":200}
{"level":"debug","ts":1712981254.1861625,"logger":"http.handlers.reverse_proxy","msg":"upstream roundtrip","upstream":"etest.wns.com:443","duration":0.029091655,"request":{"remote_ip":"X.X.X.X","remote_port":"54236","client_ip":"X.X.X.X","proto":"HTTP/3.0","method":"GET","host":"etest.wns.com:443","uri":"/Resources/StyleSheet/style.css","headers":{"X-Forwarded-Host":["6617dfefa69a11bcada86df9.SLUG-38.gw.DOMAIN.io"],"Pragma":["no-cache"],"Cache-Control":["no-cache"],"X-Forwarded-Proto":["https"],"Accept-Language":["en-US,en;q=0.9"],"Sec-Fetch-Site":["same-origin"],"Sec-Ch-Ua-Platform":["\"macOS\""],"X-Real-Ip":["X.X.X.X"],"Sec-Ch-Ua":["\"Google Chrome\";v=\"123\", \"Not:A-Brand\";v=\"8\", \"Chromium\";v=\"123\""],"User-Agent":["Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"],"Sec-Fetch-Dest":["style"],"Sec-Fetch-Mode":["no-cors"],"X-Forwarded-For":["X.X.X.X"],"Sec-Ch-Ua-Mobile":["?0"],"Accept":["text/css,*/*;q=0.1"],"Referer":["https://6617dfefa69a11bcada86df9.SLUG-38.gw.DOMAIN.io/"],"Accept-Encoding":["gzip, deflate, br, zstd"],"Cookie":[],"Dnt":["1"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h3","server_name":"6617dfefa69a11bcada86df9.SLUG-38.gw.DOMAIN.io"}},"headers":{"Pragma":["no-cache"],"Content-Type":["text/html"],"Www-Authenticate":["Negotiate","NTLM"],"X-Xss-Protection":["1; mode=block"],"X-Frame-Options":["SAMEORIGIN"],"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],"Date":["Sat, 13 Apr 2024 04:07:33 GMT"],"Content-Length":["1293"],"Cache-Control":["no-cache, no-store"],"Expires":["0"],"X-Content-Type-Options":["nosniff"]},"status":401}