Fix Microsoft 365 SCIM bridge connection and scope
Add the missing MICROSOFT_365 value to the connector_provider enum so the connector loader stops failing with SQLSTATE 22P02. Scope each Identity Provider card to its own SCIMBridge type so connecting Microsoft 365 no longer marks Google Workspace as connected (and vice versa). Filter Microsoft Graph /users to userType eq 'Member' so the bridge only syncs home-tenant members and skips B2B guest accounts that were polluting the synced People list. Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
@@ -23,6 +23,8 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
scimclient "go.probo.inc/probo/pkg/iam/scim/bridge/client"
|
||||
@@ -47,6 +49,11 @@ const graphPageSize = 999
|
||||
// API misbehaves.
|
||||
const graphMaxPages = 1000
|
||||
|
||||
// graphMemberFilter restricts /users to home-tenant members and
|
||||
// excludes B2B guest users invited from external tenants — those guests
|
||||
// should not be provisioned into the connected organization.
|
||||
const graphMemberFilter = "userType eq 'Member'"
|
||||
|
||||
var _ provider.Provider = (*Provider)(nil)
|
||||
|
||||
type Provider struct {
|
||||
@@ -102,16 +109,14 @@ type graphUsersResponse struct {
|
||||
}
|
||||
|
||||
func (p *Provider) ListUsers(ctx context.Context) (scimclient.Users, error) {
|
||||
url := fmt.Sprintf(
|
||||
"%s/users?$select=%s&$top=%d",
|
||||
graphBaseURL,
|
||||
graphUserSelect,
|
||||
graphPageSize,
|
||||
)
|
||||
endpoint, err := buildListUsersURL()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot build list users URL: %w", err)
|
||||
}
|
||||
|
||||
var allUsers scimclient.Users
|
||||
for range graphMaxPages {
|
||||
users, next, err := p.fetchPage(ctx, url)
|
||||
users, next, err := p.fetchPage(ctx, endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -146,14 +151,29 @@ func (p *Provider) ListUsers(ctx context.Context) (scimclient.Users, error) {
|
||||
if next == "" {
|
||||
return allUsers, nil
|
||||
}
|
||||
url = next
|
||||
endpoint = next
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("microsoft 365: pagination limit of %d pages reached", graphMaxPages)
|
||||
}
|
||||
|
||||
func (p *Provider) fetchPage(ctx context.Context, url string) ([]graphUser, string, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
func buildListUsersURL() (string, error) {
|
||||
u, err := url.Parse(graphBaseURL + "/users")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("cannot parse graph base URL: %w", err)
|
||||
}
|
||||
|
||||
q := u.Query()
|
||||
q.Set("$select", graphUserSelect)
|
||||
q.Set("$top", strconv.Itoa(graphPageSize))
|
||||
q.Set("$filter", graphMemberFilter)
|
||||
u.RawQuery = q.Encode()
|
||||
|
||||
return u.String(), nil
|
||||
}
|
||||
|
||||
func (p *Provider) fetchPage(ctx context.Context, endpoint string) ([]graphUser, string, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("cannot create graph users request: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user