Initial commit

This commit is contained in:
2019-05-13 09:19:33 +02:00
commit 91feda6471
22 changed files with 946 additions and 0 deletions

12
ldap/provider.go Normal file
View File

@ -0,0 +1,12 @@
package ldap
import "forge.cadoles.com/wpetit/goweb/service"
func ServiceProvider(url string) service.Provider {
srv := &Service{
url: url,
}
return func(ctn *service.Container) (interface{}, error) {
return srv, nil
}
}

65
ldap/search.go Normal file
View File

@ -0,0 +1,65 @@
package ldap
import (
"fmt"
ldap "gopkg.in/ldap.v3"
)
type SearchOptions struct {
BaseDN string
Scope int
DerefAliases int
SizeLimit int
TimeLimit int
TypesOnly bool
Attributes []string
Controls []ldap.Control
}
type SearchOptionFunc func(opts *SearchOptions)
func WithBaseDN(dn string) SearchOptionFunc {
return func(opts *SearchOptions) {
opts.BaseDN = dn
}
}
func WithSizeLimit(sizeLimit int) SearchOptionFunc {
return func(opts *SearchOptions) {
opts.SizeLimit = sizeLimit
}
}
func WithAttributes(attributes ...string) SearchOptionFunc {
return func(opts *SearchOptions) {
opts.Attributes = attributes
}
}
func WithScope(scope int) SearchOptionFunc {
return func(opts *SearchOptions) {
opts.Scope = scope
}
}
func EscapeFilter(pattern string, values ...string) string {
escapedValues := make([]interface{}, len(values))
for i, v := range values {
escapedValues[i] = ldap.EscapeFilter(v)
}
return fmt.Sprintf(pattern, escapedValues...)
}
func defaultSearchOptions() *SearchOptions {
return &SearchOptions{
BaseDN: "",
Scope: ldap.ScopeSingleLevel,
DerefAliases: ldap.NeverDerefAliases,
SizeLimit: 0,
TimeLimit: 0,
TypesOnly: false,
Attributes: make([]string, 0),
Controls: make([]ldap.Control, 0),
}
}

91
ldap/service.go Normal file
View File

@ -0,0 +1,91 @@
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
}
// 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
}