jlguenego / node-expose-sspi

Expose Microsoft Windows SSPI to Node for SSO authentication.
ISC License
128 stars 19 forks source link

Not works behind iis proxy #130

Closed lublak closed 2 years ago

lublak commented 2 years ago

Describe the bug

First of all: localhost:8090/login/ works fine. If I use iis as a reverse proxy, the whole thing doesn't work at all. test.intranet.local/login/ On the firefox browser i get an Malformed authentication token: NTLM error On the Edge browser i get repeating logins.

To Reproduce

grafik grafik grafik

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="test" stopProcessing="true">
                    <match url=".*" />
                    <conditions>
                        <add input="{HTTP_HOST}" pattern="^test.intranet.local$" />
                    </conditions>
                    <action type="Rewrite" url="http://127.0.0.1:8090/{R:0}" />
                </rule>
            </rules>
        </rewrite>
        <defaultDocument>
            <files>
                <clear />
                <add value="index.php" />
                <add value="Default.htm" />
                <add value="Default.asp" />
                <add value="index.htm" />
                <add value="index.html" />
                <add value="iisstart.htm" />
            </files>
        </defaultDocument>
            <httpErrors existingResponse="PassThrough" />
    </system.webServer>
</configuration>
import express from 'express';
import { sso } from 'node-expose-sspi';
app.use('/login', sso.auth({ useGroups: false }), (req, res) => {
    res.json(req.sso);
});
app.listen(8090);

I added also spn.

Trace

Firefox:

  node-expose-sspi:auth check the session:  Session {
  cookie: { path: '/', _expires: null, originalMaxAge: null, httpOnly: true }
} +0ms
  node-expose-sspi:auth no session.sso +10ms
  node-expose-sspi:auth no authorization key in header +12ms
  node-expose-sspi:auth check the session:  Session {
  cookie: { path: '/', _expires: null, originalMaxAge: null, httpOnly: true }
} +90ms
  node-expose-sspi:auth no session.sso +1ms
  node-expose-sspi:misc buffer length 574 +0ms
  node-expose-sspi:auth messageType:  NTLM_AUTHENTICATE_03 +15ms
  node-expose-sspi:misc buffer length 574 +7ms
  node-expose-sspi:auth 0x00000000:4e 54 4c 4d 53 53 50 00  03 00 00 00 18 00 18 00 : NTLMSSP.........
  node-expose-sspi:auth 0x00000016:7c 00 00 00 9a 01 9a 01  94 00 00 00 0c 00 0c 00 : ................
  node-expose-sspi:auth 0x00000032:58 00 00 00 0c 00 0c 00  64 00 00 00 0c 00 0c 00 : X.......d.......
  node-expose-sspi:auth 0x00000048:70 00 00 00 10 00 10 00  2e 02 00 00 15 82 88 e2 : ................
  node-expose-sspi:auth 0x00000064:0a 00 ba 47 00 00 00 0f  de fe 4c 0f 49 4a 36 c4 : ..ºG....Þ.L.IJ6.
    Some data removed because privacy
  node-expose-sspi:auth  +14ms
Error: serverContextHandle not retrieved.
    at D:\test\node_modules\node-expose-sspi\dist\sso\auth.js:113:27
    at D:\test\node_modules\node-expose-sspi\dist\sso\auth.js:190:11
    at Layer.handle [as handle_request] (D:\test\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (D:\test\node_modules\express\lib\router\index.js:323:13)
    at D:\test\node_modules\express\lib\router\index.js:284:7
    at Function.process_params (D:\test\node_modules\express\lib\router\index.js:341:12)
    at next (D:\test\node_modules\express\lib\router\index.js:275:10)
    at Immediate._onImmediate (D:\test\node_modules\express-session\index.js:506:7)
    at processImmediate (node:internal/timers:468:21)
  node-expose-sspi:adConnection openADConnection: counter:  1 +0ms
  node-expose-sspi:adConnection closeADConnection: counter:  0 +74ms
  node-expose-sspi:mutex acquire +0ms
statusInfo:  Promise { <pending> }
messageType:  NTLM_AUTHENTICATE_03
  node-expose-sspi:adConnection openADConnection: counter:  1 +39ms
UnauthorizedError: Error while doing SSO: serverContextHandle not retrieved.
    at D:\test\node_modules\node-expose-sspi\dist\sso\auth.js:188:43
    at D:\test\node_modules\node-expose-sspi\dist\sso\auth.js:190:11
    at Layer.handle [as handle_request] (D:\test\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (D:\test\node_modules\express\lib\router\index.js:323:13)
    at D:\test\node_modules\express\lib\router\index.js:284:7
    at Function.process_params (D:\test\node_modules\express\lib\router\index.js:341:12)
    at next (D:\test\node_modules\express\lib\router\index.js:275:10)
    at Immediate.<anonymous> (D:\test\node_modules\express-session\index.js:506:7)
    at processImmediate (node:internal/timers:468:21)
  node-expose-sspi:adConnection closeADConnection: counter:  0 +927ms
  node-expose-sspi:mutex release +964ms
  node-expose-sspi:auth check the session:  Session {
  cookie: { path: '/', _expires: null, originalMaxAge: null, httpOnly: true }
} +27s
  node-expose-sspi:auth no session.sso +2ms

Firefox after restarting the express server and just press F5

  node-expose-sspi:auth no authorization key in header +0ms
  node-expose-sspi:misc buffer length 2581 +0ms
  node-expose-sspi:auth messageType:  Kerberos_1 +44ms
  node-expose-sspi:misc buffer length 2581 +6ms
  node-expose-sspi:auth 0x00000000:60 82 0a 11 06 06 2b 06  01 05 05 02 a0 82 0a 05 : `...............
  node-expose-sspi:auth 0x00000016:30 82 0a 01 a0 30 30 2e  06 09 2a 86 48 82 f7 12 : 0....00.....H...
  node-expose-sspi:auth 0x00000032:01 02 02 06 09 2a 86 48  86 f7 12 01 02 02 06 0a : .......H........
  node-expose-sspi:auth 0x00000048:2b 06 01 04 01 82 37 02  02 1e 06 0a 2b 06 01 04 : ......7.........
  node-expose-sspi:auth 0x00000064:01 82 37 02 02 0a a2 82  09 cb 04 82 09 c7 60 82 : ..7...........`.
  node-expose-sspi:auth  +8ms
TypeError: Cannot read properties of undefined (reading 'value')
    at Object.getKerberosDetails (D:\test\node_modules\node-expose-sspi\dist\sso\kerberos.js:17:28)
    at D:\test\node_modules\node-expose-sspi\dist\sso\auth.js:98:62
    at D:\test\node_modules\node-expose-sspi\dist\sso\auth.js:190:11
    at Layer.handle [as handle_request] (D:\test\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (D:\test\node_modules\express\lib\router\index.js:323:13)
    at D:\test\node_modules\express\lib\router\index.js:284:7
    at Function.process_params (D:\test\node_modules\express\lib\router\index.js:341:12)
    at next (D:\test\node_modules\express\lib\router\index.js:275:10)
    at Immediate._onImmediate (D:\test\node_modules\express-session\index.js:506:7)
    at processImmediate (node:internal/timers:468:21)
  node-expose-sspi:adConnection openADConnection: counter:  1 +0ms
  node-expose-sspi:adConnection closeADConnection: counter:  0 +89ms
  node-expose-sspi:mutex acquire +0ms
statusInfo:  Promise { <pending> }
messageType:  Kerberos_1
  node-expose-sspi:adConnection openADConnection: counter:  1 +29ms
UnauthorizedError: Error while doing SSO: Cannot read properties of undefined (reading 'value')
    at D:\test\node_modules\node-expose-sspi\dist\sso\auth.js:188:43
    at D:\test\node_modules\node-expose-sspi\dist\sso\auth.js:190:11
    at Layer.handle [as handle_request] (D:\test\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (D:\test\node_modules\express\lib\router\index.js:323:13)
    at D:\test\node_modules\express\lib\router\index.js:284:7
    at Function.process_params (D:\test\node_modules\express\lib\router\index.js:341:12)
    at next (D:\test\node_modules\express\lib\router\index.js:275:10)
    at Immediate.<anonymous> (D:\test\node_modules\express-session\index.js:506:7)
    at processImmediate (node:internal/timers:468:21)
  node-expose-sspi:adConnection closeADConnection: counter:  0 +193ms
  node-expose-sspi:mutex release +223ms

Edge:

  node-expose-sspi:auth check the session:  Session {
  cookie: { path: '/', _expires: null, originalMaxAge: null, httpOnly: true }
} +0ms
  node-expose-sspi:auth no session.sso +10ms
  node-expose-sspi:auth no authorization key in header +4ms
  node-expose-sspi:auth check the session:  Session {
  cookie: { path: '/', _expires: null, originalMaxAge: null, httpOnly: true }
} +41ms
  node-expose-sspi:auth no session.sso +3ms
  node-expose-sspi:misc buffer length 574 +0ms
  node-expose-sspi:auth messageType:  NTLM_AUTHENTICATE_03 +4ms
  node-expose-sspi:misc buffer length 574 +3ms
  node-expose-sspi:auth 0x00000000:4e 54 4c 4d 53 53 50 00  03 00 00 00 18 00 18 00 : NTLMSSP.........
  node-expose-sspi:auth 0x00000016:7c 00 00 00 9a 01 9a 01  94 00 00 00 0c 00 0c 00 : ................
  node-expose-sspi:auth 0x00000032:58 00 00 00 0c 00 0c 00  64 00 00 00 0c 00 0c 00 : X.......d.......
  node-expose-sspi:auth 0x00000048:70 00 00 00 10 00 10 00  2e 02 00 00 15 82 88 e2 : ................
  node-expose-sspi:auth 0x00000064:0a 00 ba 47 00 00 00 0f  1f c6 bb 22 c9 03 f0 be : ..ºG......»....¾
  Some data removed because privacy
  node-expose-sspi:auth  +4ms
Error: serverContextHandle not retrieved.
    at D:\test\node_modules\node-expose-sspi\dist\sso\auth.js:113:27
    at D:\test\node_modules\node-expose-sspi\dist\sso\auth.js:190:11
    at Layer.handle [as handle_request] (D:\test\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (D:\test\node_modules\express\lib\router\index.js:323:13)
    at D:\test\node_modules\express\lib\router\index.js:284:7
    at Function.process_params (D:\test\node_modules\express\lib\router\index.js:341:12)
    at next (D:\test\node_modules\express\lib\router\index.js:275:10)
    at Immediate._onImmediate (D:\test\node_modules\express-session\index.js:506:7)
    at processImmediate (node:internal/timers:468:21)
  node-expose-sspi:adConnection openADConnection: counter:  1 +0ms
  node-expose-sspi:adConnection closeADConnection: counter:  0 +82ms
  node-expose-sspi:mutex acquire +0ms
statusInfo:  Promise { <pending> }
messageType:  NTLM_AUTHENTICATE_03
  node-expose-sspi:adConnection openADConnection: counter:  1 +9ms
UnauthorizedError: Error while doing SSO: serverContextHandle not retrieved.
    at D:\test\node_modules\node-expose-sspi\dist\sso\auth.js:188:43
    at D:\test\node_modules\node-expose-sspi\dist\sso\auth.js:190:11
    at Layer.handle [as handle_request] (D:\test\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (D:\test\node_modules\express\lib\router\index.js:323:13)
    at D:\test\node_modules\express\lib\router\index.js:284:7
    at Function.process_params (D:\test\node_modules\express\lib\router\index.js:341:12)
    at next (D:\test\node_modules\express\lib\router\index.js:275:10)
    at Immediate.<anonymous> (D:\test\node_modules\express-session\index.js:506:7)
    at processImmediate (node:internal/timers:468:21)
  node-expose-sspi:adConnection closeADConnection: counter:  0 +116ms
  node-expose-sspi:mutex release +125ms

Expected behavior

That it works with reverse proxy just like with iis.

Environment version:

Please indicates also:

Additional context

It can also be that settings must be made in the IIS. But then it would be good to have a documentation about it.

https://github.com/jlguenego/node-expose-sspi/blob/master/doc/use-case/production-windows.md

lublak commented 2 years ago

@jlguenego I wanted to ask if you could share your test configuration. So I can compare it with my system and see where the difference is.

anotherCoward commented 2 years ago

@lublak, I had similar challenges at first. Make sure preserve Host Headers is used and you also have to add the header Forwarded or X-Forwarded-for including the IP and port.

image

It is possible, that the server context handle manager can't find the cached handle if the proxy isn't forwarding the ip and port from the client (see #116). So make sure, you are passing both within the headers.

I for myself use nginx and the configuration is simple as this: ``` server { # ssl stuff ssl_certificate "c:/cert/server.local.crt"; ssl_certificate_key "c:/cert/server.local.key"; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384; # listen only for the specific name listen server.local:443 ssl; server_name server.local; charset utf8; # Proxy settings for the root directory location / { client_max_body_size 100M; proxy_http_version 1.1; proxy_pass_request_headers on; proxy_set_header Host $http_host; proxy_set_header Forwarded "for=\"$remote_addr:$remote_port\""; proxy_pass http://10.100.0.36:3000; } } ```
lublak commented 2 years ago

@anotherCoward We also switched to nginx because working with iis has always been difficult and has always presented us with problems. After switching to nginx, we no longer have any problems ourselves. That's why I can't test it anymore and would close the issue here (which I admittedly forgot). But thanks for the answer :) it's really nice of you!