Skip to content

Commit

Permalink
[8.15](backport #40359) x-pack/filebeat/input/entityanalytics/provide…
Browse files Browse the repository at this point in the history
…r/internal/okta: relax profile shape (#40439)

* x-pack/filebeat/input/entityanalytics/provider/internal/okta: relax profile shape (#40359)

The deserialisation of profile data was into a struct, preventing custom
profile fields from being collected. So replace these types with a
generic container.

(cherry picked from commit 99c1138)

# Conflicts:
#	x-pack/filebeat/input/entityanalytics/provider/okta/internal/okta/okta_test.go

* resolve conflicts

---------

Co-authored-by: Dan Kortschak <[email protected]>
  • Loading branch information
mergify[bot] and efd6 authored Aug 6, 2024
1 parent 5d591f6 commit 07c6c94
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 71 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ https:/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff]
- Prevent panic in CEL and salesforce inputs when github.com/hashicorp/go-retryablehttp exceeds maximum retries. {pull}40144[40144]
- Update CEL mito extensions to v1.13.1. {pull}40307[40307]
- Fix bug in CEL input rate limit logic. {issue}40106[40106] {pull}40270[40270]
- Relax requirements in Okta entity analytics provider user and device profile data shape. {pull}40359[40359]

*Heartbeat*

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,49 +39,12 @@ type User struct {
PasswordChanged *time.Time `json:"passwordChanged,omitempty"`
Type map[string]any `json:"type"`
TransitioningToStatus *string `json:"transitioningToStatus,omitempty"`
Profile Profile `json:"profile"`
Profile map[string]any `json:"profile"`
Credentials *Credentials `json:"credentials,omitempty"`
Links HAL `json:"_links,omitempty"` // See https://developer.okta.com/docs/reference/api/users/#links-object for details.
Embedded HAL `json:"_embedded,omitempty"`
}

// Profile is an Okta user's profile.
//
// See https://developer.okta.com/docs/reference/api/users/#profile-object for details.
type Profile struct {
Login string `json:"login"`
Email string `json:"email"`
SecondEmail *string `json:"secondEmail,omitempty"`
FirstName *string `json:"firstName,omitempty"`
LastName *string `json:"lastName,omitempty"`
MiddleName *string `json:"middleName,omitempty"`
HonorificPrefix *string `json:"honorificPrefix,omitempty"`
HonorificSuffix *string `json:"honorificSuffix,omitempty"`
Title *string `json:"title,omitempty"`
DisplayName *string `json:"displayName,omitempty"`
NickName *string `json:"nickName,omitempty"`
ProfileUrl *string `json:"profileUrl,omitempty"`
PrimaryPhone *string `json:"primaryPhone,omitempty"`
MobilePhone *string `json:"mobilePhone,omitempty"`
StreetAddress *string `json:"streetAddress,omitempty"`
City *string `json:"city,omitempty"`
State *string `json:"state,omitempty"`
ZipCode *string `json:"zipCode,omitempty"`
CountryCode *string `json:"countryCode,omitempty"`
PostalAddress *string `json:"postalAddress,omitempty"`
PreferredLanguage *string `json:"preferredLanguage,omitempty"`
Locale *string `json:"locale,omitempty"`
Timezone *string `json:"timezone,omitempty"`
UserType *string `json:"userType,omitempty"`
EmployeeNumber *string `json:"employeeNumber,omitempty"`
CostCenter *string `json:"costCenter,omitempty"`
Organization *string `json:"organization,omitempty"`
Division *string `json:"division,omitempty"`
Department *string `json:"department,omitempty"`
ManagerId *string `json:"managerId,omitempty"`
Manager *string `json:"manager,omitempty"`
}

// Credentials is a redacted Okta user's credential details. Only the credential provider is retained.
//
// See https://developer.okta.com/docs/reference/api/users/#credentials-object for details.
Expand Down Expand Up @@ -114,7 +77,7 @@ type Device struct {
Created time.Time `json:"created"`
ID string `json:"id"`
LastUpdated time.Time `json:"lastUpdated"`
Profile DeviceProfile `json:"profile"`
Profile map[string]any `json:"profile"`
ResourceAlternateID string `json:"resourceAlternateID"`
ResourceDisplayName DeviceDisplayName `json:"resourceDisplayName"`
ResourceID string `json:"resourceID"`
Expand All @@ -128,27 +91,6 @@ type Device struct {
Users []User `json:"users,omitempty"`
}

// DeviceProfile is an Okta device's hardware and security profile.
//
// See https://developer.okta.com/docs/api/openapi/okta-management/management/tag/Device/#tag/Device/operation/listDevices for details
type DeviceProfile struct {
DiskEncryptionType *string `json:"diskEncryptionType,omitempty"`
DisplayName string `json:"displayName"`
IMEI *string `json:"imei,omitempty"`
IntegrityJailBreak *bool `json:"integrityJailBreak,omitempty"`
Manufacturer *string `json:"manufacturer,omitempty"`
MEID *string `json:"meid,omitempty"`
Model *string `json:"model,omitempty"`
OSVersion *string `json:"osVersion,omitempty"`
Platform string `json:"platform"`
Registered bool `json:"registered"`
SecureHardwarePresent *bool `json:"secureHardwarePresent,omitempty"`
SerialNumber *string `json:"serialNumber,omitempty"`
SID *string `json:"sid,omitempty"`
TPMPublicKeyHash *string `json:"tpmPublicKeyHash,omitempty"`
UDID *string `json:"udid,omitempty"`
}

// DeviceDisplayName is an Okta device's annotated display name.
//
// See https://developer.okta.com/docs/api/openapi/okta-management/management/tag/Device/#tag/Device/operation/listDevices for details
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,22 +112,23 @@ func Test(t *testing.T) {
})

t.Run("user", func(t *testing.T) {
if me.Profile.Login == "" {
login, _ := me.Profile["login"].(string)
if login == "" {
b, _ := json.Marshal(me)
t.Skipf("cannot run user test without profile.login field set: %s", b)
}

query := make(url.Values)
query.Set("limit", "200")
users, _, err := GetUserDetails(context.Background(), http.DefaultClient, host, key, me.Profile.Login, query, omit, limiter, window)
users, _, err := GetUserDetails(context.Background(), http.DefaultClient, host, key, login, query, omit, limiter, window)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(users) != 1 {
t.Fatalf("unexpected len(users): got:%d want:1", len(users))
}
if !cmp.Equal(me, users[0]) {
t.Errorf("unexpected result:\n-'me'\n+'%s'\n%s", me.Profile.Login, cmp.Diff(me, users[0]))
t.Errorf("unexpected result:\n-'me'\n+'%s'\n%s", login, cmp.Diff(me, users[0]))
}
})

Expand Down Expand Up @@ -213,7 +214,7 @@ var localTests = []struct {
{
// Test case constructed from API-returned value with details anonymised.
name: "users",
msg: `[{"id":"userid","status":"STATUS","created":"2023-05-14T13:37:20.000Z","activated":null,"statusChanged":"2023-05-15T01:50:30.000Z","lastLogin":"2023-05-15T01:59:20.000Z","lastUpdated":"2023-05-15T01:50:32.000Z","passwordChanged":"2023-05-15T01:50:32.000Z","type":{"id":"typeid"},"profile":{"firstName":"name","lastName":"surname","mobilePhone":null,"secondEmail":null,"login":"[email protected]","email":"[email protected]"},"credentials":{"password":{"value":"secret"},"emails":[{"value":"[email protected]","status":"VERIFIED","type":"PRIMARY"}],"provider":{"type":"OKTA","name":"OKTA"}},"_links":{"self":{"href":"https://localhost/api/v1/users/userid"}}}]`,
msg: `[{"id":"userid","status":"STATUS","created":"2023-05-14T13:37:20.000Z","activated":null,"statusChanged":"2023-05-15T01:50:30.000Z","lastLogin":"2023-05-15T01:59:20.000Z","lastUpdated":"2023-05-15T01:50:32.000Z","passwordChanged":"2023-05-15T01:50:32.000Z","recovery_question":{"question":"Who's a major player in the cowboy scene?","answer":"Annie Oakley"},"type":{"id":"typeid"},"profile":{"firstName":"name","lastName":"surname","mobilePhone":null,"secondEmail":null,"login":"[email protected]","email":"[email protected]"},"credentials":{"password":{"value":"secret"},"emails":[{"value":"[email protected]","status":"VERIFIED","type":"PRIMARY"}],"provider":{"type":"OKTA","name":"OKTA"}},"_links":{"self":{"href":"https://localhost/api/v1/users/userid"}}}]`,
fn: func(ctx context.Context, cli *http.Client, host, key, user string, query url.Values, lim *rate.Limiter, window time.Duration) (any, http.Header, error) {
return GetUserDetails(context.Background(), cli, host, key, user, query, OmitNone, lim, window)
},
Expand All @@ -231,7 +232,7 @@ var localTests = []struct {
{
// Test case constructed from API-returned value with details anonymised.
name: "devices_users",
msg: `[{"created":"2023-08-07T21:48:27.000Z","managementStatus":"NOT_MANAGED","user":{"id":"userid","status":"STATUS","created":"2023-05-14T13:37:20.000Z","activated":null,"statusChanged":"2023-05-15T01:50:30.000Z","lastLogin":"2023-05-15T01:59:20.000Z","lastUpdated":"2023-05-15T01:50:32.000Z","passwordChanged":"2023-05-15T01:50:32.000Z","type":{"id":"typeid"},"profile":{"firstName":"name","lastName":"surname","mobilePhone":null,"secondEmail":null,"login":"[email protected]","email":"[email protected]"},"credentials":{"password":{"value":"secret"},"emails":[{"value":"[email protected]","status":"VERIFIED","type":"PRIMARY"}],"provider":{"type":"OKTA","name":"OKTA"}},"_links":{"self":{"href":"https://localhost/api/v1/users/userid"}}}}]`,
msg: `[{"created":"2023-08-07T21:48:27.000Z","managementStatus":"NOT_MANAGED","user":{"id":"userid","status":"STATUS","created":"2023-05-14T13:37:20.000Z","activated":null,"statusChanged":"2023-05-15T01:50:30.000Z","lastLogin":"2023-05-15T01:59:20.000Z","lastUpdated":"2023-05-15T01:50:32.000Z","passwordChanged":"2023-05-15T01:50:32.000Z","type":{"id":"typeid"},"profile":{"firstName":"name","lastName":"surname","mobilePhone":null,"secondEmail":null,"login":"[email protected]","email":"[email protected]"},"credentials":{"password":{"value":"secret"},"recovery_question":{"question":"Who's a major player in the cowboy scene?","answer":"Annie Oakley"},"emails":[{"value":"[email protected]","status":"VERIFIED","type":"PRIMARY"}],"provider":{"type":"OKTA","name":"OKTA"}},"_links":{"self":{"href":"https://localhost/api/v1/users/userid"}}}}]`,
id: "devid",
fn: func(ctx context.Context, cli *http.Client, host, key, device string, query url.Values, lim *rate.Limiter, window time.Duration) (any, http.Header, error) {
return GetDeviceUsers(context.Background(), cli, host, key, device, query, OmitNone, lim, window)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,15 @@ func TestStateStore(t *testing.T) {
Type: map[string]interface{}{
"id": "typeid",
},
Profile: okta.Profile{
Login: "[email protected]",
Email: "[email protected]",
FirstName: ptr("name"),
LastName: ptr("surname"),
Profile: map[string]interface{}{
"login": "[email protected]",
"email": "[email protected]",
"firstName": "name",
"lastName": "surname",
},
Credentials: &okta.Credentials{
Password: &struct{}{}, // Had a password: not retained.
Password: &struct{}{}, // Had a password: not retained.
RecoveryQuestion: &struct{}{}, // Had a question: not retained.
Provider: okta.Provider{
Type: "OKTA",
Name: ptr("OKTA"),
Expand Down

0 comments on commit 07c6c94

Please sign in to comment.