This repository has been archived on 2024-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
authentik/internal/outpost/ldap/search_route.go

85 lines
2.9 KiB
Go
Raw Normal View History

package ldap
import (
"strings"
"beryju.io/ldap"
goldap "github.com/go-ldap/ldap/v3"
"goauthentik.io/internal/outpost/ldap/constants"
"goauthentik.io/internal/outpost/ldap/search"
)
func (ls *LDAPServer) providerForRequest(req *search.Request) *ProviderInstance {
parsedBaseDN, err := goldap.ParseDN(strings.ToLower(req.BaseDN))
if err != nil {
req.Log().WithError(err).Info("failed to parse base DN")
return nil
}
parsedBindDN, err := goldap.ParseDN(strings.ToLower(req.BindDN))
if err != nil {
req.Log().WithError(err).Info("failed to parse bind DN")
return nil
}
var selectedProvider *ProviderInstance
longestMatch := 0
for _, provider := range ls.providers {
providerBase, _ := goldap.ParseDN(strings.ToLower(provider.BaseDN))
// Try to match the provider primarily based on the search request's base DN
baseDNMatches := providerBase.AncestorOf(parsedBaseDN) || providerBase.Equal(parsedBaseDN)
// But also try to match the provider based on the bind DN
bindDNMatches := providerBase.AncestorOf(parsedBindDN) || providerBase.Equal(parsedBindDN)
if baseDNMatches || bindDNMatches {
// Only select the provider if it's a more precise match than previously
if len(provider.BaseDN) > longestMatch {
req.Log().WithField("provider", provider.BaseDN).Trace("selecting provider for search request")
selectedProvider = provider
longestMatch = len(provider.BaseDN)
}
}
}
return selectedProvider
}
func (ls *LDAPServer) searchRoute(req *search.Request, pi *ProviderInstance) (ldap.ServerSearchResult, error) {
// Route based on the base DN
if len(req.BaseDN) == 0 {
req.Log().Trace("routing to base")
return pi.searcher.SearchBase(req)
}
if strings.EqualFold(req.BaseDN, "cn=subschema") || req.FilterObjectClass == constants.OCSubSchema {
req.Log().Trace("routing to subschema")
return pi.searcher.SearchSubschema(req)
}
req.Log().Trace("routing to default")
return pi.searcher.Search(req)
}
func (ls *LDAPServer) filterResultAttributes(req *search.Request, result ldap.ServerSearchResult) ldap.ServerSearchResult {
allowedAttributes := []string{}
if len(req.Attributes) == 1 && req.Attributes[0] == constants.SearchAttributeNone {
allowedAttributes = []string{"objectClass"}
}
if len(req.Attributes) > 0 {
// Only strictly filter allowed attributes if we haven't already narrowed the attributes
// down
if len(allowedAttributes) < 1 {
allowedAttributes = req.Attributes
}
// Filter LDAP returned attributes by search requested attributes, taking "1.1"
// into consideration
return req.FilterLDAPAttributes(result, func(attr *ldap.EntryAttribute) bool {
for _, allowed := range allowedAttributes {
if allowed == constants.SearchAttributeAllUser ||
allowed == constants.SearchAttributeAllOperational {
return true
}
if strings.EqualFold(allowed, attr.Name) {
return true
}
}
return false
})
}
return result
}