Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TokenIssuancePolicy #215

Merged
merged 7 commits into from
Apr 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions internal/test/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.TokenIssuancePolicyClient.BaseClient.Authorizer = c.Connections["default"].Authorizer
c.TokenIssuancePolicyClient.BaseClient.Endpoint = *endpoint
c.TokenIssuancePolicyClient.BaseClient.RetryableClient.RetryMax = retry

c.UserFlowAttributesClient = msgraph.NewUserFlowAttributesClient()
c.UserFlowAttributesClient.BaseClient.Authorizer = c.Connections["b2c"].Authorizer
c.UserFlowAttributesClient.BaseClient.Endpoint = *endpoint
Expand Down
9 changes: 9 additions & 0 deletions msgraph/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -1429,6 +1429,7 @@ type ServicePrincipal struct {
SignInAudience *SignInAudience `json:"signInAudience,omitempty"`
Tags *[]string `json:"tags,omitempty"`
TokenEncryptionKeyId *string `json:"tokenEncryptionKeyId,omitempty"`
TokenIssuancePolicies *[]TokenIssuancePolicy `json:"[email protected],omitempty"`
VerifiedPublisher *VerifiedPublisher `json:"verifiedPublisher,omitempty"`
}

Expand Down Expand Up @@ -1634,6 +1635,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

Expand Down
122 changes: 122 additions & 0 deletions msgraph/serviceprincipals.go
Original file line number Diff line number Diff line change
Expand Up @@ -757,3 +757,125 @@ 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, servicePrincipalId string, policies *[]TokenIssuancePolicy) (int, error) {
var status int

if policies == nil {
return status, errors.New("cannot update service principal with nil 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 {
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", servicePrincipalId),
},
})
if err != nil {
return status, fmt.Errorf("ServicePrincipalsClient.BaseClient.Post(): %v", err)
}
}

return status, nil
}

// ListTokenIssuancePolicy retrieves the tokenIssuancePolicies assigned to the specified ServicePrincipal.
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", servicePrincipalId),
},
})
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, servicePrincipalId string, policyIds *[]string) (int, error) {
var status int

if policyIds == nil {
return status, errors.New("cannot remove, nil TokenIssuancePolicyIds")
}

assignedPolicies, _, err := c.ListTokenIssuancePolicy(ctx, servicePrincipalId)
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", servicePrincipalId, policyId),
},
})
if err != nil {
return status, fmt.Errorf("ServicePrincipalsClient.BaseClient.Delete(): %v", err)
}
}

return status, nil
}
38 changes: 38 additions & 0 deletions msgraph/serviceprincipals_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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.ID(), sp.TokenIssuancePolicies)
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.ID(), &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 {
Expand Down
170 changes: 170 additions & 0 deletions msgraph/token_issuance_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package msgraph

import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"

"github.com/hashicorp/go-azure-sdk/sdk/odata"
)

type TokenIssuancePolicyClient struct {
BaseClient Client
}

// NewTokenIssuancePolicyClient returns a new TokenIssuancePolicyClient
func NewTokenIssuancePolicyClient() *TokenIssuancePolicyClient {
return &TokenIssuancePolicyClient{
BaseClient: NewClient(Version10),
}
}

// 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",
},
})
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",
},
})
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),
},
})
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")
}

tokenIssuancePolicyId := *tokenIssuancePolicy.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", tokenIssuancePolicyId),
},
})
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),
},
})
if err != nil {
return status, fmt.Errorf("TokenIssuancePolicyClient.BaseClient.Delete(): %v", err)
}

return status, nil
}
Loading