From 8418a8c89c32a1c63fed06713a298b9f30583bcc Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Fri, 9 Aug 2024 18:40:27 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=B9=20=20initialize=20`microsoft.appli?= =?UTF-8?q?cation`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- providers/ms365/resources/applications.go | 61 ++++++++++++++++++- providers/ms365/resources/ms365.lr | 11 ++-- providers/ms365/resources/ms365.lr.go | 30 ++++++--- .../ms365/resources/ms365.lr.manifest.yaml | 5 +- 4 files changed, 89 insertions(+), 18 deletions(-) diff --git a/providers/ms365/resources/applications.go b/providers/ms365/resources/applications.go index 332ee74eed..9eabbae145 100644 --- a/providers/ms365/resources/applications.go +++ b/providers/ms365/resources/applications.go @@ -6,6 +6,9 @@ package resources import ( "context" "encoding/base64" + "errors" + "fmt" + "net/url" "time" "github.com/microsoftgraph/msgraph-sdk-go/applications" @@ -42,8 +45,57 @@ func (a *mqlMicrosoft) applications() ([]interface{}, error) { return res, nil } -// expiredCredentials returns true if any of the credentials of the application are expired -func (a *mqlMicrosoftApplication) expiredCredentials() (bool, error) { +func initMicrosoftApplication(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) { + // we only look up the package, if we have been supplied by its name and nothing else + raw, ok := args["name"] + if !ok || len(args) != 1 { + return args, nil, nil + } + name := raw.Value.(string) + + conn := runtime.Connection.(*connection.Ms365Connection) + graphClient, err := conn.GraphClient() + if err != nil { + return nil, nil, err + } + + // https://graph.microsoft.com/v1.0/servicePrincipals?$count=true&$search="displayName:teams"&$select=id,displayName + filter := fmt.Sprintf("displayName eq '%s'", url.QueryEscape(name)) + ctx := context.Background() + resp, err := graphClient.Applications().Get(ctx, &applications.ApplicationsRequestBuilderGetRequestConfiguration{ + QueryParameters: &applications.ApplicationsRequestBuilderGetQueryParameters{ + Filter: &filter, + }, + }) + if err != nil { + return nil, nil, transformError(err) + } + + val := resp.GetValue() + if len(val) == 0 { + return nil, nil, errors.New("application not found") + } + + applicationId := val[0].GetId() + if applicationId == nil { + return nil, nil, errors.New("application id not found") + } + + // https://graph.microsoft.com/v1.0/applications/{application-id} + app, err := graphClient.Applications().ByApplicationId(*applicationId).Get(ctx, &applications.ApplicationItemRequestBuilderGetRequestConfiguration{}) + if err != nil { + return nil, nil, transformError(err) + } + mqlMsApp, err := newMqlMicrosoftApplication(runtime, app) + if err != nil { + return nil, nil, err + } + + return nil, mqlMsApp, nil +} + +// hasExpiredCredentials returns true if any of the credentials of the application are expired +func (a *mqlMicrosoftApplication) hasExpiredCredentials() (bool, error) { certificates := a.GetCertificates() for _, val := range certificates.Data { cert := val.(*mqlMicrosoftKeyCredential) @@ -62,8 +114,8 @@ func (a *mqlMicrosoftApplication) expiredCredentials() (bool, error) { return false, nil } +// newMqlMicrosoftApplication creates a new mqlMicrosoftApplication resource func newMqlMicrosoftApplication(runtime *plugin.Runtime, app models.Applicationable) (*mqlMicrosoftApplication, error) { - info, _ := convert.JsonToDictSlice(app.GetInfo()) // certificates @@ -95,6 +147,7 @@ func newMqlMicrosoftApplication(runtime *plugin.Runtime, app models.Applicationa "createdDateTime": llx.TimeDataPtr(app.GetCreatedDateTime()), "createdAt": llx.TimeDataPtr(app.GetCreatedDateTime()), "displayName": llx.StringDataPtr(app.GetDisplayName()), + "name": llx.StringDataPtr(app.GetDisplayName()), "description": llx.StringDataPtr(app.GetDescription()), "notes": llx.StringDataPtr(app.GetNotes()), "publisherDomain": llx.StringDataPtr(app.GetPublisherDomain()), @@ -111,6 +164,7 @@ func newMqlMicrosoftApplication(runtime *plugin.Runtime, app models.Applicationa return mqlResource.(*mqlMicrosoftApplication), nil } +// newMqlMicrosoftKeyCredential creates a new mqlMicrosoftKeyCredential resource func newMqlMicrosoftKeyCredential(runtime *plugin.Runtime, app models.KeyCredentialable) (*mqlMicrosoftKeyCredential, error) { endDate := app.GetEndDateTime() expired := true @@ -135,6 +189,7 @@ func newMqlMicrosoftKeyCredential(runtime *plugin.Runtime, app models.KeyCredent return mqlResource.(*mqlMicrosoftKeyCredential), nil } +// newMqlMicrosoftPasswordCredential creates a new mqlMicrosoftPasswordCredential resource func newMqlMicrosoftPasswordCredential(runtime *plugin.Runtime, app models.PasswordCredentialable) (*mqlMicrosoftPasswordCredential, error) { endDate := app.GetEndDateTime() expired := true diff --git a/providers/ms365/resources/ms365.lr b/providers/ms365/resources/ms365.lr index 736957e7cf..f27b70435e 100644 --- a/providers/ms365/resources/ms365.lr +++ b/providers/ms365/resources/ms365.lr @@ -163,12 +163,15 @@ private microsoft.domaindnsrecord @defaults("id label") { } // Microsoft application -private microsoft.application @defaults("id displayName expiredCredentials") { +microsoft.application @defaults("id displayName hasExpiredCredentials") { + init(name string) // Application ID id string // Application app ID appId string // Application display name + name string + // Deprecated: Application display name use `name` instead displayName string // Description description string @@ -193,7 +196,7 @@ private microsoft.application @defaults("id displayName expiredCredentials") { // Certificates certificates []microsoft.keyCredential // Indicates assigned expired credentials - expiredCredentials() bool + hasExpiredCredentials() bool } // Certificate Secret @@ -210,7 +213,7 @@ private microsoft.keyCredential @defaults("thumbprint description expires keyId" usage string // Certificate expiration date expires time - // Indicates if the secret is expired + // Indicates expired secret expired bool } @@ -224,7 +227,7 @@ private microsoft.passwordCredential @defaults("description expires keyId") { hint string // Secret expiration date expires time - // Indicates if the secret is expired + // Indicates expired secret expired bool } diff --git a/providers/ms365/resources/ms365.lr.go b/providers/ms365/resources/ms365.lr.go index eeb32e52f7..903be6c1c5 100644 --- a/providers/ms365/resources/ms365.lr.go +++ b/providers/ms365/resources/ms365.lr.go @@ -43,7 +43,7 @@ func init() { Create: createMicrosoftDomaindnsrecord, }, "microsoft.application": { - // to override args, implement: initMicrosoftApplication(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) + Init: initMicrosoftApplication, Create: createMicrosoftApplication, }, "microsoft.keyCredential": { @@ -417,6 +417,9 @@ var getDataFields = map[string]func(r plugin.Resource) *plugin.DataRes{ "microsoft.application.appId": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlMicrosoftApplication).GetAppId()).ToDataRes(types.String) }, + "microsoft.application.name": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftApplication).GetName()).ToDataRes(types.String) + }, "microsoft.application.displayName": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlMicrosoftApplication).GetDisplayName()).ToDataRes(types.String) }, @@ -453,8 +456,8 @@ var getDataFields = map[string]func(r plugin.Resource) *plugin.DataRes{ "microsoft.application.certificates": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlMicrosoftApplication).GetCertificates()).ToDataRes(types.Array(types.Resource("microsoft.keyCredential"))) }, - "microsoft.application.expiredCredentials": func(r plugin.Resource) *plugin.DataRes { - return (r.(*mqlMicrosoftApplication).GetExpiredCredentials()).ToDataRes(types.Bool) + "microsoft.application.hasExpiredCredentials": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftApplication).GetHasExpiredCredentials()).ToDataRes(types.Bool) }, "microsoft.keyCredential.keyId": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlMicrosoftKeyCredential).GetKeyId()).ToDataRes(types.String) @@ -1192,6 +1195,10 @@ var setDataFields = map[string]func(r plugin.Resource, v *llx.RawData) bool { r.(*mqlMicrosoftApplication).AppId, ok = plugin.RawToTValue[string](v.Value, v.Error) return }, + "microsoft.application.name": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftApplication).Name, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, "microsoft.application.displayName": func(r plugin.Resource, v *llx.RawData) (ok bool) { r.(*mqlMicrosoftApplication).DisplayName, ok = plugin.RawToTValue[string](v.Value, v.Error) return @@ -1240,8 +1247,8 @@ var setDataFields = map[string]func(r plugin.Resource, v *llx.RawData) bool { r.(*mqlMicrosoftApplication).Certificates, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) return }, - "microsoft.application.expiredCredentials": func(r plugin.Resource, v *llx.RawData) (ok bool) { - r.(*mqlMicrosoftApplication).ExpiredCredentials, ok = plugin.RawToTValue[bool](v.Value, v.Error) + "microsoft.application.hasExpiredCredentials": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftApplication).HasExpiredCredentials, ok = plugin.RawToTValue[bool](v.Value, v.Error) return }, "microsoft.keyCredential.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { @@ -2639,6 +2646,7 @@ type mqlMicrosoftApplication struct { // optional: if you define mqlMicrosoftApplicationInternal it will be used here Id plugin.TValue[string] AppId plugin.TValue[string] + Name plugin.TValue[string] DisplayName plugin.TValue[string] Description plugin.TValue[string] Notes plugin.TValue[string] @@ -2651,7 +2659,7 @@ type mqlMicrosoftApplication struct { Info plugin.TValue[interface{}] Secrets plugin.TValue[[]interface{}] Certificates plugin.TValue[[]interface{}] - ExpiredCredentials plugin.TValue[bool] + HasExpiredCredentials plugin.TValue[bool] } // createMicrosoftApplication creates a new instance of this resource @@ -2694,6 +2702,10 @@ func (c *mqlMicrosoftApplication) GetAppId() *plugin.TValue[string] { return &c.AppId } +func (c *mqlMicrosoftApplication) GetName() *plugin.TValue[string] { + return &c.Name +} + func (c *mqlMicrosoftApplication) GetDisplayName() *plugin.TValue[string] { return &c.DisplayName } @@ -2742,9 +2754,9 @@ func (c *mqlMicrosoftApplication) GetCertificates() *plugin.TValue[[]interface{} return &c.Certificates } -func (c *mqlMicrosoftApplication) GetExpiredCredentials() *plugin.TValue[bool] { - return plugin.GetOrCompute[bool](&c.ExpiredCredentials, func() (bool, error) { - return c.expiredCredentials() +func (c *mqlMicrosoftApplication) GetHasExpiredCredentials() *plugin.TValue[bool] { + return plugin.GetOrCompute[bool](&c.HasExpiredCredentials, func() (bool, error) { + return c.hasExpiredCredentials() }) } diff --git a/providers/ms365/resources/ms365.lr.manifest.yaml b/providers/ms365/resources/ms365.lr.manifest.yaml index 1c8dd914f7..b99e7d79ae 100755 --- a/providers/ms365/resources/ms365.lr.manifest.yaml +++ b/providers/ms365/resources/ms365.lr.manifest.yaml @@ -27,12 +27,14 @@ resources: description: min_mondoo_version: 9.0.0 displayName: {} - expiredCredentials: + hasExpiredCredentials: min_mondoo_version: 9.0.0 id: {} identifierUris: {} info: min_mondoo_version: 9.0.0 + name: + min_mondoo_version: 9.0.0 notes: min_mondoo_version: 9.0.0 publisherDomain: {} @@ -41,7 +43,6 @@ resources: signInAudience: {} tags: min_mondoo_version: 9.0.0 - is_private: true min_mondoo_version: 5.15.0 microsoft.devicemanagement: fields: