IIS proxy: username in Node-RED

Hi,

I am using an IIS proxy server with Windows Authentication to enable access to my Node-RED Dashboard UI for a defined AD user group. While this in itself works perfectly, I would like to know which AD user is logged in to the browser session so I can log this information with the Node-RED flow that is triggered.

Is there any way I can do this? Or is there any other way to achieve the (basically same) result?

Any help is greatly appreciated!
Thanks very much,
DenW

Welcome to the forums @DenW

I could be mistaken - but I don't think there will be.

The dashboard (or more accurately JavaScript) runs in the context of the browsers document - not the server.

In ASP.NET and alike - these types of properties are obtained server side, as the w3wp.exe process it's self is being executed by said logged in user.

You wouldn't be able to do this in the flow either (even though it is affectively server side) - as Node RED is being run by a system/local account of some sort.

again - I could be wrong here, but I cant imagine its doable without some custom/complex scaffolding in place.

Thank you @marcus-j-davies ! :slight_smile:
Been tinkering with Node-RED for some time now and was able to figure most things out myself. But this appears to be a tricky one..

My line of thought was that an IIS authentication header would (or could) be passed on to the NR flow.. since both are server side.. but no idea how to effectively do this..

Thanks for your quick reply!
DenW

Ok, I see where your going, I don't know too much about how dashboard works - plenty here who do.

But, I'm sure you can setup a flow that captures new Webscoket connections, this (I believe) will contain headers of the client, importantly the Authorization header (maybe)

I think your mileage will vary, as you also need to decode the header - But hopefully its not insecure such as BASIC :grimacing: and providing the IIS Proxy passes this header through - it may not due to the security implication in doing so.

Not quite. The best way is to set up an http-in/-out pair as a web endpoint. The output from the http-in node contains the headers.

However, it looks like you only get an authentication token by default, and only that if you configure IIS to pass it through. The token has to be interpreted and I only found a Python method.

There are some alternatives though that require further IIS middleware:

Note that I've not tried any of this so kind of guessing.

I've been strugling with this for a couple of days now..

Tried a method setting a cookie with a username value, but IIS Response Header (where I set the cookie) seems to be unaware of any server variables. Cookie values are always empty (or not interpreted: {HTTP_REMOTE_USER} is the value of the cookie).

After changing the IIS authentication to Basic I can now see the Authorization Request Header in my browser (Developer Tools). However, when I trigger the test flow, the HTTP-In result does not contain a req.header.

If I'm reader the docs correctly, req.header should contain the browser request header info. But I'm getting nowhere..

Obviously the mDashboard form is triggered on another machine that has access to mDashboard. Tested with Firefox and Edge, no difference in behaviour.

Node.JS version = 18.12.1
Node-RED version = 3.0.2
Node versions all up to date (23-04-17)

Again, any help is greatly appreciated!
Thanks, DenW

PS: this is the test flow i'm using (using mDashboard, but changing the form to a Dashboard one would work fine):

[
    {
        "id": "59ff2a1.fa600d4",
        "type": "http in",
        "z": "a7c3cbaf02fdf2a9",
        "name": "",
        "url": "/hello",
        "method": "post",
        "upload": false,
        "swaggerDoc": "",
        "x": 870,
        "y": 180,
        "wires": [
            [
                "54c1e70d.ab3e18",
                "907c1ea16513051b"
            ]
        ]
    },
    {
        "id": "54c1e70d.ab3e18",
        "type": "template",
        "z": "a7c3cbaf02fdf2a9",
        "name": "page",
        "field": "payload",
        "fieldType": "msg",
        "format": "handlebars",
        "syntax": "mustache",
        "template": "<html>\n    <head></head>\n    <body>\n        <h1>Hello World!</h1>\n        <h1>Headers: {{msg.req.headers.authorization}}</h1>\n    </body>\n</html>",
        "x": 1270,
        "y": 140,
        "wires": [
            [
                "266c286f.d993d8",
                "5850e296a83e3a7d"
            ]
        ]
    },
    {
        "id": "266c286f.d993d8",
        "type": "http response",
        "z": "a7c3cbaf02fdf2a9",
        "name": "",
        "statusCode": "",
        "headers": {},
        "x": 1490,
        "y": 140,
        "wires": []
    },
    {
        "id": "d413a6424598b4df",
        "type": "http request",
        "z": "a7c3cbaf02fdf2a9",
        "name": "",
        "method": "POST",
        "ret": "txt",
        "paytoqs": "body",
        "url": "127.0.0.1:1881/hello",
        "tls": "",
        "persist": true,
        "proxy": "",
        "insecureHTTPParser": true,
        "authType": "",
        "senderr": false,
        "headers": [
            {
                "keyType": "Content-Type",
                "keyValue": "",
                "valueType": "other",
                "valueValue": "text/plain"
            }
        ],
        "x": 750,
        "y": 80,
        "wires": [
            [
                "55e4572e284dc994"
            ]
        ]
    },
    {
        "id": "37d37b76e17d57a7",
        "type": "inject",
        "z": "a7c3cbaf02fdf2a9",
        "name": "",
        "props": [
            {
                "p": "payload.text",
                "v": "Hoi Den!",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 530,
        "y": 80,
        "wires": [
            [
                "d413a6424598b4df"
            ]
        ]
    },
    {
        "id": "55e4572e284dc994",
        "type": "debug",
        "z": "a7c3cbaf02fdf2a9",
        "name": "debug 3",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 980,
        "y": 80,
        "wires": []
    },
    {
        "id": "5850e296a83e3a7d",
        "type": "debug",
        "z": "a7c3cbaf02fdf2a9",
        "name": "debug 4",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1620,
        "y": 280,
        "wires": []
    },
    {
        "id": "98393730990db149",
        "type": "mui_form",
        "z": "a7c3cbaf02fdf2a9",
        "name": "",
        "label": "",
        "group": "e769dd829321faab",
        "order": 0,
        "width": 0,
        "height": 0,
        "options": [
            {
                "label": "Test",
                "value": "test",
                "type": "text",
                "required": true,
                "rows": null
            }
        ],
        "formValue": {
            "test": ""
        },
        "payload": "",
        "submit": "submit",
        "cancel": "",
        "topic": "",
        "x": 530,
        "y": 200,
        "wires": [
            [
                "d413a6424598b4df"
            ]
        ]
    },
    {
        "id": "907c1ea16513051b",
        "type": "json",
        "z": "a7c3cbaf02fdf2a9",
        "d": true,
        "name": "",
        "property": "payload",
        "action": "obj",
        "pretty": false,
        "x": 1290,
        "y": 240,
        "wires": [
            [
                "5850e296a83e3a7d"
            ]
        ]
    },
    {
        "id": "e769dd829321faab",
        "type": "mui_group",
        "name": "mGroup 1",
        "tab": "619fd859331557b7",
        "order": 1,
        "disp": true,
        "width": 6
    },
    {
        "id": "619fd859331557b7",
        "type": "mui_tab",
        "name": "Tab 1",
        "icon": "dashboard",
        "order": 1
    }
]

BlockquoteNot quite. The best way is to set up an http-in/-out pair as a web endpoint. The output from the http-in node contains the headers.

Well.. that's just it. The output from the HTTP-In node contains the headers of the ExpressJS server, not the IIS headers. So the IIS Authentication token is not part of the HTTP-In info (even when using basic auth), and the same applies when using a cookie to store the auth info.
This is probably caused by the IIS proxy setup, but not sure about that..

Does anyone know if it is possible to "transfer"' the IIS header info to ExpressJS, and if so, how? Or how can I get ExpressJS (or NodeRED) to read the local IIS cookie?

Not even sure if this is the right way to go about his, if not please let me know..

Thanks again!
DenW

Which is why you need to tell Express to trust the IIS proxy which is done via the settings.js file.

You should be able to. I can't quite remember how off the top of my head but you need to start by trusting the proxy. That might be enough on its own.

You are on the right lines. I'm not very familiar with IIS and it has been a long time since I did anything serious with it.

This article may help? HTTP server behind IIS: pass authentication headers - Stack Overflow

Hi @TotallyInformation ,

Thanks for your help and confirming I am on the right track here.
I'll spend time this week to see if I can get any further with the ExpressJS settings. Thanks!!

The article you mentioned was mentioned before, and I have even tried installing the Helicon ISAPI rewrite engine. After installing it however, my NodeRED dashboard site did not even load anymore. It loaded some JS code files (DevTools), but then failed to load anything further.
I'm currently attributing this to the Helicon engine not supporting WebSockets (which I had to enable in IIS as well), but I may be wrong here.
Removing the Helicon software returned everything to working condition.

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.