Skip to content

Commit 7f2f8d0

Browse files
committed
feat: Add LogUserBehavior model and comprehensive System Log userBehaviors support
Add structured LogUserBehavior model to replace string-based userBehaviors in System Log events. Includes OpenAPI spec updates, Python SDK implementation, and complete documentation. Key changes: - New LogUserBehavior model with id, name, and result fields - Updated LogSecurityContext to use List[LogUserBehavior] - Comprehensive documentation Backward-compatible enhancement providing structured data for risk-based authentication analysis.
1 parent 695ae58 commit 7f2f8d0

File tree

7 files changed

+222
-9
lines changed

7 files changed

+222
-9
lines changed

docs/LogSecurityContext.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Name | Type | Description | Notes
1111
**domain** | **str** | The domain name that's associated with the IP address of the inbound event request | [optional] [readonly]
1212
**isp** | **str** | The Internet service provider that's used to send the event's request | [optional] [readonly]
1313
**is_proxy** | **bool** | Specifies whether an event's request is from a known proxy | [optional] [readonly]
14-
**user_behaviors** | **List[str]** | The result of the user behavior detection models associated with the event | [optional] [readonly]
14+
**user_behaviors** | [**List[LogUserBehavior]**](LogUserBehavior.md) | The result of the user behavior detection models associated with the event | [optional] [readonly]
1515

1616
## Example
1717

docs/LogUserBehavior.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# LogUserBehavior
2+
3+
The result of the user behavior detection models associated with the event
4+
5+
## Properties
6+
7+
Name | Type | Description | Notes
8+
------------ | ------------- | ------------- | -------------
9+
**name** | **str** | The name of the user behavior detection model [configured by admins](https://developer.okta.com/docs/api/openapi/okta-management/management/tag/Behavior/) | [optional] [readonly]
10+
**id** | **str** | The unique identifier of the user behavior detection model | [optional] [readonly]
11+
**result** | **str** | The result of the user behavior analysis | [optional] [readonly]
12+
13+
## Example
14+
15+
```python
16+
from okta.models.log_user_behavior import LogUserBehavior
17+
18+
# TODO update the JSON string below
19+
json = "{}"
20+
# create an instance of LogUserBehavior from a JSON string
21+
log_user_behavior_instance = LogUserBehavior.from_json(json)
22+
# print the JSON string representation of the object
23+
print(LogUserBehavior.to_json())
24+
25+
# convert the object into a dict
26+
log_user_behavior_dict = log_user_behavior_instance.to_dict()
27+
# create an instance of LogUserBehavior from a dict
28+
log_user_behavior_from_dict = LogUserBehavior.from_dict(log_user_behavior_dict)
29+
```
30+
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
31+
32+

okta/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,7 @@
10461046
"LogTargetChangeDetails": "okta.models.log_target_change_details",
10471047
"LogTransaction": "okta.models.log_transaction",
10481048
"LogUserAgent": "okta.models.log_user_agent",
1049+
"LogUserBehavior": "okta.models.log_user_behavior",
10491050
"MDMEnrollmentPolicyEnrollment": "okta.models.mdm_enrollment_policy_enrollment",
10501051
"MDMEnrollmentPolicyRuleCondition": "okta.models.mdm_enrollment_policy_rule_condition",
10511052
"ManagedConnection": "okta.models.managed_connection",

okta/models/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,7 @@
12461246
"LogTargetChangeDetails": "okta.models.log_target_change_details",
12471247
"LogTransaction": "okta.models.log_transaction",
12481248
"LogUserAgent": "okta.models.log_user_agent",
1249+
"LogUserBehavior": "okta.models.log_user_behavior",
12491250
"MDMEnrollmentPolicyEnrollment": "okta.models.mdm_enrollment_policy_enrollment",
12501251
"MDMEnrollmentPolicyRuleCondition": "okta.models.mdm_enrollment_policy_rule_condition",
12511252
"ManagedConnection": "okta.models.managed_connection",
@@ -2135,6 +2136,8 @@
21352136
"ZscalerbyzApplicationSettings": "okta.models.zscalerbyz_application_settings",
21362137
"ZscalerbyzApplicationSettingsApplication": "okta.models.zscalerbyz_application_settings_application",
21372138
}
2139+
2140+
21382141
def __getattr__(name):
21392142
if name in _LAZY_IMPORT_MAP:
21402143
# Use lock to ensure thread-safe importing and caching

okta/models/log_security_context.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr
3232
from typing_extensions import Self
3333

34+
from okta.models.log_user_behavior import LogUserBehavior
35+
3436

3537
class LogSecurityContext(BaseModel):
3638
"""
@@ -64,7 +66,7 @@ class LogSecurityContext(BaseModel):
6466
description="Specifies whether an event's request is from a known proxy",
6567
alias="isProxy",
6668
)
67-
user_behaviors: Optional[List[StrictStr]] = Field(
69+
user_behaviors: Optional[List[LogUserBehavior]] = Field(
6870
default=None,
6971
description="The result of the user behavior detection models associated with the event",
7072
alias="userBehaviors",
@@ -130,6 +132,13 @@ def to_dict(self) -> Dict[str, Any]:
130132
exclude=excluded_fields,
131133
exclude_none=True,
132134
)
135+
# override the default output from pydantic by calling `to_dict()` of each item in user_behaviors (list)
136+
_items = []
137+
if self.user_behaviors:
138+
for _item in self.user_behaviors:
139+
if _item:
140+
_items.append(_item.to_dict())
141+
_dict["userBehaviors"] = _items
133142
# set to None if as_number (nullable) is None
134143
# and model_fields_set contains the field
135144
if self.as_number is None and "as_number" in self.model_fields_set:
@@ -155,11 +164,6 @@ def to_dict(self) -> Dict[str, Any]:
155164
if self.is_proxy is None and "is_proxy" in self.model_fields_set:
156165
_dict["isProxy"] = None
157166

158-
# set to None if user_behaviors (nullable) is None
159-
# and model_fields_set contains the field
160-
if self.user_behaviors is None and "user_behaviors" in self.model_fields_set:
161-
_dict["userBehaviors"] = None
162-
163167
return _dict
164168

165169
@classmethod
@@ -178,7 +182,11 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
178182
"domain": obj.get("domain"),
179183
"isp": obj.get("isp"),
180184
"isProxy": obj.get("isProxy"),
181-
"userBehaviors": obj.get("userBehaviors"),
185+
"userBehaviors": (
186+
[LogUserBehavior.from_dict(_item) for _item in obj["userBehaviors"]]
187+
if obj.get("userBehaviors") is not None
188+
else None
189+
),
182190
}
183191
)
184192
return _obj

okta/models/log_user_behavior.py

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# The Okta software accompanied by this notice is provided pursuant to the following terms:
2+
# Copyright © 2025-Present, Okta, Inc.
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
4+
# License.
5+
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6+
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS
7+
# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8+
# See the License for the specific language governing permissions and limitations under the License.
9+
# coding: utf-8
10+
11+
"""
12+
Okta Admin Management
13+
14+
Allows customers to easily access the Okta Management APIs
15+
16+
The version of the OpenAPI document: 5.1.0
17+
Contact: devex-public@okta.com
18+
Generated by OpenAPI Generator (https://openapi-generator.tech)
19+
20+
Do not edit the class manually.
21+
""" # noqa: E501
22+
23+
from __future__ import annotations
24+
25+
import json
26+
import pprint
27+
import re # noqa: F401
28+
from typing import Any, ClassVar, Dict, List
29+
from typing import Optional, Set
30+
31+
from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator
32+
from typing_extensions import Self
33+
34+
35+
class LogUserBehavior(BaseModel):
36+
"""
37+
The result of the user behavior detection models associated with the event
38+
""" # noqa: E501
39+
40+
name: Optional[StrictStr] = Field(
41+
default=None,
42+
description="The name of the user behavior detection model [configured by admins]("
43+
"https://developer.okta.com/docs/api/openapi/okta-management/management/tag/Behavior/)",
44+
)
45+
id: Optional[StrictStr] = Field(
46+
default=None,
47+
description="The unique identifier of the user behavior detection model",
48+
)
49+
result: Optional[StrictStr] = Field(
50+
default=None, description="The result of the user behavior analysis"
51+
)
52+
__properties: ClassVar[List[str]] = ["name", "id", "result"]
53+
54+
@field_validator("result")
55+
def result_validate_enum(cls, value):
56+
"""Validates the enum"""
57+
if value is None:
58+
return value
59+
60+
if value not in set(["UNKNOWN", "POSITIVE", "NEGATIVE", "BAD_REQUEST"]):
61+
raise ValueError(
62+
"must be one of enum values ('UNKNOWN', 'POSITIVE', 'NEGATIVE', 'BAD_REQUEST')"
63+
)
64+
return value
65+
66+
model_config = ConfigDict(
67+
populate_by_name=True,
68+
validate_assignment=True,
69+
protected_namespaces=(),
70+
)
71+
72+
def to_str(self) -> str:
73+
"""Returns the string representation of the model using alias"""
74+
return pprint.pformat(self.model_dump(by_alias=True))
75+
76+
def to_json(self) -> str:
77+
"""Returns the JSON representation of the model using alias"""
78+
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
79+
return json.dumps(self.to_dict())
80+
81+
@classmethod
82+
def from_json(cls, json_str: str) -> Optional[Self]:
83+
"""Create an instance of LogUserBehavior from a JSON string"""
84+
return cls.from_dict(json.loads(json_str))
85+
86+
def to_dict(self) -> Dict[str, Any]:
87+
"""Return the dictionary representation of the model using alias.
88+
89+
This has the following differences from calling pydantic's
90+
`self.model_dump(by_alias=True)`:
91+
92+
* `None` is only added to the output dict for nullable fields that
93+
were set at model initialization. Other fields with value `None`
94+
are ignored.
95+
* OpenAPI `readOnly` fields are excluded.
96+
* OpenAPI `readOnly` fields are excluded.
97+
* OpenAPI `readOnly` fields are excluded.
98+
"""
99+
excluded_fields: Set[str] = set(
100+
[
101+
"name",
102+
"id",
103+
"result",
104+
]
105+
)
106+
107+
_dict = self.model_dump(
108+
by_alias=True,
109+
exclude=excluded_fields,
110+
exclude_none=True,
111+
)
112+
# set to None if name (nullable) is None
113+
# and model_fields_set contains the field
114+
if self.name is None and "name" in self.model_fields_set:
115+
_dict["name"] = None
116+
117+
# set to None if id (nullable) is None
118+
# and model_fields_set contains the field
119+
if self.id is None and "id" in self.model_fields_set:
120+
_dict["id"] = None
121+
122+
# set to None if result (nullable) is None
123+
# and model_fields_set contains the field
124+
if self.result is None and "result" in self.model_fields_set:
125+
_dict["result"] = None
126+
127+
return _dict
128+
129+
@classmethod
130+
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
131+
"""Create an instance of LogUserBehavior from a dict"""
132+
if obj is None:
133+
return None
134+
135+
if not isinstance(obj, dict):
136+
return cls.model_validate(obj)
137+
138+
_obj = cls.model_validate(
139+
{"name": obj.get("name"), "id": obj.get("id"), "result": obj.get("result")}
140+
)
141+
return _obj

openapi/api.yaml

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68783,6 +68783,33 @@ components:
6878368783
- COUNTRY
6878468784
- LAT_LONG
6878568785
- SUBDIVISION
68786+
LogUserBehavior:
68787+
x-okta-lifecycle:
68788+
features:
68789+
- SECURITY_CONTEXT_AND_IP_CHAIN_SYSLOG_IMPROVEMENT
68790+
description: The result of the user behavior detection models associated with the event
68791+
type: object
68792+
properties:
68793+
name:
68794+
description: The name of the user behavior detection model [configured by admins](https://developer.okta.com/docs/api/openapi/okta-management/management/tag/Behavior/)
68795+
type: string
68796+
readOnly: true
68797+
nullable: true
68798+
id:
68799+
description: The unique identifier of the user behavior detection model
68800+
type: string
68801+
readOnly: true
68802+
nullable: true
68803+
result:
68804+
description: The result of the user behavior analysis
68805+
type: string
68806+
readOnly: true
68807+
nullable: true
68808+
enum:
68809+
- UNKNOWN
68810+
- POSITIVE
68811+
- NEGATIVE
68812+
- BAD_REQUEST
6878668813
LogActor:
6878768814
description: Describes the user, app, client, or other entity (actor) who performs an action on a target. The actor is dependent on the action that is performed. All events have actors.
6878868815
type: object
@@ -69185,7 +69212,8 @@ components:
6918569212
description: The result of the user behavior detection models associated with the event
6918669213
type: array
6918769214
readOnly: true
69188-
nullable: true
69215+
items:
69216+
$ref: '#/components/schemas/LogUserBehavior'
6918969217
LogSeverity:
6919069218
description: Indicates how severe the event is
6919169219
type: string

0 commit comments

Comments
 (0)