Implement TLS mechanisms correctly, I hope
This commit is contained in:
parent
8a605f44b0
commit
66c6479770
2 changed files with 69 additions and 31 deletions
16
README.md
16
README.md
|
@ -51,12 +51,18 @@ Change this by setting the `bind_address` key in the json config file.
|
||||||
|
|
||||||
## TLS
|
## TLS
|
||||||
|
|
||||||
`gobottin` supports SSL connections using the STARTTLS LDAP functionnality.
|
`gobottin` supports TLS connections either as a mandatory default for all
|
||||||
To use it, specify the following three keys in the json config file:
|
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
|
- `tls_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)
|
- `tls_cert_file`: path to your TLS certificate (a `.pem` file)
|
||||||
- `ssl_key_file`: path to your SSL key (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
|
## Access control list
|
||||||
|
|
||||||
|
|
84
main.go
84
main.go
|
@ -38,9 +38,10 @@ type ConfigFile struct {
|
||||||
BindAddress string `json:"bind_address"`
|
BindAddress string `json:"bind_address"`
|
||||||
ConsulHost string `json:"consul_host"`
|
ConsulHost string `json:"consul_host"`
|
||||||
Acl []string `json:"acl"`
|
Acl []string `json:"acl"`
|
||||||
SSLCertFile string `json:"ssl_cert_file"`
|
TLSCertFile string `json:"tls_cert_file"`
|
||||||
SSLKeyFile string `json:"ssl_key_file"`
|
TLSKeyFile string `json:"tls_key_file"`
|
||||||
SSLServerName string `json:"ssl_server_name"`
|
TLSServerName string `json:"tls_server_name"`
|
||||||
|
UseStartTLS bool `json:"use_starttls"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -50,7 +51,8 @@ type Config struct {
|
||||||
|
|
||||||
Acl ACL
|
Acl ACL
|
||||||
|
|
||||||
TlsConfig *tls.Config
|
TLSConfig *tls.Config
|
||||||
|
UseStartTLS bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
|
@ -92,14 +94,15 @@ func readConfig() Config {
|
||||||
BindAddress: config_file.BindAddress,
|
BindAddress: config_file.BindAddress,
|
||||||
ConsulHost: config_file.ConsulHost,
|
ConsulHost: config_file.ConsulHost,
|
||||||
Acl: acl,
|
Acl: acl,
|
||||||
|
UseStartTLS: config_file.UseStartTLS,
|
||||||
}
|
}
|
||||||
|
|
||||||
if config_file.SSLCertFile != "" && config_file.SSLKeyFile != "" && config_file.SSLServerName != "" {
|
if config_file.TLSCertFile != "" && config_file.TLSKeyFile != "" && config_file.TLSServerName != "" {
|
||||||
cert_txt, err := ioutil.ReadFile(config_file.SSLCertFile)
|
cert_txt, err := ioutil.ReadFile(config_file.TLSCertFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
key_txt, err := ioutil.ReadFile(config_file.SSLKeyFile)
|
key_txt, err := ioutil.ReadFile(config_file.TLSKeyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -107,13 +110,14 @@ func readConfig() Config {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
ret.TlsConfig = &tls.Config{
|
ret.TLSConfig = &tls.Config{
|
||||||
MinVersion: tls.VersionSSL30,
|
MinVersion: tls.VersionTLS10,
|
||||||
MaxVersion: tls.VersionTLS12,
|
MaxVersion: tls.VersionTLS12,
|
||||||
Certificates: []tls.Certificate{cert},
|
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
|
return ret
|
||||||
|
@ -160,31 +164,42 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
routes := ldap.NewRouteMux()
|
routes := ldap.NewRouteMux()
|
||||||
|
|
||||||
routes.Bind(gobottin.handleBind)
|
routes.Bind(gobottin.handleBind)
|
||||||
routes.Search(gobottin.handleSearch)
|
routes.Search(gobottin.handleSearch)
|
||||||
routes.Add(gobottin.handleAdd)
|
routes.Add(gobottin.handleAdd)
|
||||||
routes.Compare(gobottin.handleCompare)
|
routes.Compare(gobottin.handleCompare)
|
||||||
routes.Delete(gobottin.handleDelete)
|
routes.Delete(gobottin.handleDelete)
|
||||||
routes.Modify(gobottin.handleModify)
|
routes.Modify(gobottin.handleModify)
|
||||||
ldapserver.Handle(routes)
|
|
||||||
|
|
||||||
if config.TlsConfig != nil {
|
if config.TLSConfig != nil && config.UseStartTLS {
|
||||||
secureConn := func(s *ldap.Server) {
|
routes.Extended(gobottin.handleStartTLS).
|
||||||
s.Listener = tls.NewListener(s.Listener, config.TlsConfig)
|
RequestName(ldap.NoticeOfStartTLS).Label("StartTLS")
|
||||||
}
|
|
||||||
go ldapserver.ListenAndServe(config.BindAddress, secureConn)
|
|
||||||
} else {
|
|
||||||
go ldapserver.ListenAndServe(config.BindAddress)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// When CTRL+C, SIGINT and SIGTERM signal occurs
|
ldapserver.Handle(routes)
|
||||||
// Then stop server gracefully
|
|
||||||
ch := make(chan os.Signal)
|
|
||||||
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
|
|
||||||
<-ch
|
|
||||||
close(ch)
|
|
||||||
|
|
||||||
ldapserver.Stop()
|
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 {
|
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) {
|
func (server *Server) handleBind(s ldap.UserState, w ldap.ResponseWriter, m *ldap.Message) {
|
||||||
state := s.(*State)
|
state := s.(*State)
|
||||||
r := m.GetBindRequest()
|
r := m.GetBindRequest()
|
||||||
|
|
Loading…
Reference in a new issue