mirror of
https://github.com/h44z/wg-portal
synced 2025-02-26 05:49:14 +00:00
Merge branch 'asterix11-master'
This commit is contained in:
commit
f2afd4a21c
@ -27,6 +27,7 @@ type Config struct {
|
|||||||
|
|
||||||
LoginFilter string `yaml:"loginFilter" envconfig:"LDAP_LOGIN_FILTER"` // {{login_identifier}} gets replaced with the login email address
|
LoginFilter string `yaml:"loginFilter" envconfig:"LDAP_LOGIN_FILTER"` // {{login_identifier}} gets replaced with the login email address
|
||||||
SyncFilter string `yaml:"syncFilter" envconfig:"LDAP_SYNC_FILTER"`
|
SyncFilter string `yaml:"syncFilter" envconfig:"LDAP_SYNC_FILTER"`
|
||||||
|
SyncGroupFilter string `yaml:"syncGroupFilter" envconfig:"LDAP_SYNC_GROUP_FILTER"`
|
||||||
AdminLdapGroup string `yaml:"adminGroup" envconfig:"LDAP_ADMIN_GROUP"` // Members of this group receive admin rights in WG-Portal
|
AdminLdapGroup string `yaml:"adminGroup" envconfig:"LDAP_ADMIN_GROUP"` // Members of this group receive admin rights in WG-Portal
|
||||||
AdminLdapGroup_ *gldap.DN `yaml:"-"`
|
AdminLdapGroup_ *gldap.DN `yaml:"-"`
|
||||||
EveryoneAdmin bool `yaml:"everyoneAdmin" envconfig:"LDAP_EVERYONE_ADMIN"`
|
EveryoneAdmin bool `yaml:"everyoneAdmin" envconfig:"LDAP_EVERYONE_ADMIN"`
|
||||||
|
@ -8,6 +8,13 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ObjectType int64
|
||||||
|
|
||||||
|
const (
|
||||||
|
Users ObjectType = 1
|
||||||
|
Groups ObjectType = 2
|
||||||
|
)
|
||||||
|
|
||||||
type RawLdapData struct {
|
type RawLdapData struct {
|
||||||
DN string
|
DN string
|
||||||
Attributes map[string]string
|
Attributes map[string]string
|
||||||
@ -69,21 +76,34 @@ func Close(conn *ldap.Conn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindAllUsers(cfg *Config) ([]RawLdapData, error) {
|
func FindAllObjects(cfg *Config, objType ObjectType) ([]RawLdapData, error) {
|
||||||
client, err := Open(cfg)
|
client, err := Open(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithMessage(err, "failed to open ldap connection")
|
return nil, errors.WithMessage(err, "failed to open ldap connection")
|
||||||
}
|
}
|
||||||
defer Close(client)
|
defer Close(client)
|
||||||
|
|
||||||
// Search all users
|
var searchRequest *ldap.SearchRequest
|
||||||
attrs := []string{"dn", cfg.EmailAttribute, cfg.EmailAttribute, cfg.FirstNameAttribute, cfg.LastNameAttribute,
|
var attrs []string
|
||||||
cfg.PhoneAttribute, cfg.GroupMemberAttribute}
|
|
||||||
searchRequest := ldap.NewSearchRequest(
|
if objType == Users {
|
||||||
cfg.BaseDN,
|
// Search all users
|
||||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
attrs = []string{"dn", cfg.EmailAttribute, cfg.EmailAttribute, cfg.FirstNameAttribute, cfg.LastNameAttribute,
|
||||||
cfg.SyncFilter, attrs, nil,
|
cfg.PhoneAttribute, cfg.GroupMemberAttribute}
|
||||||
)
|
searchRequest = ldap.NewSearchRequest(
|
||||||
|
cfg.BaseDN,
|
||||||
|
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||||
|
cfg.SyncFilter, attrs, nil,
|
||||||
|
)
|
||||||
|
} else if objType == Groups {
|
||||||
|
// Search all groups
|
||||||
|
attrs = []string{"dn", cfg.GroupMemberAttribute}
|
||||||
|
searchRequest = ldap.NewSearchRequest(
|
||||||
|
cfg.BaseDN,
|
||||||
|
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||||
|
cfg.SyncGroupFilter, attrs, nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
sr, err := client.Search(searchRequest)
|
sr, err := client.Search(searchRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -114,6 +114,7 @@ func NewConfig() *Config {
|
|||||||
cfg.LDAP.AdminLdapGroup = "CN=WireGuardAdmins,OU=_O_IT,DC=COMPANY,DC=LOCAL"
|
cfg.LDAP.AdminLdapGroup = "CN=WireGuardAdmins,OU=_O_IT,DC=COMPANY,DC=LOCAL"
|
||||||
cfg.LDAP.LoginFilter = "(&(objectClass=organizationalPerson)(mail={{login_identifier}})(!userAccountControl:1.2.840.113556.1.4.803:=2))"
|
cfg.LDAP.LoginFilter = "(&(objectClass=organizationalPerson)(mail={{login_identifier}})(!userAccountControl:1.2.840.113556.1.4.803:=2))"
|
||||||
cfg.LDAP.SyncFilter = "(&(objectClass=organizationalPerson)(!userAccountControl:1.2.840.113556.1.4.803:=2)(mail=*))"
|
cfg.LDAP.SyncFilter = "(&(objectClass=organizationalPerson)(!userAccountControl:1.2.840.113556.1.4.803:=2)(mail=*))"
|
||||||
|
cfg.LDAP.SyncGroupFilter = "(&(objectClass=group))"
|
||||||
|
|
||||||
cfg.WG.DeviceNames = []string{"wg0"}
|
cfg.WG.DeviceNames = []string{"wg0"}
|
||||||
cfg.WG.DefaultDeviceName = "wg0"
|
cfg.WG.DefaultDeviceName = "wg0"
|
||||||
|
@ -4,20 +4,36 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
gldap "github.com/go-ldap/ldap/v3"
|
||||||
"github.com/h44z/wg-portal/internal/wireguard"
|
"github.com/h44z/wg-portal/internal/wireguard"
|
||||||
|
|
||||||
"github.com/h44z/wg-portal/internal/ldap"
|
"github.com/h44z/wg-portal/internal/ldap"
|
||||||
"github.com/h44z/wg-portal/internal/users"
|
"github.com/h44z/wg-portal/internal/users"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
gldap "github.com/go-ldap/ldap/v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) SyncLdapWithUserDatabase() {
|
func (s *Server) SyncLdapWithUserDatabase() {
|
||||||
logrus.Info("starting ldap user synchronization...")
|
logrus.Info("starting ldap user synchronization...")
|
||||||
|
|
||||||
running := true
|
running := true
|
||||||
for running {
|
for running {
|
||||||
|
// Main work here
|
||||||
|
logrus.Trace("syncing ldap users to database...")
|
||||||
|
ldapUsers, err := ldap.FindAllObjects(&s.config.LDAP, ldap.Users)
|
||||||
|
ldapGroups, errGroups := ldap.FindAllObjects(&s.config.LDAP, ldap.Groups)
|
||||||
|
if err != nil && errGroups != nil {
|
||||||
|
logrus.Errorf("failed to fetch users from ldap: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logrus.Tracef("found %d users in ldap", len(ldapUsers))
|
||||||
|
|
||||||
|
// Update existing LDAP users
|
||||||
|
s.updateLdapUsers(ldapUsers, ldapGroups)
|
||||||
|
|
||||||
|
// Disable missing LDAP users
|
||||||
|
s.disableMissingLdapUsers(ldapUsers)
|
||||||
|
|
||||||
// Select blocks until one of the cases happens
|
// Select blocks until one of the cases happens
|
||||||
select {
|
select {
|
||||||
case <-time.After(1 * time.Minute):
|
case <-time.After(1 * time.Minute):
|
||||||
@ -27,42 +43,44 @@ func (s *Server) SyncLdapWithUserDatabase() {
|
|||||||
running = false
|
running = false
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main work here
|
|
||||||
logrus.Trace("syncing ldap users to database...")
|
|
||||||
ldapUsers, err := ldap.FindAllUsers(&s.config.LDAP)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("failed to fetch users from ldap: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
logrus.Tracef("found %d users in ldap", len(ldapUsers))
|
|
||||||
|
|
||||||
// Update existing LDAP users
|
|
||||||
s.updateLdapUsers(ldapUsers)
|
|
||||||
|
|
||||||
// Disable missing LDAP users
|
|
||||||
s.disableMissingLdapUsers(ldapUsers)
|
|
||||||
}
|
}
|
||||||
logrus.Info("ldap user synchronization stopped")
|
logrus.Info("ldap user synchronization stopped")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Server) userIsInAdminGroup(ldapData *ldap.RawLdapData) bool {
|
func (s Server) userIsInAdminGroup(ldapData *ldap.RawLdapData, ldapGroupData []ldap.RawLdapData, layer int) bool {
|
||||||
if s.config.LDAP.EveryoneAdmin {
|
if s.config.LDAP.EveryoneAdmin {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if s.config.LDAP.AdminLdapGroup_ == nil {
|
if s.config.LDAP.AdminLdapGroup_ == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
//fmt.Printf("%+v\n", ldapData.Attributes)
|
||||||
|
var prefix string
|
||||||
|
for i := 0; i < layer; i++ {
|
||||||
|
prefix += "+"
|
||||||
|
}
|
||||||
|
logrus.Tracef("%s Group layer: %d\n", prefix, layer)
|
||||||
for _, group := range ldapData.RawAttributes[s.config.LDAP.GroupMemberAttribute] {
|
for _, group := range ldapData.RawAttributes[s.config.LDAP.GroupMemberAttribute] {
|
||||||
|
logrus.Tracef("%s%s\n", prefix, string(group))
|
||||||
var dn, _ = gldap.ParseDN(string(group))
|
var dn, _ = gldap.ParseDN(string(group))
|
||||||
if s.config.LDAP.AdminLdapGroup_.Equal(dn) {
|
if s.config.LDAP.AdminLdapGroup_.Equal(dn) {
|
||||||
|
logrus.Tracef("%sFOUND: %s\n", prefix, string(group))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
for _, group2 := range ldapGroupData {
|
||||||
|
if group2.DN == string(group) {
|
||||||
|
logrus.Tracef("%sChecking nested: %s\n", prefix, group2.DN)
|
||||||
|
isAdmin := s.userIsInAdminGroup(&group2, ldapGroupData, layer+1)
|
||||||
|
if isAdmin {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Server) userChangedInLdap(user *users.User, ldapData *ldap.RawLdapData) bool {
|
func (s Server) userChangedInLdap(user *users.User, ldapData *ldap.RawLdapData, ldapGroupData []ldap.RawLdapData) bool {
|
||||||
if user.Firstname != ldapData.Attributes[s.config.LDAP.FirstNameAttribute] {
|
if user.Firstname != ldapData.Attributes[s.config.LDAP.FirstNameAttribute] {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -83,7 +101,7 @@ func (s Server) userChangedInLdap(user *users.User, ldapData *ldap.RawLdapData)
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.IsAdmin != s.userIsInAdminGroup(ldapData) {
|
if user.IsAdmin != s.userIsInAdminGroup(ldapData, ldapGroupData, 0) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +144,7 @@ func (s *Server) disableMissingLdapUsers(ldapUsers []ldap.RawLdapData) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) updateLdapUsers(ldapUsers []ldap.RawLdapData) {
|
func (s *Server) updateLdapUsers(ldapUsers []ldap.RawLdapData, ldapGroups []ldap.RawLdapData) {
|
||||||
for i := range ldapUsers {
|
for i := range ldapUsers {
|
||||||
if ldapUsers[i].Attributes[s.config.LDAP.EmailAttribute] == "" {
|
if ldapUsers[i].Attributes[s.config.LDAP.EmailAttribute] == "" {
|
||||||
logrus.Tracef("skipping sync of %s, empty email attribute", ldapUsers[i].DN)
|
logrus.Tracef("skipping sync of %s, empty email attribute", ldapUsers[i].DN)
|
||||||
@ -152,13 +170,13 @@ func (s *Server) updateLdapUsers(ldapUsers []ldap.RawLdapData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sync attributes from ldap
|
// Sync attributes from ldap
|
||||||
if s.userChangedInLdap(user, &ldapUsers[i]) {
|
if s.userChangedInLdap(user, &ldapUsers[i], ldapGroups) {
|
||||||
logrus.Debugf("updating ldap user %s", user.Email)
|
logrus.Debugf("updating ldap user %s", user.Email)
|
||||||
user.Firstname = ldapUsers[i].Attributes[s.config.LDAP.FirstNameAttribute]
|
user.Firstname = ldapUsers[i].Attributes[s.config.LDAP.FirstNameAttribute]
|
||||||
user.Lastname = ldapUsers[i].Attributes[s.config.LDAP.LastNameAttribute]
|
user.Lastname = ldapUsers[i].Attributes[s.config.LDAP.LastNameAttribute]
|
||||||
user.Email = ldapUsers[i].Attributes[s.config.LDAP.EmailAttribute]
|
user.Email = ldapUsers[i].Attributes[s.config.LDAP.EmailAttribute]
|
||||||
user.Phone = ldapUsers[i].Attributes[s.config.LDAP.PhoneAttribute]
|
user.Phone = ldapUsers[i].Attributes[s.config.LDAP.PhoneAttribute]
|
||||||
user.IsAdmin = s.userIsInAdminGroup(&ldapUsers[i])
|
user.IsAdmin = s.userIsInAdminGroup(&ldapUsers[i], ldapGroups, 0)
|
||||||
user.Source = users.UserSourceLdap
|
user.Source = users.UserSourceLdap
|
||||||
user.DeletedAt = gorm.DeletedAt{} // Not deleted
|
user.DeletedAt = gorm.DeletedAt{} // Not deleted
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user