Skip to content

Commit

Permalink
Add logger interface to client (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
dlampsi committed Mar 1, 2021
1 parent d46d759 commit 7a8f178
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 12 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,15 @@ if err := cl.Connect(); err != nil {
}
```

### Custom logger

You can specifiy custom logger for client. Logger must implement `Logger` interface. Provide logger during client init:

```go
cl := New(cfg, adc.WithLogger(myCustomLogger))
```


## Contributing

1. Create new PR from `main` branch
Expand Down
16 changes: 14 additions & 2 deletions adc.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ package adc
import (
"crypto/tls"
"errors"
"fmt"
"strings"
"time"

Expand All @@ -19,6 +18,7 @@ const (
type Client struct {
cfg *Config
ldapCl ldap.Client
logger Logger
}

// Creates new client and populate provided config and options.
Expand All @@ -29,6 +29,7 @@ func New(cfg *Config, opts ...Option) *Client {
Users: DefaultUsersConfigs(),
Groups: DefaultGroupsConfigs(),
},
logger: &nopLogger{},
}

// Apply options
Expand All @@ -42,13 +43,24 @@ func New(cfg *Config, opts ...Option) *Client {
return cl
}

// Client logger interface.
type Logger interface {
Debug(args ...interface{})
Debugf(template string, args ...interface{})
}

type Option func(*Client)

// Specifies ldap client for AD client.
func WithLdapClient(l ldap.Client) Option {
return func(cl *Client) { cl.ldapCl = l }
}

// Specifies custom logger for client.
func WithLogger(l Logger) Option {
return func(cl *Client) { cl.logger = l }
}

func (cl *Client) Config() *Config {
return cl.cfg
}
Expand All @@ -57,7 +69,7 @@ func (cl *Client) Config() *Config {
func (cl *Client) Connect() error {
conn, err := cl.connect(cl.cfg.Bind)
if err != nil {
return fmt.Errorf("can't connect: %s", err.Error())
return err
}
cl.ldapCl = conn
return nil
Expand Down
46 changes: 42 additions & 4 deletions group.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ func (g *Group) MembersId() []string {
return result
}

// Adds provided accounts IDs to provided group members. Returns number of addedd accounts.
func (cl *Client) AddGroupMembers(groupId string, membersIds ...string) (int, error) {
group, err := cl.GetGroup(&GetGroupequest{Id: groupId})
if err != nil {
Expand All @@ -158,27 +159,41 @@ func (cl *Client) AddGroupMembers(groupId string, membersIds ...string) (int, er
}

ch := make(chan string, len(membersIds))
errCh := make(chan error, len(membersIds))
wg := &sync.WaitGroup{}

for _, id := range membersIds {
wg.Add(1)
go func(userId string, ch chan<- string, wg *sync.WaitGroup) {
go func(userId string, ch chan<- string, errCh chan<- error, wg *sync.WaitGroup) {
defer wg.Done()
user, err := cl.GetUser(&GetUserRequest{Id: userId})
if err != nil {
errCh <- fmt.Errorf("can't get account '%s': %s", userId, err.Error())
return
}
if user == nil {
cl.logger.Debugf("Account '%s' being added to '%s' wasn't found",
userId, groupId)
return
}
if user.IsGroupMember(groupId) {
cl.logger.Debugf("The adding account '%s' is already a member of the group '%s'",
userId, groupId)
return
}
ch <- user.DN
}(id, ch, wg)
}(id, ch, errCh, wg)
}
wg.Wait()
close(errCh)
close(ch)

for err := range errCh {
if err != nil {
return 0, err
}
}

var toAdd []string
for dn := range ch {
toAdd = append(toAdd, dn)
Expand All @@ -188,6 +203,10 @@ func (cl *Client) AddGroupMembers(groupId string, membersIds ...string) (int, er
}

newMembers := popAddGroupMembers(group, toAdd)

cl.logger.Debugf("Adding new group members to '%s'; Old count: %d; New count: %d",
groupId, len(group.MembersId()), len(newMembers))

if err := cl.updateAttribute(group.DN, "member", newMembers); err != nil {
return 0, err
}
Expand All @@ -205,6 +224,7 @@ func popAddGroupMembers(g *Group, toAdd []string) []string {
return result
}

// Deletes provided accounts IDs from provided group members. Returns number of deleted from group members.
func (cl *Client) DeleteGroupMembers(groupId string, membersIds ...string) (int, error) {
group, err := cl.GetGroup(&GetGroupequest{Id: groupId})
if err != nil {
Expand All @@ -215,27 +235,41 @@ func (cl *Client) DeleteGroupMembers(groupId string, membersIds ...string) (int,
}

ch := make(chan string, len(membersIds))
errCh := make(chan error, len(membersIds))
wg := &sync.WaitGroup{}

for _, id := range membersIds {
wg.Add(1)
go func(userId string, ch chan<- string, wg *sync.WaitGroup) {
go func(userId string, ch chan<- string, errCh chan<- error, wg *sync.WaitGroup) {
defer wg.Done()
user, err := cl.GetUser(&GetUserRequest{Id: userId})
if err != nil {
errCh <- fmt.Errorf("can't get account '%s': %s", userId, err.Error())
return
}
if user == nil {
cl.logger.Debugf("Account '%s' being deleted from '%s' wasn't found",
userId, groupId)
return
}
if !user.IsGroupMember(groupId) {
cl.logger.Debugf("The deleting account '%s' already isn't a member of the group '%s'",
userId, groupId)
return
}
ch <- user.DN
}(id, ch, wg)
}(id, ch, errCh, wg)
}
wg.Wait()
close(errCh)
close(ch)

for err := range errCh {
if err != nil {
return 0, err
}
}

var toDel []string
for dn := range ch {
toDel = append(toDel, dn)
Expand All @@ -245,6 +279,10 @@ func (cl *Client) DeleteGroupMembers(groupId string, membersIds ...string) (int,
}

newMembers := popDelGroupMembers(group, toDel)

cl.logger.Debugf("Deleting members from group '%s'; Old count: %d; New count: %d",
groupId, len(group.MembersId()), len(newMembers))

if err := cl.updateAttribute(group.DN, "member", newMembers); err != nil {
return 0, err
}
Expand Down
16 changes: 10 additions & 6 deletions group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,16 @@ func Test_AddGroupMembers(t *testing.T) {
added, err := cl.AddGroupMembers("group1", "userFake")
require.NoError(t, err)
require.Equal(t, 0, added)

// Error user
added, err = cl.AddGroupMembers("group1", "user2")
require.NoError(t, err)
require.Equal(t, 0, added)
_, err = cl.AddGroupMembers("group1", "user2")
require.Error(t, err)

// Already member user
added, err = cl.AddGroupMembers("group1", "user1")
require.NoError(t, err)
require.Equal(t, 0, added)

// Ok user
added, err = cl.AddGroupMembers("group1", "user3")
require.NoError(t, err)
Expand Down Expand Up @@ -152,14 +154,16 @@ func Test_DeleteGroupMembers(t *testing.T) {
deleted, err := cl.DeleteGroupMembers("group1", "userFake")
require.NoError(t, err)
require.Equal(t, 0, deleted)

// Error user
deleted, err = cl.DeleteGroupMembers("group1", "user2")
require.NoError(t, err)
require.Equal(t, 0, deleted)
_, err = cl.DeleteGroupMembers("group1", "user2")
require.Error(t, err)

// Already not member user
deleted, err = cl.DeleteGroupMembers("group1", "user3")
require.NoError(t, err)
require.Equal(t, 0, deleted)

// Ok user
deleted, err = cl.DeleteGroupMembers("group1", "user1")
require.NoError(t, err)
Expand Down
6 changes: 6 additions & 0 deletions mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import (
"github.com/go-ldap/ldap/v3"
)

// Dummy not operational logger.
type nopLogger struct{}

func (l *nopLogger) Debug(args ...interface{}) {}
func (l *nopLogger) Debugf(template string, args ...interface{}) {}

// Mock client. Implements ldap client interface.
type mockClient struct {
}
Expand Down

0 comments on commit 7a8f178

Please sign in to comment.