Externalize config

This commit is contained in:
Alex 2020-01-26 19:27:17 +01:00
parent 611d182907
commit c1f0247586
3 changed files with 120 additions and 34 deletions

16
README.md Normal file
View file

@ -0,0 +1,16 @@
## ACL examples
```
// Anybody (before binding) can bind to an entity under ou=users,dc=gobottin,dc=eu
"ANONYMOUS::bind:*,ou=users,dc=gobottin,dc=eu:",
// Anybody (before binding) can bind to the specific admin entity
"ANONYMOUS::bind:cn=admin,dc=gobottin,dc=eu:",
// Anybody who is logged in can read anything that is not a userpassword attribute
"*,dc=gobottin,dc=eu::read:*:* !userpassword",
// Anybody can read and modify anything from their own entry
"*::read modify:SELF:*",
// The admin can read, add, modify, delete anything
"cn=admin,dc=gobottin,dc=eu::read add modify delete:*:*",
// Members of the admin group can read, add, modify, delete anything
"*:cn=admin,ou=groups,dc=gobottin,dc=eu:read add modify delete:*:*"
```

13
config.json Normal file
View file

@ -0,0 +1,13 @@
{
"suffix": "dc=gobottin,dc=eu",
"bind_address": "127.0.0.1:10389",
"acl": [
"ANONYMOUS::bind:*,ou=users,dc=gobottin,dc=eu:",
"ANONYMOUS::bind:cn=admin,dc=gobottin,dc=eu:",
"*,dc=gobottin,dc=eu::read:*:* !userpassword",
"*::read modify:SELF:*",
"cn=admin,dc=gobottin,dc=eu::read add modify delete:*:*",
"*:cn=admin,ou=groups,dc=gobottin,dc=eu:read add modify delete:*:*"
]
}

117
main.go
View file

@ -1,14 +1,15 @@
package main
// @FIXME: Implement a real permission system: limit read/write scope/attributes, possibly based on group membership
// @FIXME: Implement missing search filters (in applyFilter)
// @FIXME: Add an initial prefix to the consul key value
// @FIXME: Add TLS connections
import (
"crypto/tls"
"encoding/base64"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"math/rand"
"os"
@ -21,9 +22,24 @@ import (
message "github.com/vjeantet/goldap/message"
)
type ConfigFile struct {
Suffix string `json:"suffix"`
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"`
}
type Config struct {
Suffix string
BindAddress string
ConsulHost string
Acl ACL
TlsConfig *tls.Config
}
type Server struct {
@ -37,42 +53,77 @@ type State struct {
type Entry map[string][]string
func main() {
//ldap logger
ldap.Logger = log.New(os.Stdout, "[server] ", log.LstdFlags)
var configFlag = flag.String("config", "./config.json", "Configuration file path")
// Connect to Consul
client, err := consul.NewClient(consul.DefaultConfig())
if err != nil {
panic(err)
func readConfig() Config {
config_file := ConfigFile{
BindAddress: "0.0.0.0:389",
}
kv := client.KV()
aclStr := []string{
// Anybody (before binding) can bind to an entity under ou=users,dc=gobottin,dc=eu
"ANONYMOUS::bind:*,ou=users,dc=gobottin,dc=eu:",
// Anybody (before binding) can bind to the specific admin entity
"ANONYMOUS::bind:cn=admin,dc=gobottin,dc=eu:",
// Anybody who is logged in can read anything that is not a userpassword attribute
"*,dc=gobottin,dc=eu::read:*:* !userpassword",
// Anybody can read and modify anything from their own entry
"*::read modify:SELF:*",
// The admin can read, add, modify, delete anything
"cn=admin,dc=gobottin,dc=eu::read add modify delete:*:*",
// Members of the admin group can read, add, modify, delete anything
"*:cn=admin,ou=groups,dc=gobottin,dc=eu:read add modify delete:*:*",
}
acl, err := ParseACL(aclStr)
bytes, err := ioutil.ReadFile(*configFlag)
if err != nil {
panic(err)
}
// TODO read config from somewhere
config := Config{
Suffix: "dc=gobottin,dc=eu",
err = json.Unmarshal(bytes, &config_file)
if err != nil {
panic(err)
}
acl, err := ParseACL(config_file.Acl)
if err != nil {
panic(err)
}
ret := Config{
Suffix: config_file.Suffix,
BindAddress: config_file.BindAddress,
ConsulHost: config_file.ConsulHost,
Acl: acl,
}
if config_file.SSLCertFile != "" && config_file.SSLKeyFile != "" && config_file.SSLServerName != "" {
cert_txt, err := ioutil.ReadFile(config_file.SSLCertFile)
if err != nil {
panic(err)
}
key_txt, err := ioutil.ReadFile(config_file.SSLKeyFile)
if err != nil {
panic(err)
}
cert, err := tls.X509KeyPair(cert_txt, key_txt)
if err != nil {
panic(err)
}
ret.TlsConfig = &tls.Config{
MinVersion: tls.VersionSSL30,
MaxVersion: tls.VersionTLS12,
Certificates: []tls.Certificate{cert},
ServerName: config_file.SSLServerName,
}
}
return ret
}
func main() {
ldap.Logger = log.New(os.Stdout, "[server] ", log.LstdFlags)
config := readConfig()
// Connect to Consul
consul_config := consul.DefaultConfig()
if config.ConsulHost != "" {
consul_config.Address = config.ConsulHost
}
consul_client, err := consul.NewClient(consul_config)
if err != nil {
panic(err)
}
kv := consul_client.KV()
// Create gobottin server
gobottin := Server{config: config, kv: kv}
err = gobottin.init()
if err != nil {
@ -99,8 +150,14 @@ func main() {
routes.Modify(gobottin.handleModify)
ldapserver.Handle(routes)
// listen on 10389
go ldapserver.ListenAndServe("127.0.0.1:10389")
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)
}
// When CTRL+C, SIGINT and SIGTERM signal occurs
// Then stop server gracefully