Switch from viper to koanf

This commit is contained in:
Bolke de Bruin 2022-08-11 13:58:24 +02:00
parent 8ef2e3c153
commit cd4182c1f5
3 changed files with 122 additions and 81 deletions

View file

@ -67,7 +67,11 @@ server:
# make sure to share this across the different pods # make sure to share this across the different pods
sessionKey: thisisasessionkeyreplacethisjetzt sessionKey: thisisasessionkeyreplacethisjetzt
sessionEncryptionKey: thisisasessionkeyreplacethisnunu! sessionEncryptionKey: thisisasessionkeyreplacethisnunu!
# tries to set the receive / send buffer of the connections to the client # 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 # in case of high latency high bandwidth the defaults set by the OS might
# be to low for a good experience # be to low for a good experience
# receiveBuf: 12582912 # receiveBuf: 12582912

View file

@ -1,102 +1,147 @@
package config package config
import ( import (
"github.com/spf13/viper" "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" "log"
"strings"
) )
type Configuration struct { type Configuration struct {
Server ServerConfig Server ServerConfig `koanf:"server"`
OpenId OpenIDConfig OpenId OpenIDConfig `koanf:"openid"`
Caps RDGCapsConfig Caps RDGCapsConfig `koanf:"caps"`
Security SecurityConfig Security SecurityConfig `koanf:"security"`
Client ClientConfig Client ClientConfig `koanf:"client"`
} }
type ServerConfig struct { type ServerConfig struct {
GatewayAddress string GatewayAddress string `koanf:"gatewayaddress"`
Port int Port int `koanf:"port"`
DisableTLS bool CertFile string `koanf:"certfile"`
CertFile string KeyFile string `koanf:"keyfile"`
KeyFile string Hosts []string `koanf:"hosts"`
Hosts []string RoundRobin bool `koanf:"roundrobin"`
RoundRobin bool SessionKey string `koanf:"sessionkey"`
SessionKey string SessionEncryptionKey string `koanf:"sessionencryptionkey"`
SessionEncryptionKey string SessionStore string `koanf:"sessionstore"`
SessionStore string SendBuf int `koanf:"sendbuf"`
SendBuf int ReceiveBuf int `koanf:"recievebuf"`
ReceiveBuf int DisableTLS bool `koanf:"disabletls"`
} }
type OpenIDConfig struct { type OpenIDConfig struct {
ProviderUrl string ProviderUrl string `koanf:"providerurl"`
ClientId string ClientId string `koanf:"clientid"`
ClientSecret string ClientSecret string `koanf:"clientsecret"`
} }
type RDGCapsConfig struct { type RDGCapsConfig struct {
SmartCardAuth bool SmartCardAuth bool `koanf:"smartcardauth"`
TokenAuth bool TokenAuth bool `koanf:"tokenauth"`
IdleTimeout int IdleTimeout int `koanf:"idletimeout"`
RedirectAll bool RedirectAll bool `koanf:"redirectall"`
DisableRedirect bool DisableRedirect bool `koanf:"disableredirect"`
EnableClipboard bool EnableClipboard bool `koanf:"enableclipboard"`
EnablePrinter bool EnablePrinter bool `koanf:"enableprinter"`
EnablePort bool EnablePort bool `koanf:"enableport"`
EnablePnp bool EnablePnp bool `koanf:"enablepnp"`
EnableDrive bool EnableDrive bool `koanf:"enabledrive"`
} }
type SecurityConfig struct { type SecurityConfig struct {
PAATokenEncryptionKey string PAATokenEncryptionKey string `koanf:"paatokenencryptionkey"`
PAATokenSigningKey string PAATokenSigningKey string `koanf:"paatokensigningkey"`
UserTokenEncryptionKey string UserTokenEncryptionKey string `koanf:"usertokenencryptionkey"`
UserTokenSigningKey string UserTokenSigningKey string `koanf:"usertokensigningkey"`
VerifyClientIp bool VerifyClientIp bool `koanf:"verifyclientip"`
EnableUserToken bool EnableUserToken bool `koanf:"enableusertoken"`
} }
type ClientConfig struct { type ClientConfig struct {
NetworkAutoDetect int NetworkAutoDetect int `koanf:"networkautodetect"`
BandwidthAutoDetect int BandwidthAutoDetect int `koanf:"bandwidthautodetect"`
ConnectionType int ConnectionType int `koanf:"connectiontype"`
UsernameTemplate string UsernameTemplate string `koanf:"usernametemplate"`
SplitUserDomain bool SplitUserDomain bool `koanf:"splituserdomain"`
DefaultDomain string DefaultDomain string `koanf:"defaultdomain"`
} }
func init() { func ToCamel(s string) string {
viper.SetDefault("server.certFile", "server.pem") s = strings.TrimSpace(s)
viper.SetDefault("server.keyFile", "key.pem") n := strings.Builder{}
viper.SetDefault("server.port", 443) n.Grow(len(s))
viper.SetDefault("client.networkAutoDetect", 1) var capNext bool = true
viper.SetDefault("client.bandwidthAutoDetect", 1) for i, v := range []byte(s) {
viper.SetDefault("security.verifyClientIp", true) vIsCap := v >= 'A' && v <= 'Z'
viper.SetDefault("server.tlsDisabled", false) vIsLow := v >= 'a' && v <= 'z'
viper.SetDefault("server.sessionStore", "cookie") if capNext {
viper.SetDefault("caps.tokenAuth", true) 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 { func Load(configFile string) Configuration {
var conf Configuration
viper.SetConfigName("rdpgw") var k = koanf.New(".")
viper.SetConfigFile(configFile)
viper.AddConfigPath(".")
viper.SetEnvPrefix("RDPGW")
viper.AutomaticEnv()
if err := viper.ReadInConfig(); err != nil { k.Load(confmap.Provider(map[string]interface{}{
log.Fatalf("No config file found (%s)", err) "Server.CertFile": "server.pem",
"Server.KeyFile": "key.pem",
"Server.TlsDisabled": false,
"Server.Port": 443,
"Server.SessionStore": "cookie",
"Client.NetworkAutoDetect": 1,
"Client.BandwidthAutoDetect": 1,
"Security.VerifyClientIp": true,
"Caps.TokenAuth": true,
}, "."), nil)
if err := k.Load(file.Provider(configFile), yaml.Parser()); err != nil {
log.Fatalf("Error loading config from file: %v", err)
} }
if err := viper.Unmarshal(&conf); err != nil { if err := k.Load(env.ProviderWithValue("RDPGW_", ".", func(s string, v string) (string, interface{}) {
log.Fatalf("Cannot unmarshal the config file; %s", err) 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)
} }
if len(conf.Security.PAATokenSigningKey) < 32 { koanfTag := koanf.UnmarshalConf{Tag: "koanf"}
log.Fatalf("Token signing key not long enough") 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 return Conf
}
}

16
go.mod
View file

@ -7,10 +7,10 @@ require (
github.com/go-jose/go-jose/v3 v3.0.0 github.com/go-jose/go-jose/v3 v3.0.0
github.com/gorilla/sessions v1.2.1 github.com/gorilla/sessions v1.2.1
github.com/gorilla/websocket v1.5.0 github.com/gorilla/websocket v1.5.0
github.com/knadh/koanf v1.4.2
github.com/patrickmn/go-cache v2.1.0+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/prometheus/client_golang v1.12.1 github.com/prometheus/client_golang v1.12.1
github.com/spf13/cobra v1.5.0 github.com/spf13/cobra v1.5.0
github.com/spf13/viper v1.12.0
golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c
) )
@ -20,29 +20,21 @@ require (
github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect github.com/gorilla/securecookie v1.1.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect github.com/prometheus/procfs v0.7.3 // indirect
github.com/spf13/afero v1.8.2 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.3.0 // indirect github.com/stretchr/testify v1.7.1 // indirect
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.0 // indirect google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/ini.v1 v1.66.4 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0 // indirect
) )