2019-05-13 09:19:33 +02:00
|
|
|
package ldap
|
|
|
|
|
|
|
|
import (
|
|
|
|
"forge.cadoles.com/wpetit/goweb/service"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
ldap "gopkg.in/ldap.v3"
|
|
|
|
)
|
|
|
|
|
|
|
|
const ServiceName service.Name = "ldap"
|
|
|
|
|
|
|
|
type Service struct {
|
|
|
|
url string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) Search(filter string, opts ...SearchOptionFunc) (*ldap.SearchResult, error) {
|
|
|
|
conn, err := s.Connect()
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "error while connecting to ldap server")
|
|
|
|
}
|
|
|
|
defer conn.Close()
|
|
|
|
return s.SearchConn(conn, filter, opts...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) SearchConn(conn *ldap.Conn, filter string, opts ...SearchOptionFunc) (*ldap.SearchResult, error) {
|
|
|
|
options := defaultSearchOptions()
|
|
|
|
for _, optFunc := range opts {
|
|
|
|
optFunc(options)
|
|
|
|
}
|
|
|
|
req := ldap.NewSearchRequest(
|
|
|
|
options.BaseDN,
|
|
|
|
options.Scope,
|
|
|
|
options.DerefAliases,
|
|
|
|
options.SizeLimit,
|
|
|
|
options.TimeLimit,
|
|
|
|
options.TypesOnly,
|
|
|
|
filter,
|
|
|
|
options.Attributes,
|
|
|
|
options.Controls,
|
|
|
|
)
|
|
|
|
result, err := conn.Search(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "error while executing ldap search")
|
|
|
|
}
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) Bind(dn, password string) error {
|
|
|
|
conn, err := s.Connect()
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "error while connecting to ldap server")
|
|
|
|
}
|
|
|
|
defer conn.Close()
|
|
|
|
return s.BindConn(conn, dn, password)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) BindConn(conn *ldap.Conn, dn, password string) error {
|
|
|
|
if err := conn.Bind(dn, password); err != nil {
|
|
|
|
return errors.Wrap(err, "error while executing ldap bind")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) Connect() (*ldap.Conn, error) {
|
|
|
|
conn, err := ldap.DialURL(s.url)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error while dialing ldap url '%s'", s.url)
|
|
|
|
}
|
|
|
|
return conn, err
|
|
|
|
}
|
|
|
|
|
2019-05-22 14:24:53 +02:00
|
|
|
func (s *Service) ModifyPassword(identity, oldPassword, newPassword string) error {
|
|
|
|
conn, err := s.Connect()
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "error while connecting to ldap server")
|
|
|
|
}
|
|
|
|
defer conn.Close()
|
|
|
|
return s.ModifyPasswordConn(conn, identity, oldPassword, newPassword)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) ModifyPasswordConn(conn *ldap.Conn, identity, oldPassword, newPassword string) error {
|
|
|
|
req := ldap.NewPasswordModifyRequest("", oldPassword, newPassword)
|
|
|
|
if _, err := conn.PasswordModify(req); err != nil {
|
|
|
|
return errors.Wrap(err, "error while modifying password")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-05-13 09:19:33 +02:00
|
|
|
// From retrieves the ldap service in the given container
|
|
|
|
func From(container *service.Container) (*Service, error) {
|
|
|
|
service, err := container.Service(ServiceName)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error while retrieving '%s' service", ServiceName)
|
|
|
|
}
|
|
|
|
srv, ok := service.(*Service)
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.Errorf("retrieved service is not a valid '%s' service", ServiceName)
|
|
|
|
}
|
|
|
|
return srv, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Must retrieves the ldap service in the given container or panic otherwise
|
|
|
|
func Must(container *service.Container) *Service {
|
|
|
|
srv, err := From(container)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return srv
|
|
|
|
}
|