Allow for both TLS and non-TLS connections

This commit is contained in:
Alex 2020-01-27 16:32:39 +01:00
parent 66c6479770
commit dce432426e
3 changed files with 100 additions and 58 deletions

View file

@ -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

View file

@ -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:",

92
main.go
View file

@ -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
Bind string
BindSecure string
ConsulHost string
Acl ACL
TLSConfig *tls.Config
UseStartTLS bool
}
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)
@ -91,10 +92,10 @@ func readConfig() Config {
ret := Config{
Suffix: config_file.Suffix,
BindAddress: config_file.BindAddress,
Bind: config_file.Bind,
BindSecure: config_file.BindSecure,
ConsulHost: config_file.ConsulHost,
Acl: acl,
UseStartTLS: config_file.UseStartTLS,
}
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
// 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)
}
}()
}
// 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)
}
}
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)
ldapserver.Stop()
}()
if config.TLSConfig != nil && !config.UseStartTLS {
secureConn := func(s *ldap.Server) {
s.Listener = tls.NewListener(s.Listener, config.TLSConfig)
if ldapServer != nil {
ldapServer.Stop()
}
err = ldapserver.ListenAndServe(config.BindAddress, secureConn)
} else {
err = ldapserver.ListenAndServe(config.BindAddress)
if ldapServerSecure != nil {
ldapServerSecure.Stop()
}
if err != nil {
panic(err)
}
func (server *Server) newUserState() ldap.UserState {
return &State{
login: Login{
user: "ANONYMOUS",
groups: []string{},
},
}
}