outpost/ldap: check access based on Group Membership
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
d84d7c26ca
commit
32934fcd38
|
@ -37,7 +37,6 @@ from authentik.outposts.docker_tls import DockerInlineTLS
|
|||
OUR_VERSION = parse(__version__)
|
||||
OUTPOST_HELLO_INTERVAL = 10
|
||||
LOGGER = get_logger()
|
||||
USER_ATTRIBUTE_LDAP_CAN_SEARCH = "goauthentik.io/ldap/can-search"
|
||||
|
||||
|
||||
class ServiceConnectionInvalid(SentryIgnoredException):
|
||||
|
@ -322,21 +321,13 @@ class Outpost(models.Model):
|
|||
"""Username for service user"""
|
||||
return f"ak-outpost-{self.uuid.hex}"
|
||||
|
||||
@property
|
||||
def user_attributes(self) -> dict[str, Any]:
|
||||
"""Attributes that will be set on the service account"""
|
||||
attrs = {USER_ATTRIBUTE_SA: True}
|
||||
if self.type == OutpostType.LDAP:
|
||||
attrs[USER_ATTRIBUTE_LDAP_CAN_SEARCH] = True
|
||||
return attrs
|
||||
|
||||
@property
|
||||
def user(self) -> User:
|
||||
"""Get/create user with access to all required objects"""
|
||||
users = User.objects.filter(username=self.user_identifier)
|
||||
if not users.exists():
|
||||
user: User = User.objects.create(username=self.user_identifier)
|
||||
user.attributes = self.user_attributes
|
||||
user.attributes[USER_ATTRIBUTE_SA] = True
|
||||
user.set_unusable_password()
|
||||
user.save()
|
||||
else:
|
||||
|
|
|
@ -4,8 +4,8 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/outpost/pkg/client/outposts"
|
||||
)
|
||||
|
@ -28,10 +28,9 @@ func (ls *LDAPServer) Refresh() error {
|
|||
UserDN: userDN,
|
||||
appSlug: *provider.ApplicationSlug,
|
||||
flowSlug: *provider.BindFlowSlug,
|
||||
searchAllowedGroups: []*strfmt.UUID{provider.SearchGroup},
|
||||
s: ls,
|
||||
log: log.WithField("logger", "authentik.outpost.ldap").WithField("provider", provider.Name),
|
||||
boundUsersMutex: sync.RWMutex{},
|
||||
boundUsers: make(map[string]UserFlags),
|
||||
}
|
||||
}
|
||||
ls.providers = providers
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/nmcclain/ldap"
|
||||
"goauthentik.io/outpost/pkg/client/core"
|
||||
"goauthentik.io/outpost/pkg/client/flows"
|
||||
"goauthentik.io/outpost/pkg/models"
|
||||
)
|
||||
|
||||
const ContextUserKey = "ak_user"
|
||||
|
@ -88,13 +89,25 @@ func (pi *ProviderInstance) Bind(username string, bindPW string, conn net.Conn)
|
|||
pi.boundUsersMutex.Lock()
|
||||
pi.boundUsers[username] = UserFlags{
|
||||
UserInfo: userInfo.Payload.User,
|
||||
CanSearch: userInfo.Payload.User.Attributes.(map[string]bool)["goauthentik.io/ldap/can-search"],
|
||||
CanSearch: pi.SearchAccessCheck(userInfo.Payload.User),
|
||||
}
|
||||
pi.boundUsersMutex.Unlock()
|
||||
pi.delayDeleteUserInfo(username)
|
||||
return ldap.LDAPResultSuccess, nil
|
||||
}
|
||||
|
||||
// SearchAccessCheck Check if the current user is allowed to search
|
||||
func (pi *ProviderInstance) SearchAccessCheck(user *models.User) bool {
|
||||
for _, group := range user.Groups {
|
||||
for _, allowedGroup := range pi.searchAllowedGroups {
|
||||
if &group.Pk == allowedGroup {
|
||||
pi.log.WithField("group", group.Name).Info("Allowed access to search")
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
func (pi *ProviderInstance) delayDeleteUserInfo(dn string) {
|
||||
ticker := time.NewTicker(30 * time.Second)
|
||||
quit := make(chan struct{})
|
||||
|
|
|
@ -3,6 +3,7 @@ package ldap
|
|||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/outpost/pkg/ak"
|
||||
"goauthentik.io/outpost/pkg/models"
|
||||
|
@ -24,6 +25,7 @@ type ProviderInstance struct {
|
|||
s *LDAPServer
|
||||
log *log.Entry
|
||||
|
||||
searchAllowedGroups []*strfmt.UUID
|
||||
boundUsersMutex sync.RWMutex
|
||||
boundUsers map[string]UserFlags
|
||||
}
|
||||
|
|
Reference in a new issue