Exclude users from google workspace bridge
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
@@ -28,10 +28,11 @@ import (
|
||||
|
||||
type (
|
||||
Bridge struct {
|
||||
provider provider.Provider
|
||||
scimClient *scimclient.Client
|
||||
forceUpdate bool
|
||||
dryRun bool
|
||||
provider provider.Provider
|
||||
scimClient *scimclient.Client
|
||||
excludedUserNames []string
|
||||
forceUpdate bool
|
||||
dryRun bool
|
||||
}
|
||||
|
||||
Option func(*Bridge)
|
||||
@@ -49,6 +50,12 @@ func WithForceUpdate(forceUpdate bool) Option {
|
||||
}
|
||||
}
|
||||
|
||||
func WithExcludedUserNames(excludedUserNames []string) Option {
|
||||
return func(s *Bridge) {
|
||||
s.excludedUserNames = excludedUserNames
|
||||
}
|
||||
}
|
||||
|
||||
func NewBridge(provider provider.Provider, scimClient *scimclient.Client, opts ...Option) *Bridge {
|
||||
s := &Bridge{
|
||||
provider: provider,
|
||||
@@ -62,15 +69,15 @@ func NewBridge(provider provider.Provider, scimClient *scimclient.Client, opts .
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Bridge) Run(ctx context.Context) (created, updated, deactivated, skipped int, err error) {
|
||||
func (s *Bridge) Run(ctx context.Context) (created, updated, deleted, deactivated, skipped int, err error) {
|
||||
providerUsers, err := s.provider.ListUsers(ctx)
|
||||
if err != nil {
|
||||
return 0, 0, 0, 0, fmt.Errorf("cannot list provider users: %w", err)
|
||||
return 0, 0, 0, 0, 0, fmt.Errorf("cannot list provider users: %w", err)
|
||||
}
|
||||
|
||||
scimUsers, err := s.scimClient.ListUsers(ctx)
|
||||
if err != nil {
|
||||
return 0, 0, 0, 0, fmt.Errorf("cannot list scim users: %w", err)
|
||||
return 0, 0, 0, 0, 0, fmt.Errorf("cannot list scim users: %w", err)
|
||||
}
|
||||
|
||||
scimUsersByEmail := make(map[string]*scimclient.User)
|
||||
@@ -125,6 +132,17 @@ func (s *Bridge) Run(ctx context.Context) (created, updated, deactivated, skippe
|
||||
continue
|
||||
}
|
||||
|
||||
if s.isExcluded(email) {
|
||||
if !s.dryRun {
|
||||
if err := s.scimClient.DeleteUser(ctx, scimUser.ID); err != nil {
|
||||
errs = append(errs, fmt.Errorf("cannot delete user %q: %w", email, err))
|
||||
continue
|
||||
}
|
||||
}
|
||||
deleted++
|
||||
continue
|
||||
}
|
||||
|
||||
if !scimUser.Active {
|
||||
continue
|
||||
}
|
||||
@@ -138,5 +156,14 @@ func (s *Bridge) Run(ctx context.Context) (created, updated, deactivated, skippe
|
||||
deactivated++
|
||||
}
|
||||
|
||||
return created, updated, deactivated, skipped, errors.Join(errs...)
|
||||
return created, updated, deleted, deactivated, skipped, errors.Join(errs...)
|
||||
}
|
||||
|
||||
func (s *Bridge) isExcluded(email string) bool {
|
||||
for _, excluded := range s.excludedUserNames {
|
||||
if strings.EqualFold(excluded, email) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -248,6 +248,29 @@ func (c *Client) DeactivateUser(ctx context.Context, userID string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) DeleteUser(ctx context.Context, userID string) error {
|
||||
reqURL := fmt.Sprintf("%s/Users/%s", c.endpoint, url.PathEscape(userID))
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodDelete, reqURL, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot create request: %w", err)
|
||||
}
|
||||
|
||||
c.setHeaders(req)
|
||||
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot delete user: %w", err)
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusNotFound {
|
||||
respBody, _ := io.ReadAll(resp.Body)
|
||||
return fmt.Errorf("SCIM API error: status %d, body: %s", resp.StatusCode, string(respBody))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) setHeaders(req *http.Request) {
|
||||
req.Header.Set("Authorization", "Bearer "+c.token)
|
||||
req.Header.Set("Accept", "application/scim+json")
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
admin "google.golang.org/api/admin/directory/v1"
|
||||
"google.golang.org/api/option"
|
||||
@@ -31,12 +32,14 @@ import (
|
||||
var _ provider.Provider = (*Provider)(nil)
|
||||
|
||||
type Provider struct {
|
||||
httpClient *http.Client
|
||||
httpClient *http.Client
|
||||
excludedUserNames []string
|
||||
}
|
||||
|
||||
func New(httpClient *http.Client) *Provider {
|
||||
func New(httpClient *http.Client, excludedUserNames []string) *Provider {
|
||||
return &Provider{
|
||||
httpClient: httpClient,
|
||||
httpClient: httpClient,
|
||||
excludedUserNames: excludedUserNames,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +47,16 @@ func (p *Provider) Name() string {
|
||||
return "google-workspace"
|
||||
}
|
||||
|
||||
func (p *Provider) isExcluded(email string) bool {
|
||||
emailLower := strings.ToLower(email)
|
||||
for _, excluded := range p.excludedUserNames {
|
||||
if strings.ToLower(excluded) == emailLower {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *Provider) ListUsers(ctx context.Context) (scimclient.Users, error) {
|
||||
adminService, err := admin.NewService(ctx, option.WithHTTPClient(p.httpClient))
|
||||
if err != nil {
|
||||
@@ -65,6 +78,10 @@ func (p *Provider) ListUsers(ctx context.Context) (scimclient.Users, error) {
|
||||
}
|
||||
|
||||
for _, u := range resp.Users {
|
||||
if p.isExcluded(u.PrimaryEmail) {
|
||||
continue
|
||||
}
|
||||
|
||||
allUsers = append(
|
||||
allUsers,
|
||||
scimclient.User{
|
||||
|
||||
Reference in New Issue
Block a user