providers/ldap: fix inconsistent saving of user flags on failed cached binds (#6096)
* feat: assign invalid pk and check * fix: only set flags if they don't exist * fix: userinfo not being set if data is available * minor cleanup Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> Co-authored-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
parent
04d0bd7fb7
commit
ad81ee2740
|
@ -36,8 +36,15 @@ func (db *DirectBinder) Bind(username string, req *bind.Request) (ldap.LDAPResul
|
||||||
passed, err := fe.Execute()
|
passed, err := fe.Execute()
|
||||||
flags := flags.UserFlags{
|
flags := flags.UserFlags{
|
||||||
Session: fe.GetSession(),
|
Session: fe.GetSession(),
|
||||||
|
UserPk: flags.InvalidUserPK,
|
||||||
}
|
}
|
||||||
|
// only set flags if we don't have flags for this DN yet
|
||||||
|
// as flags are only checked during the bind, we can remember whether a certain DN
|
||||||
|
// can search or not, as if they bind correctly first and then use incorrect credentials
|
||||||
|
// later, they won't get past this step anyways
|
||||||
|
if db.si.GetFlags(req.BindDN) == nil {
|
||||||
db.si.SetFlags(req.BindDN, &flags)
|
db.si.SetFlags(req.BindDN, &flags)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
metrics.RequestsRejected.With(prometheus.Labels{
|
metrics.RequestsRejected.With(prometheus.Labels{
|
||||||
"outpost_name": db.si.GetOutpostName(),
|
"outpost_name": db.si.GetOutpostName(),
|
||||||
|
|
|
@ -6,6 +6,8 @@ import (
|
||||||
"goauthentik.io/api/v3"
|
"goauthentik.io/api/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const InvalidUserPK = -1
|
||||||
|
|
||||||
type UserFlags struct {
|
type UserFlags struct {
|
||||||
UserInfo *api.User
|
UserInfo *api.User
|
||||||
UserPk int32
|
UserPk int32
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"goauthentik.io/api/v3"
|
"goauthentik.io/api/v3"
|
||||||
"goauthentik.io/internal/outpost/ldap/constants"
|
"goauthentik.io/internal/outpost/ldap/constants"
|
||||||
|
"goauthentik.io/internal/outpost/ldap/flags"
|
||||||
"goauthentik.io/internal/outpost/ldap/group"
|
"goauthentik.io/internal/outpost/ldap/group"
|
||||||
"goauthentik.io/internal/outpost/ldap/metrics"
|
"goauthentik.io/internal/outpost/ldap/metrics"
|
||||||
"goauthentik.io/internal/outpost/ldap/search"
|
"goauthentik.io/internal/outpost/ldap/search"
|
||||||
|
@ -73,8 +74,8 @@ func (ms *MemorySearcher) Search(req *search.Request) (ldap.ServerSearchResult,
|
||||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: BindDN %s not in our BaseDN %s", req.BindDN, ms.si.GetBaseDN())
|
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: BindDN %s not in our BaseDN %s", req.BindDN, ms.si.GetBaseDN())
|
||||||
}
|
}
|
||||||
|
|
||||||
flags := ms.si.GetFlags(req.BindDN)
|
flag := ms.si.GetFlags(req.BindDN)
|
||||||
if flags == nil {
|
if flag == nil || (flag.UserInfo == nil && flag.UserPk == flags.InvalidUserPK) {
|
||||||
req.Log().Debug("User info not cached")
|
req.Log().Debug("User info not cached")
|
||||||
metrics.RequestsRejected.With(prometheus.Labels{
|
metrics.RequestsRejected.With(prometheus.Labels{
|
||||||
"outpost_name": ms.si.GetOutpostName(),
|
"outpost_name": ms.si.GetOutpostName(),
|
||||||
|
@ -108,23 +109,23 @@ func (ms *MemorySearcher) Search(req *search.Request) (ldap.ServerSearchResult,
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if needUsers {
|
if needUsers {
|
||||||
if flags.CanSearch {
|
if flag.CanSearch {
|
||||||
users = &ms.users
|
users = &ms.users
|
||||||
} else {
|
} else {
|
||||||
u := make([]api.User, 1)
|
u := make([]api.User, 1)
|
||||||
if flags.UserInfo == nil {
|
if flag.UserInfo == nil {
|
||||||
for i, u := range ms.users {
|
for i, u := range ms.users {
|
||||||
if u.Pk == flags.UserPk {
|
if u.Pk == flag.UserPk {
|
||||||
flags.UserInfo = &ms.users[i]
|
flag.UserInfo = &ms.users[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if flag.UserInfo == nil {
|
||||||
if flags.UserInfo == nil {
|
req.Log().WithField("pk", flag.UserPk).Warning("User with pk is not in local cache")
|
||||||
req.Log().WithField("pk", flags.UserPk).Warning("User with pk is not in local cache")
|
|
||||||
err = fmt.Errorf("failed to get userinfo")
|
err = fmt.Errorf("failed to get userinfo")
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
u[0] = *flags.UserInfo
|
if flag.UserInfo != nil {
|
||||||
|
u[0] = *flag.UserInfo
|
||||||
}
|
}
|
||||||
users = &u
|
users = &u
|
||||||
}
|
}
|
||||||
|
@ -134,17 +135,17 @@ func (ms *MemorySearcher) Search(req *search.Request) (ldap.ServerSearchResult,
|
||||||
groups = make([]*group.LDAPGroup, 0)
|
groups = make([]*group.LDAPGroup, 0)
|
||||||
|
|
||||||
for _, g := range ms.groups {
|
for _, g := range ms.groups {
|
||||||
if flags.CanSearch {
|
if flag.CanSearch {
|
||||||
groups = append(groups, group.FromAPIGroup(g, ms.si))
|
groups = append(groups, group.FromAPIGroup(g, ms.si))
|
||||||
} else {
|
} else {
|
||||||
// If the user cannot search, we're going to only return
|
// If the user cannot search, we're going to only return
|
||||||
// the groups they're in _and_ only return themselves
|
// the groups they're in _and_ only return themselves
|
||||||
// as a member.
|
// as a member.
|
||||||
for _, u := range g.UsersObj {
|
for _, u := range g.UsersObj {
|
||||||
if flags.UserPk == u.Pk {
|
if flag.UserPk == u.Pk {
|
||||||
//TODO: Is there a better way to clone this object?
|
//TODO: Is there a better way to clone this object?
|
||||||
fg := api.NewGroup(g.Pk, g.NumPk, g.Name, g.ParentName, []api.GroupMember{u})
|
fg := api.NewGroup(g.Pk, g.NumPk, g.Name, g.ParentName, []api.GroupMember{u})
|
||||||
fg.SetUsers([]int32{flags.UserPk})
|
fg.SetUsers([]int32{flag.UserPk})
|
||||||
if g.Parent.IsSet() {
|
if g.Parent.IsSet() {
|
||||||
fg.SetParent(*g.Parent.Get())
|
fg.SetParent(*g.Parent.Get())
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue