From 81fb89b540a5b910c0656702c050b48ac193c74b Mon Sep 17 00:00:00 2001 From: Hans-Daniel Graf Date: Thu, 12 Jan 2023 15:37:54 +0100 Subject: [PATCH 1/6] add CreateGroup function to AdministrativeUnitsClient receiver With c.CreateGroup it is now possible to create a group directly into an AdministrativeUnit. This enables service principals to manage groups inside an AdministrativeUnit without the need for global directory permissions. --- msgraph/administrative_units.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/msgraph/administrative_units.go b/msgraph/administrative_units.go index 04b5b300..aae17677 100644 --- a/msgraph/administrative_units.go +++ b/msgraph/administrative_units.go @@ -241,6 +241,29 @@ func (c *AdministrativeUnitsClient) GetMember(ctx context.Context, administrativ return &data.Id, status, nil } +func (c *AdministrativeUnitsClient) CreateGroup(ctx context.Context, administrativeUnitId string, group *Group) (int, error) { + var status int + odataTypeGroup := odata.TypeGroup + group.ODataType = &odataTypeGroup + body, err := json.Marshal(group) + if err != nil { + return status, fmt.Errorf("json.Marshal(): %v", err) + } + _, status, _, err = c.BaseClient.Post(ctx, PostHttpRequestInput{ + Body: body, + ConsistencyFailureFunc: RetryOn404ConsistencyFailureFunc, + ValidStatusCodes: []int{http.StatusCreated}, + Uri: Uri{ + Entity: fmt.Sprintf("/administrativeUnits/%s/members", administrativeUnitId), + HasTenantId: true, + }, + }) + if err != nil { + return status, fmt.Errorf("AdministrativeUnitsClient.BaseClient.Post(): %v", err) + } + return status, nil +} + // AddMembers adds new members to a AdministrativeUnit. func (c *AdministrativeUnitsClient) AddMembers(ctx context.Context, administrativeUnitId string, members *Members) (int, error) { var status int From 2aa7bf3667e0bbed0a27120bc201d68b4d8e5f19 Mon Sep 17 00:00:00 2001 From: Hans-Daniel Graf Date: Thu, 12 Jan 2023 17:04:12 +0100 Subject: [PATCH 2/6] provide test for new CreateGroup function --- msgraph/administrative_units.go | 22 +++++++-- msgraph/administrative_units_test.go | 70 ++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 5 deletions(-) diff --git a/msgraph/administrative_units.go b/msgraph/administrative_units.go index aae17677..bc35feb3 100644 --- a/msgraph/administrative_units.go +++ b/msgraph/administrative_units.go @@ -241,15 +241,15 @@ func (c *AdministrativeUnitsClient) GetMember(ctx context.Context, administrativ return &data.Id, status, nil } -func (c *AdministrativeUnitsClient) CreateGroup(ctx context.Context, administrativeUnitId string, group *Group) (int, error) { +func (c *AdministrativeUnitsClient) CreateGroup(ctx context.Context, administrativeUnitId string, group *Group) (*Group, int, error) { var status int odataTypeGroup := odata.TypeGroup group.ODataType = &odataTypeGroup body, err := json.Marshal(group) if err != nil { - return status, fmt.Errorf("json.Marshal(): %v", err) + return nil, status, fmt.Errorf("json.Marshal(): %v", err) } - _, status, _, err = c.BaseClient.Post(ctx, PostHttpRequestInput{ + response, status, _, err := c.BaseClient.Post(ctx, PostHttpRequestInput{ Body: body, ConsistencyFailureFunc: RetryOn404ConsistencyFailureFunc, ValidStatusCodes: []int{http.StatusCreated}, @@ -259,9 +259,21 @@ func (c *AdministrativeUnitsClient) CreateGroup(ctx context.Context, administrat }, }) if err != nil { - return status, fmt.Errorf("AdministrativeUnitsClient.BaseClient.Post(): %v", err) + return nil, status, fmt.Errorf("AdministrativeUnitsClient.BaseClient.Post(): %v", err) } - return status, nil + + defer response.Body.Close() + responseBody, err := io.ReadAll(response.Body) + if err != nil { + return nil, status, fmt.Errorf("io.ReadAll(): %v", err) + } + + var newGroup Group + if err := json.Unmarshal(responseBody, &newGroup); err != nil { + return nil, status, fmt.Errorf("json.Unmarshal(): %v", err) + } + + return &newGroup, status, nil } // AddMembers adds new members to a AdministrativeUnit. diff --git a/msgraph/administrative_units_test.go b/msgraph/administrative_units_test.go index 9898e453..54b67f35 100644 --- a/msgraph/administrative_units_test.go +++ b/msgraph/administrative_units_test.go @@ -11,6 +11,53 @@ import ( "github.com/manicminer/hamilton/odata" ) +//func TestCreateGroup(t *testing.T) { +//client := test.NewTest(t) +//defer client.CancelFunc() + +//ctx := context.Background() +//auId := "a36b436e-7b28-4e51-a1c1-8553d3e2cd5b" +//var odataId odata.Id = "directoryObjects('3c2e469a-bfdb-4240-ab3c-81c167a05172')" +//var odataType odata.Type = "#microsoft.graph.servicePrincipal" +//ownerString := "3c2e469a-bfdb-4240-ab3c-81c167a05172" +//owner := msgraph.DirectoryObject{ +//ODataId: &odataId, +//ODataType: &odataType, +//Id: &ownerString, +//} +//groupName := "hansi-test" +//var groupDescription msgraph.StringNullWhenEmpty = "hansi-test" +//groupTypes := []string{"Unified"} +//behavior := []msgraph.GroupResourceBehaviorOption{ +//msgraph.GroupResourceBehaviorOptionWelcomeEmailDisabled, +//msgraph.GroupResourceBehaviorOptionSubscribeNewGroupMembers, +//msgraph.GroupResourceBehaviorOptionSubscribeMembersToCalendarEventsDisabled, +//} +//visibility := msgraph.GroupVisibilityPrivate +//falsePointer := false +//truePointer := true +//group := msgraph.Group{ +//Description: &groupDescription, +//DisplayName: &groupName, +//GroupTypes: &groupTypes, +//IsAssignableToRole: &falsePointer, +//MailEnabled: &truePointer, +//MailNickname: &groupName, +//Owners: &msgraph.Owners{ +//owner, +//}, +//ResourceBehaviorOptions: &behavior, +//SecurityEnabled: &truePointer, +//Visibility: &visibility, +//} +//returnValue, err := client.AdministrativeUnitsClient.CreateGroup(ctx, auId, &group) +//if err != nil { +//t.Fatalf("AdministrativeUnit.CreateGroup():%s", err) +//} +//println(returnValue) + +//} + func TestAdministrativeUnitsClient(t *testing.T) { c := test.NewTest(t) defer c.CancelFunc() @@ -41,6 +88,18 @@ func TestAdministrativeUnitsClient(t *testing.T) { testAdministrativeUnitsClient_GetMember(t, c, *administrativeUnit.ID, *user.ID()) testAdministrativeUnitsClient_RemoveMembers(t, c, *administrativeUnit.ID, &([]string{*user.ID()})) + self := testDirectoryObjectsClient_Get(t, c, c.Claims.ObjectId) + group := msgraph.Group{ + DisplayName: utils.StringPtr("test-group"), + MailEnabled: utils.BoolPtr(false), + MailNickname: utils.StringPtr(fmt.Sprintf("test-group-%s", c.RandomString)), + SecurityEnabled: utils.BoolPtr(true), + Owners: &msgraph.Owners{*self}, + Members: &msgraph.Members{*self}, + } + createdGroup := testAdministrativeUnitsClient_CreateGroup(t, c, *administrativeUnit.ID, &group) + testAdministrativeUnitsClient_RemoveMembers(t, c, *administrativeUnit.ID, &([]string{*createdGroup.ID()})) + directoryRoleTemplates := testDirectoryRoleTemplatesClient_List(t, c) var helpdeskAdministratorRoleId string for _, template := range *directoryRoleTemplates { @@ -177,6 +236,17 @@ func testAdministrativeUnitsClient_RemoveMembers(t *testing.T, c *test.Test, adm } } +func testAdministrativeUnitsClient_CreateGroup(t *testing.T, c *test.Test, administrativeUnitId string, g *msgraph.Group) (group *msgraph.Group) { + group, status, err := c.AdministrativeUnitsClient.CreateGroup(c.Context, administrativeUnitId, g) + if err != nil { + t.Fatalf("AdministrativeUnitsClient.CreateGroup(): %v", err) + } + if status < 200 || status >= 300 { + t.Fatalf("AdministrativeUnitsClient.CreateGroup(): invalid status: %d", status) + } + return group +} + func testAdministrativeUnitsClient_ListScopedRoleMembers(t *testing.T, c *test.Test, administrativeUnitId string) (memberships *[]msgraph.ScopedRoleMembership) { memberships, status, err := c.AdministrativeUnitsClient.ListScopedRoleMembers(c.Context, administrativeUnitId, odata.Query{}) if err != nil { From 5c3c2f85f9173d5087c8177706b0b4fd5295cc49 Mon Sep 17 00:00:00 2001 From: Hans-Daniel Graf Date: Thu, 12 Jan 2023 17:32:34 +0100 Subject: [PATCH 3/6] rename module to test it on provider fork --- go.mod | 6 ++---- go.sum | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 04c0aa92..a78b91bc 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,12 @@ -module github.com/manicminer/hamilton +module github.com/SwissGipfel/hamilton go 1.16 require ( - github.com/golang/protobuf v1.5.2 // indirect - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.0 github.com/hashicorp/go-uuid v1.0.2 github.com/hashicorp/go-version v1.3.0 + github.com/manicminer/hamilton v0.53.0 golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c - google.golang.org/appengine v1.6.7 // indirect ) diff --git a/go.sum b/go.sum index 7a8c598a..1345c5bd 100644 --- a/go.sum +++ b/go.sum @@ -118,6 +118,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/manicminer/hamilton v0.53.0 h1:QhHKE8toyJ7oDaEIzU4njMZH0J4aqhYbtA3WUW7qcV0= +github.com/manicminer/hamilton v0.53.0/go.mod h1:lbVyngC+/nCWuDp8UhC6Bw+bh7jcP/E+YwqzHTmzemk= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= From 076a552848b6386679f4d53b9a2bfccdfdcc6dad Mon Sep 17 00:00:00 2001 From: Hans-Daniel Graf Date: Thu, 12 Jan 2023 17:39:20 +0100 Subject: [PATCH 4/6] Revert "rename module to test it on provider fork" This reverts commit 5c3c2f85f9173d5087c8177706b0b4fd5295cc49. --- go.mod | 6 ++++-- go.sum | 2 -- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index a78b91bc..04c0aa92 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,14 @@ -module github.com/SwissGipfel/hamilton +module github.com/manicminer/hamilton go 1.16 require ( + github.com/golang/protobuf v1.5.2 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.0 github.com/hashicorp/go-uuid v1.0.2 github.com/hashicorp/go-version v1.3.0 - github.com/manicminer/hamilton v0.53.0 golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c + google.golang.org/appengine v1.6.7 // indirect ) diff --git a/go.sum b/go.sum index 1345c5bd..7a8c598a 100644 --- a/go.sum +++ b/go.sum @@ -118,8 +118,6 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/manicminer/hamilton v0.53.0 h1:QhHKE8toyJ7oDaEIzU4njMZH0J4aqhYbtA3WUW7qcV0= -github.com/manicminer/hamilton v0.53.0/go.mod h1:lbVyngC+/nCWuDp8UhC6Bw+bh7jcP/E+YwqzHTmzemk= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= From 9c3963a6c5352088afbb8cc9e6fe7efd7d811810 Mon Sep 17 00:00:00 2001 From: Hans-Daniel Graf Date: Mon, 16 Jan 2023 10:00:30 +0100 Subject: [PATCH 5/6] apply review suggestion --- msgraph/administrative_units_test.go | 50 ++-------------------------- 1 file changed, 2 insertions(+), 48 deletions(-) diff --git a/msgraph/administrative_units_test.go b/msgraph/administrative_units_test.go index 54b67f35..e9aacd83 100644 --- a/msgraph/administrative_units_test.go +++ b/msgraph/administrative_units_test.go @@ -2,6 +2,7 @@ package msgraph_test import ( "fmt" + "net/http" "strings" "testing" @@ -11,53 +12,6 @@ import ( "github.com/manicminer/hamilton/odata" ) -//func TestCreateGroup(t *testing.T) { -//client := test.NewTest(t) -//defer client.CancelFunc() - -//ctx := context.Background() -//auId := "a36b436e-7b28-4e51-a1c1-8553d3e2cd5b" -//var odataId odata.Id = "directoryObjects('3c2e469a-bfdb-4240-ab3c-81c167a05172')" -//var odataType odata.Type = "#microsoft.graph.servicePrincipal" -//ownerString := "3c2e469a-bfdb-4240-ab3c-81c167a05172" -//owner := msgraph.DirectoryObject{ -//ODataId: &odataId, -//ODataType: &odataType, -//Id: &ownerString, -//} -//groupName := "hansi-test" -//var groupDescription msgraph.StringNullWhenEmpty = "hansi-test" -//groupTypes := []string{"Unified"} -//behavior := []msgraph.GroupResourceBehaviorOption{ -//msgraph.GroupResourceBehaviorOptionWelcomeEmailDisabled, -//msgraph.GroupResourceBehaviorOptionSubscribeNewGroupMembers, -//msgraph.GroupResourceBehaviorOptionSubscribeMembersToCalendarEventsDisabled, -//} -//visibility := msgraph.GroupVisibilityPrivate -//falsePointer := false -//truePointer := true -//group := msgraph.Group{ -//Description: &groupDescription, -//DisplayName: &groupName, -//GroupTypes: &groupTypes, -//IsAssignableToRole: &falsePointer, -//MailEnabled: &truePointer, -//MailNickname: &groupName, -//Owners: &msgraph.Owners{ -//owner, -//}, -//ResourceBehaviorOptions: &behavior, -//SecurityEnabled: &truePointer, -//Visibility: &visibility, -//} -//returnValue, err := client.AdministrativeUnitsClient.CreateGroup(ctx, auId, &group) -//if err != nil { -//t.Fatalf("AdministrativeUnit.CreateGroup():%s", err) -//} -//println(returnValue) - -//} - func TestAdministrativeUnitsClient(t *testing.T) { c := test.NewTest(t) defer c.CancelFunc() @@ -241,7 +195,7 @@ func testAdministrativeUnitsClient_CreateGroup(t *testing.T, c *test.Test, admin if err != nil { t.Fatalf("AdministrativeUnitsClient.CreateGroup(): %v", err) } - if status < 200 || status >= 300 { + if status != http.StatusCreated { t.Fatalf("AdministrativeUnitsClient.CreateGroup(): invalid status: %d", status) } return group From 5dc77b242f665b7c489324ffc41f49e411437ed1 Mon Sep 17 00:00:00 2001 From: swissgipfel Date: Thu, 19 Jan 2023 15:04:12 +0100 Subject: [PATCH 6/6] remove created group after test --- msgraph/administrative_units_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/msgraph/administrative_units_test.go b/msgraph/administrative_units_test.go index e9aacd83..5118090d 100644 --- a/msgraph/administrative_units_test.go +++ b/msgraph/administrative_units_test.go @@ -53,6 +53,7 @@ func TestAdministrativeUnitsClient(t *testing.T) { } createdGroup := testAdministrativeUnitsClient_CreateGroup(t, c, *administrativeUnit.ID, &group) testAdministrativeUnitsClient_RemoveMembers(t, c, *administrativeUnit.ID, &([]string{*createdGroup.ID()})) + testGroup_Delete(t, c, createdGroup) directoryRoleTemplates := testDirectoryRoleTemplatesClient_List(t, c) var helpdeskAdministratorRoleId string