providers/ldap: rework Schema and DSE (#5838)

* rework Root DSE

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* always parse filter objectClass

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* start adding LDAP Schema

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add more schema

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* update schema more

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix cn for schema

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* only include main DN in namingContexts

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* use schema from gh

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add description

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add response filtering

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix response filtering

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* don't return rootDSE entry when searching for singleLevel

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* remove currentTime

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix attribute filtering

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* set SINGLE-VALUE

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix numbers

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L
2023-06-08 15:16:40 +02:00
committed by GitHub
parent bf1a363124
commit 54ef88a6fa
13 changed files with 369 additions and 188 deletions

View File

@ -31,7 +31,6 @@ func NewDirectSearcher(si server.LDAPServerInstance) *DirectSearcher {
si: si,
log: log.WithField("logger", "authentik.outpost.ldap.searcher.direct"),
}
ds.log.Info("initialised direct searcher")
return ds
}
@ -39,16 +38,6 @@ func (ds *DirectSearcher) Search(req *search.Request) (ldap.ServerSearchResult,
accsp := sentry.StartSpan(req.Context(), "authentik.providers.ldap.search.check_access")
baseDN := ds.si.GetBaseDN()
filterOC, err := ldap.GetFilterObjectClass(req.Filter)
if err != nil {
metrics.RequestsRejected.With(prometheus.Labels{
"outpost_name": ds.si.GetOutpostName(),
"type": "search",
"reason": "filter_parse_fail",
"app": ds.si.GetAppSlug(),
}).Inc()
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: error parsing filter: %s", req.Filter)
}
if len(req.BindDN) < 1 {
metrics.RequestsRejected.With(prometheus.Labels{
"outpost_name": ds.si.GetOutpostName(),
@ -99,11 +88,17 @@ func (ds *DirectSearcher) Search(req *search.Request) (ldap.ServerSearchResult,
c.GetConfig().AddDefaultHeader("X-authentik-outpost-ldap-query", req.Filter)
scope := req.SearchRequest.Scope
needUsers, needGroups := ds.si.GetNeededObjects(scope, req.BaseDN, filterOC)
needUsers, needGroups := ds.si.GetNeededObjects(scope, req.BaseDN, req.FilterObjectClass)
if scope >= 0 && strings.EqualFold(req.BaseDN, baseDN) {
if utils.IncludeObjectClass(filterOC, constants.GetDomainOCs()) {
entries = append(entries, ds.si.GetBaseEntry())
if utils.IncludeObjectClass(req.FilterObjectClass, constants.GetDomainOCs()) {
rootEntries, _ := ds.SearchBase(req)
// Since `SearchBase` returns entries for the root DN, we need to go through the
// entries and update the base DN
for _, e := range rootEntries.Entries {
e.DN = ds.si.GetBaseDN()
entries = append(entries, e)
}
}
scope -= 1 // Bring it from WholeSubtree to SingleLevel and so on
@ -197,12 +192,12 @@ func (ds *DirectSearcher) Search(req *search.Request) (ldap.ServerSearchResult,
if scope >= 0 && (strings.EqualFold(req.BaseDN, ds.si.GetBaseDN()) || utils.HasSuffixNoCase(req.BaseDN, ds.si.GetBaseUserDN())) {
singleu := utils.HasSuffixNoCase(req.BaseDN, ","+ds.si.GetBaseUserDN())
if !singleu && utils.IncludeObjectClass(filterOC, constants.GetContainerOCs()) {
entries = append(entries, utils.GetContainerEntry(filterOC, ds.si.GetBaseUserDN(), constants.OUUsers))
if !singleu && utils.IncludeObjectClass(req.FilterObjectClass, constants.GetContainerOCs()) {
entries = append(entries, utils.GetContainerEntry(req.FilterObjectClass, ds.si.GetBaseUserDN(), constants.OUUsers))
scope -= 1
}
if scope >= 0 && users != nil && utils.IncludeObjectClass(filterOC, constants.GetUserOCs()) {
if scope >= 0 && users != nil && utils.IncludeObjectClass(req.FilterObjectClass, constants.GetUserOCs()) {
for _, u := range *users {
entry := ds.si.UserEntry(u)
if strings.EqualFold(req.BaseDN, entry.DN) || !singleu {
@ -217,12 +212,12 @@ func (ds *DirectSearcher) Search(req *search.Request) (ldap.ServerSearchResult,
if scope >= 0 && (strings.EqualFold(req.BaseDN, ds.si.GetBaseDN()) || utils.HasSuffixNoCase(req.BaseDN, ds.si.GetBaseGroupDN())) {
singleg := utils.HasSuffixNoCase(req.BaseDN, ","+ds.si.GetBaseGroupDN())
if !singleg && utils.IncludeObjectClass(filterOC, constants.GetContainerOCs()) {
entries = append(entries, utils.GetContainerEntry(filterOC, ds.si.GetBaseGroupDN(), constants.OUGroups))
if !singleg && utils.IncludeObjectClass(req.FilterObjectClass, constants.GetContainerOCs()) {
entries = append(entries, utils.GetContainerEntry(req.FilterObjectClass, ds.si.GetBaseGroupDN(), constants.OUGroups))
scope -= 1
}
if scope >= 0 && groups != nil && utils.IncludeObjectClass(filterOC, constants.GetGroupOCs()) {
if scope >= 0 && groups != nil && utils.IncludeObjectClass(req.FilterObjectClass, constants.GetGroupOCs()) {
for _, g := range *groups {
entry := group.FromAPIGroup(g, ds.si).Entry()
if strings.EqualFold(req.BaseDN, entry.DN) || !singleg {
@ -237,12 +232,12 @@ func (ds *DirectSearcher) Search(req *search.Request) (ldap.ServerSearchResult,
if scope >= 0 && (strings.EqualFold(req.BaseDN, ds.si.GetBaseDN()) || utils.HasSuffixNoCase(req.BaseDN, ds.si.GetBaseVirtualGroupDN())) {
singlevg := utils.HasSuffixNoCase(req.BaseDN, ","+ds.si.GetBaseVirtualGroupDN())
if !singlevg && utils.IncludeObjectClass(filterOC, constants.GetContainerOCs()) {
entries = append(entries, utils.GetContainerEntry(filterOC, ds.si.GetBaseVirtualGroupDN(), constants.OUVirtualGroups))
if !singlevg && utils.IncludeObjectClass(req.FilterObjectClass, constants.GetContainerOCs()) {
entries = append(entries, utils.GetContainerEntry(req.FilterObjectClass, ds.si.GetBaseVirtualGroupDN(), constants.OUVirtualGroups))
scope -= 1
}
if scope >= 0 && users != nil && utils.IncludeObjectClass(filterOC, constants.GetVirtualGroupOCs()) {
if scope >= 0 && users != nil && utils.IncludeObjectClass(req.FilterObjectClass, constants.GetVirtualGroupOCs()) {
for _, u := range *users {
entry := group.FromAPIUser(u, ds.si).Entry()
if strings.EqualFold(req.BaseDN, entry.DN) || !singlevg {