From 61c7f5dac6a205704b6252fe36068fd0a60e363a Mon Sep 17 00:00:00 2001 From: kenchan0130 Date: Sat, 11 Feb 2023 00:16:53 +0900 Subject: [PATCH 1/7] Add TokenIssuancePolicy This adds initial support for the TokenIssuancePolicy resource. Graph API Reference: https://learn.microsoft.com/en-us/graph/api/resources/tokenissuancepolicy?view=graph-rest-1.0 --- internal/test/testing.go | 6 + msgraph/models.go | 8 ++ msgraph/token_issuance_policy.go | 174 ++++++++++++++++++++++++++ msgraph/token_issuance_policy_test.go | 91 ++++++++++++++ 4 files changed, 279 insertions(+) create mode 100644 msgraph/token_issuance_policy.go create mode 100644 msgraph/token_issuance_policy_test.go diff --git a/internal/test/testing.go b/internal/test/testing.go index 1d7be465..58b56da4 100644 --- a/internal/test/testing.go +++ b/internal/test/testing.go @@ -129,6 +129,7 @@ type Test struct { SignInReportsClient *msgraph.SignInReportsClient SynchronizationJobClient *msgraph.SynchronizationJobClient TermsOfUseAgreementClient *msgraph.TermsOfUseAgreementClient + TokenIssuancePolicyClient *msgraph.TokenIssuancePolicyClient UserFlowAttributesClient *msgraph.UserFlowAttributesClient UsersAppRoleAssignmentsClient *msgraph.AppRoleAssignmentsClient UsersClient *msgraph.UsersClient @@ -379,6 +380,11 @@ func NewTest(t *testing.T) (c *Test) { c.TermsOfUseAgreementClient.BaseClient.Endpoint = *endpoint c.TermsOfUseAgreementClient.BaseClient.RetryableClient.RetryMax = retry + c.TokenIssuancePolicyClient = msgraph.NewTokenIssuancePolicyClient(c.Connections["default"].AuthConfig.TenantID) + c.TokenIssuancePolicyClient.BaseClient.Authorizer = c.Connections["default"].Authorizer + c.TokenIssuancePolicyClient.BaseClient.Endpoint = c.Connections["default"].AuthConfig.Environment.MsGraph.Endpoint + c.TokenIssuancePolicyClient.BaseClient.RetryableClient.RetryMax = retry + c.UserFlowAttributesClient = msgraph.NewUserFlowAttributesClient() c.UserFlowAttributesClient.BaseClient.Authorizer = c.Connections["b2c"].Authorizer c.UserFlowAttributesClient.BaseClient.Endpoint = *endpoint diff --git a/msgraph/models.go b/msgraph/models.go index 4f44753e..6c05ec2b 100644 --- a/msgraph/models.go +++ b/msgraph/models.go @@ -1634,6 +1634,14 @@ type TemporaryAccessPassAuthenticationMethod struct { MethodUsabilityReason *MethodUsabilityReason `json:"methodUsabilityReason,omitempty"` } +type TokenIssuancePolicy struct { + DirectoryObject + Definition *[]string `json:"definition,omitempty"` + Description *string `json:"description,omitempty"` + DisplayName *string `json:"displayName,omitempty"` + IsOrganizationDefault *bool `json:"isOrganizationDefault,omitempty"` +} + type UnifiedRoleAssignment struct { DirectoryObject diff --git a/msgraph/token_issuance_policy.go b/msgraph/token_issuance_policy.go new file mode 100644 index 00000000..72153f1c --- /dev/null +++ b/msgraph/token_issuance_policy.go @@ -0,0 +1,174 @@ +package msgraph + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + + "github.com/manicminer/hamilton/odata" +) + +type TokenIssuancePolicyClient struct { + BaseClient Client +} + +// NewTokenIssuancePolicyClient returns a new TokenIssuancePolicyClient +func NewTokenIssuancePolicyClient(tenantId string) *TokenIssuancePolicyClient { + return &TokenIssuancePolicyClient{ + BaseClient: NewClient(Version10, tenantId), + } +} + +// Create creates a new TokenIssuancePolicy. +func (c *TokenIssuancePolicyClient) Create(ctx context.Context, policy TokenIssuancePolicy) (*TokenIssuancePolicy, int, error) { + var status int + + body, err := json.Marshal(policy) + if err != nil { + return nil, status, fmt.Errorf("json.Marshal(): %v", err) + } + + resp, status, _, err := c.BaseClient.Post(ctx, PostHttpRequestInput{ + Body: body, + OData: odata.Query{Metadata: odata.MetadataFull}, + ValidStatusCodes: []int{http.StatusCreated}, + Uri: Uri{ + Entity: "/policies/tokenIssuancePolicies", + HasTenantId: false, + }, + }) + if err != nil { + return nil, status, fmt.Errorf("TokenIssuancePolicyClient.BaseClient.Post(): %v", err) + } + + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return nil, status, fmt.Errorf("io.ReadAll(): %v", err) + } + + var newPolicy TokenIssuancePolicy + if err := json.Unmarshal(respBody, &newPolicy); err != nil { + return nil, status, fmt.Errorf("json.Unmarshal(): %v", err) + } + + return &newPolicy, status, nil +} + +// List returns a list of TokenIssuancePolicy, optionally queried using OData. +func (c *TokenIssuancePolicyClient) List(ctx context.Context, query odata.Query) (*[]TokenIssuancePolicy, int, error) { + query.Metadata = odata.MetadataFull + + resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{ + DisablePaging: query.Top > 0, + OData: query, + ValidStatusCodes: []int{http.StatusOK}, + Uri: Uri{ + Entity: "/policies/tokenIssuancePolicies", + HasTenantId: false, + }, + }) + if err != nil { + return nil, status, fmt.Errorf("TokenIssuancePolicyClient.BaseClient.Get(): %v", err) + } + + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return nil, status, fmt.Errorf("io.ReadAll(): %v", err) + } + + var data struct { + TokenIssuancePolicies []TokenIssuancePolicy `json:"value"` + } + if err := json.Unmarshal(respBody, &data); err != nil { + return nil, status, fmt.Errorf("json.Unmarshal(): %v", err) + } + + return &data.TokenIssuancePolicies, status, nil +} + +// Get retrieves a TokenIssuancePolicy. +func (c *TokenIssuancePolicyClient) Get(ctx context.Context, id string, query odata.Query) (*TokenIssuancePolicy, int, error) { + query.Metadata = odata.MetadataFull + + resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{ + ConsistencyFailureFunc: RetryOn404ConsistencyFailureFunc, + OData: query, + ValidStatusCodes: []int{http.StatusOK}, + Uri: Uri{ + Entity: fmt.Sprintf("/policies/tokenIssuancePolicies/%s", id), + HasTenantId: false, + }, + }) + if err != nil { + return nil, status, fmt.Errorf("TokenIssuancePolicyClient.BaseClient.Get(): %v", err) + } + + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return nil, status, fmt.Errorf("io.ReadAll(): %v", err) + } + + var tokenIssuancePolicy TokenIssuancePolicy + if err := json.Unmarshal(respBody, &tokenIssuancePolicy); err != nil { + return nil, status, fmt.Errorf("json.Unmarshal(): %v", err) + } + + return &tokenIssuancePolicy, status, nil +} + +// Update amends an existing TokenIssuancePolicy. +func (c *TokenIssuancePolicyClient) Update(ctx context.Context, tokenIssuancePolicy TokenIssuancePolicy) (int, error) { + var status int + + if tokenIssuancePolicy.ID() == nil { + return status, fmt.Errorf("cannot update TokenIssuancePolicy with nil ID") + } + + tokenIssuancePolicy.Id = nil + tokenIssuancePolicy.ObjectId = nil + + body, err := json.Marshal(tokenIssuancePolicy) + if err != nil { + return status, fmt.Errorf("json.Marshal(): %v", err) + } + + _, status, _, err = c.BaseClient.Patch(ctx, PatchHttpRequestInput{ + Body: body, + ConsistencyFailureFunc: RetryOn404ConsistencyFailureFunc, + ValidStatusCodes: []int{ + http.StatusOK, + http.StatusNoContent, + }, + Uri: Uri{ + Entity: fmt.Sprintf("/policies/tokenIssuancePolicies/%s", *tokenIssuancePolicy.ID()), + HasTenantId: true, + }, + }) + if err != nil { + return status, fmt.Errorf("TokenIssuancePolicyClient.BaseClient.Patch(): %v", err) + } + + return status, nil +} + +// Delete removes a TokenIssuancePolicy. +func (c *TokenIssuancePolicyClient) Delete(ctx context.Context, id string) (int, error) { + _, status, _, err := c.BaseClient.Delete(ctx, DeleteHttpRequestInput{ + ConsistencyFailureFunc: RetryOn404ConsistencyFailureFunc, + ValidStatusCodes: []int{http.StatusNoContent}, + Uri: Uri{ + Entity: fmt.Sprintf("/policies/tokenIssuancePolicies/%s", id), + HasTenantId: false, + }, + }) + if err != nil { + return status, fmt.Errorf("TokenIssuancePolicyClient.BaseClient.Delete(): %v", err) + } + + return status, nil +} diff --git a/msgraph/token_issuance_policy_test.go b/msgraph/token_issuance_policy_test.go new file mode 100644 index 00000000..ebfda01a --- /dev/null +++ b/msgraph/token_issuance_policy_test.go @@ -0,0 +1,91 @@ +package msgraph_test + +import ( + "fmt" + "testing" + + "github.com/manicminer/hamilton/internal/test" + "github.com/manicminer/hamilton/internal/utils" + "github.com/manicminer/hamilton/msgraph" + "github.com/manicminer/hamilton/odata" +) + +func TestTokenPolicyClient(t *testing.T) { + c := test.NewTest(t) + defer c.CancelFunc() + policy := testTokenIssuancePolicyClient_Create(t, c, msgraph.TokenIssuancePolicy{ + DisplayName: utils.StringPtr(fmt.Sprintf("test-token-issuance-policy-%s", c.RandomString)), + Definition: utils.ArrayStringPtr( + []string{ + "{\"TokenIssuancePolicy\":{\"Version\":1,\"SigningAlgorithm\":\"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\",\"TokenResponseSigningPolicy\":\"ResponseAndToken\",\"SamlTokenVersion\":\"2.0\",\"EmitSamlNameFormat\":false}}", + }, + ), + }) + testTokenIssuancePolicyClient_List(t, c) + testTokenIssuancePolicyClient_Get(t, c, *policy.ID()) + policy.DisplayName = utils.StringPtr(fmt.Sprintf("test-token-issuance-policy-%s", c.RandomString)) + testTokenIssuancePolicyClient_Update(t, c, *policy) + testTokenIssuancePolicyClient_Delete(t, c, *policy.ID()) +} + +func testTokenIssuancePolicyClient_Create(t *testing.T, c *test.Test, p msgraph.TokenIssuancePolicy) (policy *msgraph.TokenIssuancePolicy) { + policy, status, err := c.TokenIssuancePolicyClient.Create(c.Context, p) + if err != nil { + t.Fatalf("TokenIssuancePolicyClient.Create(): %v", err) + } + if status < 200 || status >= 300 { + t.Fatalf("TokenIssuancePolicyClient.Create(): invalid status: %d", status) + } + if policy == nil { + t.Fatal("TokenIssuancePolicyClient.Create(): policy was nil") + } + if policy.ID() == nil { + t.Fatal("TokenIssuancePolicyClient.Create(): policy.ID was nil") + } + return +} + +func testTokenIssuancePolicyClient_List(t *testing.T, c *test.Test) (policy *[]msgraph.ClaimsMappingPolicy) { + policies, _, err := c.TokenIssuancePolicyClient.List(c.Context, odata.Query{Top: 10}) + if err != nil { + t.Fatalf("TokenIssuancePolicyClient.List(): %v", err) + } + if policies == nil { + t.Fatal("TokenIssuancePolicyClient.List(): TokenIssuancePolicies was nil") + } + return +} + +func testTokenIssuancePolicyClient_Get(t *testing.T, c *test.Test, id string) (policy *msgraph.TokenIssuancePolicy) { + policies, status, err := c.TokenIssuancePolicyClient.Get(c.Context, id, odata.Query{}) + if err != nil { + t.Fatalf("TokenIssuancePolicyClient.Get(): %v", err) + } + if status < 200 || status >= 300 { + t.Fatalf("TokenIssuancePolicyClient.Get(): invalid status: %d", status) + } + if policies == nil { + t.Fatal("TokenIssuancePolicyClient.Get(): policies was nil") + } + return +} + +func testTokenIssuancePolicyClient_Update(t *testing.T, c *test.Test, p msgraph.TokenIssuancePolicy) { + status, err := c.TokenIssuancePolicyClient.Update(c.Context, p) + if err != nil { + t.Fatalf("TokenIssuancePolicyClient.Update(): %v", err) + } + if status < 200 || status >= 300 { + t.Fatalf("TokenIssuancePolicyClient.Update(): invalid status: %d", status) + } +} + +func testTokenIssuancePolicyClient_Delete(t *testing.T, c *test.Test, id string) { + status, err := c.TokenIssuancePolicyClient.Delete(c.Context, id) + if err != nil { + t.Fatalf("TokenIssuancePolicyClient.Delete(): %v", err) + } + if status < 200 || status >= 300 { + t.Fatalf("TokenIssuancePolicyClient.Delete(): invalid status: %d", status) + } +} From 8fbd2dc724c18dc31faaf29912a699bb08830ac5 Mon Sep 17 00:00:00 2001 From: kenchan0130 Date: Sat, 11 Feb 2023 00:51:38 +0900 Subject: [PATCH 2/7] Add TokenIssuancePolicy assignments This adds tokenIssuancePolicy assignment support for Applications and implements Assign, List and Remove. Graph API Reference: https://learn.microsoft.com/en-us/graph/api/application-post-tokenissuancepolicies?view=graph-rest-1.0 https://learn.microsoft.com/en-us/graph/api/application-list-tokenissuancepolicies?view=graph-rest-1.0 https://learn.microsoft.com/en-us/graph/api/application-delete-tokenissuancepolicies?view=graph-rest-1.0 --- msgraph/applications.go | 129 +++++++++++++++++++++++++++++++++++ msgraph/applications_test.go | 38 +++++++++++ msgraph/models.go | 1 + 3 files changed, 168 insertions(+) diff --git a/msgraph/applications.go b/msgraph/applications.go index ec8dd954..d597c76e 100644 --- a/msgraph/applications.go +++ b/msgraph/applications.go @@ -739,3 +739,132 @@ func (c *ApplicationsClient) DeleteFederatedIdentityCredential(ctx context.Conte return status, nil } + +// AssignTokenIssuancePolicy assigns a tokenIssuancePolicy to an application +func (c *ApplicationsClient) AssignTokenIssuancePolicy(ctx context.Context, application *Application) (int, error) { + var status int + + if application.ID() == nil { + return status, errors.New("cannot update application with nil ID") + } + if application.TokenIssuancePolicies == nil { + return status, errors.New("cannot update application with nil TokenIssuancePolicies") + } + + for _, policy := range *application.TokenIssuancePolicies { + // don't fail if an owner already exists + checkPolicyAlreadyExists := func(resp *http.Response, o *odata.OData) bool { + if resp != nil && resp.StatusCode == http.StatusBadRequest && o != nil && o.Error != nil { + return o.Error.Match(odata.ErrorAddedObjectReferencesAlreadyExist) + } + return false + } + + body, err := json.Marshal(DirectoryObject{ODataId: policy.ODataId}) + 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.StatusNoContent}, + ValidStatusFunc: checkPolicyAlreadyExists, + Uri: Uri{ + Entity: fmt.Sprintf("/applications/%s/tokenIssuancePolicies/$ref", *application.ID()), + HasTenantId: false, + }, + }) + if err != nil { + return status, fmt.Errorf("ApplicationsClient.BaseClient.Post(): %v", err) + } + } + + return status, nil +} + +// ListTokenIssuancePolicy retrieves the tokenIssuancePolicies assigned to the specified Application. +// applicationId is the object ID of the application. +func (c *ApplicationsClient) ListTokenIssuancePolicy(ctx context.Context, applicationId string) (*[]TokenIssuancePolicy, int, error) { + resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{ + ConsistencyFailureFunc: RetryOn404ConsistencyFailureFunc, + ValidStatusCodes: []int{http.StatusOK}, + Uri: Uri{ + Entity: fmt.Sprintf("/applications/%s/tokenIssuancePolicies", applicationId), + HasTenantId: true, + }, + }) + if err != nil { + return nil, status, fmt.Errorf("ApplicationsClient.BaseClient.Get(): %v", err) + } + + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return nil, status, fmt.Errorf("io.ReadAll(): %v", err) + } + + var data struct { + Policies []TokenIssuancePolicy `json:"value"` + } + + if err := json.Unmarshal(respBody, &data); err != nil { + return nil, status, fmt.Errorf("json.Unmarshal(): %v", err) + } + + return &data.Policies, status, nil +} + +// RemoveTokenIssuancePolicy removes a tokenIssuancePolicy from a servicePrincipal +func (c *ApplicationsClient) RemoveTokenIssuancePolicy(ctx context.Context, application *Application, policyIds *[]string) (int, error) { + var status int + + if policyIds == nil { + return status, errors.New("cannot remove, nil TokenIssuancePolicyIds") + } + + assignedPolicies, _, err := c.ListTokenIssuancePolicy(ctx, *application.ID()) + if err != nil { + return status, fmt.Errorf("ApplicationsClient.BaseClient.ListTokenIssuancePolicy(): %v", err) + } + + if len(*assignedPolicies) == 0 { + return http.StatusNoContent, nil + } + + mapTokenIssuancePolicy := map[string]TokenIssuancePolicy{} + for _, v := range *assignedPolicies { + mapTokenIssuancePolicy[*v.ID()] = v + } + + for _, policyId := range *policyIds { + + // Check if policy is currently assigned + _, ok := mapTokenIssuancePolicy[policyId] + if !ok { + continue + } + + checkPolicyStatus := func(resp *http.Response, o *odata.OData) bool { + if resp != nil && resp.StatusCode == http.StatusNotFound && o != nil && o.Error != nil { + return o.Error.Match(odata.ErrorResourceDoesNotExist) + } + return false + } + + _, status, _, err = c.BaseClient.Delete(ctx, DeleteHttpRequestInput{ + ConsistencyFailureFunc: RetryOn404ConsistencyFailureFunc, + ValidStatusCodes: []int{http.StatusNoContent}, + ValidStatusFunc: checkPolicyStatus, + Uri: Uri{ + Entity: fmt.Sprintf("/applications/%s/tokenIssuancePolicies/%s/$ref", *application.ID(), policyId), + HasTenantId: false, + }, + }) + if err != nil { + return status, fmt.Errorf("ApplicationsClient.BaseClient.Delete(): %v", err) + } + } + + return status, nil +} diff --git a/msgraph/applications_test.go b/msgraph/applications_test.go index 1374ef2e..6019620b 100644 --- a/msgraph/applications_test.go +++ b/msgraph/applications_test.go @@ -81,6 +81,24 @@ func TestApplicationsClient(t *testing.T) { testApplicationsClient_ListFederatedIdentityCredentials(t, c, *app.ID()) testApplicationsClient_DeleteFederatedIdentityCredential(t, c, *app.ID(), *credential.ID) + tokenIssuancePolicy := testTokenIssuancePolicyClient_Create(t, c, msgraph.TokenIssuancePolicy{ + DisplayName: utils.StringPtr(fmt.Sprintf("test-token-issuance-policy-%s", c.RandomString)), + Definition: utils.ArrayStringPtr( + []string{ + "{\"TokenIssuancePolicy\":{\"Version\":1,\"SigningAlgorithm\":\"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\",\"TokenResponseSigningPolicy\":\"ResponseAndToken\",\"SamlTokenVersion\":\"2.0\",\"EmitSamlNameFormat\":false}}", + }, + ), + }) + + app.TokenIssuancePolicies = &[]msgraph.TokenIssuancePolicy{*tokenIssuancePolicy} + + testApplicationsClient_AssignTokenIssuancePolicy(t, c, app) + // ListTokenIssuancePolicy is called within RemoveTokenIssuancePolicy + testApplicationsClient_RemoveTokenIssuancePolicy(t, c, app, []string{*tokenIssuancePolicy.Id}) + // A Second call tests that a remove call on an empty assignment list returns ok + testApplicationsClient_RemoveTokenIssuancePolicy(t, c, app, []string{*tokenIssuancePolicy.Id}) + testTokenIssuancePolicyClient_Delete(t, c, *tokenIssuancePolicy.Id) + testApplicationsClient_List(t, c) testApplicationsClient_Delete(t, c, *app.ID()) testApplicationsClient_ListDeleted(t, c, *app.ID()) @@ -437,3 +455,23 @@ func testApplicationsClient_DeleteFederatedIdentityCredential(t *testing.T, c *t t.Fatalf("ApplicationsClient.DeleteFederatedIdentityCredential(): invalid status: %d", status) } } + +func testApplicationsClient_AssignTokenIssuancePolicy(t *testing.T, c *test.Test, a *msgraph.Application) { + status, err := c.ApplicationsClient.AssignTokenIssuancePolicy(c.Context, a) + if err != nil { + t.Fatalf("ApplicationsClient.AssignTokenIssuancePolicy(): %v", err) + } + if status < 200 || status >= 300 { + t.Fatalf("ApplicationsClient.AssignTokenIssuancePolicy(): invalid status: %d", status) + } +} + +func testApplicationsClient_RemoveTokenIssuancePolicy(t *testing.T, c *test.Test, a *msgraph.Application, policyIds []string) { + status, err := c.ApplicationsClient.RemoveTokenIssuancePolicy(c.Context, a, &policyIds) + if err != nil { + t.Fatalf("ApplicationsClient.RemoveTokenIssuancePolicy(): %v", err) + } + if status < 200 || status >= 300 { + t.Fatalf("ApplicationsClient.RemoveTokenIssuancePolicy(): invalid status: %d", status) + } +} diff --git a/msgraph/models.go b/msgraph/models.go index 6c05ec2b..924f0ac2 100644 --- a/msgraph/models.go +++ b/msgraph/models.go @@ -243,6 +243,7 @@ type Application struct { AppId *string `json:"appId,omitempty"` ApplicationTemplateId *string `json:"applicationTemplateId,omitempty"` AppRoles *[]AppRole `json:"appRoles,omitempty"` + TokenIssuancePolicies *[]TokenIssuancePolicy `json:"tokenIssuancePolicies@odata.bind,omitempty"` CreatedDateTime *time.Time `json:"createdDateTime,omitempty"` DefaultRedirectUri *string `json:"defaultRedirectUri,omitempty"` DeletedDateTime *time.Time `json:"deletedDateTime,omitempty"` From d95199f3dc04e23138515737640679edcb3643e5 Mon Sep 17 00:00:00 2001 From: Tom Bamford Date: Mon, 13 Feb 2023 14:11:24 +0200 Subject: [PATCH 3/7] Linting --- msgraph/models.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msgraph/models.go b/msgraph/models.go index 924f0ac2..3c18ad8f 100644 --- a/msgraph/models.go +++ b/msgraph/models.go @@ -243,7 +243,6 @@ type Application struct { AppId *string `json:"appId,omitempty"` ApplicationTemplateId *string `json:"applicationTemplateId,omitempty"` AppRoles *[]AppRole `json:"appRoles,omitempty"` - TokenIssuancePolicies *[]TokenIssuancePolicy `json:"tokenIssuancePolicies@odata.bind,omitempty"` CreatedDateTime *time.Time `json:"createdDateTime,omitempty"` DefaultRedirectUri *string `json:"defaultRedirectUri,omitempty"` DeletedDateTime *time.Time `json:"deletedDateTime,omitempty"` @@ -272,6 +271,7 @@ type Application struct { Spa *ApplicationSpa `json:"spa,omitempty"` Tags *[]string `json:"tags,omitempty"` TokenEncryptionKeyId *string `json:"tokenEncryptionKeyId,omitempty"` + TokenIssuancePolicies *[]TokenIssuancePolicy `json:"tokenIssuancePolicies@odata.bind,omitempty"` UniqueName *string `json:"uniqueName,omitempty"` VerifiedPublisher *VerifiedPublisher `json:"verifiedPublisher,omitempty"` Web *ApplicationWeb `json:"web,omitempty"` From efdb32a75cfba6cd4b99547cae505eff396cf2f1 Mon Sep 17 00:00:00 2001 From: kenchan0130 Date: Wed, 22 Feb 2023 01:02:07 +0900 Subject: [PATCH 4/7] fix panic bug --- msgraph/token_issuance_policy.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/msgraph/token_issuance_policy.go b/msgraph/token_issuance_policy.go index 72153f1c..a87371a9 100644 --- a/msgraph/token_issuance_policy.go +++ b/msgraph/token_issuance_policy.go @@ -129,6 +129,7 @@ func (c *TokenIssuancePolicyClient) Update(ctx context.Context, tokenIssuancePol return status, fmt.Errorf("cannot update TokenIssuancePolicy with nil ID") } + tokenIssuancePolicyId := *tokenIssuancePolicy.ID() tokenIssuancePolicy.Id = nil tokenIssuancePolicy.ObjectId = nil @@ -145,7 +146,7 @@ func (c *TokenIssuancePolicyClient) Update(ctx context.Context, tokenIssuancePol http.StatusNoContent, }, Uri: Uri{ - Entity: fmt.Sprintf("/policies/tokenIssuancePolicies/%s", *tokenIssuancePolicy.ID()), + Entity: fmt.Sprintf("/policies/tokenIssuancePolicies/%s", tokenIssuancePolicyId), HasTenantId: true, }, }) From e00db1b6616ebeba83917a17a021702545a8778e Mon Sep 17 00:00:00 2001 From: kenchan0130 Date: Wed, 22 Feb 2023 01:05:12 +0900 Subject: [PATCH 5/7] allowed tokenIssuancePolicies to operate on service principals --- msgraph/applications.go | 129 ----------------------------- msgraph/applications_test.go | 38 --------- msgraph/models.go | 2 +- msgraph/serviceprincipals.go | 132 ++++++++++++++++++++++++++++++ msgraph/serviceprincipals_test.go | 38 +++++++++ 5 files changed, 171 insertions(+), 168 deletions(-) diff --git a/msgraph/applications.go b/msgraph/applications.go index d597c76e..ec8dd954 100644 --- a/msgraph/applications.go +++ b/msgraph/applications.go @@ -739,132 +739,3 @@ func (c *ApplicationsClient) DeleteFederatedIdentityCredential(ctx context.Conte return status, nil } - -// AssignTokenIssuancePolicy assigns a tokenIssuancePolicy to an application -func (c *ApplicationsClient) AssignTokenIssuancePolicy(ctx context.Context, application *Application) (int, error) { - var status int - - if application.ID() == nil { - return status, errors.New("cannot update application with nil ID") - } - if application.TokenIssuancePolicies == nil { - return status, errors.New("cannot update application with nil TokenIssuancePolicies") - } - - for _, policy := range *application.TokenIssuancePolicies { - // don't fail if an owner already exists - checkPolicyAlreadyExists := func(resp *http.Response, o *odata.OData) bool { - if resp != nil && resp.StatusCode == http.StatusBadRequest && o != nil && o.Error != nil { - return o.Error.Match(odata.ErrorAddedObjectReferencesAlreadyExist) - } - return false - } - - body, err := json.Marshal(DirectoryObject{ODataId: policy.ODataId}) - 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.StatusNoContent}, - ValidStatusFunc: checkPolicyAlreadyExists, - Uri: Uri{ - Entity: fmt.Sprintf("/applications/%s/tokenIssuancePolicies/$ref", *application.ID()), - HasTenantId: false, - }, - }) - if err != nil { - return status, fmt.Errorf("ApplicationsClient.BaseClient.Post(): %v", err) - } - } - - return status, nil -} - -// ListTokenIssuancePolicy retrieves the tokenIssuancePolicies assigned to the specified Application. -// applicationId is the object ID of the application. -func (c *ApplicationsClient) ListTokenIssuancePolicy(ctx context.Context, applicationId string) (*[]TokenIssuancePolicy, int, error) { - resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{ - ConsistencyFailureFunc: RetryOn404ConsistencyFailureFunc, - ValidStatusCodes: []int{http.StatusOK}, - Uri: Uri{ - Entity: fmt.Sprintf("/applications/%s/tokenIssuancePolicies", applicationId), - HasTenantId: true, - }, - }) - if err != nil { - return nil, status, fmt.Errorf("ApplicationsClient.BaseClient.Get(): %v", err) - } - - defer resp.Body.Close() - respBody, err := io.ReadAll(resp.Body) - if err != nil { - return nil, status, fmt.Errorf("io.ReadAll(): %v", err) - } - - var data struct { - Policies []TokenIssuancePolicy `json:"value"` - } - - if err := json.Unmarshal(respBody, &data); err != nil { - return nil, status, fmt.Errorf("json.Unmarshal(): %v", err) - } - - return &data.Policies, status, nil -} - -// RemoveTokenIssuancePolicy removes a tokenIssuancePolicy from a servicePrincipal -func (c *ApplicationsClient) RemoveTokenIssuancePolicy(ctx context.Context, application *Application, policyIds *[]string) (int, error) { - var status int - - if policyIds == nil { - return status, errors.New("cannot remove, nil TokenIssuancePolicyIds") - } - - assignedPolicies, _, err := c.ListTokenIssuancePolicy(ctx, *application.ID()) - if err != nil { - return status, fmt.Errorf("ApplicationsClient.BaseClient.ListTokenIssuancePolicy(): %v", err) - } - - if len(*assignedPolicies) == 0 { - return http.StatusNoContent, nil - } - - mapTokenIssuancePolicy := map[string]TokenIssuancePolicy{} - for _, v := range *assignedPolicies { - mapTokenIssuancePolicy[*v.ID()] = v - } - - for _, policyId := range *policyIds { - - // Check if policy is currently assigned - _, ok := mapTokenIssuancePolicy[policyId] - if !ok { - continue - } - - checkPolicyStatus := func(resp *http.Response, o *odata.OData) bool { - if resp != nil && resp.StatusCode == http.StatusNotFound && o != nil && o.Error != nil { - return o.Error.Match(odata.ErrorResourceDoesNotExist) - } - return false - } - - _, status, _, err = c.BaseClient.Delete(ctx, DeleteHttpRequestInput{ - ConsistencyFailureFunc: RetryOn404ConsistencyFailureFunc, - ValidStatusCodes: []int{http.StatusNoContent}, - ValidStatusFunc: checkPolicyStatus, - Uri: Uri{ - Entity: fmt.Sprintf("/applications/%s/tokenIssuancePolicies/%s/$ref", *application.ID(), policyId), - HasTenantId: false, - }, - }) - if err != nil { - return status, fmt.Errorf("ApplicationsClient.BaseClient.Delete(): %v", err) - } - } - - return status, nil -} diff --git a/msgraph/applications_test.go b/msgraph/applications_test.go index 6019620b..1374ef2e 100644 --- a/msgraph/applications_test.go +++ b/msgraph/applications_test.go @@ -81,24 +81,6 @@ func TestApplicationsClient(t *testing.T) { testApplicationsClient_ListFederatedIdentityCredentials(t, c, *app.ID()) testApplicationsClient_DeleteFederatedIdentityCredential(t, c, *app.ID(), *credential.ID) - tokenIssuancePolicy := testTokenIssuancePolicyClient_Create(t, c, msgraph.TokenIssuancePolicy{ - DisplayName: utils.StringPtr(fmt.Sprintf("test-token-issuance-policy-%s", c.RandomString)), - Definition: utils.ArrayStringPtr( - []string{ - "{\"TokenIssuancePolicy\":{\"Version\":1,\"SigningAlgorithm\":\"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\",\"TokenResponseSigningPolicy\":\"ResponseAndToken\",\"SamlTokenVersion\":\"2.0\",\"EmitSamlNameFormat\":false}}", - }, - ), - }) - - app.TokenIssuancePolicies = &[]msgraph.TokenIssuancePolicy{*tokenIssuancePolicy} - - testApplicationsClient_AssignTokenIssuancePolicy(t, c, app) - // ListTokenIssuancePolicy is called within RemoveTokenIssuancePolicy - testApplicationsClient_RemoveTokenIssuancePolicy(t, c, app, []string{*tokenIssuancePolicy.Id}) - // A Second call tests that a remove call on an empty assignment list returns ok - testApplicationsClient_RemoveTokenIssuancePolicy(t, c, app, []string{*tokenIssuancePolicy.Id}) - testTokenIssuancePolicyClient_Delete(t, c, *tokenIssuancePolicy.Id) - testApplicationsClient_List(t, c) testApplicationsClient_Delete(t, c, *app.ID()) testApplicationsClient_ListDeleted(t, c, *app.ID()) @@ -455,23 +437,3 @@ func testApplicationsClient_DeleteFederatedIdentityCredential(t *testing.T, c *t t.Fatalf("ApplicationsClient.DeleteFederatedIdentityCredential(): invalid status: %d", status) } } - -func testApplicationsClient_AssignTokenIssuancePolicy(t *testing.T, c *test.Test, a *msgraph.Application) { - status, err := c.ApplicationsClient.AssignTokenIssuancePolicy(c.Context, a) - if err != nil { - t.Fatalf("ApplicationsClient.AssignTokenIssuancePolicy(): %v", err) - } - if status < 200 || status >= 300 { - t.Fatalf("ApplicationsClient.AssignTokenIssuancePolicy(): invalid status: %d", status) - } -} - -func testApplicationsClient_RemoveTokenIssuancePolicy(t *testing.T, c *test.Test, a *msgraph.Application, policyIds []string) { - status, err := c.ApplicationsClient.RemoveTokenIssuancePolicy(c.Context, a, &policyIds) - if err != nil { - t.Fatalf("ApplicationsClient.RemoveTokenIssuancePolicy(): %v", err) - } - if status < 200 || status >= 300 { - t.Fatalf("ApplicationsClient.RemoveTokenIssuancePolicy(): invalid status: %d", status) - } -} diff --git a/msgraph/models.go b/msgraph/models.go index 3c18ad8f..d751ab00 100644 --- a/msgraph/models.go +++ b/msgraph/models.go @@ -271,7 +271,6 @@ type Application struct { Spa *ApplicationSpa `json:"spa,omitempty"` Tags *[]string `json:"tags,omitempty"` TokenEncryptionKeyId *string `json:"tokenEncryptionKeyId,omitempty"` - TokenIssuancePolicies *[]TokenIssuancePolicy `json:"tokenIssuancePolicies@odata.bind,omitempty"` UniqueName *string `json:"uniqueName,omitempty"` VerifiedPublisher *VerifiedPublisher `json:"verifiedPublisher,omitempty"` Web *ApplicationWeb `json:"web,omitempty"` @@ -1430,6 +1429,7 @@ type ServicePrincipal struct { SignInAudience *SignInAudience `json:"signInAudience,omitempty"` Tags *[]string `json:"tags,omitempty"` TokenEncryptionKeyId *string `json:"tokenEncryptionKeyId,omitempty"` + TokenIssuancePolicies *[]TokenIssuancePolicy `json:"tokenIssuancePolicies@odata.bind,omitempty"` VerifiedPublisher *VerifiedPublisher `json:"verifiedPublisher,omitempty"` } diff --git a/msgraph/serviceprincipals.go b/msgraph/serviceprincipals.go index e74ecfc0..ea7bfbb0 100644 --- a/msgraph/serviceprincipals.go +++ b/msgraph/serviceprincipals.go @@ -757,3 +757,135 @@ func (c *ServicePrincipalsClient) AssignAppRoleForResource(ctx context.Context, return &appRoleAssignment, status, nil } + +// AssignTokenIssuancePolicy assigns tokenIssuancePolicies to a service principal +func (c *ServicePrincipalsClient) AssignTokenIssuancePolicy(ctx context.Context, servicePrincipal *ServicePrincipal) (int, error) { + var status int + + if servicePrincipal.ID() == nil { + return status, errors.New("cannot update service principal with nil ID") + } + if servicePrincipal.TokenIssuancePolicies == nil { + return status, errors.New("cannot update service principal with nil TokenIssuancePolicies") + } + + for _, policy := range *servicePrincipal.TokenIssuancePolicies { + // don't fail if an owner already exists + checkPolicyAlreadyExists := func(resp *http.Response, o *odata.OData) bool { + if resp != nil && resp.StatusCode == http.StatusBadRequest && o != nil && o.Error != nil { + return o.Error.Match(odata.ErrorAddedObjectReferencesAlreadyExist) + } + return false + } + + body, err := json.Marshal(DirectoryObject{ODataId: policy.ODataId}) + 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.StatusNoContent}, + ValidStatusFunc: checkPolicyAlreadyExists, + Uri: Uri{ + Entity: fmt.Sprintf("/servicePrincipals/%s/tokenIssuancePolicies/$ref", *servicePrincipal.ID()), + HasTenantId: false, + }, + }) + if err != nil { + return status, fmt.Errorf("ServicePrincipalsClient.BaseClient.Post(): %v", err) + } + } + + return status, nil +} + +// ListTokenIssuancePolicy retrieves the tokenIssuancePolicies assigned to the specified ServicePrincipal. +// principalId is the object ID of the service principal. +func (c *ServicePrincipalsClient) ListTokenIssuancePolicy(ctx context.Context, principalId string) (*[]TokenIssuancePolicy, int, error) { + resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{ + ConsistencyFailureFunc: RetryOn404ConsistencyFailureFunc, + ValidStatusCodes: []int{http.StatusOK}, + Uri: Uri{ + Entity: fmt.Sprintf("/servicePrincipals/%s/tokenIssuancePolicies", principalId), + HasTenantId: true, + }, + }) + if err != nil { + return nil, status, fmt.Errorf("ServicePrincipalsClient.BaseClient.Get(): %v", err) + } + + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return nil, status, fmt.Errorf("io.ReadAll(): %v", err) + } + + var data struct { + Policies []TokenIssuancePolicy `json:"value"` + } + + if err := json.Unmarshal(respBody, &data); err != nil { + return nil, status, fmt.Errorf("json.Unmarshal(): %v", err) + } + + return &data.Policies, status, nil +} + +// RemoveTokenIssuancePolicy removes a tokenIssuancePolicy from a service principal +func (c *ServicePrincipalsClient) RemoveTokenIssuancePolicy(ctx context.Context, servicePrincipal *ServicePrincipal, policyIds *[]string) (int, error) { + var status int + + if servicePrincipal.ID() == nil { + return status, errors.New("cannot update service principal with nil ID") + } + if policyIds == nil { + return status, errors.New("cannot remove, nil TokenIssuancePolicyIds") + } + + assignedPolicies, _, err := c.ListTokenIssuancePolicy(ctx, *servicePrincipal.ID()) + if err != nil { + return status, fmt.Errorf("ServicePrincipalsClient.BaseClient.ListTokenIssuancePolicy(): %v", err) + } + + if len(*assignedPolicies) == 0 { + return http.StatusNoContent, nil + } + + mapTokenIssuancePolicy := map[string]TokenIssuancePolicy{} + for _, v := range *assignedPolicies { + mapTokenIssuancePolicy[*v.ID()] = v + } + + for _, policyId := range *policyIds { + + // Check if policy is currently assigned + _, ok := mapTokenIssuancePolicy[policyId] + if !ok { + continue + } + + checkPolicyStatus := func(resp *http.Response, o *odata.OData) bool { + if resp != nil && resp.StatusCode == http.StatusNotFound && o != nil && o.Error != nil { + return o.Error.Match(odata.ErrorResourceDoesNotExist) + } + return false + } + + _, status, _, err = c.BaseClient.Delete(ctx, DeleteHttpRequestInput{ + ConsistencyFailureFunc: RetryOn404ConsistencyFailureFunc, + ValidStatusCodes: []int{http.StatusNoContent}, + ValidStatusFunc: checkPolicyStatus, + Uri: Uri{ + Entity: fmt.Sprintf("/servicePrincipals/%s/tokenIssuancePolicies/%s/$ref", *servicePrincipal.ID(), policyId), + HasTenantId: false, + }, + }) + if err != nil { + return status, fmt.Errorf("ServicePrincipalsClient.BaseClient.Delete(): %v", err) + } + } + + return status, nil +} diff --git a/msgraph/serviceprincipals_test.go b/msgraph/serviceprincipals_test.go index 4c8af49d..e95e96ce 100644 --- a/msgraph/serviceprincipals_test.go +++ b/msgraph/serviceprincipals_test.go @@ -68,6 +68,24 @@ func TestServicePrincipalsClient(t *testing.T) { testServicePrincipalsClient_RemoveClaimsMappingPolicy(t, c, sp, []string{*claimsMappingPolicy.ID()}) testClaimsMappingPolicyClient_Delete(t, c, *claimsMappingPolicy.ID()) + tokenIssuancePolicy := testTokenIssuancePolicyClient_Create(t, c, msgraph.TokenIssuancePolicy{ + DisplayName: utils.StringPtr(fmt.Sprintf("test-token-issuance-policy-%s", c.RandomString)), + Definition: utils.ArrayStringPtr( + []string{ + "{\"TokenIssuancePolicy\":{\"Version\":1,\"SigningAlgorithm\":\"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\",\"TokenResponseSigningPolicy\":\"ResponseAndToken\",\"SamlTokenVersion\":\"2.0\",\"EmitSamlNameFormat\":false}}", + }, + ), + }) + + sp.TokenIssuancePolicies = &[]msgraph.TokenIssuancePolicy{*tokenIssuancePolicy} + + testServicePrincipalsClient_AssignTokenIssuancePolicy(t, c, sp) + // ListTokenIssuancePolicy is called within RemoveTokenIssuancePolicy + testServicePrincipalsClient_RemoveTokenIssuancePolicy(t, c, sp, []string{*tokenIssuancePolicy.Id}) + // A Second call tests that a remove call on an empty assignment list returns ok + testServicePrincipalsClient_RemoveTokenIssuancePolicy(t, c, sp, []string{*tokenIssuancePolicy.Id}) + testTokenIssuancePolicyClient_Delete(t, c, *tokenIssuancePolicy.Id) + newGroupParent := msgraph.Group{ DisplayName: utils.StringPtr("test-group-servicePrincipal-parent"), MailEnabled: utils.BoolPtr(false), @@ -420,6 +438,26 @@ func testServicePrincipalsClient_RemoveClaimsMappingPolicy(t *testing.T, c *test } } +func testServicePrincipalsClient_AssignTokenIssuancePolicy(t *testing.T, c *test.Test, sp *msgraph.ServicePrincipal) { + status, err := c.ServicePrincipalsClient.AssignTokenIssuancePolicy(c.Context, sp) + if err != nil { + t.Fatalf("ServicePrincipalsClient.AssignTokenIssuancePolicy(): %v", err) + } + if status < 200 || status >= 300 { + t.Fatalf("ServicePrincipalsClient.AssignTokenIssuancePolicy(): invalid status: %d", status) + } +} + +func testServicePrincipalsClient_RemoveTokenIssuancePolicy(t *testing.T, c *test.Test, sp *msgraph.ServicePrincipal, policyIds []string) { + status, err := c.ServicePrincipalsClient.RemoveTokenIssuancePolicy(c.Context, sp, &policyIds) + if err != nil { + t.Fatalf("ServicePrincipalsClient.RemoveTokenIssuancePolicy(): %v", err) + } + if status < 200 || status >= 300 { + t.Fatalf("ServicePrincipalsClient.RemoveTokenIssuancePolicy(): invalid status: %d", status) + } +} + func testServicePrincipalsClient_AssignAppRole(t *testing.T, c *test.Test, principalId, resourceId, appRoleId string) (appRoleAssignment *msgraph.AppRoleAssignment) { appRoleAssignment, status, err := c.ServicePrincipalsClient.AssignAppRoleForResource(c.Context, principalId, resourceId, appRoleId) if err != nil { From 16b22534e677c1d22604431b9f2e13cd530fc4e7 Mon Sep 17 00:00:00 2001 From: kenchan0130 Date: Thu, 2 Mar 2023 23:17:32 +0900 Subject: [PATCH 6/7] follow mainstream breaking changes --- internal/test/testing.go | 4 ++-- msgraph/serviceprincipals.go | 9 +++------ msgraph/token_issuance_policy.go | 21 ++++++++------------- msgraph/token_issuance_policy_test.go | 2 +- 4 files changed, 14 insertions(+), 22 deletions(-) diff --git a/internal/test/testing.go b/internal/test/testing.go index 58b56da4..d0bd88bc 100644 --- a/internal/test/testing.go +++ b/internal/test/testing.go @@ -380,9 +380,9 @@ func NewTest(t *testing.T) (c *Test) { c.TermsOfUseAgreementClient.BaseClient.Endpoint = *endpoint c.TermsOfUseAgreementClient.BaseClient.RetryableClient.RetryMax = retry - c.TokenIssuancePolicyClient = msgraph.NewTokenIssuancePolicyClient(c.Connections["default"].AuthConfig.TenantID) + c.TokenIssuancePolicyClient = msgraph.NewTokenIssuancePolicyClient() c.TokenIssuancePolicyClient.BaseClient.Authorizer = c.Connections["default"].Authorizer - c.TokenIssuancePolicyClient.BaseClient.Endpoint = c.Connections["default"].AuthConfig.Environment.MsGraph.Endpoint + c.TokenIssuancePolicyClient.BaseClient.Endpoint = *endpoint c.TokenIssuancePolicyClient.BaseClient.RetryableClient.RetryMax = retry c.UserFlowAttributesClient = msgraph.NewUserFlowAttributesClient() diff --git a/msgraph/serviceprincipals.go b/msgraph/serviceprincipals.go index ea7bfbb0..710a2446 100644 --- a/msgraph/serviceprincipals.go +++ b/msgraph/serviceprincipals.go @@ -789,8 +789,7 @@ func (c *ServicePrincipalsClient) AssignTokenIssuancePolicy(ctx context.Context, ValidStatusCodes: []int{http.StatusNoContent}, ValidStatusFunc: checkPolicyAlreadyExists, Uri: Uri{ - Entity: fmt.Sprintf("/servicePrincipals/%s/tokenIssuancePolicies/$ref", *servicePrincipal.ID()), - HasTenantId: false, + Entity: fmt.Sprintf("/servicePrincipals/%s/tokenIssuancePolicies/$ref", *servicePrincipal.ID()), }, }) if err != nil { @@ -808,8 +807,7 @@ func (c *ServicePrincipalsClient) ListTokenIssuancePolicy(ctx context.Context, p ConsistencyFailureFunc: RetryOn404ConsistencyFailureFunc, ValidStatusCodes: []int{http.StatusOK}, Uri: Uri{ - Entity: fmt.Sprintf("/servicePrincipals/%s/tokenIssuancePolicies", principalId), - HasTenantId: true, + Entity: fmt.Sprintf("/servicePrincipals/%s/tokenIssuancePolicies", principalId), }, }) if err != nil { @@ -878,8 +876,7 @@ func (c *ServicePrincipalsClient) RemoveTokenIssuancePolicy(ctx context.Context, ValidStatusCodes: []int{http.StatusNoContent}, ValidStatusFunc: checkPolicyStatus, Uri: Uri{ - Entity: fmt.Sprintf("/servicePrincipals/%s/tokenIssuancePolicies/%s/$ref", *servicePrincipal.ID(), policyId), - HasTenantId: false, + Entity: fmt.Sprintf("/servicePrincipals/%s/tokenIssuancePolicies/%s/$ref", *servicePrincipal.ID(), policyId), }, }) if err != nil { diff --git a/msgraph/token_issuance_policy.go b/msgraph/token_issuance_policy.go index a87371a9..4867351e 100644 --- a/msgraph/token_issuance_policy.go +++ b/msgraph/token_issuance_policy.go @@ -7,7 +7,7 @@ import ( "io" "net/http" - "github.com/manicminer/hamilton/odata" + "github.com/hashicorp/go-azure-sdk/sdk/odata" ) type TokenIssuancePolicyClient struct { @@ -15,9 +15,9 @@ type TokenIssuancePolicyClient struct { } // NewTokenIssuancePolicyClient returns a new TokenIssuancePolicyClient -func NewTokenIssuancePolicyClient(tenantId string) *TokenIssuancePolicyClient { +func NewTokenIssuancePolicyClient() *TokenIssuancePolicyClient { return &TokenIssuancePolicyClient{ - BaseClient: NewClient(Version10, tenantId), + BaseClient: NewClient(Version10), } } @@ -35,8 +35,7 @@ func (c *TokenIssuancePolicyClient) Create(ctx context.Context, policy TokenIssu OData: odata.Query{Metadata: odata.MetadataFull}, ValidStatusCodes: []int{http.StatusCreated}, Uri: Uri{ - Entity: "/policies/tokenIssuancePolicies", - HasTenantId: false, + Entity: "/policies/tokenIssuancePolicies", }, }) if err != nil { @@ -66,8 +65,7 @@ func (c *TokenIssuancePolicyClient) List(ctx context.Context, query odata.Query) OData: query, ValidStatusCodes: []int{http.StatusOK}, Uri: Uri{ - Entity: "/policies/tokenIssuancePolicies", - HasTenantId: false, + Entity: "/policies/tokenIssuancePolicies", }, }) if err != nil { @@ -99,8 +97,7 @@ func (c *TokenIssuancePolicyClient) Get(ctx context.Context, id string, query od OData: query, ValidStatusCodes: []int{http.StatusOK}, Uri: Uri{ - Entity: fmt.Sprintf("/policies/tokenIssuancePolicies/%s", id), - HasTenantId: false, + Entity: fmt.Sprintf("/policies/tokenIssuancePolicies/%s", id), }, }) if err != nil { @@ -146,8 +143,7 @@ func (c *TokenIssuancePolicyClient) Update(ctx context.Context, tokenIssuancePol http.StatusNoContent, }, Uri: Uri{ - Entity: fmt.Sprintf("/policies/tokenIssuancePolicies/%s", tokenIssuancePolicyId), - HasTenantId: true, + Entity: fmt.Sprintf("/policies/tokenIssuancePolicies/%s", tokenIssuancePolicyId), }, }) if err != nil { @@ -163,8 +159,7 @@ func (c *TokenIssuancePolicyClient) Delete(ctx context.Context, id string) (int, ConsistencyFailureFunc: RetryOn404ConsistencyFailureFunc, ValidStatusCodes: []int{http.StatusNoContent}, Uri: Uri{ - Entity: fmt.Sprintf("/policies/tokenIssuancePolicies/%s", id), - HasTenantId: false, + Entity: fmt.Sprintf("/policies/tokenIssuancePolicies/%s", id), }, }) if err != nil { diff --git a/msgraph/token_issuance_policy_test.go b/msgraph/token_issuance_policy_test.go index ebfda01a..bb5724f5 100644 --- a/msgraph/token_issuance_policy_test.go +++ b/msgraph/token_issuance_policy_test.go @@ -4,10 +4,10 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/sdk/odata" "github.com/manicminer/hamilton/internal/test" "github.com/manicminer/hamilton/internal/utils" "github.com/manicminer/hamilton/msgraph" - "github.com/manicminer/hamilton/odata" ) func TestTokenPolicyClient(t *testing.T) { From bd28117d7a6b1be24c320b97195ac46319044956 Mon Sep 17 00:00:00 2001 From: kenchan0130 Date: Thu, 2 Mar 2023 23:44:47 +0900 Subject: [PATCH 7/7] Changed interface for linking token issuance to service principal --- msgraph/serviceprincipals.go | 25 +++++++++---------------- msgraph/serviceprincipals_test.go | 4 ++-- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/msgraph/serviceprincipals.go b/msgraph/serviceprincipals.go index 710a2446..a0d3dfdf 100644 --- a/msgraph/serviceprincipals.go +++ b/msgraph/serviceprincipals.go @@ -759,17 +759,14 @@ func (c *ServicePrincipalsClient) AssignAppRoleForResource(ctx context.Context, } // AssignTokenIssuancePolicy assigns tokenIssuancePolicies to a service principal -func (c *ServicePrincipalsClient) AssignTokenIssuancePolicy(ctx context.Context, servicePrincipal *ServicePrincipal) (int, error) { +func (c *ServicePrincipalsClient) AssignTokenIssuancePolicy(ctx context.Context, servicePrincipalId string, policies *[]TokenIssuancePolicy) (int, error) { var status int - if servicePrincipal.ID() == nil { - return status, errors.New("cannot update service principal with nil ID") - } - if servicePrincipal.TokenIssuancePolicies == nil { + if policies == nil { return status, errors.New("cannot update service principal with nil TokenIssuancePolicies") } - for _, policy := range *servicePrincipal.TokenIssuancePolicies { + for _, policy := range *policies { // don't fail if an owner already exists checkPolicyAlreadyExists := func(resp *http.Response, o *odata.OData) bool { if resp != nil && resp.StatusCode == http.StatusBadRequest && o != nil && o.Error != nil { @@ -789,7 +786,7 @@ func (c *ServicePrincipalsClient) AssignTokenIssuancePolicy(ctx context.Context, ValidStatusCodes: []int{http.StatusNoContent}, ValidStatusFunc: checkPolicyAlreadyExists, Uri: Uri{ - Entity: fmt.Sprintf("/servicePrincipals/%s/tokenIssuancePolicies/$ref", *servicePrincipal.ID()), + Entity: fmt.Sprintf("/servicePrincipals/%s/tokenIssuancePolicies/$ref", servicePrincipalId), }, }) if err != nil { @@ -801,13 +798,12 @@ func (c *ServicePrincipalsClient) AssignTokenIssuancePolicy(ctx context.Context, } // ListTokenIssuancePolicy retrieves the tokenIssuancePolicies assigned to the specified ServicePrincipal. -// principalId is the object ID of the service principal. -func (c *ServicePrincipalsClient) ListTokenIssuancePolicy(ctx context.Context, principalId string) (*[]TokenIssuancePolicy, int, error) { +func (c *ServicePrincipalsClient) ListTokenIssuancePolicy(ctx context.Context, servicePrincipalId string) (*[]TokenIssuancePolicy, int, error) { resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{ ConsistencyFailureFunc: RetryOn404ConsistencyFailureFunc, ValidStatusCodes: []int{http.StatusOK}, Uri: Uri{ - Entity: fmt.Sprintf("/servicePrincipals/%s/tokenIssuancePolicies", principalId), + Entity: fmt.Sprintf("/servicePrincipals/%s/tokenIssuancePolicies", servicePrincipalId), }, }) if err != nil { @@ -832,17 +828,14 @@ func (c *ServicePrincipalsClient) ListTokenIssuancePolicy(ctx context.Context, p } // RemoveTokenIssuancePolicy removes a tokenIssuancePolicy from a service principal -func (c *ServicePrincipalsClient) RemoveTokenIssuancePolicy(ctx context.Context, servicePrincipal *ServicePrincipal, policyIds *[]string) (int, error) { +func (c *ServicePrincipalsClient) RemoveTokenIssuancePolicy(ctx context.Context, servicePrincipalId string, policyIds *[]string) (int, error) { var status int - if servicePrincipal.ID() == nil { - return status, errors.New("cannot update service principal with nil ID") - } if policyIds == nil { return status, errors.New("cannot remove, nil TokenIssuancePolicyIds") } - assignedPolicies, _, err := c.ListTokenIssuancePolicy(ctx, *servicePrincipal.ID()) + assignedPolicies, _, err := c.ListTokenIssuancePolicy(ctx, servicePrincipalId) if err != nil { return status, fmt.Errorf("ServicePrincipalsClient.BaseClient.ListTokenIssuancePolicy(): %v", err) } @@ -876,7 +869,7 @@ func (c *ServicePrincipalsClient) RemoveTokenIssuancePolicy(ctx context.Context, ValidStatusCodes: []int{http.StatusNoContent}, ValidStatusFunc: checkPolicyStatus, Uri: Uri{ - Entity: fmt.Sprintf("/servicePrincipals/%s/tokenIssuancePolicies/%s/$ref", *servicePrincipal.ID(), policyId), + Entity: fmt.Sprintf("/servicePrincipals/%s/tokenIssuancePolicies/%s/$ref", servicePrincipalId, policyId), }, }) if err != nil { diff --git a/msgraph/serviceprincipals_test.go b/msgraph/serviceprincipals_test.go index e95e96ce..b6552f7c 100644 --- a/msgraph/serviceprincipals_test.go +++ b/msgraph/serviceprincipals_test.go @@ -439,7 +439,7 @@ func testServicePrincipalsClient_RemoveClaimsMappingPolicy(t *testing.T, c *test } func testServicePrincipalsClient_AssignTokenIssuancePolicy(t *testing.T, c *test.Test, sp *msgraph.ServicePrincipal) { - status, err := c.ServicePrincipalsClient.AssignTokenIssuancePolicy(c.Context, sp) + status, err := c.ServicePrincipalsClient.AssignTokenIssuancePolicy(c.Context, *sp.ID(), sp.TokenIssuancePolicies) if err != nil { t.Fatalf("ServicePrincipalsClient.AssignTokenIssuancePolicy(): %v", err) } @@ -449,7 +449,7 @@ func testServicePrincipalsClient_AssignTokenIssuancePolicy(t *testing.T, c *test } func testServicePrincipalsClient_RemoveTokenIssuancePolicy(t *testing.T, c *test.Test, sp *msgraph.ServicePrincipal, policyIds []string) { - status, err := c.ServicePrincipalsClient.RemoveTokenIssuancePolicy(c.Context, sp, &policyIds) + status, err := c.ServicePrincipalsClient.RemoveTokenIssuancePolicy(c.Context, *sp.ID(), &policyIds) if err != nil { t.Fatalf("ServicePrincipalsClient.RemoveTokenIssuancePolicy(): %v", err) }