diff --git a/pkg/connector/role.go b/pkg/connector/role.go index ba32c4e..685ec5c 100644 --- a/pkg/connector/role.go +++ b/pkg/connector/role.go @@ -3,6 +3,7 @@ package connector import ( "context" "fmt" + "slices" "github.com/conductorone/baton-jamf/pkg/jamf" v2 "github.com/conductorone/baton-sdk/pb/c1/connector/v2" @@ -22,11 +23,10 @@ func (o *roleResourceType) ResourceType(_ context.Context) *v2.ResourceType { return o.resourceType } -var privileges = []string{ +var privilegeSets = []string{ "Administrator", "Auditor", "Enrollment Only", - "Custom", } // Create a new connector resource for a Jamf role. @@ -56,7 +56,20 @@ func roleResource(ctx context.Context, role string, parentResourceID *v2.Resourc func (o *roleResourceType) List(ctx context.Context, parentId *v2.ResourceId, token *pagination.Token) ([]*v2.Resource, string, annotations.Annotations, error) { var rv []*v2.Resource - for _, privilege := range privileges { + for _, privilegeSet := range privilegeSets { + rr, err := roleResource(ctx, privilegeSet, parentId) + if err != nil { + return nil, "", nil, err + } + rv = append(rv, rr) + } + + res, err := o.client.GetPrivileges(ctx) + if err != nil { + return nil, "", nil, err + } + + for _, privilege := range res.Privileges { rr, err := roleResource(ctx, privilege, parentId) if err != nil { return nil, "", nil, err @@ -84,7 +97,7 @@ func (o *roleResourceType) Entitlements(_ context.Context, resource *v2.Resource func (o *roleResourceType) Grants(ctx context.Context, resource *v2.Resource, token *pagination.Token) ([]*v2.Grant, string, annotations.Annotations, error) { var rv []*v2.Grant - + isCustomPrivilege := !slices.Contains(privilegeSets, resource.Id.Resource) userAccounts, groups, err := o.client.GetAccounts(ctx) if err != nil { return nil, "", nil, err @@ -97,7 +110,12 @@ func (o *roleResourceType) Grants(ctx context.Context, resource *v2.Resource, to return nil, "", nil, err } - if resource.Id.Resource == group.PrivilegeSet { + if isCustomPrivilege && slices.Contains(group.Privileges.JSSObjects, resource.Id.Resource) { + privilegeGrant := grant.NewGrant(resource, memberEntitlement, gr.Id) + rv = append(rv, privilegeGrant) + continue + } + if group.PrivilegeSet == resource.Id.Resource { privilegeGrant := grant.NewGrant(resource, memberEntitlement, gr.Id) rv = append(rv, privilegeGrant) } @@ -110,12 +128,16 @@ func (o *roleResourceType) Grants(ctx context.Context, resource *v2.Resource, to return nil, "", nil, err } - if resource.Id.Resource == userAccount.PrivilegeSet { + if isCustomPrivilege && slices.Contains(userAccount.Privileges.JSSObjects, resource.Id.Resource) { + privilegeGrant := grant.NewGrant(resource, memberEntitlement, gr.Id) + rv = append(rv, privilegeGrant) + continue + } + if userAccount.PrivilegeSet == resource.Id.Resource { privilegeGrant := grant.NewGrant(resource, memberEntitlement, gr.Id) rv = append(rv, privilegeGrant) } } - return rv, "", nil, nil } diff --git a/pkg/jamf/client.go b/pkg/jamf/client.go index 66689bc..3a586f1 100644 --- a/pkg/jamf/client.go +++ b/pkg/jamf/client.go @@ -28,6 +28,7 @@ const ( userUrlPath = "/JSSResource/users/id/%d" usersUrlPath = "/JSSResource/users" keepAliveUrlPath = "/api/v1/auth/keep-alive" + privilegesUrlPath = "/api/v1/api-role-privileges" ) type Client struct { @@ -430,3 +431,17 @@ func logBody(body []byte, size int) string { } return string(body) } + +func (c *Client) GetPrivileges(ctx context.Context) (*PrivilegesResponse, error) { + url, err := c.getUrl(privilegesUrlPath) + if err != nil { + return nil, err + } + + var target PrivilegesResponse + if err := c.doRequest(ctx, url, &target); err != nil { + return nil, err + } + + return &target, nil +} diff --git a/pkg/jamf/models.go b/pkg/jamf/models.go index 3a72b30..d47b58a 100644 --- a/pkg/jamf/models.go +++ b/pkg/jamf/models.go @@ -25,20 +25,36 @@ type BaseAccount struct { // UserAccount - user that has access to their system and can be granted permissions. type UserAccount struct { BaseType - FullName string `json:"full_name"` - Email string `json:"email"` - EmailAddress string `json:"email_address"` - Enabled string `json:"enabled"` - AccessLevel string `json:"access_level"` - PrivilegeSet string `json:"privilege_set"` - Site BaseType `json:"site"` + FullName string `json:"full_name"` + Email string `json:"email"` + EmailAddress string `json:"email_address"` + Enabled string `json:"enabled"` + AccessLevel string `json:"access_level"` + PrivilegeSet string `json:"privilege_set"` + Privileges Privileges `json:"privileges"` + Site BaseType `json:"site"` +} + +type Privileges struct { + // array of privileges the resource has access to + JSSObjects []string `json:"jss_objects"` } type Group struct { BaseType - AccessLevel string `json:"access_level"` - PrivilegeSet string `json:"privilege_set"` - Site BaseType `json:"site"` + AccessLevel string `json:"access_level"` + // PrivilegeSet can take the following values: + // + // - "Administrator" + // + // - "Auditor" + // + // - "Enrollment Only" + // + // - "Custom" + PrivilegeSet string `json:"privilege_set"` + Privileges Privileges `json:"privileges"` + Site BaseType `json:"site"` Members []struct { User BaseType `json:"user"` } `json:"members"` @@ -111,3 +127,7 @@ type AccountsResponse struct { type SitesResponse struct { Sites []Site `json:"sites"` } + +type PrivilegesResponse struct { + Privileges []string `json:"privileges"` +}