package main
import (
"fmt"
"strings"
"sync"
"github.com/go-ldap/ldap/v3"
"github.com/sirupsen/logrus"
)
//Mux value, this value permits do not have two identicals values in the parallel instances
type StoreAllCN struct {
mu sync.Mutex
cn map[string]struct{}
}
var allNames = StoreAllCN{cn: make(map[string]struct{})}
//Type used for the tests
type attributes struct {
Name string
Data []string
}
type data_DN struct {
DN string
Attributes []attributes
}
type instance struct {
numberUsers, numberGroups int
dataGroups, dataUsers []data_DN
logging *ldap.Conn
}
//Create a new object instance
//With this instance, we can obtain an isolated container where
//we have our users and groups. It allows to run tests in parallel.
func NewInstance(numberUsers, numberGroups int) (*instance, error) {
l, err := Connect()
if err != nil {
return nil, err
}
logging.Level = logrus.InfoLevel
inst := instance{
numberUsers: numberUsers,
numberGroups: numberGroups,
dataGroups: []data_DN{},
dataUsers: []data_DN{},
logging: l,
}
err = inst.createOrganizationnalUnit()
if ldap.IsErrorWithCode(err, uint16(68)) {
logging.Warn("OrganizationnalUnit already created")
err = nil
}
if err != nil {
return nil, err
}
err = inst.CreateGroups()
if err != nil {
return nil, err
}
err = inst.CreateUsers()
if err != nil {
return nil, err
}
return &inst, nil
}
//Part: Created users or groups or OU
func (inst *instance) createOrganizationnalUnit() error {
dn := []string{"ou=groups,dc=deuxfleurs,dc=fr", "ou=users,dc=deuxfleurs,dc=fr"}
attributes := []map[string][]string{{
"description": []string{"OrganizationalUnit qui regroupe tous les groupes"},
"objectclass": []string{"organizationalUnit", "top"},
"ou": []string{"groups"},
"structuralobjectclass": []string{"organizationalUnit"},
},
{
"description": []string{"OrganizationalUnit qui regroupe tous les users"},
"objectclass": []string{"organizationalUnit", "top"},
"ou": []string{"users"},
"structuralobjectclass": []string{"organizationalUnit"},
},
}
for index := range dn {
err := inst.Add_Request(dn[index], attributes[index])
if err != nil {
return err
}
}
return nil
}
//Part: Create User or group
func (inst *instance) CreateUsers() (err error) {
dn := "cn=%s,ou=users,dc=deuxfleurs,dc=fr"
attributes := map[string][]string{
"displayname": {},
"objectclass": {"inetOrgPerson", "organizationalPerson", "person", "top"},
"structuralobjectclass": {"inetOrgPerson"},
}
du, err := inst.create(dn, []string{"displayname"}, inst.numberUsers, attributes, inst.dataUsers)
if err == nil {
inst.dataUsers = du
}
return err
}
func (inst *instance) CreateGroups() error {
dn := "cn=%s,ou=groups,dc=deuxfleurs,dc=fr"
attributes := map[string][]string{
"description": {},
"objectclass": {"groupOfNames", "top"},
"structuralobjectclass": {"groupOfNames"},
}
dg, err := inst.create(dn, []string{"description"}, inst.numberGroups, attributes, inst.dataGroups)
if err == nil {
inst.dataGroups = dg
}
return err
}
//Hard Function: She does:
//- generate an unique name
//- store the Data of each AddRequest in instance struct
//- send AddRequest to Bottin
func (inst *instance) create(dn string, unique_attr []string, number int, attributes map[string][]string, data []data_DN) ([]data_DN, error) {
for i := 0; i < number; i++ {
name := inst.GenerateName()
datDn := data_DN{DN: fmt.Sprintf(dn, name)}
for _, value := range unique_attr {
attributes[value] = []string{name}
}
datDn.Attributes = MapAttToStruct(attributes)
data = append(data, datDn)
err := inst.Add_Request(fmt.Sprintf(dn, name), attributes)
if err != nil {
return nil, err
}
}
return data, nil
}
//Part: clean
func (inst *instance) Clean() error {
err := inst.CleanGroups()
if err != nil {
return err
}
err = inst.CleanUsers()
return err
}
func (inst *instance) CleanUsers() error {
err := inst.clean(inst.dataUsers)
if err != nil {
return err
}
inst.dataUsers = []data_DN{}
return err
}
func (inst *instance) CleanGroups() error {
err := inst.clean(inst.dataGroups)
if err != nil {
return err
}
inst.dataGroups = []data_DN{}
return err
}
func (inst *instance) clean(stock []data_DN) error {
logging.Debugf("Delete %d elements.", len(stock))
for _, value := range stock {
err := inst.Delete_Request(value.DN)
if err != nil {
return err
}
}
return nil
}
//Part: Verify if a data_Dn is a group or an user
func (inst *instance) VerifyUser(user data_DN) (bool, error) {
dn := "ou=users,dc=deuxfleurs,dc=fr"
cn := strings.Split(user.DN, ",")[0]
filter := fmt.Sprintf("(%s)", cn)
res, err := inst.Search_Request(dn, filter, []string{"cn"})
return len(res.Entries) == 1, err
}
func (inst *instance) VerifyGroup(group data_DN) (bool, error) {
dn := "ou=groups,dc=deuxfleurs,dc=fr"
cn := strings.Split(group.DN, ",")[0]
filter := fmt.Sprintf("(%s)", cn)
res, err := inst.Search_Request(dn, filter, []string{"cn"})
return len(res.Entries) == 1, err
}
//Part: Add user in a group
func (inst *instance) AddUserInGroup(user, group data_DN) error {
err := inst.Modify_Request(group.DN, nil, nil, map[string][]string{
"member": {user.DN},
})
return err
}
func (inst *instance) AddUserSliceInGroup(users_cn []string, group_dn string) error {
err := inst.Modify_Request(group_dn, nil, nil, map[string][]string{
"member": users_cn,
})
return err
}
//Part: modify, add, delete data_DN struct
func AddAtt(name string, data []string, dat data_DN) data_DN {
dat.Attributes = append(dat.Attributes, attributes{
Name: name,
Data: data,
})
logging.Debug(fmt.Sprintf("Attributes %s add from %s.", name, dat.DN))
return dat
}
func DelAtt(name string, dat data_DN) data_DN {
for index, value := range dat.Attributes {
if value.Name == name {
dat.Attributes[index] = dat.Attributes[len(dat.Attributes)-1]
//tmp := dat.Attributes[:len(dat.Attributes)-1]
dat.Attributes = []attributes{}
logging.Debugf("Attributes %s delete from %s.", name, dat.DN)
return dat
}
}
logging.Debugf("Can't delete attribute %s from %s.", name, dat.DN)
return dat
}
func ReplaceAtt(name string, data []string, dat data_DN) data_DN {
for index, value := range dat.Attributes {
if value.Name == name {
dat.Attributes[index] = attributes{
Name: name,
Data: data,
}
logging.Debugf("Replace attributes %s from %s succesful..", name, dat.DN)
return dat
}
}
logging.Debugf("Can't replace attributes %s from %s.", name, dat.DN)
return dat
}