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 support for PIM AAD Policies and Rules #256

Closed
wants to merge 6 commits into from
Closed
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
18 changes: 18 additions & 0 deletions internal/test/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ type Test struct {
RoleAssignmentsClient *msgraph.RoleAssignmentsClient
RoleDefinitionsClient *msgraph.RoleDefinitionsClient
RoleEligibilityScheduleRequestClient *msgraph.RoleEligibilityScheduleRequestClient
RoleManagementPolicyClient *msgraph.RoleManagementPolicyClient
RoleManagementPolicyAssignmentClient *msgraph.RoleManagementPolicyAssignmentClient
RoleManagementPolicyRuleClient *msgraph.RoleManagementPolicyRuleClient
SchemaExtensionsClient *msgraph.SchemaExtensionsClient
ServicePrincipalsAppRoleAssignmentsClient *msgraph.AppRoleAssignmentsClient
ServicePrincipalsClient *msgraph.ServicePrincipalsClient
Expand Down Expand Up @@ -365,6 +368,21 @@ func NewTest(t *testing.T) (c *Test) {
c.RoleEligibilityScheduleRequestClient.BaseClient.Endpoint = *endpoint
c.RoleEligibilityScheduleRequestClient.BaseClient.RetryableClient.RetryMax = retry

c.RoleManagementPolicyClient = msgraph.NewRoleManagementPolicyClient()
c.RoleManagementPolicyClient.BaseClient.Authorizer = c.Connections["default"].Authorizer
c.RoleManagementPolicyClient.BaseClient.Endpoint = *endpoint
c.RoleManagementPolicyClient.BaseClient.RetryableClient.RetryMax = retry

c.RoleManagementPolicyAssignmentClient = msgraph.NewRoleManagementPolicyAssignmentClient()
c.RoleManagementPolicyAssignmentClient.BaseClient.Authorizer = c.Connections["default"].Authorizer
c.RoleManagementPolicyAssignmentClient.BaseClient.Endpoint = *endpoint
c.RoleManagementPolicyAssignmentClient.BaseClient.RetryableClient.RetryMax = retry

c.RoleManagementPolicyRuleClient = msgraph.NewRoleManagementPolicyRuleClient()
c.RoleManagementPolicyRuleClient.BaseClient.Authorizer = c.Connections["default"].Authorizer
c.RoleManagementPolicyRuleClient.BaseClient.Endpoint = *endpoint
c.RoleManagementPolicyRuleClient.BaseClient.RetryableClient.RetryMax = retry

c.SchemaExtensionsClient = msgraph.NewSchemaExtensionsClient()
c.SchemaExtensionsClient.BaseClient.Authorizer = c.Connections["default"].Authorizer
c.SchemaExtensionsClient.BaseClient.Endpoint = *endpoint
Expand Down
76 changes: 75 additions & 1 deletion msgraph/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,11 @@ type AppRoleAssignment struct {
ResourceId *string `json:"resourceId,omitempty"`
}

type Approval struct {
ID *string `json:"id,omitempty"`
Steps *[]ApprovalStep `json:"steps,omitempty"`
}

type ApprovalSettings struct {
IsApprovalRequiredForAdd *bool `json:"isApprovalRequiredForAdd,omitempty"`
IsApprovalRequiredForUpdate *bool `json:"isApprovalRequiredForUpdate,omitempty"`
Expand All @@ -563,6 +568,17 @@ type ApprovalStage struct {
EscalationApprovers *[]UserSet `json:"escalationApprovers,omitempty"`
}

type ApprovalStep struct {
ID *string `json:"id,omitempty"`
AssignedToMe *bool `json:"assignedToMe,omitempty"`
DisplayName *string `json:"displayName,omitempty"`
Justification *string `json:"justification,omitempty"`
ReviewResult *string `json:"reviewResult,omitempty"`
ReviewedBy *[]UserIdentity `json:"reviewedBy,omitempty"`
ReviewedDateTime *time.Time `json:"reviewedDateTime,omitempty"`
Status ApprovalStepStatus `json:"status,omitempty"`
}

type AssignmentReviewSettings struct {
IsEnabled *bool `json:"isEnabled,omitempty"`
RecurrenceType AccessReviewRecurrenceType `json:"recurrenceType,omitempty"`
Expand Down Expand Up @@ -1728,6 +1744,62 @@ type UnifiedRoleEligibilityScheduleRequest struct {
TicketInfo *TicketInfo `json:"ticketInfo,omitempty"`
}

type UnifiedRoleManagementPolicy struct {
ID *string `json:"id,omitempty"`
Description *string `json:"description,omitempty"`
DisplayName *string `json:"displayName,omitempty"`
EffectiveRules *[]UnifiedRoleManagementPolicyRule `json:"effectiveRules,omitempty"`
IsOrganizationDefault *bool `json:"isOrganizationDefault,omitempty"`
LastModifiedBy *Identity `json:"lastModifiedBy,omitempty"`
LastModifiedDateTime *time.Time `json:"lastModifiedDateTime,omitempty"`
Rules *[]UnifiedRoleManagementPolicyRule `json:"rules,omitempty"`
ScopeId *string `json:"scopeId,omitempty"`
ScopeType UnifiedRoleManagementPolicyScope `json:"scopeType,omitempty"`
}

type UnifiedRoleManagementPolicyAssignment struct {
ID *string `json:"id,omitempty"`
PolicyId *string `json:"policyId,omitempty"`
RoleDefinitionId *string `json:"roleDefinitionId,omitempty"`
ScopeId *string `json:"scopeId,omitempty"`
ScopeType UnifiedRoleManagementPolicyScope `json:"scopeType,omitempty"`
}

type UnifiedRoleManagementPolicyRule struct {
ID *string `json:"id,omitempty"`
ODataType *odata.Type `json:"@odata.type,omitempty"`
Target *UnifiedRoleManagementPolicyRuleTarget `json:"target,omitempty"`

// unifiedRoleManagementPolicyApprovalRule
Setting *ApprovalSettings `json:"setting,omitempty"`

// unifiedRoleManagementPolicyAuthenticationContextRule
ClaimValue *string `json:"claimValue,omitempty"`
IsEnabled *bool `json:"isEnabled,omitempty"`

// unifiedRoleManagementPolicyEnablementRule
EnabledRules *[]string `json:"enabledRules,omitempty"`

// unifiedRoleManagementPolicyExpirationRule
IsExpirationRequired *bool `json:"isExpirationRequired,omitempty"`
MaximumDuration *string `json:"maximumDuration,omitempty"`

//
IsDefaultRecipientsEnabled *bool `json:"isDefaultRecipientsEnabled,omitempty"`
NotificationLevel UnifiedRoleManagementPolicyRuleNotificationLevel `json:"notificationLevel,omitempty"`
NotificationRecipients *[]string `json:"notificationRecipients,omitempty"`
NotificationType UnifiedRoleManagementPolicyRuleNotificationType `json:"notificationType,omitempty"`
RecipientType UnifiedRoleManagementPolicyRuleNotificationRecipientType `json:"recipientType,omitempty"`
}

type UnifiedRoleManagementPolicyRuleTarget struct {
Caller UnifiedRoleManagementPolicyRuleTargetCallerType `json:"caller,omitempty"`
EnforcedSettings *[]string `json:"enforcedSettings,omitempty"`
InheritableSettings *[]string `json:"inheritableSettings,omitempty"`
Level UnifiedRoleManagementPolicyRuleLevel `json:"level,omitempty"`
Operations *[]UnifiedRoleManagementPolicyRuleOperation `json:"operations,omitempty"`
}

type UnifiedRolePermission struct {
AllowedResourceActions *[]string `json:"allowedResourceActions,omitempty"`
Condition *StringNullWhenEmpty `json:"condition,omitempty"`
Expand Down Expand Up @@ -1891,7 +1963,9 @@ type UserRegistrationMethodSummary struct {
type UserSet struct {
ODataType *odata.Type `json:"@odata.type,omitempty"`
IsBackup *bool `json:"isBackup,omitempty"`
ID *string `json:"id,omitempty"` // Either user or group ID
ID *string `json:"id,omitempty"` // Either user or group ID
GroupID *string `json:"groupId,omitempty"` // oData groupMembers
UserID *string `json:"userId,omitempty"` // oData singleUser
Description *string `json:"description,omitempty"`
ManagerLevel *int32 `json:"managerLevel,omitempty"`
}
Expand Down
104 changes: 104 additions & 0 deletions msgraph/role_management_policies.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package msgraph

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

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

type RoleManagementPolicyClient struct {
BaseClient Client
}

func NewRoleManagementPolicyClient() *RoleManagementPolicyClient {
return &RoleManagementPolicyClient{
BaseClient: NewClient(VersionBeta),
}
}

// List retrieves a list of Role Management Policies
func (c *RoleManagementPolicyClient) List(ctx context.Context, query odata.Query) (*[]UnifiedRoleManagementPolicy, int, error) {
query.Expand = odata.Expand{Relationship: "*"}
resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{
ConsistencyFailureFunc: RetryOn404ConsistencyFailureFunc,
OData: query,
ValidStatusCodes: []int{http.StatusOK},
Uri: Uri{
Entity: "/policies/roleManagementPolicies",
},
})
if err != nil {
return nil, status, fmt.Errorf("RoleManagementPolicyClient.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 {
UnifiedRoleManagementPolicy []UnifiedRoleManagementPolicy `json:"value"`
}
if err := json.Unmarshal(respBody, &data); err != nil {
return nil, status, fmt.Errorf("json.Unmarshal(): %v", err)
}

return &data.UnifiedRoleManagementPolicy, status, nil
}

// Get retrieves a UnifiedRoleManagementPolicy
func (c *RoleManagementPolicyClient) Get(ctx context.Context, id string) (*UnifiedRoleManagementPolicy, int, error) {
resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{
OData: odata.Query{
Expand: odata.Expand{Relationship: "*"},
},
ValidStatusCodes: []int{http.StatusOK},
Uri: Uri{
Entity: fmt.Sprintf("/policies/roleManagementPolicies/%s", id),
},
})
if err != nil {
return nil, status, fmt.Errorf("RoleDefinitionsClient.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 policy UnifiedRoleManagementPolicy
if err := json.Unmarshal(respBody, &policy); err != nil {
return nil, status, fmt.Errorf("json.Unmarshal(): %v", err)
}

return &policy, status, nil
}

// Update amends an existing UnifiedRoleManagementPolicy.
func (c *RoleManagementPolicyClient) Update(ctx context.Context, policy UnifiedRoleManagementPolicy) (int, error) {
var status int

body, err := json.Marshal(policy)
if err != nil {
return status, fmt.Errorf("json.Marshal(): %v", err)
}

_, status, _, err = c.BaseClient.Patch(ctx, PatchHttpRequestInput{
Body: body,
ValidStatusCodes: []int{http.StatusOK},
Uri: Uri{
Entity: fmt.Sprintf("/policies/roleManagementPolicies/%s", *policy.ID),
},
})
if err != nil {
return status, fmt.Errorf("RoleDefinitionsClient.BaseClient.Patch(): %v", err)
}

return status, nil
}
80 changes: 80 additions & 0 deletions msgraph/role_management_policies_assignment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package msgraph

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

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

type RoleManagementPolicyAssignmentClient struct {
BaseClient Client
}

func NewRoleManagementPolicyAssignmentClient() *RoleManagementPolicyAssignmentClient {
return &RoleManagementPolicyAssignmentClient{
BaseClient: NewClient(VersionBeta),
}
}

// List retrieves a list of Role Management Policies
func (c *RoleManagementPolicyAssignmentClient) List(ctx context.Context, query odata.Query) (*[]UnifiedRoleManagementPolicyAssignment, int, error) {
query.Expand = odata.Expand{Relationship: "*"}
resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{
OData: query,
ValidStatusCodes: []int{http.StatusOK},
Uri: Uri{
Entity: "/policies/roleManagementPolicyAssignments",
},
})
if err != nil {
return nil, status, fmt.Errorf("RoleManagementPolicyAssignmentClient.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 {
UnifiedRoleManagementPolicyAssignment []UnifiedRoleManagementPolicyAssignment `json:"value"`
}
if err := json.Unmarshal(respBody, &data); err != nil {
return nil, status, fmt.Errorf("json.Unmarshal(): %v", err)
}

return &data.UnifiedRoleManagementPolicyAssignment, status, nil
}

// Get retrieves a UnifiedRoleManagementPolicy
func (c *RoleManagementPolicyAssignmentClient) Get(ctx context.Context, id string) (*UnifiedRoleManagementPolicyAssignment, int, error) {
resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{
OData: odata.Query{
Expand: odata.Expand{Relationship: "*"},
},
ValidStatusCodes: []int{http.StatusOK},
Uri: Uri{
Entity: fmt.Sprintf("/policies/roleManagementPolicyAssignments/%s", id),
},
})
if err != nil {
return nil, status, fmt.Errorf("RoleDefinitionsClient.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 assign UnifiedRoleManagementPolicyAssignment
if err := json.Unmarshal(respBody, &assign); err != nil {
return nil, status, fmt.Errorf("json.Unmarshal(): %v", err)
}

return &assign, status, nil
}
37 changes: 37 additions & 0 deletions msgraph/role_management_policies_assignment_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package msgraph_test

import (
"testing"

"github.com/hashicorp/go-azure-sdk/sdk/odata"
"github.com/manicminer/hamilton/internal/test"
"github.com/manicminer/hamilton/msgraph"
)

func testRoleManagementPolicyAssignmentClient_List(t *testing.T, c *test.Test, query odata.Query) (rules *[]msgraph.UnifiedRoleManagementPolicyAssignment) {
rules, status, err := c.RoleManagementPolicyAssignmentClient.List(c.Context, query)
if err != nil {
t.Fatalf("RoleManagementPolicyAssignmentClient.List(): %v", err)
}
if status < 200 || status >= 300 {
t.Fatalf("RoleManagementPolicyAssignmentClient.List(): invalid status: %d", status)
}
if rules == nil {
t.Fatal("RoleManagementPolicyAssignmentClient.List(): response was nil")
}
return
}

func testRoleManagementPolicyAssignmentClient_Get(t *testing.T, c *test.Test, assignmentId string) (rule *msgraph.UnifiedRoleManagementPolicyAssignment) {
rule, status, err := c.RoleManagementPolicyAssignmentClient.Get(c.Context, assignmentId)
if err != nil {
t.Fatalf("RoleManagementPolicyAssignmentClient.Get(): %v", err)
}
if status < 200 || status >= 300 {
t.Fatalf("RoleManagementPolicyAssignmentClient.Get(): invalid status: %d", status)
}
if rule == nil {
t.Fatal("RoleManagementPolicyAssignmentClient.Get(): response was nil")
}
return
}
Loading