Fix --users "*' not finding user in tenant (#2033)

## Description

DataCollections validation step was still using the full resourceOwner list in the selector to validate every backup, rather than checking only the DiscreteOwner.

## Does this PR need a docs update or release note?

- [x]  No 

## Type of change

- [x] 🐛 Bugfix

## Issue(s)

* #1617

## Test Plan

- [x]  Unit test
This commit is contained in:
Keepers 2023-01-04 17:29:21 -07:00 committed by GitHub
parent bb5b2f23e9
commit edc4426b9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 31 deletions

View File

@ -272,7 +272,7 @@ func createExchangeCmd(cmd *cobra.Command, args []string) error {
sel := exchangeBackupCreateSelectors(user, exchangeData) sel := exchangeBackupCreateSelectors(user, exchangeData)
users, err := m365.UserIDs(ctx, acct) users, err := m365.UserPNs(ctx, acct)
if err != nil { if err != nil {
return Only(ctx, errors.Wrap(err, "Failed to retrieve M365 users")) return Only(ctx, errors.Wrap(err, "Failed to retrieve M365 users"))
} }

View File

@ -194,7 +194,7 @@ func createOneDriveCmd(cmd *cobra.Command, args []string) error {
sel := oneDriveBackupCreateSelectors(user) sel := oneDriveBackupCreateSelectors(user)
users, err := m365.UserIDs(ctx, acct) users, err := m365.UserPNs(ctx, acct)
if err != nil { if err != nil {
return Only(ctx, errors.Wrap(err, "Failed to retrieve M365 users")) return Only(ctx, errors.Wrap(err, "Failed to retrieve M365 users"))
} }

View File

@ -98,8 +98,6 @@ func (gc *GraphConnector) DataCollections(
func verifyBackupInputs(sels selectors.Selector, userPNs, siteIDs []string) error { func verifyBackupInputs(sels selectors.Selector, userPNs, siteIDs []string) error {
var ids []string var ids []string
resourceOwners := sels.DiscreteResourceOwners()
switch sels.Service { switch sels.Service {
case selectors.ServiceExchange, selectors.ServiceOneDrive: case selectors.ServiceExchange, selectors.ServiceOneDrive:
ids = userPNs ids = userPNs
@ -115,10 +113,8 @@ func verifyBackupInputs(sels selectors.Selector, userPNs, siteIDs []string) erro
normROs[strings.ToLower(id)] = struct{}{} normROs[strings.ToLower(id)] = struct{}{}
} }
for _, ro := range resourceOwners { if _, ok := normROs[strings.ToLower(sels.DiscreteOwner)]; !ok {
if _, ok := normROs[strings.ToLower(ro)]; !ok { return fmt.Errorf("resource owner [%s] not found within tenant", sels.DiscreteOwner)
return fmt.Errorf("included resource owner %s not found within tenant", ro)
}
} }
return nil return nil

View File

@ -131,12 +131,11 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestExchangeDataCollection
} }
// TestInvalidUserForDataCollections ensures verification process for users // TestInvalidUserForDataCollections ensures verification process for users
func (suite *ConnectorDataCollectionIntegrationSuite) TestInvalidUserForDataCollections() { func (suite *ConnectorDataCollectionIntegrationSuite) TestDataCollections_invalidResourceOwner() {
ctx, flush := tester.NewContext() ctx, flush := tester.NewContext()
defer flush() defer flush()
invalidUser := "foo@example.com" owners := []string{"snuffleupagus"}
selUsers := []string{invalidUser}
connector := loadConnector(ctx, suite.T(), Users) connector := loadConnector(ctx, suite.T(), Users)
tests := []struct { tests := []struct {
@ -146,16 +145,51 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestInvalidUserForDataColl
{ {
name: "invalid exchange backup user", name: "invalid exchange backup user",
getSelector: func(t *testing.T) selectors.Selector { getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewExchangeBackup(selUsers) sel := selectors.NewExchangeBackup(owners)
sel.Include(sel.MailFolders(selUsers, selectors.Any())) sel.Include(sel.MailFolders(owners, selectors.Any()))
return sel.Selector return sel.Selector
}, },
}, },
{ {
name: "Invalid onedrive backup user", name: "Invalid onedrive backup user",
getSelector: func(t *testing.T) selectors.Selector { getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewOneDriveBackup(selUsers) sel := selectors.NewOneDriveBackup(owners)
sel.Include(sel.Folders(selUsers, selectors.Any())) sel.Include(sel.Folders(owners, selectors.Any()))
return sel.Selector
},
},
{
name: "Invalid sharepoint backup site",
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewSharePointBackup(owners)
sel.Include(sel.Libraries(owners, selectors.Any()))
return sel.Selector
},
},
{
name: "missing exchange backup user",
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewExchangeBackup(owners)
sel.Include(sel.MailFolders(owners, selectors.Any()))
sel.DiscreteOwner = ""
return sel.Selector
},
},
{
name: "missing onedrive backup user",
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewOneDriveBackup(owners)
sel.Include(sel.Folders(owners, selectors.Any()))
sel.DiscreteOwner = ""
return sel.Selector
},
},
{
name: "missing sharepoint backup site",
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewSharePointBackup(owners)
sel.Include(sel.Libraries(owners, selectors.Any()))
sel.DiscreteOwner = ""
return sel.Selector return sel.Selector
}, },
}, },

View File

@ -227,19 +227,7 @@ func (suite *DisconnectedGraphConnectorSuite) TestVerifyBackupInputs() {
getSelector: func(t *testing.T) selectors.Selector { getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewExchangeBackup([]string{"bobkelso@someHospital.org", "janitor@someHospital.org"}) sel := selectors.NewExchangeBackup([]string{"bobkelso@someHospital.org", "janitor@someHospital.org"})
sel.Include(sel.MailFolders([]string{"bobkelso@someHospital.org", "janitor@someHospital.org"}, selectors.Any())) sel.Include(sel.MailFolders([]string{"bobkelso@someHospital.org", "janitor@someHospital.org"}, selectors.Any()))
return sel.Selector sel.DiscreteOwner = "janitor@someHospital.org"
},
},
{
name: "Multiple Valid Users",
checkError: assert.NoError,
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewOneDriveBackup(
[]string{"elliotReid@someHospital.org", "johnDorian@someHospital.org", "christurk@somehospital.org"},
)
sel.Include(
sel.Users([]string{"elliotReid@someHospital.org", "johnDorian@someHospital.org", "christurk@somehospital.org"}))
return sel.Selector return sel.Selector
}, },
}, },
@ -268,18 +256,21 @@ func (suite *DisconnectedGraphConnectorSuite) TestVerifyBackupInputs_allServices
name: "Valid User", name: "Valid User",
checkError: assert.NoError, checkError: assert.NoError,
excludes: func(t *testing.T) selectors.Selector { excludes: func(t *testing.T) selectors.Selector {
sel := selectors.NewOneDriveBackup([]string{"elliotReid@someHospital.org"}) sel := selectors.NewOneDriveBackup([]string{"elliotReid@someHospital.org", "foo@SomeCompany.org"})
sel.Exclude(sel.Folders([]string{"elliotReid@someHospital.org"}, selectors.Any())) sel.Exclude(sel.Folders([]string{"elliotReid@someHospital.org"}, selectors.Any()))
sel.DiscreteOwner = "elliotReid@someHospital.org"
return sel.Selector return sel.Selector
}, },
filters: func(t *testing.T) selectors.Selector { filters: func(t *testing.T) selectors.Selector {
sel := selectors.NewOneDriveBackup([]string{"elliotReid@someHospital.org"}) sel := selectors.NewOneDriveBackup([]string{"elliotReid@someHospital.org", "foo@SomeCompany.org"})
sel.Filter(sel.Folders([]string{"elliotReid@someHospital.org"}, selectors.Any())) sel.Filter(sel.Folders([]string{"elliotReid@someHospital.org"}, selectors.Any()))
sel.DiscreteOwner = "elliotReid@someHospital.org"
return sel.Selector return sel.Selector
}, },
includes: func(t *testing.T) selectors.Selector { includes: func(t *testing.T) selectors.Selector {
sel := selectors.NewOneDriveBackup([]string{"elliotReid@someHospital.org"}) sel := selectors.NewOneDriveBackup([]string{"elliotReid@someHospital.org", "foo@SomeCompany.org"})
sel.Include(sel.Folders([]string{"elliotReid@someHospital.org"}, selectors.Any())) sel.Include(sel.Folders([]string{"elliotReid@someHospital.org"}, selectors.Any()))
sel.DiscreteOwner = "elliotReid@someHospital.org"
return sel.Selector return sel.Selector
}, },
}, },
@ -308,16 +299,19 @@ func (suite *DisconnectedGraphConnectorSuite) TestVerifyBackupInputs_allServices
excludes: func(t *testing.T) selectors.Selector { excludes: func(t *testing.T) selectors.Selector {
sel := selectors.NewSharePointBackup([]string{"abc.site.foo", "bar.site.baz"}) sel := selectors.NewSharePointBackup([]string{"abc.site.foo", "bar.site.baz"})
sel.Exclude(sel.Sites([]string{"abc.site.foo", "bar.site.baz"})) sel.Exclude(sel.Sites([]string{"abc.site.foo", "bar.site.baz"}))
sel.DiscreteOwner = "abc.site.foo"
return sel.Selector return sel.Selector
}, },
filters: func(t *testing.T) selectors.Selector { filters: func(t *testing.T) selectors.Selector {
sel := selectors.NewSharePointBackup([]string{"abc.site.foo", "bar.site.baz"}) sel := selectors.NewSharePointBackup([]string{"abc.site.foo", "bar.site.baz"})
sel.Filter(sel.Sites([]string{"abc.site.foo", "bar.site.baz"})) sel.Filter(sel.Sites([]string{"abc.site.foo", "bar.site.baz"}))
sel.DiscreteOwner = "abc.site.foo"
return sel.Selector return sel.Selector
}, },
includes: func(t *testing.T) selectors.Selector { includes: func(t *testing.T) selectors.Selector {
sel := selectors.NewSharePointBackup([]string{"abc.site.foo", "bar.site.baz"}) sel := selectors.NewSharePointBackup([]string{"abc.site.foo", "bar.site.baz"})
sel.Include(sel.Sites([]string{"abc.site.foo", "bar.site.baz"})) sel.Include(sel.Sites([]string{"abc.site.foo", "bar.site.baz"}))
sel.DiscreteOwner = "abc.site.foo"
return sel.Selector return sel.Selector
}, },
}, },
@ -327,16 +321,19 @@ func (suite *DisconnectedGraphConnectorSuite) TestVerifyBackupInputs_allServices
excludes: func(t *testing.T) selectors.Selector { excludes: func(t *testing.T) selectors.Selector {
sel := selectors.NewSharePointBackup([]string{"fnords.smarfs.brawnhilda"}) sel := selectors.NewSharePointBackup([]string{"fnords.smarfs.brawnhilda"})
sel.Exclude(sel.Sites([]string{"fnords.smarfs.brawnhilda"})) sel.Exclude(sel.Sites([]string{"fnords.smarfs.brawnhilda"}))
sel.DiscreteOwner = "fnords.smarfs.brawnhilda"
return sel.Selector return sel.Selector
}, },
filters: func(t *testing.T) selectors.Selector { filters: func(t *testing.T) selectors.Selector {
sel := selectors.NewSharePointBackup([]string{"fnords.smarfs.brawnhilda"}) sel := selectors.NewSharePointBackup([]string{"fnords.smarfs.brawnhilda"})
sel.Filter(sel.Sites([]string{"fnords.smarfs.brawnhilda"})) sel.Filter(sel.Sites([]string{"fnords.smarfs.brawnhilda"}))
sel.DiscreteOwner = "fnords.smarfs.brawnhilda"
return sel.Selector return sel.Selector
}, },
includes: func(t *testing.T) selectors.Selector { includes: func(t *testing.T) selectors.Selector {
sel := selectors.NewSharePointBackup([]string{"fnords.smarfs.brawnhilda"}) sel := selectors.NewSharePointBackup([]string{"fnords.smarfs.brawnhilda"})
sel.Include(sel.Sites([]string{"fnords.smarfs.brawnhilda"})) sel.Include(sel.Sites([]string{"fnords.smarfs.brawnhilda"}))
sel.DiscreteOwner = "fnords.smarfs.brawnhilda"
return sel.Selector return sel.Selector
}, },
}, },

View File

@ -58,6 +58,22 @@ func UserIDs(ctx context.Context, m365Account account.Account) ([]string, error)
return ret, nil return ret, nil
} }
// UserPNs retrieves all user principleNames in the tenant. Principle Names
// can be used analogous userIDs in graph API queries.
func UserPNs(ctx context.Context, m365Account account.Account) ([]string, error) {
users, err := Users(ctx, m365Account)
if err != nil {
return nil, err
}
ret := make([]string, 0, len(users))
for _, u := range users {
ret = append(ret, u.PrincipalName)
}
return ret, nil
}
// SiteURLs returns a list of SharePoint site WebURLs in the specified M365 tenant // SiteURLs returns a list of SharePoint site WebURLs in the specified M365 tenant
func SiteURLs(ctx context.Context, m365Account account.Account) ([]string, error) { func SiteURLs(ctx context.Context, m365Account account.Account) ([]string, error) {
gc, err := connector.NewGraphConnector(ctx, m365Account, connector.Sites) gc, err := connector.NewGraphConnector(ctx, m365Account, connector.Sites)