diff --git a/providers/ms365/resources/ms365.lr b/providers/ms365/resources/ms365.lr index 395f75d44..aaddead22 100644 --- a/providers/ms365/resources/ms365.lr +++ b/providers/ms365/resources/ms365.lr @@ -747,4 +747,22 @@ private ms365.teams.teamsMeetingPolicyConfig { private ms365.teams.teamsMessagingPolicyConfig { // Whether users can report security concerns allowSecurityEndUserReporting bool +} + +// Microsoft Admin Portal +microsoft.adminPortal { + // List of delegated admin partners + delegatedAdminPartners() []microsoft.adminPortal.delegatedAdminPartner +} + +// Microsoft 365 Entra ID Delegated Admin Partner +microsoft.adminPortal.delegatedAdminPartner @defaults("id displayName") { + // Partner ID + id string + // Partner Display Name + displayName string + // List of Unified Roles for the partner + unifiedRoles []string + // Status of the delegated admin relationship + status string } \ No newline at end of file diff --git a/providers/ms365/resources/ms365.lr.go b/providers/ms365/resources/ms365.lr.go index f4476575c..e5464a6b8 100644 --- a/providers/ms365/resources/ms365.lr.go +++ b/providers/ms365/resources/ms365.lr.go @@ -158,6 +158,14 @@ func init() { // to override args, implement: initMs365TeamsTeamsMessagingPolicyConfig(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) Create: createMs365TeamsTeamsMessagingPolicyConfig, }, + "microsoft.adminPortal": { + // to override args, implement: initMicrosoftAdminPortal(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) + Create: createMicrosoftAdminPortal, + }, + "microsoft.adminPortal.delegatedAdminPartner": { + // to override args, implement: initMicrosoftAdminPortalDelegatedAdminPartner(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) + Create: createMicrosoftAdminPortalDelegatedAdminPartner, + }, } } @@ -1129,6 +1137,21 @@ var getDataFields = map[string]func(r plugin.Resource) *plugin.DataRes{ "ms365.teams.teamsMessagingPolicyConfig.allowSecurityEndUserReporting": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlMs365TeamsTeamsMessagingPolicyConfig).GetAllowSecurityEndUserReporting()).ToDataRes(types.Bool) }, + "microsoft.adminPortal.delegatedAdminPartners": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftAdminPortal).GetDelegatedAdminPartners()).ToDataRes(types.Array(types.Resource("microsoft.adminPortal.delegatedAdminPartner"))) + }, + "microsoft.adminPortal.delegatedAdminPartner.id": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftAdminPortalDelegatedAdminPartner).GetId()).ToDataRes(types.String) + }, + "microsoft.adminPortal.delegatedAdminPartner.displayName": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftAdminPortalDelegatedAdminPartner).GetDisplayName()).ToDataRes(types.String) + }, + "microsoft.adminPortal.delegatedAdminPartner.unifiedRoles": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftAdminPortalDelegatedAdminPartner).GetUnifiedRoles()).ToDataRes(types.Array(types.String)) + }, + "microsoft.adminPortal.delegatedAdminPartner.status": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftAdminPortalDelegatedAdminPartner).GetStatus()).ToDataRes(types.String) + }, } func GetData(resource plugin.Resource, field string, args map[string]*llx.RawData) *plugin.DataRes { @@ -2485,6 +2508,34 @@ var setDataFields = map[string]func(r plugin.Resource, v *llx.RawData) bool { r.(*mqlMs365TeamsTeamsMessagingPolicyConfig).AllowSecurityEndUserReporting, ok = plugin.RawToTValue[bool](v.Value, v.Error) return }, + "microsoft.adminPortal.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftAdminPortal).__id, ok = v.Value.(string) + return + }, + "microsoft.adminPortal.delegatedAdminPartners": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftAdminPortal).DelegatedAdminPartners, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, + "microsoft.adminPortal.delegatedAdminPartner.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftAdminPortalDelegatedAdminPartner).__id, ok = v.Value.(string) + return + }, + "microsoft.adminPortal.delegatedAdminPartner.id": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftAdminPortalDelegatedAdminPartner).Id, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "microsoft.adminPortal.delegatedAdminPartner.displayName": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftAdminPortalDelegatedAdminPartner).DisplayName, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "microsoft.adminPortal.delegatedAdminPartner.unifiedRoles": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftAdminPortalDelegatedAdminPartner).UnifiedRoles, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, + "microsoft.adminPortal.delegatedAdminPartner.status": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftAdminPortalDelegatedAdminPartner).Status, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, } func SetData(resource plugin.Resource, field string, val *llx.RawData) error { @@ -5884,3 +5935,118 @@ func (c *mqlMs365TeamsTeamsMessagingPolicyConfig) MqlID() string { func (c *mqlMs365TeamsTeamsMessagingPolicyConfig) GetAllowSecurityEndUserReporting() *plugin.TValue[bool] { return &c.AllowSecurityEndUserReporting } + +// mqlMicrosoftAdminPortal for the microsoft.adminPortal resource +type mqlMicrosoftAdminPortal struct { + MqlRuntime *plugin.Runtime + __id string + // optional: if you define mqlMicrosoftAdminPortalInternal it will be used here + DelegatedAdminPartners plugin.TValue[[]interface{}] +} + +// createMicrosoftAdminPortal creates a new instance of this resource +func createMicrosoftAdminPortal(runtime *plugin.Runtime, args map[string]*llx.RawData) (plugin.Resource, error) { + res := &mqlMicrosoftAdminPortal{ + MqlRuntime: runtime, + } + + err := SetAllData(res, args) + if err != nil { + return res, err + } + + // to override __id implement: id() (string, error) + + if runtime.HasRecording { + args, err = runtime.ResourceFromRecording("microsoft.adminPortal", res.__id) + if err != nil || args == nil { + return res, err + } + return res, SetAllData(res, args) + } + + return res, nil +} + +func (c *mqlMicrosoftAdminPortal) MqlName() string { + return "microsoft.adminPortal" +} + +func (c *mqlMicrosoftAdminPortal) MqlID() string { + return c.__id +} + +func (c *mqlMicrosoftAdminPortal) GetDelegatedAdminPartners() *plugin.TValue[[]interface{}] { + return plugin.GetOrCompute[[]interface{}](&c.DelegatedAdminPartners, func() ([]interface{}, error) { + if c.MqlRuntime.HasRecording { + d, err := c.MqlRuntime.FieldResourceFromRecording("microsoft.adminPortal", c.__id, "delegatedAdminPartners") + if err != nil { + return nil, err + } + if d != nil { + return d.Value.([]interface{}), nil + } + } + + return c.delegatedAdminPartners() + }) +} + +// mqlMicrosoftAdminPortalDelegatedAdminPartner for the microsoft.adminPortal.delegatedAdminPartner resource +type mqlMicrosoftAdminPortalDelegatedAdminPartner struct { + MqlRuntime *plugin.Runtime + __id string + // optional: if you define mqlMicrosoftAdminPortalDelegatedAdminPartnerInternal it will be used here + Id plugin.TValue[string] + DisplayName plugin.TValue[string] + UnifiedRoles plugin.TValue[[]interface{}] + Status plugin.TValue[string] +} + +// createMicrosoftAdminPortalDelegatedAdminPartner creates a new instance of this resource +func createMicrosoftAdminPortalDelegatedAdminPartner(runtime *plugin.Runtime, args map[string]*llx.RawData) (plugin.Resource, error) { + res := &mqlMicrosoftAdminPortalDelegatedAdminPartner{ + MqlRuntime: runtime, + } + + err := SetAllData(res, args) + if err != nil { + return res, err + } + + // to override __id implement: id() (string, error) + + if runtime.HasRecording { + args, err = runtime.ResourceFromRecording("microsoft.adminPortal.delegatedAdminPartner", res.__id) + if err != nil || args == nil { + return res, err + } + return res, SetAllData(res, args) + } + + return res, nil +} + +func (c *mqlMicrosoftAdminPortalDelegatedAdminPartner) MqlName() string { + return "microsoft.adminPortal.delegatedAdminPartner" +} + +func (c *mqlMicrosoftAdminPortalDelegatedAdminPartner) MqlID() string { + return c.__id +} + +func (c *mqlMicrosoftAdminPortalDelegatedAdminPartner) GetId() *plugin.TValue[string] { + return &c.Id +} + +func (c *mqlMicrosoftAdminPortalDelegatedAdminPartner) GetDisplayName() *plugin.TValue[string] { + return &c.DisplayName +} + +func (c *mqlMicrosoftAdminPortalDelegatedAdminPartner) GetUnifiedRoles() *plugin.TValue[[]interface{}] { + return &c.UnifiedRoles +} + +func (c *mqlMicrosoftAdminPortalDelegatedAdminPartner) GetStatus() *plugin.TValue[string] { + return &c.Status +} diff --git a/providers/ms365/resources/ms365.lr.manifest.yaml b/providers/ms365/resources/ms365.lr.manifest.yaml index 87d39b4c2..00379cc93 100755 --- a/providers/ms365/resources/ms365.lr.manifest.yaml +++ b/providers/ms365/resources/ms365.lr.manifest.yaml @@ -18,6 +18,17 @@ resources: min_mondoo_version: latest users: {} min_mondoo_version: 5.15.0 + microsoft.adminPortal: + fields: + delegatedAdminPartners: {} + min_mondoo_version: 9.0.0 + microsoft.adminPortal.delegatedAdminPartner: + fields: + displayName: {} + id: {} + status: {} + unifiedRoles: {} + min_mondoo_version: 9.0.0 microsoft.application: fields: api: diff --git a/providers/ms365/resources/rolemanagement.go b/providers/ms365/resources/rolemanagement.go index cb99dee8f..2d1615678 100644 --- a/providers/ms365/resources/rolemanagement.go +++ b/providers/ms365/resources/rolemanagement.go @@ -5,6 +5,8 @@ package resources import ( "context" + "log" + "go.mondoo.com/cnquery/v11/providers-sdk/v1/plugin" "github.com/microsoftgraph/msgraph-sdk-go/rolemanagement" @@ -117,3 +119,74 @@ func (a *mqlMicrosoftRolemanagementRoledefinition) assignments() ([]interface{}, } return res, nil } + +// Related to Delegated Admin Portal under Roles & admin in Entra ID +func (a *mqlMicrosoftAdminPortal) delegatedAdminPartners() ([]interface{}, error) { + conn := a.MqlRuntime.Connection.(*connection.Ms365Connection) + graphClient, err := conn.GraphClient() + if err != nil { + return nil, err + } + + ctx := context.Background() + + partnersResp, err := graphClient.TenantRelationships().DelegatedAdminRelationships().Get(ctx, nil) + if err != nil { + return nil, transformError(err) + } + + var partnerDetails []interface{} + + for _, partner := range partnersResp.GetValue() { + partnerId := partner.GetId() + displayName := partner.GetDisplayName() + accessDetails := partner.GetAccessDetails() + status := partner.GetStatus() // Fetch the status property + + if partnerId != nil && displayName != nil { + unifiedRoles := []interface{}{} + if accessDetails != nil && accessDetails.GetUnifiedRoles() != nil { + for _, role := range accessDetails.GetUnifiedRoles() { + roleDefinitionId := role.GetRoleDefinitionId() + if roleDefinitionId != nil { + unifiedRoles = append(unifiedRoles, *roleDefinitionId) + } + } + } + + unifiedRolesData, err := convert.JsonToDictSlice(unifiedRoles) + if err != nil { + return nil, err + } + + var statusStr *string + if status != nil { + s := status.String() + statusStr = &s + } + + partnerInfo, err := CreateResource(a.MqlRuntime, "microsoft.adminPortal.delegatedAdminPartner", + map[string]*llx.RawData{ + "id": llx.StringDataPtr(partnerId), + "displayName": llx.StringDataPtr(displayName), + "unifiedRoles": llx.ArrayData(unifiedRolesData, types.String), + "status": llx.StringDataPtr(statusStr), + }) + if err != nil { + return nil, err + } + + partnerDetails = append(partnerDetails, partnerInfo) + } else { + log.Printf("Skipped a partner with missing ID or Display Name") + } + } + + // If no partners are found + if len(partnerDetails) == 0 { + log.Println("No delegated admin partners are defined.") + return nil, nil + } + + return partnerDetails, nil +}