coredns-ldap/setup.go

248 lines
5.5 KiB
Go
Raw Permalink Normal View History

2020-06-01 07:48:07 +00:00
package ldap
import (
2020-06-10 06:40:13 +00:00
"fmt"
2020-06-04 17:41:04 +00:00
"strconv"
"sync"
2020-06-09 03:01:53 +00:00
"time"
2020-06-04 17:41:04 +00:00
"github.com/coredns/caddy"
"github.com/coredns/coredns/core/dnsserver"
2017-09-15 20:29:47 +00:00
"github.com/coredns/coredns/plugin"
"github.com/prometheus/client_golang/prometheus"
2020-06-03 17:47:21 +00:00
clog "github.com/coredns/coredns/plugin/pkg/log"
"github.com/coredns/coredns/plugin/pkg/upstream"
)
2020-06-03 17:47:21 +00:00
const pluginName = "ldap"
// Define log to be a logger with the plugin name in it.
2020-06-10 08:03:59 +00:00
// nolint: gochecknoglobals
2020-06-03 17:47:21 +00:00
var log = clog.NewWithPlugin(pluginName)
// init registers this plugin.
2020-06-10 08:03:59 +00:00
// nolint: gochecknoinits
2020-06-03 17:47:21 +00:00
func init() { plugin.Register(pluginName, setup) }
2020-06-01 07:48:07 +00:00
// setup is the function that gets called when the config parser see the token "ldap". Setup is responsible
// for parsing any extra options the ldap plugin may have. The first token this function sees is "ldap".
func setup(c *caddy.Controller) error {
2020-06-03 17:47:21 +00:00
// parse corefile config
l, err := ldapParse(c)
if err != nil {
return plugin.Error(pluginName, err)
}
2020-06-08 04:12:18 +00:00
err = l.InitClient()
2020-06-03 17:47:21 +00:00
if err != nil {
return plugin.Error(pluginName, err)
}
2020-06-03 17:47:21 +00:00
// add prometheus metrics on startup
c.OnStartup(func() error {
2020-06-03 17:47:21 +00:00
// add plugin-global metric once
once.Do(func() {
prometheus.MustRegister(requestCount)
2020-06-03 17:47:21 +00:00
})
return nil
})
2018-02-25 08:52:52 +00:00
// Add the Plugin to CoreDNS, so Servers can use it in their plugin chain.
2017-09-15 20:29:47 +00:00
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
2020-06-03 17:47:21 +00:00
l.Next = next
return l
})
return nil
}
2020-06-03 17:47:21 +00:00
2020-06-10 08:03:59 +00:00
// nolint: gochecknoglobals
2020-06-03 17:47:21 +00:00
var once sync.Once
func ldapParse(c *caddy.Controller) (*Ldap, error) {
var (
ldap *Ldap
2020-06-04 17:41:04 +00:00
err error
2020-06-03 17:47:21 +00:00
)
i := 0
for c.Next() {
if i > 0 {
return nil, plugin.ErrOnce
}
i++
2020-06-08 04:12:18 +00:00
ldap, err = ParseStanza(c)
2020-06-03 17:47:21 +00:00
if err != nil {
return ldap, err
}
}
2020-06-10 07:41:44 +00:00
2020-06-03 17:47:21 +00:00
return ldap, nil
}
2020-06-10 07:16:34 +00:00
// ParseStanza parses a ldap stanza.
2020-06-10 08:03:59 +00:00
// nolint: funlen, gocognit, gocyclo
2020-06-03 17:47:21 +00:00
func ParseStanza(c *caddy.Controller) (*Ldap, error) {
2020-06-09 03:01:53 +00:00
zoneNames := c.RemainingArgs()
if len(zoneNames) != 0 {
for i := 0; i < len(zoneNames); i++ {
zoneNames[i] = plugin.Host(zoneNames[i]).Normalize()
2020-06-03 17:47:21 +00:00
}
} else {
2020-06-09 03:01:53 +00:00
zoneNames = make([]string, len(c.ServerBlockKeys))
for i := 0; i < len(zoneNames); i++ {
zoneNames[i] = plugin.Host(c.ServerBlockKeys[i]).Normalize()
2020-06-03 17:47:21 +00:00
}
}
2020-06-09 03:01:53 +00:00
ldap := New(zoneNames)
2020-06-03 17:47:21 +00:00
ldap.Upstream = upstream.New()
for c.NextBlock() {
switch c.Val() {
// RFC 4516 URL
2020-06-08 04:12:18 +00:00
case "ldap_url":
2020-06-10 06:40:13 +00:00
if !c.NextArg() {
return nil, c.ArgErr()
}
2020-06-10 07:41:44 +00:00
2020-06-08 04:12:18 +00:00
ldap.ldapURL = c.Val()
case "paging_limit":
2020-06-10 06:40:13 +00:00
if !c.NextArg() {
return nil, c.ArgErr()
}
2020-06-10 07:41:44 +00:00
2020-06-09 03:01:53 +00:00
pagingLimit, err := strconv.ParseUint(c.Val(), 10, 0)
2020-06-08 04:12:18 +00:00
if err != nil {
2020-06-10 06:40:13 +00:00
return nil, c.Errf("paging_limit: %w", err)
2020-06-03 17:47:21 +00:00
}
2020-06-10 07:41:44 +00:00
2020-06-09 03:01:53 +00:00
ldap.pagingLimit = uint32(pagingLimit)
case "base_dn":
2020-06-10 06:40:13 +00:00
if !c.NextArg() {
return nil, c.ArgErr()
}
2020-06-10 07:41:44 +00:00
ldap.SearchRequest.BaseDN = c.Val() // ou=ae-dir
2020-06-09 03:01:53 +00:00
case "filter":
2020-06-10 06:40:13 +00:00
if !c.NextArg() {
return nil, c.ArgErr()
}
2020-06-10 07:41:44 +00:00
ldap.SearchRequest.Filter = c.Val() // (objectClass=aeNwDevice)
2020-06-09 03:01:53 +00:00
case "attributes":
2020-06-10 06:40:13 +00:00
c.Next()
2020-06-10 07:41:44 +00:00
2020-06-08 04:12:18 +00:00
for c.NextBlock() {
switch c.Val() {
2020-06-09 03:01:53 +00:00
case "fqdn":
2020-06-10 06:40:13 +00:00
if !c.NextArg() {
return nil, c.ArgErr()
}
2020-06-10 07:41:44 +00:00
ldap.SearchRequest.Attributes = append(ldap.SearchRequest.Attributes, c.Val())
ldap.FqdnAttr = c.Val() // aeFqdn
2020-06-09 03:01:53 +00:00
case "ip4":
2020-06-10 06:40:13 +00:00
if !c.NextArg() {
return nil, c.ArgErr()
}
2020-06-10 07:41:44 +00:00
ldap.SearchRequest.Attributes = append(ldap.SearchRequest.Attributes, c.Val())
ldap.Ip4Attr = c.Val() // ipHostNumber
2021-05-28 23:47:39 +00:00
case "ip6":
if !c.NextArg() {
return nil, c.ArgErr()
}
ldap.SearchRequest.Attributes = append(ldap.SearchRequest.Attributes, c.Val())
ldap.Ip6Attr = c.Val() // ipHostNumber
2020-06-03 17:47:21 +00:00
default:
2020-06-09 03:01:53 +00:00
return nil, c.Errf("unknown attributes property '%s'", c.Val())
2020-06-03 17:47:21 +00:00
}
}
2020-06-10 07:41:44 +00:00
2020-06-08 04:12:18 +00:00
continue
case "username":
2020-06-10 06:40:13 +00:00
if !c.NextArg() {
return nil, c.ArgErr()
}
2020-06-10 07:41:44 +00:00
2020-06-08 04:12:18 +00:00
ldap.username = c.Val()
case "password":
2020-06-10 06:40:13 +00:00
if !c.NextArg() {
return nil, c.ArgErr()
}
2020-06-10 07:41:44 +00:00
2020-06-08 04:12:18 +00:00
ldap.password = c.Val()
case "sasl":
ldap.sasl = true
2020-06-09 03:01:53 +00:00
case "ttl":
2020-06-10 06:40:13 +00:00
if !c.NextArg() {
return nil, c.ArgErr()
}
2020-06-10 07:41:44 +00:00
2020-06-09 03:01:53 +00:00
ttl, err := time.ParseDuration(c.Val())
if err != nil {
2020-06-10 06:40:13 +00:00
return nil, c.Errf("ttl: %w", err)
2020-06-09 03:01:53 +00:00
}
2020-06-10 07:41:44 +00:00
2020-06-09 03:01:53 +00:00
ldap.ttl = ttl
case "sync_interval":
2020-06-10 06:40:13 +00:00
if !c.NextArg() {
return nil, c.ArgErr()
}
2020-06-10 07:41:44 +00:00
2020-06-09 03:01:53 +00:00
syncInterval, err := time.ParseDuration(c.Val())
if err != nil {
2020-06-10 06:40:13 +00:00
return nil, c.Errf("sync_interval: %w", err)
2020-06-09 03:01:53 +00:00
}
2020-06-10 07:41:44 +00:00
2020-06-09 03:01:53 +00:00
ldap.syncInterval = syncInterval
2020-06-03 17:47:21 +00:00
case "fallthrough":
ldap.Fall.SetZonesFromArgs(c.RemainingArgs())
default:
return nil, c.Errf("unknown property '%s'", c.Val())
}
}
2020-06-10 07:41:44 +00:00
2020-06-08 04:12:18 +00:00
// validate non-default ldap values ...
2020-06-10 06:40:13 +00:00
if ldap.ldapURL == "" {
return nil, c.Err("ldap_url cannot be empty")
2020-06-08 04:12:18 +00:00
}
2020-06-10 07:41:44 +00:00
if ldap.SearchRequest.BaseDN == "" {
2020-06-10 06:40:13 +00:00
return nil, c.Err("base_dn cannot be empty")
2020-06-08 04:12:18 +00:00
}
2020-06-10 07:41:44 +00:00
if ldap.SearchRequest.Filter == "" {
2020-06-10 06:40:13 +00:00
return nil, c.Err("filter cannot be empty")
}
2020-06-10 07:41:44 +00:00
if ldap.FqdnAttr == "" {
2020-06-10 06:40:13 +00:00
return nil, c.Err("fqdn attribute cannot be empty")
2020-06-08 04:12:18 +00:00
}
2020-06-10 07:41:44 +00:00
if ldap.Ip4Attr == "" {
2020-06-10 06:40:13 +00:00
return nil, c.Err("ip4 attribute cannot be empty")
2020-06-08 04:12:18 +00:00
}
2020-06-10 07:41:44 +00:00
2020-06-08 04:12:18 +00:00
// if only one of password and username set
2020-06-10 06:40:13 +00:00
if (ldap.username == "") != (ldap.password == "") {
return nil, c.Err("if not using sasl, both, username and password must be set")
2020-06-08 04:12:18 +00:00
}
2020-06-10 07:41:44 +00:00
2020-06-08 04:12:18 +00:00
// if both username/password and sasl are set
2020-06-10 07:16:34 +00:00
if ldap.username != "" && ldap.sasl {
2020-06-10 06:40:13 +00:00
fmt.Printf("666 %#v\t%#v", ldap.username, ldap.sasl)
return nil, c.Err("cannot use sasl and username based authentication at the same time")
2020-06-08 04:12:18 +00:00
}
2020-06-10 07:41:44 +00:00
2020-06-08 04:12:18 +00:00
// if neither username/password nor sasl are set
2020-06-10 07:16:34 +00:00
if ldap.username == "" && !ldap.sasl {
2021-02-10 22:33:30 +00:00
return nil, c.Err("authenticate either via username/password or sasl")
2020-06-03 17:47:21 +00:00
}
return ldap, nil
2020-06-04 17:41:04 +00:00
}