From e1b8fa95e559f2835dde74307c440cde963a94c0 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Wed, 14 Aug 2024 18:42:49 +0200 Subject: [PATCH] =?UTF-8?q?=E2=AD=90=EF=B8=8F=20microsoft=20365=20user=20a?= =?UTF-8?q?uthentication=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- providers/ms365/resources/errors.go | 5 + providers/ms365/resources/ms365.lr | 24 ++ providers/ms365/resources/ms365.lr.go | 223 +++++++++++++--- .../ms365/resources/ms365.lr.manifest.yaml | 15 ++ providers/ms365/resources/structs.go | 11 + providers/ms365/resources/users.go | 247 +++++++++++++++++- 6 files changed, 487 insertions(+), 38 deletions(-) diff --git a/providers/ms365/resources/errors.go b/providers/ms365/resources/errors.go index f7afc7f863..4ff51f8569 100644 --- a/providers/ms365/resources/errors.go +++ b/providers/ms365/resources/errors.go @@ -17,3 +17,8 @@ func transformError(err error) error { } return err } + +func isOdataError(err error) (*odataerrors.ODataError, bool) { + oDataErr, ok := err.(*odataerrors.ODataError) + return oDataErr, ok +} diff --git a/providers/ms365/resources/ms365.lr b/providers/ms365/resources/ms365.lr index 2bdf759848..ea0f6019b6 100644 --- a/providers/ms365/resources/ms365.lr +++ b/providers/ms365/resources/ms365.lr @@ -94,6 +94,30 @@ private microsoft.user @defaults("id displayName userPrincipalName") { job() dict // Contact information contact() dict + // Authentication information + authMethods() microsoft.user.authenticationMethods +} + +// Microsoft Entra authentication methods +private microsoft.user.authenticationMethods @defaults("count") { + // Count of authentication methods + count int + // Phone number and type registered to a user + phoneMethods []dict + // Email authentication method for self-service password reset (SSPR) + emailMethods []dict + // FIDO2 security key registered to a user + fido2Methods []dict + // Software OATH token registered to a user + softwareMethods []dict + // Microsoft Authenticator app registered to a user + microsoftAuthenticator []dict + // User password authentication method + passwordMethods []dict + // Temporary Access Pass registered to a user + temporaryAccessPassMethods []dict + // Windows Hello for Business authentication method registered to a user + windowsHelloMethods []dict } // Microsoft group diff --git a/providers/ms365/resources/ms365.lr.go b/providers/ms365/resources/ms365.lr.go index 01557a7fc6..3d433c601c 100644 --- a/providers/ms365/resources/ms365.lr.go +++ b/providers/ms365/resources/ms365.lr.go @@ -30,6 +30,10 @@ func init() { Init: initMicrosoftUser, Create: createMicrosoftUser, }, + "microsoft.user.authenticationMethods": { + // to override args, implement: initMicrosoftUserAuthenticationMethods(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) + Create: createMicrosoftUserAuthenticationMethods, + }, "microsoft.group": { // to override args, implement: initMicrosoftGroup(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) Create: createMicrosoftGroup, @@ -330,6 +334,36 @@ var getDataFields = map[string]func(r plugin.Resource) *plugin.DataRes{ "microsoft.user.contact": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlMicrosoftUser).GetContact()).ToDataRes(types.Dict) }, + "microsoft.user.authMethods": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftUser).GetAuthMethods()).ToDataRes(types.Resource("microsoft.user.authenticationMethods")) + }, + "microsoft.user.authenticationMethods.count": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftUserAuthenticationMethods).GetCount()).ToDataRes(types.Int) + }, + "microsoft.user.authenticationMethods.phoneMethods": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftUserAuthenticationMethods).GetPhoneMethods()).ToDataRes(types.Array(types.Dict)) + }, + "microsoft.user.authenticationMethods.emailMethods": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftUserAuthenticationMethods).GetEmailMethods()).ToDataRes(types.Array(types.Dict)) + }, + "microsoft.user.authenticationMethods.fido2Methods": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftUserAuthenticationMethods).GetFido2Methods()).ToDataRes(types.Array(types.Dict)) + }, + "microsoft.user.authenticationMethods.softwareMethods": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftUserAuthenticationMethods).GetSoftwareMethods()).ToDataRes(types.Array(types.Dict)) + }, + "microsoft.user.authenticationMethods.microsoftAuthenticator": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftUserAuthenticationMethods).GetMicrosoftAuthenticator()).ToDataRes(types.Array(types.Dict)) + }, + "microsoft.user.authenticationMethods.passwordMethods": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftUserAuthenticationMethods).GetPasswordMethods()).ToDataRes(types.Array(types.Dict)) + }, + "microsoft.user.authenticationMethods.temporaryAccessPassMethods": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftUserAuthenticationMethods).GetTemporaryAccessPassMethods()).ToDataRes(types.Array(types.Dict)) + }, + "microsoft.user.authenticationMethods.windowsHelloMethods": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlMicrosoftUserAuthenticationMethods).GetWindowsHelloMethods()).ToDataRes(types.Array(types.Dict)) + }, "microsoft.group.id": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlMicrosoftGroup).GetId()).ToDataRes(types.String) }, @@ -1168,6 +1202,50 @@ var setDataFields = map[string]func(r plugin.Resource, v *llx.RawData) bool { r.(*mqlMicrosoftUser).Contact, ok = plugin.RawToTValue[interface{}](v.Value, v.Error) return }, + "microsoft.user.authMethods": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftUser).AuthMethods, ok = plugin.RawToTValue[*mqlMicrosoftUserAuthenticationMethods](v.Value, v.Error) + return + }, + "microsoft.user.authenticationMethods.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftUserAuthenticationMethods).__id, ok = v.Value.(string) + return + }, + "microsoft.user.authenticationMethods.count": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftUserAuthenticationMethods).Count, ok = plugin.RawToTValue[int64](v.Value, v.Error) + return + }, + "microsoft.user.authenticationMethods.phoneMethods": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftUserAuthenticationMethods).PhoneMethods, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, + "microsoft.user.authenticationMethods.emailMethods": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftUserAuthenticationMethods).EmailMethods, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, + "microsoft.user.authenticationMethods.fido2Methods": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftUserAuthenticationMethods).Fido2Methods, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, + "microsoft.user.authenticationMethods.softwareMethods": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftUserAuthenticationMethods).SoftwareMethods, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, + "microsoft.user.authenticationMethods.microsoftAuthenticator": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftUserAuthenticationMethods).MicrosoftAuthenticator, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, + "microsoft.user.authenticationMethods.passwordMethods": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftUserAuthenticationMethods).PasswordMethods, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, + "microsoft.user.authenticationMethods.temporaryAccessPassMethods": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftUserAuthenticationMethods).TemporaryAccessPassMethods, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, + "microsoft.user.authenticationMethods.windowsHelloMethods": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlMicrosoftUserAuthenticationMethods).WindowsHelloMethods, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, "microsoft.group.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { r.(*mqlMicrosoftGroup).__id, ok = v.Value.(string) return @@ -2468,6 +2546,7 @@ type mqlMicrosoftUser struct { Settings plugin.TValue[interface{}] Job plugin.TValue[interface{}] Contact plugin.TValue[interface{}] + AuthMethods plugin.TValue[*mqlMicrosoftUserAuthenticationMethods] } // createMicrosoftUser creates a new instance of this resource @@ -2515,27 +2594,19 @@ func (c *mqlMicrosoftUser) GetCity() *plugin.TValue[string] { } func (c *mqlMicrosoftUser) GetCompanyName() *plugin.TValue[string] { - return plugin.GetOrCompute[string](&c.CompanyName, func() (string, error) { - return c.companyName() - }) + return &c.CompanyName } func (c *mqlMicrosoftUser) GetCountry() *plugin.TValue[string] { - return plugin.GetOrCompute[string](&c.Country, func() (string, error) { - return c.country() - }) + return &c.Country } func (c *mqlMicrosoftUser) GetCreatedDateTime() *plugin.TValue[*time.Time] { - return plugin.GetOrCompute[*time.Time](&c.CreatedDateTime, func() (*time.Time, error) { - return c.createdDateTime() - }) + return &c.CreatedDateTime } func (c *mqlMicrosoftUser) GetDepartment() *plugin.TValue[string] { - return plugin.GetOrCompute[string](&c.Department, func() (string, error) { - return c.department() - }) + return &c.Department } func (c *mqlMicrosoftUser) GetDisplayName() *plugin.TValue[string] { @@ -2543,9 +2614,7 @@ func (c *mqlMicrosoftUser) GetDisplayName() *plugin.TValue[string] { } func (c *mqlMicrosoftUser) GetEmployeeId() *plugin.TValue[string] { - return plugin.GetOrCompute[string](&c.EmployeeId, func() (string, error) { - return c.employeeId() - }) + return &c.EmployeeId } func (c *mqlMicrosoftUser) GetGivenName() *plugin.TValue[string] { @@ -2553,9 +2622,7 @@ func (c *mqlMicrosoftUser) GetGivenName() *plugin.TValue[string] { } func (c *mqlMicrosoftUser) GetJobTitle() *plugin.TValue[string] { - return plugin.GetOrCompute[string](&c.JobTitle, func() (string, error) { - return c.jobTitle() - }) + return &c.JobTitle } func (c *mqlMicrosoftUser) GetMail() *plugin.TValue[string] { @@ -2563,9 +2630,7 @@ func (c *mqlMicrosoftUser) GetMail() *plugin.TValue[string] { } func (c *mqlMicrosoftUser) GetMobilePhone() *plugin.TValue[string] { - return plugin.GetOrCompute[string](&c.MobilePhone, func() (string, error) { - return c.mobilePhone() - }) + return &c.MobilePhone } func (c *mqlMicrosoftUser) GetOtherMails() *plugin.TValue[[]interface{}] { @@ -2573,27 +2638,19 @@ func (c *mqlMicrosoftUser) GetOtherMails() *plugin.TValue[[]interface{}] { } func (c *mqlMicrosoftUser) GetOfficeLocation() *plugin.TValue[string] { - return plugin.GetOrCompute[string](&c.OfficeLocation, func() (string, error) { - return c.officeLocation() - }) + return &c.OfficeLocation } func (c *mqlMicrosoftUser) GetPostalCode() *plugin.TValue[string] { - return plugin.GetOrCompute[string](&c.PostalCode, func() (string, error) { - return c.postalCode() - }) + return &c.PostalCode } func (c *mqlMicrosoftUser) GetState() *plugin.TValue[string] { - return plugin.GetOrCompute[string](&c.State, func() (string, error) { - return c.state() - }) + return &c.State } func (c *mqlMicrosoftUser) GetStreetAddress() *plugin.TValue[string] { - return plugin.GetOrCompute[string](&c.StreetAddress, func() (string, error) { - return c.streetAddress() - }) + return &c.StreetAddress } func (c *mqlMicrosoftUser) GetSurname() *plugin.TValue[string] { @@ -2626,6 +2683,106 @@ func (c *mqlMicrosoftUser) GetContact() *plugin.TValue[interface{}] { }) } +func (c *mqlMicrosoftUser) GetAuthMethods() *plugin.TValue[*mqlMicrosoftUserAuthenticationMethods] { + return plugin.GetOrCompute[*mqlMicrosoftUserAuthenticationMethods](&c.AuthMethods, func() (*mqlMicrosoftUserAuthenticationMethods, error) { + if c.MqlRuntime.HasRecording { + d, err := c.MqlRuntime.FieldResourceFromRecording("microsoft.user", c.__id, "authMethods") + if err != nil { + return nil, err + } + if d != nil { + return d.Value.(*mqlMicrosoftUserAuthenticationMethods), nil + } + } + + return c.authMethods() + }) +} + +// mqlMicrosoftUserAuthenticationMethods for the microsoft.user.authenticationMethods resource +type mqlMicrosoftUserAuthenticationMethods struct { + MqlRuntime *plugin.Runtime + __id string + // optional: if you define mqlMicrosoftUserAuthenticationMethodsInternal it will be used here + Count plugin.TValue[int64] + PhoneMethods plugin.TValue[[]interface{}] + EmailMethods plugin.TValue[[]interface{}] + Fido2Methods plugin.TValue[[]interface{}] + SoftwareMethods plugin.TValue[[]interface{}] + MicrosoftAuthenticator plugin.TValue[[]interface{}] + PasswordMethods plugin.TValue[[]interface{}] + TemporaryAccessPassMethods plugin.TValue[[]interface{}] + WindowsHelloMethods plugin.TValue[[]interface{}] +} + +// createMicrosoftUserAuthenticationMethods creates a new instance of this resource +func createMicrosoftUserAuthenticationMethods(runtime *plugin.Runtime, args map[string]*llx.RawData) (plugin.Resource, error) { + res := &mqlMicrosoftUserAuthenticationMethods{ + 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.user.authenticationMethods", res.__id) + if err != nil || args == nil { + return res, err + } + return res, SetAllData(res, args) + } + + return res, nil +} + +func (c *mqlMicrosoftUserAuthenticationMethods) MqlName() string { + return "microsoft.user.authenticationMethods" +} + +func (c *mqlMicrosoftUserAuthenticationMethods) MqlID() string { + return c.__id +} + +func (c *mqlMicrosoftUserAuthenticationMethods) GetCount() *plugin.TValue[int64] { + return &c.Count +} + +func (c *mqlMicrosoftUserAuthenticationMethods) GetPhoneMethods() *plugin.TValue[[]interface{}] { + return &c.PhoneMethods +} + +func (c *mqlMicrosoftUserAuthenticationMethods) GetEmailMethods() *plugin.TValue[[]interface{}] { + return &c.EmailMethods +} + +func (c *mqlMicrosoftUserAuthenticationMethods) GetFido2Methods() *plugin.TValue[[]interface{}] { + return &c.Fido2Methods +} + +func (c *mqlMicrosoftUserAuthenticationMethods) GetSoftwareMethods() *plugin.TValue[[]interface{}] { + return &c.SoftwareMethods +} + +func (c *mqlMicrosoftUserAuthenticationMethods) GetMicrosoftAuthenticator() *plugin.TValue[[]interface{}] { + return &c.MicrosoftAuthenticator +} + +func (c *mqlMicrosoftUserAuthenticationMethods) GetPasswordMethods() *plugin.TValue[[]interface{}] { + return &c.PasswordMethods +} + +func (c *mqlMicrosoftUserAuthenticationMethods) GetTemporaryAccessPassMethods() *plugin.TValue[[]interface{}] { + return &c.TemporaryAccessPassMethods +} + +func (c *mqlMicrosoftUserAuthenticationMethods) GetWindowsHelloMethods() *plugin.TValue[[]interface{}] { + return &c.WindowsHelloMethods +} + // mqlMicrosoftGroup for the microsoft.group resource type mqlMicrosoftGroup struct { MqlRuntime *plugin.Runtime diff --git a/providers/ms365/resources/ms365.lr.manifest.yaml b/providers/ms365/resources/ms365.lr.manifest.yaml index aabc178e4d..a484014c83 100755 --- a/providers/ms365/resources/ms365.lr.manifest.yaml +++ b/providers/ms365/resources/ms365.lr.manifest.yaml @@ -332,6 +332,8 @@ resources: microsoft.user: fields: accountEnabled: {} + authMethods: + min_mondoo_version: 9.0.0 city: {} companyName: {} contact: @@ -359,6 +361,19 @@ resources: userType: {} is_private: true min_mondoo_version: 5.15.0 + microsoft.user.authenticationMethods: + fields: + count: {} + emailMethods: {} + fido2Methods: {} + microsoftAuthenticator: {} + passwordMethods: {} + phoneMethods: {} + softwareMethods: {} + temporaryAccessPassMethods: {} + windowsHelloMethods: {} + is_private: true + min_mondoo_version: 9.0.0 ms365.exchangeonline: fields: adminAuditLogConfig: {} diff --git a/providers/ms365/resources/structs.go b/providers/ms365/resources/structs.go index bf34b37e0a..afdc9a0abd 100644 --- a/providers/ms365/resources/structs.go +++ b/providers/ms365/resources/structs.go @@ -424,6 +424,17 @@ func newUserSettings(p models.UserSettingsable) *UserSettings { } } +type Authentication struct { +} + +func newAuthentication(p models.Authenticationable) *Authentication { + if p == nil { + return nil + } + return &Authentication{} + +} + type ( DeviceAndAppManagementAssignmentSource int DeviceAndAppManagementAssignmentFilterType int diff --git a/providers/ms365/resources/users.go b/providers/ms365/resources/users.go index 0aee6a45f7..9ac7651667 100644 --- a/providers/ms365/resources/users.go +++ b/providers/ms365/resources/users.go @@ -264,18 +264,255 @@ func (a *mqlMicrosoftUser) settings() (interface{}, error) { return convert.JsonToDict(newUserSettings(userSettings)) } -func (a *mqlMicrosoftUser) mfa() (interface{}, error) { +type authMethod struct { + Id string `json:"id"` +} + +type phoneMethod struct { + authMethod + Type string `json:"type"` + PhoneNumber *string `json:"phoneNumber"` + SsmSignInState string `json:"ssmSignInState"` +} + +type fido2Method struct { + authMethod + Name *string `json:"name"` + AttestationLevel string `json:"attestationLevel"` + Model *string `json:"model"` + AttestationCertificates []string `json:"attestationCertificates"` +} + +type emailMethod struct { + authMethod + EmailAddress *string `json:"emailAddress"` +} + +type windowsHelloMethod struct { + authMethod + Name *string `json:"name"` + DeviceId *string `json:"deviceId"` + KeyStrength string `json:"keyStrength"` +} + +type softwareMethod struct { + authMethod +} + +type passwordMethod struct { + authMethod +} + +type microsoftAuthenticatorMethod struct { + authMethod + Name *string `json:"name"` + PhoneAppVersion *string `json:"phoneAppVersion"` + DeviceTag *string `json:"deviceTag"` +} + +type temporaryAccessPassMethod struct { + authMethod + IsUsable *bool `json:"isUsable"` + IsUsableOnce *bool `json:"isUsableOnce"` + LifetimeInMinutes *int32 `json:"lifetimeInMinutes"` +} + +type userAuthentication struct { + userID string `json:"userId"` + methodCount int `json:"methodCount"` + PhoneMethods []phoneMethod `json:"phoneMethods"` + Fido2Methods []fido2Method `json:"fido2Methods"` + SoftwareMethods []softwareMethod `json:"softwareMethods"` + MicrosoftAuthenticator []microsoftAuthenticatorMethod `json:"microsoftAuthenticator"` + PasswordMethods []passwordMethod `json:"passwordMethods"` + TemporaryAccessPassMethods []temporaryAccessPassMethod `json:"temporaryAccessPassMethods"` + WindowsHelloMethods []windowsHelloMethod `json:"windowsHelloMethods"` + EmailMethods []emailMethod `json:"emailMethods"` +} + +// needs the permission UserAuthenticationMethod.Read.All +func (a *mqlMicrosoftUser) authMethods() (*mqlMicrosoftUserAuthenticationMethods, error) { + runtime := a.MqlRuntime conn := a.MqlRuntime.Connection.(*connection.Ms365Connection) graphClient, err := conn.GraphClient() if err != nil { return nil, err } + + userID := a.Id.Data + ua := userAuthentication{ + userID: userID, + } + ctx := context.Background() - id := a.Id.Data - userAuthSettings, err := graphClient.Users().ByUserId(id).Authentication().Get(ctx, &users.ItemAuthenticationRequestBuilderGetRequestConfiguration{}) - if err != nil { + authMethods, err := graphClient.Users().ByUserId(userID).Authentication().Methods().Get(ctx, &users.ItemAuthenticationMethodsRequestBuilderGetRequestConfiguration{}) + if oErr, ok := isOdataError(err); ok { + if oErr.ResponseStatusCode == 403 { + return nil, errors.New("UserAuthenticationMethod.Read.All permission is required") + } + return nil, transformError(err) + } else if err != nil { return nil, transformError(err) } - return convert.JsonToDict(newAuthentication(userAuthSettings)) + methods := authMethods.GetValue() + ua.methodCount = len(methods) + for i := range methods { + entry := methods[i] + switch x := entry.(type) { + case *models.PhoneAuthenticationMethod: + if x.GetId() == nil { + continue + } + + m := phoneMethod{ + authMethod: authMethod{ + Id: *x.GetId(), + }, + PhoneNumber: x.GetPhoneNumber(), + } + + if x.GetPhoneType() != nil { + m.Type = x.GetPhoneType().String() + } + + if x.GetSmsSignInState() != nil { + m.SsmSignInState = x.GetSmsSignInState().String() + } + + ua.PhoneMethods = append(ua.PhoneMethods, m) + case *models.Fido2AuthenticationMethod: + if x.GetId() == nil { + continue + } + m := fido2Method{ + authMethod: authMethod{ + Id: *x.GetId(), + }, + Name: x.GetDisplayName(), + Model: x.GetModel(), + AttestationCertificates: x.GetAttestationCertificates(), + } + if x.GetAttestationLevel() != nil { + m.AttestationLevel = x.GetAttestationLevel().String() + } + ua.Fido2Methods = append(ua.Fido2Methods, m) + case *models.SoftwareOathAuthenticationMethod: + if x.GetId() == nil { + continue + } + m := softwareMethod{ + authMethod: authMethod{ + Id: *x.GetId(), + }, + } + + ua.SoftwareMethods = append(ua.SoftwareMethods, m) + case *models.MicrosoftAuthenticatorAuthenticationMethod: + if x.GetId() == nil { + continue + } + m := microsoftAuthenticatorMethod{ + authMethod: authMethod{ + Id: *x.GetId(), + }, + Name: x.GetDisplayName(), + PhoneAppVersion: x.GetPhoneAppVersion(), + DeviceTag: x.GetDeviceTag(), + } + + ua.MicrosoftAuthenticator = append(ua.MicrosoftAuthenticator, m) + case *models.PasswordAuthenticationMethod: + if x.GetId() == nil { + continue + } + m := passwordMethod{ + authMethod: authMethod{ + Id: *x.GetId(), + }, + } + + ua.PasswordMethods = append(ua.PasswordMethods, m) + case *models.TemporaryAccessPassAuthenticationMethod: + if x.GetId() == nil { + continue + } + m := temporaryAccessPassMethod{ + authMethod: authMethod{ + Id: *x.GetId(), + }, + IsUsable: x.GetIsUsable(), + IsUsableOnce: x.GetIsUsableOnce(), + LifetimeInMinutes: x.GetLifetimeInMinutes(), + } + ua.TemporaryAccessPassMethods = append(ua.TemporaryAccessPassMethods, m) + case *models.WindowsHelloForBusinessAuthenticationMethod: + if x.GetId() == nil { + continue + } + m := windowsHelloMethod{ + authMethod: authMethod{ + Id: *x.GetId(), + }, + Name: x.GetDisplayName(), + } + if x.GetDevice() != nil { + m.DeviceId = x.GetDevice().GetDeviceId() + } + + if x.GetKeyStrength() != nil { + m.KeyStrength = x.GetKeyStrength().String() + } + + ua.WindowsHelloMethods = append(ua.WindowsHelloMethods, m) + case *models.EmailAuthenticationMethod: + if x.GetId() == nil { + continue + } + + m := emailMethod{ + authMethod: authMethod{ + Id: *x.GetId(), + }, + EmailAddress: x.GetEmailAddress(), + } + ua.EmailMethods = append(ua.EmailMethods, m) + default: + + } + } + + return newMqlMicrosoftUserAuthentication(runtime, ua) +} + +func newMqlMicrosoftUserAuthentication(runtime *plugin.Runtime, u userAuthentication) (*mqlMicrosoftUserAuthenticationMethods, error) { + if u.userID == "" { + return nil, errors.New("user id is required") + } + phoneMethods, _ := convert.JsonToDictSlice(u.PhoneMethods) + emailMethods, _ := convert.JsonToDictSlice(u.EmailMethods) + fido2Methods, _ := convert.JsonToDictSlice(u.Fido2Methods) + softwareMethods, _ := convert.JsonToDictSlice(u.SoftwareMethods) + microsoftAuthenticator, _ := convert.JsonToDictSlice(u.MicrosoftAuthenticator) + passwordMethods, _ := convert.JsonToDictSlice(u.PasswordMethods) + temporaryAccessPassMethods, _ := convert.JsonToDictSlice(u.TemporaryAccessPassMethods) + windowsHelloMethods, _ := convert.JsonToDictSlice(u.WindowsHelloMethods) + + graphUser, err := CreateResource(runtime, "microsoft.user.authenticationMethods", + map[string]*llx.RawData{ + "__id": llx.StringData(u.userID), + "count": llx.IntData(u.methodCount), + "phoneMethods": llx.DictData(phoneMethods), + "emailMethods": llx.DictData(emailMethods), + "fido2Methods": llx.DictData(fido2Methods), + "softwareMethods": llx.DictData(softwareMethods), + "microsoftAuthenticator": llx.DictData(microsoftAuthenticator), + "passwordMethods": llx.DictData(passwordMethods), + "temporaryAccessPassMethods": llx.DictData(temporaryAccessPassMethods), + "windowsHelloMethods": llx.DictData(windowsHelloMethods), + }) + if err != nil { + return nil, err + } + return graphUser.(*mqlMicrosoftUserAuthenticationMethods), nil }