diff --git a/providers/ms365/resources/applications.go b/providers/ms365/resources/applications.go index 4829d0a608..d88da0ce38 100644 --- a/providers/ms365/resources/applications.go +++ b/providers/ms365/resources/applications.go @@ -8,6 +8,7 @@ import ( "encoding/base64" "errors" "fmt" + "github.com/rs/zerolog/log" "net/url" "time" @@ -97,6 +98,33 @@ func newMqlMicrosoftApplication(runtime *plugin.Runtime, app models.Applicationa nativeAuthenticationApisEnabled = &val } + mqlAppRoleList := []interface{}{} + appRoles := app.GetAppRoles() + for i := range appRoles { + appRole := appRoles[i] + + uuid := appRole.GetId() + if uuid == nil { + log.Debug().Msg("appRole ID is nil") + continue + } + + mqlAppRoleResource, err := CreateResource(runtime, "microsoft.application.role", + map[string]*llx.RawData{ + "__id": llx.StringData(uuid.String()), + "id": llx.StringData(uuid.String()), + "name": llx.StringDataPtr(appRole.GetDisplayName()), + "description": llx.StringDataPtr(appRole.GetDescription()), + "value": llx.StringDataPtr(appRole.GetValue()), + "allowedMemberTypes": llx.ArrayData(convert.SliceAnyToInterface(appRole.GetAllowedMemberTypes()), types.String), + "isEnabled": llx.BoolDataPtr(appRole.GetIsEnabled()), + }) + if err != nil { + return nil, err + } + mqlAppRoleList = append(mqlAppRoleList, mqlAppRoleResource) + } + mqlResource, err := CreateResource(runtime, "microsoft.application", map[string]*llx.RawData{ "__id": llx.StringDataPtr(app.GetId()), @@ -134,6 +162,7 @@ func newMqlMicrosoftApplication(runtime *plugin.Runtime, app models.Applicationa "requestSignatureVerification": llx.DictData(requestSignatureVerification), "parentalControlSettings": llx.DictData(parentalControlSettings), "publicClient": llx.DictData(publicClient), + "appRoles": llx.ArrayData(mqlAppRoleList, types.Resource("microsoft.application.role")), }) if err != nil { return nil, err diff --git a/providers/ms365/resources/ms365.lr b/providers/ms365/resources/ms365.lr index 5350973fb1..00b8942d3f 100644 --- a/providers/ms365/resources/ms365.lr +++ b/providers/ms365/resources/ms365.lr @@ -269,6 +269,24 @@ microsoft.application @defaults("id displayName hasExpiredCredentials") { parentalControlSettings dict // Public client configuration publicClient dict + // Application roles + appRoles []microsoft.application.role +} + +// Microsoft Entra ID app roles are custom roles to assign permissions to users or apps +private microsoft.application.role @defaults("name value isEnabled"){ + // App role ID + id string + // Display name + name string + // Description + description string + // Value + value string + // Allowed member types + allowedMemberTypes []string + // App state + isEnabled bool } // Microsoft Entra AD Application certificate @@ -357,6 +375,8 @@ private microsoft.serviceprincipal @defaults("name") { accountEnabled bool // Whether it is a first-party Microsoft application isFirstParty() bool + // Application roles + appRoles []microsoft.application.role } // Microsoft Service Principal Assignment diff --git a/providers/ms365/resources/ms365.lr.go b/providers/ms365/resources/ms365.lr.go index 01d9dc4b28..9ed3be0bcd 100644 --- a/providers/ms365/resources/ms365.lr.go +++ b/providers/ms365/resources/ms365.lr.go @@ -50,6 +50,10 @@ func init() { Init: initMicrosoftApplication, Create: createMicrosoftApplication, }, + "microsoft.application.role": { + // to override args, implement: initMicrosoftApplicationRole(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) + Create: createMicrosoftApplicationRole, + }, "microsoft.keyCredential": { // to override args, implement: initMicrosoftKeyCredential(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) Create: createMicrosoftKeyCredential, @@ -565,6 +569,27 @@ var getDataFields = map[string]func(r plugin.Resource) *plugin.DataRes{ "microsoft.application.publicClient": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlMicrosoftApplication).GetPublicClient()).ToDataRes(types.Dict) }, + "microsoft.application.appRoles": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftApplication).GetAppRoles()).ToDataRes(types.Array(types.Resource("microsoft.application.role"))) + }, + "microsoft.application.role.id": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftApplicationRole).GetId()).ToDataRes(types.String) + }, + "microsoft.application.role.name": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftApplicationRole).GetName()).ToDataRes(types.String) + }, + "microsoft.application.role.description": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftApplicationRole).GetDescription()).ToDataRes(types.String) + }, + "microsoft.application.role.value": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftApplicationRole).GetValue()).ToDataRes(types.String) + }, + "microsoft.application.role.allowedMemberTypes": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftApplicationRole).GetAllowedMemberTypes()).ToDataRes(types.Array(types.String)) + }, + "microsoft.application.role.isEnabled": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftApplicationRole).GetIsEnabled()).ToDataRes(types.Bool) + }, "microsoft.keyCredential.keyId": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlMicrosoftKeyCredential).GetKeyId()).ToDataRes(types.String) }, @@ -679,6 +704,9 @@ var getDataFields = map[string]func(r plugin.Resource) *plugin.DataRes{ "microsoft.serviceprincipal.isFirstParty": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlMicrosoftServiceprincipal).GetIsFirstParty()).ToDataRes(types.Bool) }, + "microsoft.serviceprincipal.appRoles": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftServiceprincipal).GetAppRoles()).ToDataRes(types.Array(types.Resource("microsoft.application.role"))) + }, "microsoft.serviceprincipal.assignment.id": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlMicrosoftServiceprincipalAssignment).GetId()).ToDataRes(types.String) }, @@ -1539,6 +1567,38 @@ var setDataFields = map[string]func(r plugin.Resource, v *llx.RawData) bool { r.(*mqlMicrosoftApplication).PublicClient, ok = plugin.RawToTValue[interface{}](v.Value, v.Error) return }, + "microsoft.application.appRoles": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftApplication).AppRoles, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, + "microsoft.application.role.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftApplicationRole).__id, ok = v.Value.(string) + return + }, + "microsoft.application.role.id": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftApplicationRole).Id, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "microsoft.application.role.name": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftApplicationRole).Name, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "microsoft.application.role.description": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftApplicationRole).Description, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "microsoft.application.role.value": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftApplicationRole).Value, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "microsoft.application.role.allowedMemberTypes": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftApplicationRole).AllowedMemberTypes, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, + "microsoft.application.role.isEnabled": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftApplicationRole).IsEnabled, ok = plugin.RawToTValue[bool](v.Value, v.Error) + return + }, "microsoft.keyCredential.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { r.(*mqlMicrosoftKeyCredential).__id, ok = v.Value.(string) return @@ -1703,6 +1763,10 @@ var setDataFields = map[string]func(r plugin.Resource, v *llx.RawData) bool { r.(*mqlMicrosoftServiceprincipal).IsFirstParty, ok = plugin.RawToTValue[bool](v.Value, v.Error) return }, + "microsoft.serviceprincipal.appRoles": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftServiceprincipal).AppRoles, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, "microsoft.serviceprincipal.assignment.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { r.(*mqlMicrosoftServiceprincipalAssignment).__id, ok = v.Value.(string) return @@ -3152,6 +3216,7 @@ type mqlMicrosoftApplication struct { RequestSignatureVerification plugin.TValue[interface{}] ParentalControlSettings plugin.TValue[interface{}] PublicClient plugin.TValue[interface{}] + AppRoles plugin.TValue[[]interface{}] } // createMicrosoftApplication creates a new instance of this resource @@ -3360,6 +3425,79 @@ func (c *mqlMicrosoftApplication) GetPublicClient() *plugin.TValue[interface{}] return &c.PublicClient } +func (c *mqlMicrosoftApplication) GetAppRoles() *plugin.TValue[[]interface{}] { + return &c.AppRoles +} + +// mqlMicrosoftApplicationRole for the microsoft.application.role resource +type mqlMicrosoftApplicationRole struct { + MqlRuntime *plugin.Runtime + __id string + // optional: if you define mqlMicrosoftApplicationRoleInternal it will be used here + Id plugin.TValue[string] + Name plugin.TValue[string] + Description plugin.TValue[string] + Value plugin.TValue[string] + AllowedMemberTypes plugin.TValue[[]interface{}] + IsEnabled plugin.TValue[bool] +} + +// createMicrosoftApplicationRole creates a new instance of this resource +func createMicrosoftApplicationRole(runtime *plugin.Runtime, args map[string]*llx.RawData) (plugin.Resource, error) { + res := &mqlMicrosoftApplicationRole{ + 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.application.role", res.__id) + if err != nil || args == nil { + return res, err + } + return res, SetAllData(res, args) + } + + return res, nil +} + +func (c *mqlMicrosoftApplicationRole) MqlName() string { + return "microsoft.application.role" +} + +func (c *mqlMicrosoftApplicationRole) MqlID() string { + return c.__id +} + +func (c *mqlMicrosoftApplicationRole) GetId() *plugin.TValue[string] { + return &c.Id +} + +func (c *mqlMicrosoftApplicationRole) GetName() *plugin.TValue[string] { + return &c.Name +} + +func (c *mqlMicrosoftApplicationRole) GetDescription() *plugin.TValue[string] { + return &c.Description +} + +func (c *mqlMicrosoftApplicationRole) GetValue() *plugin.TValue[string] { + return &c.Value +} + +func (c *mqlMicrosoftApplicationRole) GetAllowedMemberTypes() *plugin.TValue[[]interface{}] { + return &c.AllowedMemberTypes +} + +func (c *mqlMicrosoftApplicationRole) GetIsEnabled() *plugin.TValue[bool] { + return &c.IsEnabled +} + // mqlMicrosoftKeyCredential for the microsoft.keyCredential resource type mqlMicrosoftKeyCredential struct { MqlRuntime *plugin.Runtime @@ -3529,6 +3667,7 @@ type mqlMicrosoftServiceprincipal struct { AppRoleAssignmentRequired plugin.TValue[bool] AccountEnabled plugin.TValue[bool] IsFirstParty plugin.TValue[bool] + AppRoles plugin.TValue[[]interface{}] } // createMicrosoftServiceprincipal creates a new instance of this resource @@ -3674,6 +3813,10 @@ func (c *mqlMicrosoftServiceprincipal) GetIsFirstParty() *plugin.TValue[bool] { }) } +func (c *mqlMicrosoftServiceprincipal) GetAppRoles() *plugin.TValue[[]interface{}] { + return &c.AppRoles +} + // mqlMicrosoftServiceprincipalAssignment for the microsoft.serviceprincipal.assignment resource type mqlMicrosoftServiceprincipalAssignment struct { MqlRuntime *plugin.Runtime diff --git a/providers/ms365/resources/ms365.lr.manifest.yaml b/providers/ms365/resources/ms365.lr.manifest.yaml index b5b3459c89..667d077e90 100755 --- a/providers/ms365/resources/ms365.lr.manifest.yaml +++ b/providers/ms365/resources/ms365.lr.manifest.yaml @@ -23,6 +23,8 @@ resources: api: min_mondoo_version: 9.0.0 appId: {} + appRoles: + min_mondoo_version: 9.0.0 applicationTemplateId: min_mondoo_version: 9.0.0 certificates: @@ -92,6 +94,16 @@ resources: web: min_mondoo_version: 9.0.0 min_mondoo_version: 5.15.0 + microsoft.application.role: + fields: + allowedMemberTypes: {} + description: {} + id: {} + isEnabled: {} + name: {} + value: {} + is_private: true + min_mondoo_version: 9.0.0 microsoft.devicemanagement: fields: deviceCompliancePolicies: {} @@ -271,6 +283,8 @@ resources: min_mondoo_version: 9.0.0 appRoleAssignments: min_mondoo_version: latest + appRoles: + min_mondoo_version: 9.0.0 applicationTemplateId: min_mondoo_version: 9.0.0 assignmentRequired: diff --git a/providers/ms365/resources/serviceprincipals.go b/providers/ms365/resources/serviceprincipals.go index 30756a68a7..4bd4fc2b04 100644 --- a/providers/ms365/resources/serviceprincipals.go +++ b/providers/ms365/resources/serviceprincipals.go @@ -5,6 +5,7 @@ package resources import ( "context" + "github.com/rs/zerolog/log" "github.com/microsoftgraph/msgraph-sdk-go/models" "github.com/microsoftgraph/msgraph-sdk-go/serviceprincipals" @@ -68,6 +69,7 @@ var servicePrincipalFields = []string{ "appRoleAssignmentRequired", "accountEnabled", "verifiedPublisher", + "appRoles", } func (a *mqlMicrosoft) serviceprincipals() ([]interface{}, error) { @@ -130,6 +132,33 @@ func newMqlMicrosoftServicePrincipal(runtime *plugin.Runtime, sp models.ServiceP verifiedPublisher, _ := convert.JsonToDict(newVerifiedPublisher(sp.GetVerifiedPublisher())) + mqlAppRoleList := []interface{}{} + appRoles := sp.GetAppRoles() + for i := range appRoles { + appRole := appRoles[i] + + uuid := appRole.GetId() + if uuid == nil { + log.Debug().Msg("appRole ID is nil") + continue + } + + mqlAppRoleResource, err := CreateResource(runtime, "microsoft.application.role", + map[string]*llx.RawData{ + "__id": llx.StringData(uuid.String()), + "id": llx.StringData(uuid.String()), + "name": llx.StringDataPtr(appRole.GetDisplayName()), + "description": llx.StringDataPtr(appRole.GetDescription()), + "value": llx.StringDataPtr(appRole.GetValue()), + "allowedMemberTypes": llx.ArrayData(convert.SliceAnyToInterface(appRole.GetAllowedMemberTypes()), types.String), + "isEnabled": llx.BoolDataPtr(appRole.GetIsEnabled()), + }) + if err != nil { + return nil, err + } + mqlAppRoleList = append(mqlAppRoleList, mqlAppRoleResource) + } + args := map[string]*llx.RawData{ "id": llx.StringDataPtr(sp.GetId()), "type": llx.StringDataPtr(sp.GetServicePrincipalType()), @@ -155,6 +184,7 @@ func newMqlMicrosoftServicePrincipal(runtime *plugin.Runtime, sp models.ServiceP "appRoleAssignmentRequired": llx.BoolDataPtr(sp.GetAppRoleAssignmentRequired()), "accountEnabled": llx.BoolDataPtr(sp.GetAccountEnabled()), "verifiedPublisher": llx.DictData(verifiedPublisher), + "appRoles": llx.ArrayData(mqlAppRoleList, types.Resource("microsoft.application.role")), } info := sp.GetInfo() if info != nil {