Implement TLS mechanisms correctly, I hope

This commit is contained in:
Alex 2020-01-27 16:08:35 +01:00
parent 8a605f44b0
commit 66c6479770
2 changed files with 69 additions and 31 deletions

View file

@ -51,12 +51,18 @@ Change this by setting the `bind_address` key in the json config file.
## TLS
`gobottin` supports SSL connections using the STARTTLS LDAP functionnality.
To use it, specify the following three keys in the json config file:
`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:
- `ssl_server_name`: the host name that clients will use to reach your LDAP server
- `ssl_cert_file`: path to your SSL certificate (a `.pem` file)
- `ssl_key_file`: path to your SSL key (a `.pem` 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.
## Access control list

74
main.go
View file

@ -38,9 +38,10 @@ type ConfigFile struct {
BindAddress string `json:"bind_address"`
ConsulHost string `json:"consul_host"`
Acl []string `json:"acl"`
SSLCertFile string `json:"ssl_cert_file"`
SSLKeyFile string `json:"ssl_key_file"`
SSLServerName string `json:"ssl_server_name"`
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 {
@ -50,7 +51,8 @@ type Config struct {
Acl ACL
TlsConfig *tls.Config
TLSConfig *tls.Config
UseStartTLS bool
}
type Server struct {
@ -92,14 +94,15 @@ func readConfig() Config {
BindAddress: config_file.BindAddress,
ConsulHost: config_file.ConsulHost,
Acl: acl,
UseStartTLS: config_file.UseStartTLS,
}
if config_file.SSLCertFile != "" && config_file.SSLKeyFile != "" && config_file.SSLServerName != "" {
cert_txt, err := ioutil.ReadFile(config_file.SSLCertFile)
if config_file.TLSCertFile != "" && config_file.TLSKeyFile != "" && config_file.TLSServerName != "" {
cert_txt, err := ioutil.ReadFile(config_file.TLSCertFile)
if err != nil {
panic(err)
}
key_txt, err := ioutil.ReadFile(config_file.SSLKeyFile)
key_txt, err := ioutil.ReadFile(config_file.TLSKeyFile)
if err != nil {
panic(err)
}
@ -107,13 +110,14 @@ func readConfig() Config {
if err != nil {
panic(err)
}
ret.TlsConfig = &tls.Config{
MinVersion: tls.VersionSSL30,
ret.TLSConfig = &tls.Config{
MinVersion: tls.VersionTLS10,
MaxVersion: tls.VersionTLS12,
Certificates: []tls.Certificate{cert},
ServerName: config_file.SSLServerName,
ServerName: config_file.TLSServerName,
}
} else {
log.Printf("Warning: no TLS configuration provided, running an insecure server.")
}
return ret
@ -160,31 +164,42 @@ func main() {
}
routes := ldap.NewRouteMux()
routes.Bind(gobottin.handleBind)
routes.Search(gobottin.handleSearch)
routes.Add(gobottin.handleAdd)
routes.Compare(gobottin.handleCompare)
routes.Delete(gobottin.handleDelete)
routes.Modify(gobottin.handleModify)
if config.TLSConfig != nil && config.UseStartTLS {
routes.Extended(gobottin.handleStartTLS).
RequestName(ldap.NoticeOfStartTLS).Label("StartTLS")
}
ldapserver.Handle(routes)
if config.TlsConfig != nil {
secureConn := func(s *ldap.Server) {
s.Listener = tls.NewListener(s.Listener, config.TlsConfig)
}
go ldapserver.ListenAndServe(config.BindAddress, secureConn)
} else {
go ldapserver.ListenAndServe(config.BindAddress)
}
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()
}()
if config.TLSConfig != nil && !config.UseStartTLS {
secureConn := func(s *ldap.Server) {
s.Listener = tls.NewListener(s.Listener, config.TLSConfig)
}
err = ldapserver.ListenAndServe(config.BindAddress, secureConn)
} else {
err = ldapserver.ListenAndServe(config.BindAddress)
}
if err != nil {
panic(err)
}
}
func (server *Server) init() error {
@ -328,6 +343,23 @@ func (server *Server) checkSuffix(dn string, allow_extend bool) (string, error)
}
}
func (server *Server) handleStartTLS(s ldap.UserState, w ldap.ResponseWriter, m *ldap.Message) {
tlsConn := tls.Server(m.Client.GetConn(), server.config.TLSConfig)
res := ldap.NewExtendedResponse(ldap.LDAPResultSuccess)
res.SetResponseName(ldap.NoticeOfStartTLS)
w.Write(res)
if err := tlsConn.Handshake(); err != nil {
log.Printf("StartTLS Handshake error %v", err)
res.SetDiagnosticMessage(fmt.Sprintf("StartTLS Handshake error : \"%s\"", err.Error()))
res.SetResultCode(ldap.LDAPResultOperationsError)
w.Write(res)
return
}
m.Client.SetConn(tlsConn)
}
func (server *Server) handleBind(s ldap.UserState, w ldap.ResponseWriter, m *ldap.Message) {
state := s.(*State)
r := m.GetBindRequest()