diff --git a/clients/serviceprincipals.go b/clients/serviceprincipals.go index 1f46a75c..8a5c6db9 100644 --- a/clients/serviceprincipals.go +++ b/clients/serviceprincipals.go @@ -151,7 +151,6 @@ func (c *ServicePrincipalsClient) ListOwners(ctx context.Context, id string) (*[ Params: url.Values{"$select": []string{"id"}}, HasTenantId: true, }, - }) if err != nil { return nil, status, err @@ -185,7 +184,6 @@ func (c *ServicePrincipalsClient) GetOwner(ctx context.Context, servicePrincipal Params: url.Values{"$select": []string{"id,url"}}, HasTenantId: true, }, - }) if err != nil { return nil, status, err @@ -287,3 +285,31 @@ func (c *ServicePrincipalsClient) RemoveOwners(ctx context.Context, servicePrinc } return status, nil } + +// ListGroupMemberships returns a list of Groups the Service Principal is member of, optionally filtered using OData. +func (c *ServicePrincipalsClient) ListGroupMemberships(ctx context.Context, id string, filter string) (*[]models.Group, int, error) { + params := url.Values{} + if filter != "" { + params.Add("$filter", filter) + } + resp, status, err := c.BaseClient.Get(ctx, base.GetHttpRequestInput{ + ValidStatusCodes: []int{http.StatusOK}, + Uri: base.Uri{ + Entity: fmt.Sprintf("/servicePrincipals/%s/transitiveMemberOf", id), + Params: params, + HasTenantId: true, + }, + }) + if err != nil { + return nil, status, err + } + defer resp.Body.Close() + respBody, _ := ioutil.ReadAll(resp.Body) + var data struct { + Groups []models.Group `json:"value"` + } + if err := json.Unmarshal(respBody, &data); err != nil { + return nil, status, err + } + return &data.Groups, status, nil +} diff --git a/clients/serviceprincipals_test.go b/clients/serviceprincipals_test.go index accc364b..e492eebd 100644 --- a/clients/serviceprincipals_test.go +++ b/clients/serviceprincipals_test.go @@ -18,7 +18,7 @@ type ServicePrincipalsClientTest struct { func TestServicePrincipalsClient(t *testing.T) { rs := internal.RandomString() c := ServicePrincipalsClientTest{ - connection: internal.NewConnection(), + connection: internal.NewConnection(), randomString: rs, } c.client = clients.NewServicePrincipalsClient(c.connection.AuthConfig.TenantID) @@ -37,12 +37,44 @@ func TestServicePrincipalsClient(t *testing.T) { sp := testServicePrincipalsClient_Create(t, c, models.ServicePrincipal{ AccountEnabled: internal.Bool(true), AppId: app.AppId, - DisplayName: internal.String(fmt.Sprintf("test-serviceprincipal-%s", c.randomString)), + DisplayName: internal.String(fmt.Sprintf("test-serviceprincipal-%s", c.randomString)), }) testServicePrincipalsClient_Get(t, c, *sp.ID) sp.Tags = &([]string{"TestTag"}) testServicePrincipalsClient_Update(t, c, *sp) testServicePrincipalsClient_List(t, c) + + g := GroupsClientTest{ + connection: internal.NewConnection(), + randomString: rs, + } + g.client = clients.NewGroupsClient(g.connection.AuthConfig.TenantID) + g.client.BaseClient.Authorizer = g.connection.Authorizer + + newGroupParent := models.Group{ + DisplayName: internal.String("Test Group Parent"), + MailEnabled: internal.Bool(false), + MailNickname: internal.String(fmt.Sprintf("test-group-parent-%s", c.randomString)), + SecurityEnabled: internal.Bool(true), + } + newGroupChild := models.Group{ + DisplayName: internal.String("Test Group Child"), + MailEnabled: internal.Bool(false), + MailNickname: internal.String(fmt.Sprintf("test-group-child-%s", c.randomString)), + SecurityEnabled: internal.Bool(true), + } + + groupParent := testGroupsClient_Create(t, g, newGroupParent) + groupChild := testGroupsClient_Create(t, g, newGroupChild) + groupParent.AppendMember(g.client.BaseClient.Endpoint, g.client.BaseClient.ApiVersion, *groupChild.ID) + testGroupsClient_AddMembers(t, g, groupParent) + groupChild.AppendMember(g.client.BaseClient.Endpoint, g.client.BaseClient.ApiVersion, *sp.ID) + testGroupsClient_AddMembers(t, g, groupChild) + + testServicePrincipalsClient_ListGroupMemberships(t, c, *sp.ID) + testGroupsClient_Delete(t, g, *groupParent.ID) + testGroupsClient_Delete(t, g, *groupChild.ID) + testServicePrincipalsClient_Delete(t, c, *sp.ID) testApplicationsClient_Delete(t, a, *app.ID) @@ -110,3 +142,20 @@ func testServicePrincipalsClient_Delete(t *testing.T, c ServicePrincipalsClientT t.Fatalf("ServicePrincipalsClient.Delete(): invalid status: %d", status) } } + +func testServicePrincipalsClient_ListGroupMemberships(t *testing.T, c ServicePrincipalsClientTest, id string) (groups *[]models.Group) { + groups, _, err := c.client.ListGroupMemberships(c.connection.Context, id, "") + if err != nil { + t.Fatalf("ServicePrincipalsClient.ListGroupMemberships(): %v", err) + } + + if groups == nil { + t.Fatal("ServicePrincipalsClient.ListGroupMemberships(): groups was nil") + } + + if len(*groups) != 2 { + t.Fatalf("ServicePrincipalsClient.ListGroupMemberships(): expected groups length 2. was: %d", len(*groups)) + } + + return +}