From dce432426e325ab43757da9485c612421c912957 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Mon, 27 Jan 2020 16:32:39 +0100 Subject: Allow for both TLS and non-TLS connections --- README.md | 34 ++++++++++----- config.json.example | 2 +- main.go | 118 ++++++++++++++++++++++++++++++++-------------------- 3 files changed, 98 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 259c234..5a696e7 100644 --- a/README.md +++ b/README.md @@ -44,25 +44,39 @@ suffix in the `suffix` key of the json config file. By default, `gobottin` connects to the Consul server on localhost. Change this by specifying the `consul_host` key in the json config file. -## Bind address +## Bind addresses -By default, `gobottin` listens on all interfaces on port 389. -Change this by setting the `bind_address` key in the json config file. +### Insecure port + +By default, `gobottin` listens on all interfaces on port 389 for standard +non-TLS connections. Change the value of the `bind` key in the json config +file to change this behaviour (default value: `0.0.0.0:389`). An empty string +will disable this port and `gobottin` will not listen for non-TLS connections. + +### Secure port + +If a TLS configuration is provided (see next section), `gobottin` also listens +on all interfaces on port 636 for TLS connections. Change the value of the +`bind_secure` key in the json config file to change this behaviour (default +value: `0.0.0.0:636`). An empty string will disable this port and `gobottin` +will not listen for TLS connections. ## TLS -`gobottin` supports TLS connections either as a mandatory default for all -connections or using the STARTLS functionnality of the LDAP protocol. To use -it, specify the following three keys in the json config file: +`gobottin` supports TLS connections using either fully secure connections or +using the STARTLS functionnality of the LDAP protocol to upgrade from an +insecure connection. To use it, specify the following three keys in the json +config file: - `tls_server_name`: the host name that clients will use to reach your LDAP server - `tls_cert_file`: path to your TLS certificate (a `.pem` file) - `tls_key_file`: path to your TLS key (a `.pem` file) -Specify `"use_starttls": true` to allow connections to start as insecure -connections and allow them to use the STARTTLS mechanism to upgrade to a secure -connection. If `use_starttls` is not specified or set to `false`, TLS is made -mandatory for all clients. +If a TLS configuration is provided, the `STARTTLS` mechanism may be used on the +insecure port, independently of whether the secure port is enabled or not. + +The secure port is disabled and a warning is shown if the `bind_secure` value +is set (non-empty) and no valid TLS configuration is provided. ## Access control list diff --git a/config.json.example b/config.json.example index f4c2781..4249e26 100644 --- a/config.json.example +++ b/config.json.example @@ -1,6 +1,6 @@ { "suffix": "dc=gobottin,dc=eu", - "bind_address": "127.0.0.1:10389", + "bind": "127.0.0.1:1389", "acl": [ "ANONYMOUS::bind:*,ou=users,dc=gobottin,dc=eu:", "ANONYMOUS::bind:cn=admin,dc=gobottin,dc=eu:", diff --git a/main.go b/main.go index 88ea3dd..a8acc18 100644 --- a/main.go +++ b/main.go @@ -35,24 +35,24 @@ const ATTR_MODIFYTIMESTAMP = "modifytimestamp" type ConfigFile struct { Suffix string `json:"suffix"` - BindAddress string `json:"bind_address"` + Bind string `json:"bind"` + BindSecure string `json:"bind_secure"` ConsulHost string `json:"consul_host"` Acl []string `json:"acl"` TLSCertFile string `json:"tls_cert_file"` TLSKeyFile string `json:"tls_key_file"` TLSServerName string `json:"tls_server_name"` - UseStartTLS bool `json:"use_starttls"` } type Config struct { - Suffix string - BindAddress string - ConsulHost string + Suffix string + Bind string + BindSecure string + ConsulHost string Acl ACL - TLSConfig *tls.Config - UseStartTLS bool + TLSConfig *tls.Config } type Server struct { @@ -71,7 +71,8 @@ var configFlag = flag.String("config", "./config.json", "Configuration file path func readConfig() Config { config_file := ConfigFile{ - BindAddress: "0.0.0.0:389", + Bind: "0.0.0.0:389", + BindSecure: "0.0.0.0:636", } bytes, err := ioutil.ReadFile(*configFlag) @@ -90,11 +91,11 @@ func readConfig() Config { } ret := Config{ - Suffix: config_file.Suffix, - BindAddress: config_file.BindAddress, - ConsulHost: config_file.ConsulHost, - Acl: acl, - UseStartTLS: config_file.UseStartTLS, + Suffix: config_file.Suffix, + Bind: config_file.Bind, + BindSecure: config_file.BindSecure, + ConsulHost: config_file.ConsulHost, + Acl: acl, } if config_file.TLSCertFile != "" && config_file.TLSKeyFile != "" && config_file.TLSServerName != "" { @@ -116,8 +117,6 @@ func readConfig() Config { Certificates: []tls.Certificate{cert}, ServerName: config_file.TLSServerName, } - } else { - log.Printf("Warning: no TLS configuration provided, running an insecure server.") } return ret @@ -152,17 +151,7 @@ func main() { panic(err) } - //Create a new LDAP Server - ldapserver := ldap.NewServer() - ldapserver.NewUserState = func() ldap.UserState { - return &State{ - login: Login{ - user: "ANONYMOUS", - groups: []string{}, - }, - } - } - + // Create routes routes := ldap.NewRouteMux() routes.Bind(gobottin.handleBind) @@ -172,33 +161,72 @@ func main() { routes.Delete(gobottin.handleDelete) routes.Modify(gobottin.handleModify) - if config.TLSConfig != nil && config.UseStartTLS { + if config.TLSConfig != nil { routes.Extended(gobottin.handleStartTLS). RequestName(ldap.NoticeOfStartTLS).Label("StartTLS") } - ldapserver.Handle(routes) + // Create LDAP servers + var ldapServer, ldapServerSecure *ldap.Server = nil, nil - go func() { - // When CTRL+C, SIGINT and SIGTERM signal occurs - // Then stop server gracefully - ch := make(chan os.Signal) - signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM) - <-ch - close(ch) - ldapserver.Stop() - }() + // Bind on standard LDAP port without TLS + if config.Bind != "" { + ldapServer = ldap.NewServer() + ldapServer.Handle(routes) + ldapServer.NewUserState = gobottin.newUserState + go func() { + err := ldapServer.ListenAndServe(config.Bind) + if err != nil { + panic(err) + } + }() + } - if config.TLSConfig != nil && !config.UseStartTLS { - secureConn := func(s *ldap.Server) { - s.Listener = tls.NewListener(s.Listener, config.TLSConfig) + // Bind on LDAP secure port with TLS + if config.BindSecure != "" { + if config.TLSConfig != nil { + ldapServerSecure := ldap.NewServer() + ldapServerSecure.Handle(routes) + ldapServerSecure.NewUserState = gobottin.newUserState + secureConn := func(s *ldap.Server) { + s.Listener = tls.NewListener(s.Listener, config.TLSConfig) + } + go func() { + err := ldapServerSecure.ListenAndServe(config.BindSecure, secureConn) + if err != nil { + panic(err) + } + }() + } else { + fmt.Printf("Warning: no valid TLS configuration was provided, not binding on %s", config.BindSecure) } - err = ldapserver.ListenAndServe(config.BindAddress, secureConn) - } else { - err = ldapserver.ListenAndServe(config.BindAddress) } - if err != nil { - panic(err) + + if ldapServer == nil && ldapServerSecure == nil { + panic("Not doing anything.") + } + + // When CTRL+C, SIGINT and SIGTERM signal occurs + // Then stop server gracefully + ch := make(chan os.Signal) + signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM) + <-ch + close(ch) + + if ldapServer != nil { + ldapServer.Stop() + } + if ldapServerSecure != nil { + ldapServerSecure.Stop() + } +} + +func (server *Server) newUserState() ldap.UserState { + return &State{ + login: Login{ + user: "ANONYMOUS", + groups: []string{}, + }, } } -- cgit v1.2.3