Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using NTLM with a container #118

Open
ency98 opened this issue Jun 14, 2024 · 8 comments
Open

Using NTLM with a container #118

ency98 opened this issue Jun 14, 2024 · 8 comments

Comments

@ency98
Copy link

ency98 commented Jun 14, 2024

Using NTLM with a container.

Before I start I just want to say thank you to bolkedebruin. I may get a little snarky in this post but I do appreciate the work you have done creating this project and providing the documentation you have provided. I know it's impossibly hard to help everyone or write documentation that will cover the majority of "normal" cases let alone the edge cases that can be thrown at you. I also know it can be difficult helping people that don't know enough to ask the correct questions or have any idea how things function on the back end. You have done some good work and thank you.

I’m just posting this here to help anyone else having issues trying to figure out where to map various files how to get rdpgw-auth going and get the rdpgw-auth.sock in /tmp/

I’m not a programmer my my scripting skills are rather primitive so this took me WAY too long to figure out. But I really wanted to get it going so I banged my head against it until I got it going. The lack of explanations and documentation was very frustrating. But home labers ticking about on the weekend are not the target audience and the people that would actually need this and actually decided to look for a non MS solution probably know more than me when it comes to reading go and editing Dockerbuild files. A simple list of directories that the yaml files were supposed to be mapped to while running in a container would have saved me a lot of time.

Again, I'm not a developer, programmer, or do much dev-ops work. I'm sure there are better ways to accomplish what I wanted and I'm sure I walked all over best practices.

I hope this can help save someone’s weekend.

I decided I wanted to use NTLM as it was a pain to do the whole OAuth thing while I was on my LAN or connected to my VPN. I do have an external facing instance using oauth with Authentik as the backend just to be cool and win a nerd contest with a co-worker. But that's a whole other story. The OAuth implimentation is a lot easier and has much better documentation.

I'm also not using the provided docker-compose file as I had no need for the xrdp container for testing or for regular use.

Step 1: editing the run.sh script

Use git to clone the project.

cd into the docker directory "cd ./rdpgw/dev/docker"

Open the run.sh script. This is the "entry point for the rdpgw container and launches the rdpgw server and starts rdpgw-auth for local and NTLM authentication.

Delete everything between

USER=rdpgw

And

cd /opt/rdpgw || exit 1

Then delete everything after

cd /opt/rdpgw || exit 1

All the way to

# drop privileges and run the application

Now we need to add back the part that starts rdpgw-auth with some bits that will create rdpgw-auth.sock

Between

cd /opt/rdpgw || exit 1

And

# drop privileges and run the application

Add this line

/opt/rdpgw/rdpgw-auth -n rdpgw -s /tmp/rdpgw-auth.sock &

The entire run.sh script should look something like this.

#!/bin/sh

USER=rdpgw

cd /opt/rdpgw || exit 1
/opt/rdpgw/rdpgw-auth -n rdpgw -s /tmp/rdpgw-auth.sock &

# drop privileges and run the application
su -c /opt/rdpgw/rdpgw "${USER}" -- "$@" &
wait
exit $?

That's pretty much all I had to change to get the container up and going with /tmp/rdpgw-auth.sock available for authentication.

Step 2: building the container.

This step want too bad and there are a bunch of good guides out there.

Make sure you are still in the directory that contains the run.sh script and Dockerfile.

Run the following command to build the container.

docker build -t rdpgw-ntlm:latest .

The container will start building. I had no issues on this step. You may or may not need some dependancies but I seemed to have everything the build required already installed on my dev machine.

If you are like me and are in a serious nerd pissing contest with some coworkers and host your own registry the command will look something like this.

docker build -t repo.domain.tld/rdpgw:latest . 
docker push repo.domain.tld/rdpgw:latest

We now have the container built and ready to do some NTLM authentication.

Step 3: docker-compose.yml

Now on to the docker compose file.

You will need to map the following directories and files from your host into the container.

    volumes:
      - ./appdata/opt/rdpgw/rdpgw.yaml:/opt/rdpgw/rdpgw.yaml
      - ./appdata/opt/rdpgw/rdpgw-auth.yaml:/opt/rdpgw/rdpgw-auth.yaml
      - ./appdata/opt/rdpgw/server.pem:/opt/rdpgw/server.pem
      - ./appdata/opt/rdpgw/key.pem:/opt/rdpgw/key.pem
      - ./appdata/ect/rdpgw/default.rdp:/etc/rdpgw/default.rdp

I tried just mapping

      - ./appdata/opt/rdpgw/:/opt/rdpgw

But that never worked.

The environmental section looks like this.

    environment:
      RDPGW_SERVER__CERT_FILE: /opt/rdpgw/server.pem
      RDPGW_SERVER__KEY_FILE: /opt/rdpgw/key.pem
      RDPGW_SERVER__SESSION_STORE: "file"
      RDPGW_SERVER__GATEWAY_ADDRESS: https://rdg.domain.tld
      RDPGW_SERVER__PORT: "9443"

I found that a lot of the information on the issues page and in the read me's had me putting duplicate information in the rdpgw.yaml and the compose file. I'm sure that was me just reading things wrong. One issue I was not able to sort out was the paatokenencryptionkey and usertokensigningkey. It does not matter if I provide my own keys in the compose file in the rdpgw.yaml file or both the logs always report

No valid `security.paatokenencryptionkey` specified (empty or not 32 characters). Setting to random
No valid `security.usertokensigningkey` specified (empty or not 32 characters). Setting to random

The rest of your compose file is going to be filled with fiddly bits relating to your specific setup and workflow. Here is a basic config that should work.

---
services:

  app:
    image: rdpgw-ntlm:latest # Assuming you are deploying this on the same host you built the container on.  

    ports:
      - 9443:9443

    restart: on-failure

    volumes:
      - ./appdata/opt/rdpgw/rdpgw.yaml:/opt/rdpgw/rdpgw.yaml
      - ./appdata/opt/rdpgw/rdpgw-auth.yaml:/opt/rdpgw/rdpgw-auth.yaml
      - ./appdata/opt/rdpgw/server.pem:/opt/rdpgw/server.pem
      - ./appdata/opt/rdpgw/key.pem:/opt/rdpgw/key.pem
      - ./appdata/ect/rdpgw/default.rdp:/etc/rdpgw/default.rdp

    environment:
      RDPGW_SERVER__CERT_FILE: /opt/rdpgw/server.pem
      RDPGW_SERVER__KEY_FILE: /opt/rdpgw/key.pem
      RDPGW_SERVER__SESSION_STORE: "file"
      RDPGW_SERVER__GATEWAY_ADDRESS: https://rdg.domain.tld
      RDPGW_SERVER__PORT: "9443"

Step 4: yaml config files

This was a real pain to sort out. There a lot of brief mentions or hinting about things in the issues pages and in the read me. It took a lot of making a change, spinning things up, test, spin down, cry, and try a different way. I'm not even going to attempt to walk through these settings as I have no clue what I'm talking about.

rdpgw.yaml

Would really have been nice to have all the options listed even if they were not described. I know nothing about programming or go apps and had to dig through every file in this repo to try references to settings and where they might need to be applied.

Server:
  Authentication:
    - ntlm

  BasicAuthTimeout: "5"

  Tls: "auto"

  Hosts:
    - "HOST_1_DNS/IP:3389" # Don't get cute and think you're smarter than the author who made the app. Your gonna need the port
    - "HOST_2_DNS/IP:3389" # Don't forget that this is linux. What you use in the rdp file or the default.rdp if you add one, has to match the case of what you enter here. 
    - "HOST_3_DNS/IP:3389"

  HostSelection: "unsigned" # somewhere on the issues page its listed what options are available. This was the only option that worked for me if I had multiple hosts
  SessionKey: "GENERATE A 32 CHAR KEY" # CHANNGE
  SessionEncryptionKey: "GENERATE A 32 CHAR KEY" # CHANNGE

AuthSocket: /tmp/rdpgw-auth.sock # this MF thing... Remember the run.sh script... yeah...

Caps:
  TokenAuth: "false"
  IdleTimeout: "120"
  EnableClipboard: "true" # If you do not add this you will not be able to copy/paste no matter what setting you put into your RDP configs
  EnableDrive: "true" # If you do not add this you will not be able to copy/paste no matter what setting you put into your RDP configs

Client:
  defaults: "/etc/rdpgw/default.rdp"
  UsernameTemplate: "{{ username }}@DN.domain.tld" # Change the domain or remove I did not notice a difference either way
  SplitUserDomain: "false"

Security:
  PAATokenSigningKey: "GENERATE A 32 CHAR KEY" # CHANNGE
  UserTokenEncryptionKey: "GENERATE A 32 CHAR KEY" # CHANNGE
  EnableUserToken: "true"
  VerifyClientIp: "true"

rdpgw-auth.yaml

No problems here. Simple as.

Users:
 - {Username: "USERNAME", Password: "PASSWORD"} 

default.rdp

Nothing to fancy here. Just some basic settings for the network, disabling audio, and a failed attempt to get the clipboard working before I figured out it had to be enabled in rdpgw.yaml file. My coworker and I spent a whole day digging through our GPO's at work to see if it was being blocked by gpo, image local policy, mdm, or any of the handful of other systems we had in place that could have been blocking it.

connection type:i:7
bandwidthautodetect:i:1
networkautodetect:i:1
audiomode:i:2
autoreconnect max retries:i:5
autoreconnection enabled:i:1
session bpp:i:16
smart sizing:i:1
redirectclipboard:i:1

Step 5: Certs

Take a look at certstrap if you want to use your own and dont feel like googling how to use openssl. Your you are bound and determined to run your own CA but refuse to do it the right way.... Dont judge me!!!

certstrap

The container will also generate its own certs. No matter what you do it is important that your client computer trusts the certs.

I run mine behind a proxy using this project for certs and tcp pass through.

tlsproxy

You can use NGINX but I was already frustrated and did not feel like learning anything new last weekend. NGINX proxy manager should have been able to do it but I wasn't able to get the tcp streams working.

That's pretty much it.

You have the container that will have rdpgw-auth running and the rdpgw-auth.sock in /tmp/ ready to authenticate.

You have a basic docker-compose file to spin up the container

You have the rdpgw.yaml to configure the application and the rdpgw-auth.ymal supplying the user used to authenticate against the application.

You have a basic default.rdp file if you don't configure anything by hand in the rdp client or carry around your own rdp files.

And hopefully you have a weekend or two you can spend with your family instead getting stuck in a rabbit hole. trying to figure out something that should be "fun" and "easy".

Bonus info. If you want to try your hand at deploying remote apps add these lines to your RDP file to specify the specific app

alternate shell:s:rdpinit.exe
remoteapplicationmode:i:1
remoteapplicationname:s:Firefox
remoteapplicationprogram:s:||Firefox

The specific name was a pain for me to figure out deploying apps using the MS console and powershell. I just did not know enough to ask the right questions. Kasm had a pretty cool page on deploying remote apps using their server and I was able to use a lot of info from that page to configure some remote apps and deploy the apps in a way that didn't cause more problems than it fixed.

kasmweb

@banbu1118
Copy link

banbu1118 commented Aug 19, 2024

@ency98 Hello, I followed your instructions to implement NTLM, but it didn't work. Could you please provide the Docker Compose file?

docker logs error:
2024/08/19 03:12:18 Cannot upgrade falling back to old protocol: {%!t(string=websocket: not a websocket handshake: 'Sec-WebSocket-Key' header must be Base64 encoded value of 16-byte in length)}

@ency98
Copy link
Author

ency98 commented Aug 23, 2024

@banbu1118

I here is my compose file. I run it on a docker swarm cluster so its slightly diffrent.

With some timkering I figured out it was nto manditory to map the cert files.

---
services:
  server:
    image: PERSONAL-REPO/rdpgw:latest
    ports:
      - PORT:9443

    volumes:
      - /mnt/swarm/rdpgw/appdata/opt/rdpgw.yaml:/opt/rdpgw/rdpgw.yaml
      - /mnt/swarm/rdpgw/appdata/ect/default.rdp:/etc/rdpgw/default.rdp
      - /mnt/swarm/rdpgw/appdata/opt/rdpgw-auth.yaml:/opt/rdpgw/rdpgw-auth.yaml

    environment:
      RDPGW_SERVER__CERT_FILE: /opt/rdpgw/server.pem
      RDPGW_SERVER__KEY_FILE: /opt/rdpgw/key.pem
      RDPGW_SERVER__SESSION_STORE: "file"
      RDPGW_SERVER__GATEWAY_ADDRESS: https://DOMAIN.com
      RDPGW_SERVER__PORT: "PORT"

    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure
        delay: 10s
        max_attempts: 5
        window: 120s

    networks:
      - public_network

networks:
  public_network:
    external: true

@IrbisNN
Copy link

IrbisNN commented Oct 9, 2024

Hello. I have a problem with NTLM. Client just trying to connect and that's all. Didn't ask login or pwd. What I did wrong?

2024/10/09 14:49:10 No valid `security.paatokenencryptionkey` specified (empty or not 32 characters). Setting to random
2024/10/09 14:49:10 No valid `security.paatokensigningkey` specified (empty or not 32 characters). Setting to random
2024/10/09 14:49:10 No valid `server.sessionkey` specified (empty or not 32 characters). Setting to random
2024/10/09 14:49:10 No valid `server.sessionencryptionkey` specified (empty or not 32 characters). Setting to random
2024/10/09 14:49:10 Cookies are used as session storage
2024/10/09 14:49:10 Starting remote desktop gateway server
2024/10/09 14:49:10 enabling NTLM authentication
2024/10/09 14:49:18 Identity SessionId: 8e18c590-9869-411b-9f48-0a7769b2f84e, UserName: : Authenticated: false
2024/10/09 14:49:18 Identity SessionId: 8e18c590-9869-411b-9f48-0a7769b2f84e, UserName: : Authenticated: false
2024/10/09 14:49:18 Sending NTLM challenge

@ency98
Copy link
Author

ency98 commented Oct 9, 2024

@IrbisNN

Did you create a file with the username and password?

The errors about keys should not break anything as it will generate random keys when starting and I have never gotten a static config for that portion to work. But I'm still able to connect just fine.

I did write a script to restart the container nightly and to generate a random username and password for the NTLM auth.

@IrbisNN
Copy link

IrbisNN commented Oct 9, 2024

Yes, I did. Error about that rdpgw-auth didn't find yaml file didn't appear. And one thing I did it not in container.

@Darkangeel-hd
Copy link

@ency98 I used your setup too, and everything seems okay BUT
my client (mstsc) complains about not being able to access the remote resources

The logs on the container are as follows (two attempts to authenticate were made)

2024/10/24 18:46:01 Starting auth server on /tmp/rdpgw-auth.sock
2024/10/24 18:46:01 No valid `security.paatokenencryptionkey` specified (empty or not 32 characters). Setting to random
2024/10/24 18:46:01 No valid `security.usertokensigningkey` specified (empty or not 32 characters). Setting to random
2024/10/24 18:46:01 Cookies are used as session storage
2024/10/24 18:46:01 Starting remote desktop gateway server
2024/10/24 18:46:01 TLS disabled - rdp gw connections require tls, make sure to have a terminator
2024/10/24 18:46:01 enabling NTLM authentication
2024/10/24 18:46:38 Identity SessionId: f8b86f43-6bd4-4eed-8087-de56b7bc1e8e, UserName: : Authenticated: false
2024/10/24 18:46:38 [192.168.1.5:43514] Sending NTLM challenge
2024/10/24 18:46:38 Sending NTLM challenge
2024/10/24 18:46:38 Identity SessionId: f8b86f43-6bd4-4eed-8087-de56b7bc1e8e, UserName: : Authenticated: false
2024/10/24 18:46:38 [192.168.1.5:43530] NTLM failed: New NTLM auth sequence should start with negotioate request
2024/10/24 18:46:38 Error talking to authentication provider: rpc error: code = Unknown desc = New NTLM auth sequence should start with negotioate request
2024/10/24 18:49:12 Identity SessionId: 39f52888-2371-4de4-98b2-7022e70b8b22, UserName: : Authenticated: false
2024/10/24 18:49:12 [192.168.1.5:38846] Sending NTLM challenge
2024/10/24 18:49:12 Sending NTLM challenge
2024/10/24 18:49:12 Identity SessionId: 39f52888-2371-4de4-98b2-7022e70b8b22, UserName: : Authenticated: false
2024/10/24 18:49:12 [192.168.1.5:38856] NTLM failed: New NTLM auth sequence should start with negotioate request
2024/10/24 18:49:12 Error talking to authentication provider: rpc error: code = Unknown desc = New NTLM auth sequence should start with negotioate request

TLS connections are being terminated on a nginx proxy manager (192.168.1.5) using default config + web-sockets
that same config works if I setup this using keycloack and openid, so I don't think the problem lies there

I dunno what I'm missing here
I tried login with both .\user and [email protected] both with the same results

I also tried using remmina
client logs:

g.remmina.Remmina:1788): Gtk-WARNING **: 21:03:21.321: gtk_menu_attach_to_widget(): menu already attached to GtkMenuItem
[21:03:23:856] [1788:1794] [ERROR][com.freerdp.common.settings] - [freerdp_settings_get_bool] Invalid key index 131
[21:03:23:856] [1788:1794] [ERROR][com.freerdp.common.settings] - [freerdp_settings_get_bool] Invalid key index 0
[21:03:23:879] [1788:1794] [DEBUG][com.freerdp.core] - freerdp_connect:freerdp_set_last_error_ex resetting error state
[21:03:23:879] [1788:1794] [DEBUG][com.freerdp.client.common.cmdline] - loading channelEx rdpdr
[21:03:23:879] [1788:1794] [DEBUG][com.freerdp.client.common.cmdline] - loading channelEx rdpsnd
[21:03:23:880] [1788:1794] [DEBUG][com.freerdp.channels.cliprdr.client] - VirtualChannelEntryEx
[21:03:23:880] [1788:1794] [DEBUG][com.freerdp.client.common.cmdline] - loading channelEx cliprdr
[21:03:23:880] [1788:1794] [DEBUG][com.freerdp.channels.drdynvc.client] - VirtualChannelEntryEx
[21:03:23:880] [1788:1794] [DEBUG][com.freerdp.client.common.cmdline] - loading channelEx drdynvc
[21:03:23:898] [1788:1794] [DEBUG][com.freerdp.primitives] - primitives benchmark result:
[21:03:23:065] [1788:1794] [DEBUG][com.freerdp.primitives] -  * generic= 21
[21:03:23:223] [1788:1794] [DEBUG][com.freerdp.primitives] -  * optimized= 24
[21:03:23:223] [1788:1794] [DEBUG][com.freerdp.primitives] - primitives autodetect, using optimized
[21:03:23:226] [1788:1794] [DEBUG][com.freerdp.core.nego] - Enabling security layer negotiation: TRUE
[21:03:23:226] [1788:1794] [DEBUG][com.freerdp.core.nego] - Enabling restricted admin mode: FALSE
[21:03:23:226] [1788:1794] [DEBUG][com.freerdp.core.nego] - Enabling RDP security: TRUE
[21:03:23:226] [1788:1794] [DEBUG][com.freerdp.core.nego] - Enabling TLS security: TRUE
[21:03:23:226] [1788:1794] [DEBUG][com.freerdp.core.nego] - Enabling NLA security: TRUE
[21:03:23:226] [1788:1794] [DEBUG][com.freerdp.core.nego] - Enabling NLA extended security: FALSE
[21:03:23:226] [1788:1794] [DEBUG][com.freerdp.core.nego] - state: NEGO_STATE_NLA
[21:03:23:226] [1788:1794] [DEBUG][com.freerdp.core.nego] - Attempting NLA security
[21:03:23:227] [1788:1794] [DEBUG][com.freerdp.core] - freerdp_tcp_connect:freerdp_set_last_error_ex resetting error state
[21:03:23:228] [1788:1794] [DEBUG][com.freerdp.core] - connecting to peer ***.***.***.***
[21:03:24:299] [1788:1794] [DEBUG][com.winpr.sspi] - InitSecurityInterfaceExA
[21:03:24:299] [1788:1794] [DEBUG][com.winpr.sspi.NTLM] - change state from NTLM_STATE_INITIAL to NTLM_STATE_INITIAL
[21:03:24:299] [1788:1794] [DEBUG][com.winpr.sspi.NTLM] - change state from NTLM_STATE_INITIAL to NTLM_STATE_NEGOTIATE
[21:03:24:299] [1788:1794] [DEBUG][com.winpr.sspi.NTLM] - Write flags [0xe20882b7] NTLMSSP_NEGOTIATE_UNICODE|NTLMSSP_NEGOTIATE_OEM|NTLMSSP_REQUEST_TARGET|NTLMSSP_NEGOTIATE_SIGN|NTLMSSP_NEGOTIATE_SEAL|NTLMSSP_NEGOTIATE_LM_KEY|NTLMSSP_NEGOTIATE_NTLM|NTLMSSP_NEGOTIATE_ALWAYS_SIGN|NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY|NTLMSSP_NEGOTIATE_VERSION|NTLMSSP_NEGOTIATE_128|NTLMSSP_NEGOTIATE_KEY_EXCH
[21:03:24:300] [1788:1794] [DEBUG][com.winpr.sspi.NTLM] - change state from NTLM_STATE_NEGOTIATE to NTLM_STATE_CHALLENGE
[21:03:24:335] [1788:1794] [DEBUG][com.winpr.sspi.NTLM] - Read flags [0x62988255] NTLMSSP_NEGOTIATE_UNICODE|NTLMSSP_REQUEST_TARGET|NTLMSSP_NEGOTIATE_SIGN|NTLMSSP_NEGOTIATE_DATAGRAM|NTLMSSP_NEGOTIATE_NTLM|NTLMSSP_NEGOTIATE_ALWAYS_SIGN|NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY|NTLMSSP_NEGOTIATE_IDENTIFY|NTLMSSP_NEGOTIATE_TARGET_INFO|NTLMSSP_NEGOTIATE_VERSION|NTLMSSP_NEGOTIATE_128|NTLMSSP_NEGOTIATE_KEY_EXCH
[21:03:24:335] [1788:1794] [DEBUG][com.winpr.sspi.NTLM] - change state from NTLM_STATE_CHALLENGE to NTLM_STATE_AUTHENTICATE
[21:03:24:335] [1788:1794] [DEBUG][com.winpr.sspi.NTLM] - Write flags [0xe288a235] NTLMSSP_NEGOTIATE_UNICODE|NTLMSSP_REQUEST_TARGET|NTLMSSP_NEGOTIATE_SIGN|NTLMSSP_NEGOTIATE_SEAL|NTLMSSP_NEGOTIATE_NTLM|NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED|NTLMSSP_NEGOTIATE_ALWAYS_SIGN|NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY|NTLMSSP_NEGOTIATE_TARGET_INFO|NTLMSSP_NEGOTIATE_VERSION|NTLMSSP_NEGOTIATE_128|NTLMSSP_NEGOTIATE_KEY_EXCH
[21:03:24:335] [1788:1794] [DEBUG][com.winpr.sspi.NTLM] - change state from NTLM_STATE_AUTHENTICATE to NTLM_STATE_FINAL
[21:03:24:370] [1788:1794] [DEBUG][com.freerdp.core.gateway.rdg] - RDG_OUT_DATA authorization result: 500
[21:03:24:370] [1788:1794] [ERROR][com.freerdp.core.nego] - Protocol Security Negotiation Failure
[21:03:24:370] [1788:1794] [ERROR][com.freerdp.core] - rdp_client_connect:freerdp_set_last_error_ex ERRCONNECT_SECURITY_NEGO_CONNECT_FAILED [0x0002000C]
[21:03:24:370] [1788:1794] [ERROR][com.freerdp.core.connection] - Error: protocol security negotiation or connection failure

rdpgw logs:

2024/10/24 19:03:07 No valid `security.paatokenencryptionkey` specified (empty or not 32 characters). Setting to random
2024/10/24 19:03:07 No valid `security.usertokensigningkey` specified (empty or not 32 characters). Setting to random
2024/10/24 19:03:07 Cookies are used as session storage
2024/10/24 19:03:07 Starting remote desktop gateway server
2024/10/24 19:03:07 TLS disabled - rdp gw connections require tls, make sure to have a terminator
2024/10/24 19:03:07 enabling NTLM authentication
2024/10/24 19:03:24 Identity SessionId: 643a5f1e-32b4-4020-93e1-faa96299aae8, UserName: : Authenticated: false
2024/10/24 19:03:24 [192.168.1.5:57928] Sending NTLM challenge
2024/10/24 19:03:24 Sending NTLM challenge
2024/10/24 19:03:24 Identity SessionId: d3a55245-a1b5-4024-a8dd-f571e2bf2104, UserName: : Authenticated: false
2024/10/24 19:03:24 [192.168.1.5:57942] NTLM failed: New NTLM auth sequence should start with negotioate request
2024/10/24 19:03:24 Error talking to authentication provider: rpc error: code = Unknown desc = New NTLM auth sequence should start with negotioate request```

Same error as you see

I cant help but think I'm missing something

@Darkangeel-hd
Copy link

Darkangeel-hd commented Oct 25, 2024

I think this may be an issue on go-ntlm
cause i just saw in its README:

The major missing piece is the negotiation of capabilities between the client and the server. Currently, the negotiation flags are hardcoded, which should be fine for most (modern) clients/servers.

@afish
Copy link

afish commented Nov 20, 2024

@Darkangeel-hd Did you figure this out? I'm facing the same issue. I noticed I get this problem only when I expose rdpgw behind Nginx. It all works well when exposed directly on the web.

Edit: I think this requires NTLM support from nginx. It comes with Nginx Plus or with this module: https://github.com/gabihodoroaga/nginx-ntlm-module I haven't tried that, though. OTOH NTLM is a security risk so maybe it's better not to use it at all: https://www.silverfort.com/blog/understanding-the-security-risks-of-ntlm/

Edit 2: I tried this module with nginx and it didn't work end-to-end. Logs show that nginx passes the NTLM credentials correctly and rdpgw-auth authenticates the user, but then everything hangs like there is no traffic anymore. I tried adding some keep alive settings but that didn't help. I'm not sure if the issue is in the nginx's module or in the rdpgw. One might try using other reverse proxy like Apache.

Edit 3: This can actually be achieved with nginx quite easily with ssl_preread module and SNI. The trick is to move regular nginx binding from 443 to something else (444 in my example) and then use SNI to redirect to the website or to the rdpgw (which is on port 1234 in the example below)

http {
	# Normal HTTP on your_domain.com
	server {
		listen 80;
		server_name your_domain.com
		
		# ...
	}
	
	# Normal HTTPS on your_domain.com. Listening on 444 (not the default 443)
	server {
		listen 444 ssl http2;
		server_name your_domain.com
		
		# ...
	}
}


# Here goes SNI
stream {
    map $ssl_preread_server_name $proxy_name {
        your_domain.com              websites;
        your_other_domain.com           rdpgw;
        default                      websites;
    }

    upstream rdpgw {
	# IP:port of rdpgw
        server 127.0.0.1:1234;
    }

    upstream websites {
	# IP:port of website hosting, in this case it's the same nginx but on different port
        server 127.0.0.1:444;
    }

    server {
        listen 443;
        proxy_pass $proxy_name;
        ssl_preread on;
    }
}

Just make sure you put stream section on the same level as http. If you're including your default.conf into http directly, then you may need to tweak your /etc/nginx/nginx.conf accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants