Giter VIP home page Giter VIP logo

rdpgw's Introduction

GO Remote Desktop Gateway

Go Docker Pulls Docker Stars Docker Image Size

⭐ Star us on GitHub — it helps!

RDPGW is an implementation of the Remote Desktop Gateway protocol. This allows you to connect with the official Microsoft clients to remote desktops over HTTPS. These desktops could be, for example, XRDP desktops running in containers on Kubernetes.

AIM

RDPGW aims to provide a full open source replacement for MS Remote Desktop Gateway, including access policies.

Security requirements

Several security requirements are stipulated by the client that is connecting to it and some are enforced by the gateway. The client requires that the server's TLS certificate is valid and that it is signed by a trusted authority. In addition, the common name in the certificate needs to match the DNS hostname of the gateway. If these requirements are not met the client will refuse to connect.

The gateway has several security phases. In the authentication phase the client's credentials are verified. Depending the authentication mechanism used, the client's credentials are verified against an OpenID Connect provider, Kerberos, a local PAM service or a local database.

If OpenID Connect is used the user will need to connect to a webpage provided by the gateway to authenticate, which in turn will redirect the user to the OpenID Connect provider. If the authentication is successful the browser will download a RDP file with temporary credentials that allow the user to connect to the gateway by using a remote desktop client.

If Kerberos is used the client will need to have a valid ticket granting ticket (TGT). The gateway will proxy the TGT request to the KDC. Therefore, the gateway needs to be able to connect to the KDC and a krb5.conf file needs to be provided. The proxy works without the need for an RDP file and thus the client can connect directly to the gateway.

If local authentication is used the client will need to provide a username and password that is verified against PAM. This requires, to ensure privilege separation, that rdpgw-auth is also running and a valid PAM configuration is provided per typical configuration.

If NTLM authentication is used, the allowed user credentials for the gateway should be configured in the configuration file of rdpgw-auth.

Finally, RDP hosts that the client wants to connect to are verified against what was provided by / allowed by the server. Next to that the client's ip address needs to match the one it obtained the gateway token with if using OpenID Connect. Due to proxies and NAT this is not always possible and thus can be disabled. However, this is a security risk.

Configuration

The configuration is done through a YAML file. The configuration file is read from rdpgw.yaml by default. At the bottom of this README is an example configuration file. In these sections you will find the most important settings.

Authentication

RDPGW wants to be secure when you set it up from the start. It supports several authentication mechanisms such as OpenID Connect, Kerberos, PAM or NTLM.

Technically, cookies are encrypted and signed on the client side relying on Gorilla Sessions. PAA tokens (gateway access tokens) are generated and signed according to the JWT spec by using jwt-go signed with a 256 bit HMAC.

Multi Factor Authentication (MFA)

RDPGW provides multi-factor authentication out of the box with OpenID Connect integration. Thus you can integrate your remote desktops with Keycloak, Okta, Google, Azure, Apple or Facebook if you want.

Mixing authentication mechanisms

It is technically possible to mix authentication mechanisms. Currently, you can mix local with Kerberos or NTLM. If you enable OpenID Connect it is not possible to mix it with local or Kerberos at the moment.

Open ID Connect

OpenID Connect

To use OpenID Connect make sure you have properly configured your OpenID Connect provider, and you have a client id and secret. The client id and secret are used to authenticate the gateway to the OpenID Connect provider. The provider will then authenticate the user and provide the gateway with a token. The gateway will then use this token to generate a PAA token that is used to connect to the RDP host.

To enable OpenID Connect make sure to set the following variables in the configuration file.

Server:
  Authentication: 
    - openid
OpenId:
    ProviderUrl: http://<provider_url>
    ClientId: <your client id>
    ClientSecret: <your-secret>
Caps:
  TokenAuth: true

As you can see in the flow diagram when using OpenID Connect the user will use a browser to connect to the gateway first at https://your-gateway/connect. If authentication is successful the browser will download a RDP file with temporary credentials that allow the user to connect to the gateway by using a remote desktop client.

Kerberos

Kerberos

NOTE: Kerberos is heavily reliant on DNS (forward and reverse). Make sure that your DNS is properly configured. Next to that, its errors are not always very descriptive. It is beyond the scope of this project to provide a full Kerberos tutorial.

To use Kerberos make sure you have a keytab and krb5.conf file. The keytab is used to authenticate the gateway to the KDC and the krb5.conf file is used to configure the KDC. The keytab needs to contain a valid principal for the gateway.

Use ktutil or a similar tool provided by your Kerberos server to create a keytab file for the newly created service principal. Place this keytab file in a secure location on the server and make sure that the file is only readable by the user that runs the gateway.

ktutil
addent -password -p HTTP/[email protected] -k 1 -e aes256-cts-hmac-sha1-96
wkt rdpgw.keytab

Then set the following in the configuration file.

Server:
  Authentication:
    - kerberos
Kerberos:
    Keytab: /etc/keytabs/rdpgw.keytab
    Krb5conf: /etc/krb5.conf
Caps:
  TokenAuth: false

The client can then connect directly to the gateway without the need for a RDP file.

PAM / Local (Basic Auth)

PAM

The gateway can also support authentication against PAM. Sometimes this is referred to as local or passwd authentication, but it also supports LDAP authentication or even Active Directory if you have the correct modules installed. Typically (for passwd), PAM requires that it is accessed as root. Therefore, the gateway comes with a small helper program called rdpgw-auth that is used to authenticate the user. This program needs to be run as root or setuid.

NOTE: The default windows client mstsc does not support basic auth. You will need to use a different client or switch to OpenID Connect, Kerberos or NTLM authentication.

NOTE: Using PAM for passwd (i.e. LDAP is fine) within a container is not recommended. It is better to use OpenID Connect or Kerberos. If you do want to use it within a container you can choose to run the helper program outside the container and have the socket available within. Alternatively, you can mount all what is needed into the container but PAM is quite sensitive to the environment.

Ensure you have a PAM service file for the gateway, /etc/pam.d/rdpgw. For authentication against local accounts on the host located in /etc/passwd and /etc/shadow you can use the following.

auth required pam_unix.so
account required pam_unix.so

Then set the following in the configuration file.

Server:
  Authentication:
    - local
AuthSocket: /tmp/rdpgw-auth.sock
Caps:
  TokenAuth: false

Make sure to run both the gateway and rdpgw-auth. The gateway will connect to the socket to authenticate the user.

# ./rdpgw-auth -n rdpgw -s /tmp/rdpgw-auth.sock

The client can then connect to the gateway directly by using a remote desktop client.

NTLM

The gateway can also support NTLM authentication. Currently, only the configuration file is supported as a database for credential lookup. In the future, support for real databases (e.g. sqlite) may be added.

NTLM authentication has the advantage that it is easy to setup, especially in case the gateway is used for a limited number of users. Unlike PAM / local, NTLM authentication supports the default windows client mstsc.

WARNING: The password is currently saved in plain text. So, you should keep the config file as secure as possible and avoid reusing the same password for other applications. The password is stored in plain text to support the NTLM authentication protocol.

To enable NTLM authentication make sure to set the following variables in the configuration file.

Configuration file for rdpgw:

Server:
  Authentication:
    - ntlm
Caps:
  TokenAuth: false

Configuration file for rdpgw-auth:

Users:
 - {Username: "my_username", Password: "my_secure_password"} # Modify this password!

The client can then connect to the gateway directly by using a remote desktop client using the gateway credentials configured in the YAML configuration file.

TLS

The gateway requires a valid TLS certificate. This means a certificate that is signed by a valid CA that is in the store of your clients. If this is not the case particularly Windows clients will fail to connect. You can either provide a certificate and key file or let the gateway obtain a certificate from letsencrypt. If you want to use letsencrypt make sure that the host is reachable on port 80 from the letsencrypt servers.

For letsencrypt:

Tls: auto

for your own certificate:

Tls: enable
CertFile: server.pem 
KeyFile: key.pem

NOTE: You can disable TLS on the gateway, but you will then need to make sure a proxy is run in front of it that does TLS termination.

Example configuration file for Open ID Connect

# web server configuration. 
Server:
 # can be set to openid, kerberos, local and ntlm. If openid is used rdpgw expects
 # a configured openid provider, make sure to set caps.tokenauth to true. If local
 # rdpgw connects to rdpgw-auth over a socket to verify users and password. Note:
 # rdpgw-auth needs to be run as root or setuid in order to work. If kerberos is
 # used a keytab and krb5conf need to be supplied. local can be stacked with 
 # kerberos or ntlm authentication, so that the clients selects what it wants.
 Authentication:
  # - kerberos
  # - local
  - openid
  # - ntlm
 # The socket to connect to if using local auth. Ensure rdpgw auth is configured to
 # use the same socket.
 # AuthSocket: /tmp/rdpgw-auth.sock
 # Basic auth timeout (in seconds). Useful if you're planning on waiting for MFA
 BasicAuthTimeout: 5
 # The default option 'auto' uses a certificate file if provided and found otherwise
 # it uses letsencrypt to obtain a certificate, the latter requires that the host is reachable
 # from letsencrypt servers. If TLS termination happens somewhere else (e.g. a load balancer)
 # set this option to 'disable'. This is mutually exclusive with 'authentication: local'
 # Note: rdp connections over a gateway require TLS
 Tls: auto
 # gateway address advertised in the rdp files and browser
 GatewayAddress: localhost
 # port to listen on (change to 80 or equivalent if not using TLS)
 Port: 443
 # list of acceptable desktop hosts to connect to
 Hosts:
  - localhost:3389
  - my-{{ preferred_username }}-host:3389
 # if true the server randomly selects a host to connect to
 # valid options are: 
 #  - roundrobin, which selects a random host from the list (default)
 #  - signed, a listed host specified in the signed query parameter
 #  - unsigned, a listed host specified in the query parameter
 #  - any, insecurely allow any host specified in the query parameter
 HostSelection: roundrobin 
 # a random strings of at least 32 characters to secure cookies on the client
 # make sure to share this across the different pods
 SessionKey: thisisasessionkeyreplacethisjetzt
 SessionEncryptionKey: thisisasessionkeyreplacethisnunu!
  # where to store session details. This can be either file or cookie (default: cookie)
  # if a file store is chosen, it is required to have clients 'keep state' to the rdpgw
  # instance they are connected to.
 SessionStore: cookie
  # tries to set the receive / send buffer of the connections to the client
 # in case of high latency high bandwidth the defaults set by the OS might
 # be to low for a good experience
 # ReceiveBuf: 12582912
 # SendBuf: 12582912 
# Open ID Connect specific settings
OpenId:
 ProviderUrl: http://keycloak/auth/realms/test
 ClientId: rdpgw
 ClientSecret: your-secret
# Kerberos:
#  Keytab: /etc/keytabs/rdpgw.keytab
#  Krb5conf: /etc/krb5.conf
#  enabled / disabled capabilities
Caps:
 SmartCardAuth: false
 # required for openid connect
 TokenAuth: true
 # connection timeout in minutes, 0 is limitless
 IdleTimeout: 10
 EnablePrinter: true
 EnablePort: true
 EnablePnp: true
 EnableDrive: true
 EnableClipboard: true
Client:
  # template rdp file to use for clients
  # rdp file settings and their defaults see here: 
  # https://docs.microsoft.com/en-us/windows-server/remote/remote-desktop-services/clients/rdp-files
  defaults: /etc/rdpgw/default.rdp
  # this is a go string templated with {{ username }} and {{ token }}
  # the example below uses the ASCII field separator to distinguish
  # between user and token 
  UsernameTemplate: "{{ username }}@bla.com\x1f{{ token }}"
  # If true puts splits "[email protected]" into the user and domain component so that
  # domain gets set in the rdp file and the domain name is stripped from the username
  SplitUserDomain: false
  # If true, removes "username" (and "domain" if SplitUserDomain is true) from RDP file.
  # NoUsername: true
Security:
  # a random string of 32 characters to secure cookies on the client
  # make sure to share this amongst different pods
  PAATokenSigningKey: thisisasessionkeyreplacethisjetzt
  # PAATokenEncryptionKey: thisisasessionkeyreplacethisjetzt
  # a random string of 32 characters to secure cookies on the client
  UserTokenEncryptionKey: thisisasessionkeyreplacethisjetzt
  # Signing makes the token bigger and we are limited to 511 characters
  # UserTokenSigningKey: thisisasessionkeyreplacethisjetzt
  # if you want to enable token generation for the user
  # if true the username will be set to a jwt with the username embedded into it
  EnableUserToken: true
  # Verifies if the ip used to connect to download the rdp file equals from where the
  # connection is opened.
  VerifyClientIp: true

How to build & install

NOTE: a docker image is available on docker hub, which removes the need for building and installing go.

Ensure that you have make (comes with standard build tools, like build-essential on Debian), go (version 1.19 or above), and development files for PAM (libpam0g-dev on Debian) installed.

Then clone the repo and issues the following.

cd rdpgw
make
make install

Testing locally

A convenience docker-compose allows you to test the RDPGW locally. It uses Keycloak and xrdp and exposes it services on port 9443. You will need to allow your browser to connect to localhost with and self signed security certificate. For chrome set chrome://flags/#allow-insecure-localhost. The username to login to both Keycloak and xrdp is admin as is the password.

NOTE: The redirecting relies on DNS. Make sure to add 127.0.0.1 keycloak to your /etc/hosts file to ensure that the redirect works.

NOTE: The local testing environment uses a self signed certificate. This works for MAC clients, but not for Windows. If you want to test it on Windows you will need to provide a valid certificate.

# with open id
cd dev/docker
docker-compose -f docker-compose.yml up

# or for arm64 with open id
docker-compose -f docker-compose-arm64.yml up

# or for local or pam
docker-compose -f docker-compose-local.yml up

You can then connect to the gateway at https://localhost:9443/connect for the OpenID connect flavors which will start the authentication flow. Or you can connect directly with the gateway set and the host set to xrdp if using the local flavor. You can login with 'admin/admin'. The RDP file will download and you can open it with a remote desktop client. Also for logging in 'admin/admin' will work.

Use

Point your browser to https://your-gateway/connect. After authentication and RDP file will download to your desktop. This file can be opened by one of the remote desktop clients and it will try to connect to the gateway and desktop host behind it.

Integration

The gateway exposes an endpoint for the verification of user tokens at https://yourserver/tokeninfo . The query parameter is 'access_token' so you can just do a GET to https://yourserver/tokeninfo?access_token= . It will return 200 OK with the decrypted token.

In this way you can integrate, for example, it with pam-jwt.

Client Caveats

The several clients that Microsoft provides come with their own caveats. The most important one is that the default client on Windows mstsc does not support basic authentication. This means you need to use either OpenID Connect, Kerberos or ntlm authentication.

In addition to that, mstsc, when configuring a gateway directly in the client requires you to either:

  • "save the credentials" for the gateway
  • or specify a (random) domain name in the username field (e.g. .\username) when prompted for the gateway credentials,

otherwise the client will not connect at all (it won't send any packages to the gateway) and it will keep on asking for new credentials.

Finally, mstsc requires a valid certificate on the gateway.

The Microsoft Remote Desktop Client from the Microsoft Store does not have these issues, but it requires that the username and password used for authentication are the same for both the gateway and the RDP host.

The Microsoft Remote Desktop Client for Mac does not have these issues and is the most flexible. It supports basic authentication, OpenID Connect and Kerberos and can use different credentials

The official Microsoft IOS and Android clients seem also more flexible.

Third party clients like FreeRDP might also provide more flexibility.

TODO

  • Improve Web Interface

Acknowledgements

  • This product includes software developed by the Thomson Reuters Global Resources. (go-ntlm - BSD-4 License)

rdpgw's People

Contributors

aaronburchfield avatar alexpilotti avatar alphabet5 avatar azathoth88 avatar benthetechguy avatar bolkedebruin avatar dependabot[bot] avatar fliaping avatar koltesdigital avatar krisss85 avatar m7913d avatar ryanblenis avatar tobsec avatar totomz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rdpgw's Issues

Documentation seems to be unclear on options 'any' and 'roundRobin'

From the docs it reads like having 'any' in the list of hosts should allow you to modify the rdp file and connect to any host.

  # Allow the user to connect to any host (insecure)
  - any 

Trying this and modifying the rdp file to connect to 10.111.111.101:3389 gives the following error.

There was a problem connecting to the remote resource. Ask your network administrator for help.

Looking at the logs, it's getting blocked because the host does not match the token host 'any'.

2022/03/15 02:09:05 Starting remote desktop gateway server
2022/03/15 02:10:29 Client handshakeRequest from 10.111.111.13
2022/03/15 02:10:29 major: 1, minor: 0, version: 0, ext auth: 2
2022/03/15 02:10:29 Tunnel create
2022/03/15 02:10:29 Tunnel auth
2022/03/15 02:10:29 Channel create
2022/03/15 02:10:29 Client specified host 10.111.111.101:3389 does not match token host any
2022/03/15 02:10:29 Not allowed to connect to 10.111.111.101:3389 by policy handler

If I add in 10.111.111.101:3389 to the list of hosts the .rdp file downloaded seems to be for a random host with 'roundRobin' set to false. When the host is changed to another host that is specified in the configuration file, I still receive the 'not allowed to connect' message.

2022/03/15 02:23:04 Client handshakeRequest from 10.111.111.13
2022/03/15 02:23:04 major: 1, minor: 0, version: 0, ext auth: 2
2022/03/15 02:23:04 Tunnel create
2022/03/15 02:23:04 Tunnel auth
2022/03/15 02:23:04 Channel create
2022/03/15 02:23:04 Client specified host 10.111.111.101:3389 does not match token host 10.111.111.103:3389
2022/03/15 02:23:04 Not allowed to connect to 10.111.111.101:3389 by policy handler

Example config file:

server:
  certFile: /certs/tls.crt
  keyFile: /certs/tls.key
  gatewayAddress: rdpgw.demo.cybertrol.app
  port: 9443
  hosts:
    - 10.111.111.101:3389
    - 10.111.111.102:3389
    - 10.111.111.103:3389
    - 10.111.111.104:3389
    - 10.111.111.105:3389
    - 10.111.111.106:3389
    - any
  roundRobin: false
  sessionKey: thisisasessionkeyreplacethisjetz
  sessionEncryptionKey: thisisasessionkeyreplacethisnunu
caps:
  smartCardAuth: false
  tokenAuth: true
  idleTimeout: 60
  enablePrinter: false
  enablePort: false
  enablePnp: false
  enableDrive: false
  enableClipboard: true
openId:
  providerUrl: https://auth.demo.domain.com
  clientId: rdpgw
  clientSecret: 01cd304c-6f43-4480-9479-618eb6fd578f
client:
  usernameTemplate: "domain\\{{ username }}"
  networkAutoDetect: 0
  bandwidthAutoDetect: 1
  ConnectionType: 6
  SplitUserDomain: true
security:
  PAATokenSigningKey: prettypleasereplacemeinproductio
  UserTokenEncryptionKey: prettypleasereplacemeinproductio
  EnableUserToken: true
  VerifyClientIp: false

With that I have a few questions.

  • What does 'roundRobin' change?
  • What does 'any' do when in the list of hosts?

Disable domain certificate verification ?

The website/domain cert is managed at the load balancer level. There is no control over that and the certificate can't be shared. I'm unable to provide a valid certificate in the rdpgw.yaml file. Is there any way around that ?

keycloak:8080 failing

Am i supposed to create a host entry on the host file for keycloak -> 127.0.0.1 ?

For some reason keycloak:8080/auth doesn't work hence localhost:9443/connect fails because it redirects me to keycloak:8080 for authentication.

If i enter localhost:8080/auth. that works fine without issues.
If i enter keycloak:8080/auth, i get page not found error.

new macos rdp client >= 10.7.2 doesn't work over rdpgw

It does look like the connection cannot be upgraded to websocket, but more investigation i�s required. It works still with 10.7.1
Plausible reason is the following entry from the release notes:
Improved compatibility with third-party network devices and load balancers for workspace download and RD Gateway-based connections.

Make image available on hub.docker.com

Hello, the project sounds promising and exciting. I would like to test it and install it on my Synology NAS. Unfortunately, I have difficulties with the installation. It would be easier if a ready-made image was available on hub.docker.com.

Is something already being thought of here?

Best regards

license needed?

just wondering - what is the current status of the RDP protocol licensing from Microsoft... has it been released for general implementation? I see it used both for linux and windows servers, but just wondering if this is generally OK or have folks gotten licenses to use it?

Allow passing of configuration with environment variables.

I was unable to get viper to allow setting of config items with environment variables. I was able to get it working by switching to koanf instead. There are a few other benefits to koanf, but the largest drawback is that it is case sensitive. The current implementation I have working allows for all lowercase, but the .yaml file is required to match the camel case defined in the configuration structs.

package config

import (
	"github.com/knadh/koanf"
	"github.com/knadh/koanf/parsers/yaml"
	"github.com/knadh/koanf/providers/confmap"
	"github.com/knadh/koanf/providers/env"
	"github.com/knadh/koanf/providers/file"
	"log"
	"strings"
)

type Configuration struct {
	Server   ServerConfig   `koanf:"server"`
	OpenId   OpenIDConfig   `koanf:"openid"`
	Caps     RDGCapsConfig  `koanf:"caps"`
	Security SecurityConfig `koanf:"security"`
	Client   ClientConfig   `koanf:"client"`
}

type ServerConfig struct {
	GatewayAddress       string   `koanf:"gatewayaddress"`
	Port                 int      `koanf:"port"`
	CertFile             string   `koanf:"certfile"`
	KeyFile              string   `koanf:"keyfile"`
	Hosts                []string `koanf:"hosts"`
	RoundRobin           bool     `koanf:"roundrobin"`
	SessionKey           string   `koanf:"sessionkey"`
	SessionEncryptionKey string   `koanf:"sessionencryptionkey"`
	SendBuf              int      `koanf:"sendbuf"`
	ReceiveBuf           int      `koanf:"recievebuf"`
}

type OpenIDConfig struct {
	ProviderUrl  string `koanf:"providerurl"`
	ClientId     string `koanf:"clientid"`
	ClientSecret string `koanf:"clientsecret"`
}

type RDGCapsConfig struct {
	SmartCardAuth   bool `koanf:"smartcardauth"`
	TokenAuth       bool `koanf:"tokenauth"`
	IdleTimeout     int  `koanf:"idletimeout"`
	RedirectAll     bool `koanf:"redirectall"`
	DisableRedirect bool `koanf:"disableredirect"`
	EnableClipboard bool `koanf:"enableclipboard"`
	EnablePrinter   bool `koanf:"enableprinter"`
	EnablePort      bool `koanf:"enableport"`
	EnablePnp       bool `koanf:"enablepnp"`
	EnableDrive     bool `koanf:"enabledrive"`
}

type SecurityConfig struct {
	PAATokenEncryptionKey  string `koanf:"paatokenencryptionkey"`
	PAATokenSigningKey     string `koanf:"paatokensigningkey"`
	UserTokenEncryptionKey string `koanf:"usertokenencryptionkey"`
	UserTokenSigningKey    string `koanf:"usertokensigningkey"`
	VerifyClientIp         bool   `koanf:"verifyclientip"`
	EnableUserToken        bool   `koanf:"enableusertoken"`
}

type ClientConfig struct {
	NetworkAutoDetect   int    `koanf:"networkautodetect"`
	BandwidthAutoDetect int    `koanf:"bandwidthautodetect"`
	ConnectionType      int    `koanf:"connectiontype"`
	UsernameTemplate    string `koanf:"usernametemplate"`
	SplitUserDomain     bool   `koanf:"splituserdomain"`
	DefaultDomain       string `koanf:"defaultdomain"`
}

func ToCamel(s string) string {
	s = strings.TrimSpace(s)
	n := strings.Builder{}
	n.Grow(len(s))
	var capNext bool = true
	for i, v := range []byte(s) {
		vIsCap := v >= 'A' && v <= 'Z'
		vIsLow := v >= 'a' && v <= 'z'
		if capNext {
			if vIsLow {
				v += 'A'
				v -= 'a'
			}
		} else if i == 0 {
			if vIsCap {
				v += 'a'
				v -= 'A'
			}
		}
		if vIsCap || vIsLow {
			n.WriteByte(v)
			capNext = false
		} else if vIsNum := v >= '0' && v <= '9'; vIsNum {
			n.WriteByte(v)
			capNext = true
		} else {
			capNext = v == '_' || v == ' ' || v == '-' || v == '.'
			if v == '.' {
				n.WriteByte(v)
			}
		}
	}
	return n.String()
}

var Conf Configuration

func Load(configFile string) Configuration {

	var k = koanf.New(".")

	k.Load(confmap.Provider(map[string]interface{}{
		"Server.CertFile":            "server.pem",
		"Server.KeyFile":             "key.pem",
		"Server.Port":                443,
		"Client.NetworkAutoDetect":   1,
		"Client.BandwidthAutoDetect": 1,
		"Security.VerifyClientIp":    true,
	}, "."), nil)

	if err := k.Load(file.Provider(configFile), yaml.Parser()); err != nil {
		log.Fatalf("Error loading config from file: %v", err)
	}

	if err := k.Load(env.ProviderWithValue("RDPGW_", ".", func(s string, v string) (string, interface{}) {
		key := strings.Replace(strings.ToLower(strings.TrimPrefix(s, "RDPGW_")), "__", ".", -1)
		key = ToCamel(key)
		return key, v
	}), nil); err != nil {
		log.Fatalf("Error loading config from file: %v", err)
	}

	koanfTag := koanf.UnmarshalConf{Tag: "koanf"}
	k.UnmarshalWithConf("Server", &Conf.Server, koanfTag)
	k.UnmarshalWithConf("OpenId", &Conf.OpenId, koanfTag)
	k.UnmarshalWithConf("Caps", &Conf.Caps, koanfTag)
	k.UnmarshalWithConf("Security", &Conf.Security, koanfTag)
	k.UnmarshalWithConf("Client", &Conf.Client, koanfTag)

	return Conf

}

With this, the environment variables must use double underscores for nested config items, and single underscores where there is camel case.

i.e.

Server:
  CertFile: /certs/tls.crt
  KeyFile: /certs/tls.key
OpenId:
  ProviderUrl: https://auth.rdpgw.local
  ClientId: rdpgw

==

RDPGW_SERVER__CERT_FILE="/certs/tls.crt"
RDPGW_SERVER_KEY_FILE="/certs/tls.key"
RDPGW_OPEN_ID__PROVIDER_URL="https://auth.rdpgw.local"
RDPGW_OPEN_ID__CLIENT_ID="rdpgw"

Failed to shadow a user's session

After rdp client connected to target through rdpgw, always fails to shadow a user's rdp session with following error:

image

but it will succeeds on direct connection without rdpgw.

Not working with remmina with rdp Gateway

Hi there,

Very useful project. I appreciate the effort her.
I was trying to use this implementation on linux and tried rdp with remmina. But it seems to fail due to NTLM negotiation failures. I see people getting it to work, not sure what am I missing. Plz help.

21:26:54:263] [51107:52041] [DEBUG][com.winpr.sspi] - InitSecurityInterfaceExA
[21:26:54:263] [51107:52041] [DEBUG][com.winpr.sspi.NTLM] - change
state from NTLM_STATE_INITIAL to NTLM_STATE_INITIAL
[21:26:54:263] [51107:52041] [DEBUG][com.winpr.sspi.NTLM] - change
state from NTLM_STATE_INITIAL to NTLM_STATE_NEGOTIATE
[21:26:54:263] [51107:52041] [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:26:54:263] [51107:52041] [DEBUG][com.winpr.sspi.NTLM] - change
state from NTLM_STATE_NEGOTIATE to NTLM_STATE_CHALLENGE
[21:26:54:263] [51107:52041] [DEBUG][com.freerdp.core.gateway.rdg] -
Unexpected NTLM challenge HTTP status: 101
[21:26:54:264] [51107:52041] [ERROR][com.freerdp.core.nego] - Protocol
Security Negotiation Failure
[21:26:54:264] [51107:52041] [ERROR][com.freerdp.core] -
rdp_client_connect:freerdp_set_last_error_ex
ERRCONNECT_SECURITY_NEGO_CONNECT_FAILED [0x0002000C]
[21:26:54:264] [51107:52041] [ERROR][com.freerdp.core.connection] -
Error: protocol security negotiation or connection failure
** (org.remmina.Remmina:51107): DEBUG: 21:26:54.417: [postcommand] (null)
** (org.remmina.Remmina:51107): DEBUG: 21:26:54.417: [postcommand] updated to:

Unable to run in docker

after running

cd dev/docker
docker-compose build
docker-compose up

I'm getting the following errors

rdpgw_1     | 2022/09/21 22:11:40 Cookies are used as session storage
rdpgw_1     | 2022/09/21 22:11:40 Starting remote desktop gateway server
rdpgw_1     | 2022/09/21 22:11:40 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp 172.18.0.3:8080: connect: connection refused
rdpgw_1     | 2022/09/21 22:11:44 No valid `security.paatokenencryptionkey` specified (empty or not 32 characters). Setting to random
rdpgw_1     | 2022/09/21 22:11:44 Cookies are used as session storage
rdpgw_1     | 2022/09/21 22:11:44 Starting remote desktop gateway server
rdpgw_1     | 2022/09/21 22:11:44 Cannot get oidc provider: 404 Not Found: {"error":"RESTEASY003210: Could not find resource for full path: http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration"}
rdpgw_1     | 2022/09/21 22:11:51 No valid `security.paatokenencryptionkey` specified (empty or not 32 characters). Setting to random
rdpgw_1     | 2022/09/21 22:11:51 Cookies are used as session storage
rdpgw_1     | 2022/09/21 22:11:51 Starting remote desktop gateway server

can i get help?

hello, i use windows mstsc client to connect to this rdpgw by gateway method, i want to get some gw account info from rdpgw, not rdp server account, but i have't analyse it. can give me some ideas?

go: error loading module requirements

make
go mod tidy
go: finding github.com/spf13/cobra v1.1.3
go: finding github.com/spf13/viper v1.7.1
go: finding github.com/patrickmn/go-cache v2.1.0+incompatible
go: finding github.com/gorilla/websocket v1.4.2
go: finding github.com/coreos/go-oidc/v3 v3.0.0
go: finding github.com/gorilla/sessions v1.2.1
go: finding github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693
go: finding github.com/prometheus/client_golang v1.10.0
go: golang.org/x/[email protected]: unrecognized import path "golang.org/x/oauth2" (https fetch: Get https://golang.org/x/oauth2?go-get=1: dial tcp 216.239.37.1:443: i/o timeout)
go: github.com/coreos/go-oidc/[email protected]: unknown revision v3.0.0
go: github.com/spf13/[email protected]: unknown revision v1.7.1
go: github.com/spf13/[email protected]: unknown revision v1.1.3
go: github.com/gorilla/[email protected]: unknown revision v1.4.2
go: github.com/prometheus/[email protected]: unknown revision v1.10.0
go: github.com/patrickmn/[email protected]+incompatible: unknown revision v2.1.0
go: github.com/gorilla/[email protected]: unknown revision v1.2.1
go: error loading module requirements
Makefile:51: recipe for target 'mod' failed
make: *** [mod] Error 1

Client certificate authentication

Hello,
I wanted to know if ssl client certificate (token) is is available for authentication , I added the ca-cert of my pki, but i have this error message.
Thanks by advance

logs 2022/09/29 08:35:50 RemoteAddr: x.y.x.y:57259
2022/09/29 08:35:50 Client handshakeRequest from x.y.x.y
2022/09/29 08:35:50 major: 1, minor: 0, version: 0, ext auth: 1
2022/09/29 08:35:50 Cannot read message from stream websocket: close 1000 (normal)
2022/09/29 08:39:55 preferred_username not found in context

protocol/types.go drive mapping

Looks like a typo HTTP_TUNNEL_REDIR_DISABLE_PORT
Drive mapping working now


const (
        HTTP_TUNNEL_REDIR_ENABLE_ALL        = 0x80000000
        HTTP_TUNNEL_REDIR_DISABLE_ALL       = 0x40000000
        HTTP_TUNNEL_REDIR_DISABLE_DRIVE     = 0x01
        HTTP_TUNNEL_REDIR_DISABLE_PRINTER   = 0x02
//      HTTP_TUNNEL_REDIR_DISABLE_PORT      = 0x03
        HTTP_TUNNEL_REDIR_DISABLE_PORT      = 0x04  // MS-TSGU 2.2.5.3.7 should be 0x4?
        HTTP_TUNNEL_REDIR_DISABLE_CLIPBOARD = 0x08
        HTTP_TUNNEL_REDIR_DISABLE_PNP       = 0x10
)

Enable logs to stdout/stderr

Greetings.
Can you tell me how to enable logs in rdpgw.
Built and raised from the wizard in the docker, trying to check authentication connection via keycloak, but it gives a security error. Maybe the logs will tell me more details.

Thanks.
image

update:
I set up this connection, client -> https:443(public cert domain.com) -> reverse proxy -> https:9443 -> rdpgw -> .
rdpgw -> keycloak in docker http://keycloak:8080/realms/test
rdpgw -> rds server :3389 + internal cert (domain.local)

can't connect with browser or mstsc (windows)

  • first off, can I disable openid? I just want a simple rdpgw I can install standalone on jump box

  • docs: key(s) in rdpgw.yaml should be only 32 characters - I got an error about crypto/aes key being 33

  • I downloaded rdpgw-1.0-stable and built rdpgw on ubuntu 20.04

  • I think I have openid working with Google - looks like Google part works and it redirects me. There's an auth.json with tokens in it. But on https://localhost:9443/connect I get

cannot find session or user

the logs show:

2020/12/10 13:53:51 Starting remote desktop gateway server
2020/12/10 13:53:56 preferred_username not found in context

  • I imported my self signed cert into Windows and I can connect to localhost:9443 with mstsc
    mstsc prompts for RD gateway credentials - I assume I enter the google credentials here?
    rdpgw logs a runtime error:
 2020/12/10 13:58:54 Client handshakeRequest from 172.24.128.1
2020/12/10 13:58:54 major: 1, minor: 0, version: 0, ext auth: 0
2020/12/10 13:58:54 Tunnel create
2020/12/10 13:58:54 http: panic serving 172.24.128.1:49991: runtime error: invalid memory address or nil pointer dereference
goroutine 11 [running]:
net/http.(*conn).serve.func1(0xc000438960)
        /usr/lib/go-1.13/src/net/http/server.go:1767 +0x139
panic(0xb0e100, 0x1173360)
        /usr/lib/go-1.13/src/runtime/panic.go:679 +0x1b2
github.com/bolkedebruin/rdpgw/security.VerifyPAAToken(0xcdec20, 0xc0001426f0, 0x0, 0x0, 0x3f, 0x0, 0x0)
        /home/jmorrison/rdpgw-1.0-stable/security/jwt.go:39 +0x5d
github.com/bolkedebruin/rdpgw/protocol.(*Server).Process(0xc0001b8660, 0xcdec20, 0xc0001426f0, 0x0, 0x0)
        /home/jmorrison/rdpgw-1.0-stable/protocol/server.go:89 +0xf00
github.com/bolkedebruin/rdpgw/protocol.(*Gateway).handleWebsocketProtocol(0xc00016e058, 0xcdec20, 0xc0001426f0, 0xc0002aa000, 0xc0001ba050)
        /home/jmorrison/rdpgw-1.0-stable/protocol/gateway.go:98 +0x10f
github.com/bolkedebruin/rdpgw/protocol.(*Gateway).HandleGatewayProtocol(0xc00016e058, 0xcdc6e0, 0xc000472700, 0xc0001ca500)
        /home/jmorrison/rdpgw-1.0-stable/protocol/gateway.go:84 +0x7b8
net/http.HandlerFunc.ServeHTTP(0xc0003a8640, 0xcdc6e0, 0xc000472700, 0xc0001ca500)
        /usr/lib/go-1.13/src/net/http/server.go:2007 +0x44
github.com/bolkedebruin/rdpgw/common.EnrichContext.func1(0xcdc6e0, 0xc000472700, 0xc0001ca200)
        /home/jmorrison/rdpgw-1.0-stable/common/remote.go:41 +0x41a
net/http.HandlerFunc.ServeHTTP(0xc000416940, 0xcdc6e0, 0xc000472700, 0xc0001ca200)
        /usr/lib/go-1.13/src/net/http/server.go:2007 +0x44
net/http.(*ServeMux).ServeHTTP(0x1189140, 0xcdc6e0, 0xc000472700, 0xc0001ca200)
        /usr/lib/go-1.13/src/net/http/server.go:2387 +0x1bd
net/http.serverHandler.ServeHTTP(0xc000458000, 0xcdc6e0, 0xc000472700, 0xc0001ca200)
        /usr/lib/go-1.13/src/net/http/server.go:2802 +0xa4
net/http.(*conn).serve(0xc000438960, 0xcdeb60, 0xc0001a0240)
        /usr/lib/go-1.13/src/net/http/server.go:1890 +0x875
created by net/http.(*Server).Serve
        /usr/lib/go-1.13/src/net/http/server.go:2928 +0x384

RDP UDP support

This looks like a very promising project! Nice work.
Does it also support RDP over UDP for the remote desktop connection?

Improve packet fragment handling

Currently only one fragment can be handled, it should be made more robust to check the length of the packet and wait for all data to arrive.

make tls optional

since we are using ssl/tls-offload via firewall it would be a nice to be able to turn off the tls encryption.

and as a bonus evaluating something like the x-proto and the x-forwarded-for headers and logging / displaying them would be a pretty large plus :)

ingo

OIDC / AzureAD error: "securecookie: the value is too long"

Very interesting project - thought I'd give this a try.

  • Compiled master (3919a7e)
  • Configured to use Azure AD for OIDC auth
  • Getting the following error after successful authentication:
    securecookie: the value is too long
  • The service logs this:
    2021/02/24 18:46:51 http: superfluous response.WriteHeader call from github.com/bolkedebruin/rdpgw/api.(*Config).HandleCallback (web.go:118)

Any idea? Is there a flag to get more debug output?

Thanks :)

Cannot find module for path crypto/ed25519

docker-compose build fails with:

build github.com/bolkedebruin/rdpgw: cannot find module for path crypto/ed25519

due to Debian buster using golang version 1.11.
Using golang 1.14.

Events, Hooks, Tiggers and Status

Is there any plan to emit events or execute some hooks/triggers and query the connection status

I am looking for a possibility to get a "connecting" event to be able to start the VM for the connecting user
and be able to query disconnected sessions to stop VM's after a period.

Starting problem

Hi, I've this error after docker-compose up from /opt/rdpgw/dev/docker:
Cannot get oidc provider: Get "http://localhost:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp 127.0.0.1:8080: connect: connection refused

How can I fix it?
Thank you

Feature Request: Scope based Host Authorization

Hey,
currently I don't see a good way to Authorize Users to Hosts (with the GW, not the Host). My suggestion would be, that an OpenId Provider like Keycloak can add a Host Claim to the Access Token, which consists of an array of hosts. The user is than only allowed these hosts.
Access Token Snippet:

...
"hosts" : [
  "0.0.0.0:3389",
  "1.1.1.1:3389"
],
...

In Keycloak you could create a role for every host and assign the roles to users. Then you can use a Custom Client Scope to create the host claim.

Websocket error

trying to connect from windows MSTSC to a windows server getting the below errors

2021/07/02 11:35:16 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:16 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:16 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:16 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:16 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:16 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 Client handshakeRequest from 192.168.4.106
2021/07/02 11:35:17 major: 1, minor: 0, version: 0, ext auth: 2
2021/07/02 11:35:17 Cannot read message from stream websocket: close 1000 (normal)
2021/07/02 11:35:17 http: TLS handshake error from 192.168.4.106:59149: EOF

Websocet problem:invalid memory address or nil pointer dereference

Hi!
Sorry, I don't speak much English.
Im compile your project. Configuration succes and run rdpgw binary. Try connect websocet application writte error massage:
runtime error: invalid memory address or nil pointer dereference goroutine 51 [running]: net/http.(*conn).serve.func1() net/http/server.go:1850 +0xbf panic({0xa76f00, 0x102c100}) runtime/panic.go:890 +0x262 github.com/bolkedebruin/rdpgw/cmd/rdpgw/api.(*Config).HandleDownload(0xc00022b540, {0xc39e80, 0xc000458000}, 0xc00015a700) github.com/bolkedebruin/rdpgw/cmd/rdpgw/api/web.go:279 +0xae2 net/http.HandlerFunc.ServeHTTP(...) net/http/server.go:2109 github.com/bolkedebruin/rdpgw/cmd/rdpgw/api.(*Config).BasicAuth.func1({0xc39e80, 0xc000458000}, 0xc00009ce00) github.com/bolkedebruin/rdpgw/cmd/rdpgw/api/basic.go:52 +0x59b net/http.HandlerFunc.ServeHTTP(0xc3a858?, {0xc39e80?, 0xc000458000?}, 0xc32e00?) net/http/server.go:2109 +0x2f github.com/bolkedebruin/rdpgw/cmd/rdpgw/common.EnrichContext.func1({0xc39e80, 0xc000458000}, 0xc00009cc00) github.com/bolkedebruin/rdpgw/cmd/rdpgw/common/remote.go:41 +0x282 net/http.HandlerFunc.ServeHTTP(0xc00001baf0?, {0xc39e80?, 0xc000458000?}, 0x0?) net/http/server.go:2109 +0x2f net/http.(*ServeMux).ServeHTTP(0xc00013687d?, {0xc39e80, 0xc000458000}, 0xc00009cc00) net/http/server.go:2487 +0x149 net/http.serverHandler.ServeHTTP({0xc0000a0570?}, {0xc39e80, 0xc000458000}, 0xc00009cc00) net/http/server.go:2947 +0x30c net/http.(*conn).serve(0xc000000280, {0xc3a858, 0xc0002477a0}) net/http/server.go:1991 +0x607 created by net/http.(*Server).Serve net/http/server.go:3102 +0x4db
Problem maked patch: https://github.com/bolkedebruin/rdpgw/commit/f94e73b1ecd674771f1e1f4ea4417ae138f76934

Im try modify old source code manual adding modification. Compoile work not problem.
Try runing new binary replaced error massage.

Thanks your wok and help!

Way to disable tls listed in template config is not working

in config template given in a readme we have

 # The default option 'auto' uses a certificate file if provided and found otherwise
 # it uses letsencrypt to obtain a certificate, the latter requires that the host is reachable
 # from letsencrypt servers. If TLS termination happens somewhere else (e.g. a load balancer)
 # set this option to 'disable'. This is mutually exclusive with 'authentication: local'
 # Note: rdp connections over a gateway require TLS
 Tls: auto

but it's just wont work

as we can from code here, it requires DisableTls key instead of just Tls.

Docker-compose demo keycloak exits on startup.

Running

git clone https://github.com/bolkedebruin/rdpgw.git
cd rdpgw/dev/docker
docker-compose build
docker-compose up

Gives this output.

Attaching to docker_xrdp_1, docker_keycloak_1, docker_rdpgw_1
xrdp_1      | 
xrdp_1      | Current default time zone: 'Europe/Amsterdam'
xrdp_1      | Local time is now:      Thu Mar 10 20:45:59 CET 2022.
xrdp_1      | Universal Time is now:  Thu Mar 10 19:45:59 UTC 2022.
xrdp_1      | 
xrdp_1      | Username: admin, Password: admin , Sudo: Y
rdpgw_1     | 2022/03/10 19:45:59 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp 172.18.0.2:8080: connect: connection refused
xrdp_1      | 2022-03-10 20:46:00,190 CRIT Supervisor is running as root.  Privileges were not dropped because no user is specified in the config file.  If you intend to run as root, you can set user=root in the config file to avoid this message.
xrdp_1      | 2022-03-10 20:46:00,190 INFO Included extra file "/etc/supervisor/conf.d/xrdp.conf" during parsing
xrdp_1      | 2022-03-10 20:46:00,199 INFO RPC interface 'supervisor' initialized
xrdp_1      | 2022-03-10 20:46:00,199 CRIT Server 'unix_http_server' running without any HTTP authentication checking
xrdp_1      | 2022-03-10 20:46:00,199 INFO supervisord started with pid 75
rdpgw_1     | 2022/03/10 19:46:00 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp 172.18.0.2:8080: connect: connection refused
keycloak_1  | Keycloak - Open Source Identity and Access Management
keycloak_1  | 
keycloak_1  | Find more information at: https://www.keycloak.org/docs/latest
keycloak_1  | 
keycloak_1  | Usage:
keycloak_1  | 
keycloak_1  | kc.sh [OPTIONS] [COMMAND]
keycloak_1  | 
keycloak_1  | Use this command-line tool to manage your Keycloak cluster.
keycloak_1  | Make sure the command is available on your "PATH" or prefix it with "./" (e.g.:
keycloak_1  | "./kc.sh") to execute from the current folder.
keycloak_1  | 
keycloak_1  | Options:
keycloak_1  | 
keycloak_1  | -cf, --config-file <file>
keycloak_1  |                      Set the path to a configuration file. By default, configuration properties are
keycloak_1  |                        read from the "keycloak.conf" file in the "conf" directory.
keycloak_1  | -h, --help           This help message.
keycloak_1  | -v, --verbose        Print out error details when running this command.
keycloak_1  | -V, --version        Show version information
keycloak_1  | 
keycloak_1  | Commands:
keycloak_1  | 
keycloak_1  |   build                   Creates a new and optimized server image.
keycloak_1  |   start                   Start the server.
keycloak_1  |   start-dev               Start the server in development mode.
keycloak_1  |   export                  Export data from realms to a file or directory.
keycloak_1  |   import                  Import data from a directory or a file.
keycloak_1  |   show-config             Print out the current configuration.
keycloak_1  |   tools                   Utilities for use and interaction with the server.
keycloak_1  |     completion            Generate bash/zsh completion script for kc.sh.
keycloak_1  | 
keycloak_1  | Examples:
keycloak_1  | 
keycloak_1  |   Start the server in development mode for local development or testing:
keycloak_1  | 
keycloak_1  |       $ kc.sh start-dev
keycloak_1  | 
keycloak_1  |   Building an optimized server runtime:
keycloak_1  | 
keycloak_1  |       $ kc.sh build <OPTIONS>
keycloak_1  | 
keycloak_1  |   Start the server in production mode:
keycloak_1  | 
keycloak_1  |       $ kc.sh start <OPTIONS>
keycloak_1  | 
keycloak_1  |   Enable auto-completion to bash/zsh:
keycloak_1  | 
keycloak_1  |       $ source <(kc.sh tools completion)
keycloak_1  | 
keycloak_1  |   Please, take a look at the documentation for more details before deploying in
keycloak_1  | production.
keycloak_1  | 
keycloak_1  | Use "kc.sh start --help" for the available options when starting the server.
keycloak_1  | Use "kc.sh <command> --help" for more information about other commands.
docker_rdpgw_1 exited with code 1
docker_keycloak_1 exited with code 0
xrdp_1      | 2022-03-10 20:46:01,201 INFO spawned: 'xrdp' with pid 77
xrdp_1      | 2022-03-10 20:46:01,202 INFO spawned: 'xrdp-sesman' with pid 78
docker_rdpgw_1 exited with code 1
rdpgw_1     | 2022/03/10 19:45:59 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp 172.18.0.2:8080: connect: connection refused
rdpgw_1     | 2022/03/10 19:46:00 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp 172.18.0.2:8080: connect: connection refused
rdpgw_1     | 2022/03/10 19:46:01 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
xrdp_1      | 2022-03-10 20:46:02,203 INFO success: xrdp entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
xrdp_1      | 2022-03-10 20:46:02,203 INFO success: xrdp-sesman entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
docker_rdpgw_1 exited with code 1
rdpgw_1     | 2022/03/10 19:45:59 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp 172.18.0.2:8080: connect: connection refused
rdpgw_1     | 2022/03/10 19:46:00 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp 172.18.0.2:8080: connect: connection refused
rdpgw_1     | 2022/03/10 19:46:01 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:02 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
docker_rdpgw_1 exited with code 1
rdpgw_1     | 2022/03/10 19:45:59 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp 172.18.0.2:8080: connect: connection refused
rdpgw_1     | 2022/03/10 19:46:00 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp 172.18.0.2:8080: connect: connection refused
rdpgw_1     | 2022/03/10 19:46:01 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:02 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:03 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
docker_rdpgw_1 exited with code 1
rdpgw_1     | 2022/03/10 19:45:59 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp 172.18.0.2:8080: connect: connection refused
rdpgw_1     | 2022/03/10 19:46:00 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp 172.18.0.2:8080: connect: connection refused
rdpgw_1     | 2022/03/10 19:46:01 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:02 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:03 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:05 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
docker_rdpgw_1 exited with code 1
rdpgw_1     | 2022/03/10 19:45:59 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp 172.18.0.2:8080: connect: connection refused
rdpgw_1     | 2022/03/10 19:46:00 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp 172.18.0.2:8080: connect: connection refused
rdpgw_1     | 2022/03/10 19:46:01 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:02 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:03 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:05 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:09 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
docker_rdpgw_1 exited with code 1
rdpgw_1     | 2022/03/10 19:45:59 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp 172.18.0.2:8080: connect: connection refused
rdpgw_1     | 2022/03/10 19:46:00 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp 172.18.0.2:8080: connect: connection refused
rdpgw_1     | 2022/03/10 19:46:01 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:02 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:03 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:05 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:09 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:15 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
docker_rdpgw_1 exited with code 1
rdpgw_1     | 2022/03/10 19:45:59 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp 172.18.0.2:8080: connect: connection refused
rdpgw_1     | 2022/03/10 19:46:00 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp 172.18.0.2:8080: connect: connection refused
rdpgw_1     | 2022/03/10 19:46:01 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:02 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:03 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:05 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:09 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:15 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving
rdpgw_1     | 2022/03/10 19:46:29 Cannot get oidc provider: Get "http://keycloak:8080/auth/realms/rdpgw/.well-known/openid-configuration": dial tcp: lookup keycloak on 127.0.0.11:53: server misbehaving

docker-compose build failed

when Setup 5/13,Timeout exception found,The specific information is: fatal:go: github.com/coreos/go-oidc/[email protected]:Get "https:proxy.golang.org/github.com/coreos/go-oidc/v3/@v/v3.0.0.mod": dial tcp 142.251.42.241:44 : i/o timeout

Installation failed

Hello,
i try to install rdpgw in ubuntu server and it fails.
here's the issue
thanks by advance

#make
go mod tidy -compat=1.19
flag provided but not defined: -compat
usage: go mod tidy [-v]
Run 'go help mod tidy' for details.
make: *** [Makefile:53: mod] Error 2

make failed!

Hie,
Thanks a lot for your project I'll try to find a substitute to MS RDP Gateway to connect to single desktops.
I try to install RDPGW to a raspberry pi 3 with raspbian.
In this raspberry I have a functional installation of apache with a c# webservice in mono from a project of mine.
I have installed GO 1.16 but when I try to make your project it return to me this errors:
"cmd/rdpgw/protocol/server.go:321:3: constant 2147483648 overflows int
make: *** [Makefile:37: /home/pi/rdpgw-master/bin/rdpgw] Error 2"
Where I was wrong?
Thanks a lot,
Francesco

mstsc always use NTLM to authenticate

When rdpgw is running in local auth mode, I was supposed to enter PAM credentials to authenticate myself but turns out mstsc in Windows doesn't support basic auth anymore. Even if I set gatewaycredentialssource to 3 in my rdp file, it still sent credentials in NTLM.

Attached is a packet dump of handshake in cleartext.
rdp.zip

Installation Doc

Hello!

This project looks very promissing, i only have seen guacamole server which a very huge frankenstein and so complex...

Your RDP GW looks awesome, but i just can't figure out how to install it, is there any tutorial, installation documentation, or a blog post, etc? i'm unfamiliar with Keycloak how should i configure it to work with rdpgw?
can you point me to the right path plz?

I have a Debian KVM server with several windows VM's, currently i'm just port forwarding the RDP ports to each VM, but i'd love to use your software as a frontend to all of that.

Kudos for your project!

Hope to hear back from you...

Best regards.

How can insert user credential (pwd) in RDP Gateway

Hi, I love this project and it can run like i expect. But i have a situation that, after user can rdp to server by using their rdp client. They have to input pwd manually to login. If i have a user credential, so can i inject it to rdp server from RDP gateway ?

How to disable Open-ID

Hello,

i want to use RDPGW as RDP-Gateway for a office. I have created a AlmaLinux-VM and compiled it. When starting the binary, it throws a error

[myuser@RDPGWVM bin]$ ./rdpgw
2022/07/07 18:51:03 Cannot get oidc provider: Get "/.well-known/openid-configuration": unsupported protocol scheme ""

because i don't want to use openid, i would like to disable that whole functionality. How to do that?

By the way, the project, at least the config-file needs more documentation.

Thank you

I need installation instructions

I've been trying to get rdpgw to run for 2 days now. It does not reveal to me what exactly has to be set up where with rdp. I would be very grateful if there would be detailed instructions. Or a complete docker image

Failed to start wtihout tls

2022/09/01 16:12:31 Cookies are used as session storage
2022/09/01 16:12:31 Starting remote desktop gateway server
2022/09/01 16:12:31 TLS disabled - rdp gw connections require tls, make sure to have a terminator
2022/09/01 16:12:31 ListenAndServe: open : no such file or directory

getting this while trying to start docker container
happens only when tls is disabled (im using traefik as tls terminating proxy)

User / Password based RDP gateway to use with Guacamole?

I'm looking for a solution to connect securely to internal RDP servers from remote using Apache Guacamole.

My idea is to run this rdpgw on a non standard port and configure the firewall so that it is only publicly reachable from the Guacamole server.

Apache Guacamole does support Remote Desktop Gateways which are configurable with Hostname/IP, Port, Username, Password and Domain.
As far as I know there is no special support for certificate based authentication or OpenID or anything other than Username / Password authentication.

Is it possible to configure this RDP Gateway implementation, so that it would work under the given circumstances?

Is it works?

I've tried to use example from dev/docker directory, but connection hangs up o initialization of remote connection.
In container log I see next message repeated some times:

2020/11/02 14:32:05 Client handshakeRequest from 10.65.11.25
2020/11/02 14:32:05 major: 1, minor: 0, version: 0, ext auth: 2
2020/11/02 14:32:05 Cannot read message from stream websocket: close 1000 (normal)

This message I also see when deploy in k8s cluster.

[QUESTION] disallow TLS disabled + basic auth

Hello,

First, I would like to thank you for this great project. It's always good to have FOSS alternatives to Windows-only, closed-source softwares.

I have a question about these lines of code (in configuration.go):

if Conf.Server.Authentication == "local" && Conf.Server.DisableTLS {
	log.Fatalf("basicauth=local and disabletls are mutually exclusive")
}

Is there a technical limitation that prevent using rdpgw behind a reverse proxy with a local authentication, or you did this to enforce end-to-end credentials encryption ?

Thank you

[Question] Nginx

@bolkedebruin
can this be setup behind a nginx reverse proxy so that is can share the IP address with other websites, i know you can do this with mesh central, but the goals are slightly different

label:question

Client Example

Hi,

do you have an example of a client implementation?
I'm currently building an application to tunnel non-rdp traffic through an rd gateway server and can't get the tunnel initialization to work

My first tries are implemented here: https://github.com/develerik/rdtunnel
It always gets stuck at receiving the handshake response

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.