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 } 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 } // 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 }