Cache for LDAP username lookups
It is unnecessary to request the same user's username attribute more than once.
This commit is contained in:
parent
84fc80bf0a
commit
c84f52b012
2 changed files with 35 additions and 21 deletions
|
@ -57,7 +57,6 @@ To Do
|
||||||
* Sending logs to... well, Graylog... through CLI switches.
|
* Sending logs to... well, Graylog... through CLI switches.
|
||||||
* Writing logs to a file.
|
* Writing logs to a file.
|
||||||
* Document command line flags.
|
* Document command line flags.
|
||||||
* Cache LDAP username lookups
|
|
||||||
* Add TLS options (skip checks / specify CA) for the Graylog API.
|
* Add TLS options (skip checks / specify CA) for the Graylog API.
|
||||||
* Read object ownership using `grn_permissions` to preserve privileges on users'
|
* Read object ownership using `grn_permissions` to preserve privileges on users'
|
||||||
own objects
|
own objects
|
||||||
|
|
55
ldap.go
55
ldap.go
|
@ -15,9 +15,11 @@ type (
|
||||||
// LDAP connection encapsulation. This includes the connection itself, as well as a logger
|
// LDAP connection encapsulation. This includes the connection itself, as well as a logger
|
||||||
// that includes fields related to the LDAP server and a copy of the initial configuration.
|
// that includes fields related to the LDAP server and a copy of the initial configuration.
|
||||||
ldapConn struct {
|
ldapConn struct {
|
||||||
conn *ldap.Conn
|
conn *ldap.Conn
|
||||||
log *logrus.Entry
|
log *logrus.Entry
|
||||||
cfg LdapConfig
|
cfg LdapConfig
|
||||||
|
usernames map[string]string
|
||||||
|
counter uint
|
||||||
}
|
}
|
||||||
|
|
||||||
// LDAP group members
|
// LDAP group members
|
||||||
|
@ -25,7 +27,7 @@ type (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Establish a connection to the LDAP server
|
// Establish a connection to the LDAP server
|
||||||
func getLdapConnection(cfg LdapConfig) ldapConn {
|
func getLdapConnection(cfg LdapConfig) *ldapConn {
|
||||||
dest := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)
|
dest := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)
|
||||||
log := log.WithFields(logrus.Fields{
|
log := log.WithFields(logrus.Fields{
|
||||||
"ldap_server": dest,
|
"ldap_server": dest,
|
||||||
|
@ -77,20 +79,22 @@ func getLdapConnection(cfg LdapConfig) ldapConn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Debug("LDAP connection established")
|
log.Debug("LDAP connection established")
|
||||||
return ldapConn{
|
return &ldapConn{
|
||||||
conn: lc,
|
conn: lc,
|
||||||
log: log,
|
log: log,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
usernames: make(map[string]string),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run a LDAP query to obtain a single object.
|
// Run a LDAP query to obtain a single object.
|
||||||
func (conn ldapConn) query(dn string, attrs []string) (bool, *ldap.Entry) {
|
func (conn *ldapConn) query(dn string, attrs []string) (bool, *ldap.Entry) {
|
||||||
log := conn.log.WithFields(logrus.Fields{
|
log := conn.log.WithFields(logrus.Fields{
|
||||||
"dn": dn,
|
"dn": dn,
|
||||||
"attributes": attrs,
|
"attributes": attrs,
|
||||||
})
|
})
|
||||||
log.Trace("Accessing DN")
|
log.Trace("Accessing DN")
|
||||||
|
conn.counter++
|
||||||
req := ldap.NewSearchRequest(
|
req := ldap.NewSearchRequest(
|
||||||
dn,
|
dn,
|
||||||
ldap.ScopeBaseObject, ldap.NeverDerefAliases, 1, 0, false,
|
ldap.ScopeBaseObject, ldap.NeverDerefAliases, 1, 0, false,
|
||||||
|
@ -114,18 +118,15 @@ func (conn ldapConn) query(dn string, attrs []string) (bool, *ldap.Entry) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close a LDAP connection
|
// Close a LDAP connection
|
||||||
func (conn ldapConn) close() {
|
func (conn *ldapConn) close() {
|
||||||
conn.log.Trace("Closing LDAP connection")
|
conn.log.WithField("queries", conn.counter).Debug("Closing LDAP connection")
|
||||||
conn.conn.Close()
|
conn.conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read a username from a LDAP record based on a DN.
|
// Read a username from a LDAP record based on a DN.
|
||||||
func (conn ldapConn) readUsername(dn string) (bool, string) {
|
func (conn *ldapConn) readUsername(dn string) (bool, string) {
|
||||||
log := conn.log.WithFields(logrus.Fields{
|
log := conn.log.WithField("dn", dn)
|
||||||
"dn": dn,
|
log.Debug("LDAP username lookup")
|
||||||
"attribute": conn.cfg.UsernameAttr,
|
|
||||||
})
|
|
||||||
log.Trace("Converting DN to username")
|
|
||||||
ok, res := conn.query(dn, []string{conn.cfg.UsernameAttr})
|
ok, res := conn.query(dn, []string{conn.cfg.UsernameAttr})
|
||||||
if !ok {
|
if !ok {
|
||||||
return false, ""
|
return false, ""
|
||||||
|
@ -141,7 +142,7 @@ func (conn ldapConn) readUsername(dn string) (bool, string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract an username from something that may be an username or a DN.
|
// Extract an username from something that may be an username or a DN.
|
||||||
func (conn ldapConn) usernameFromMember(member string) (bool, string) {
|
func (conn *ldapConn) usernameFromMember(member string) (bool, string) {
|
||||||
eqPos := strings.Index(member, "=")
|
eqPos := strings.Index(member, "=")
|
||||||
if eqPos == -1 {
|
if eqPos == -1 {
|
||||||
return true, member
|
return true, member
|
||||||
|
@ -160,8 +161,22 @@ func (conn ldapConn) usernameFromMember(member string) (bool, string) {
|
||||||
return true, member[eqPos+1 : commaPos]
|
return true, member[eqPos+1 : commaPos]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read a username from the cache. If the username is not cached, extract it or request it from
|
||||||
|
// the LDAP.
|
||||||
|
func (conn *ldapConn) getUsername(member string) (bool, string) {
|
||||||
|
name, ok := conn.usernames[member]
|
||||||
|
if ok {
|
||||||
|
return true, name
|
||||||
|
}
|
||||||
|
ok, name = conn.usernameFromMember(member)
|
||||||
|
if ok {
|
||||||
|
conn.usernames[member] = name
|
||||||
|
}
|
||||||
|
return ok, name
|
||||||
|
}
|
||||||
|
|
||||||
// Read the list of members from a LDAP group
|
// Read the list of members from a LDAP group
|
||||||
func (conn ldapConn) getGroupMembers(group string) (members []string) {
|
func (conn *ldapConn) getGroupMembers(group string) (members []string) {
|
||||||
log := conn.log.WithField("group", group)
|
log := conn.log.WithField("group", group)
|
||||||
log.Trace("Obtaining group members")
|
log.Trace("Obtaining group members")
|
||||||
ok, entry := conn.query(group, conn.cfg.MemberFields)
|
ok, entry := conn.query(group, conn.cfg.MemberFields)
|
||||||
|
@ -174,7 +189,7 @@ func (conn ldapConn) getGroupMembers(group string) (members []string) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, value := range values {
|
for _, value := range values {
|
||||||
ok, name := conn.usernameFromMember(value)
|
ok, name := conn.getUsername(value)
|
||||||
if ok {
|
if ok {
|
||||||
members = append(members, name)
|
members = append(members, name)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue