From 7f2f8d073d87bd3c2638f097db3356090415090a Mon Sep 17 00:00:00 2001 From: BinoyOza-okta Date: Tue, 10 Mar 2026 03:40:39 +0530 Subject: [PATCH] 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. --- docs/LogSecurityContext.md | 2 +- docs/LogUserBehavior.md | 32 +++++++ okta/__init__.py | 1 + okta/models/__init__.py | 3 + okta/models/log_security_context.py | 22 +++-- okta/models/log_user_behavior.py | 141 ++++++++++++++++++++++++++++ openapi/api.yaml | 30 +++++- 7 files changed, 222 insertions(+), 9 deletions(-) create mode 100644 docs/LogUserBehavior.md create mode 100644 okta/models/log_user_behavior.py diff --git a/docs/LogSecurityContext.md b/docs/LogSecurityContext.md index d4fe4fee..8676bd82 100644 --- a/docs/LogSecurityContext.md +++ b/docs/LogSecurityContext.md @@ -11,7 +11,7 @@ Name | Type | Description | Notes **domain** | **str** | The domain name that's associated with the IP address of the inbound event request | [optional] [readonly] **isp** | **str** | The Internet service provider that's used to send the event's request | [optional] [readonly] **is_proxy** | **bool** | Specifies whether an event's request is from a known proxy | [optional] [readonly] -**user_behaviors** | **List[str]** | The result of the user behavior detection models associated with the event | [optional] [readonly] +**user_behaviors** | [**List[LogUserBehavior]**](LogUserBehavior.md) | The result of the user behavior detection models associated with the event | [optional] [readonly] ## Example diff --git a/docs/LogUserBehavior.md b/docs/LogUserBehavior.md new file mode 100644 index 00000000..3fd43958 --- /dev/null +++ b/docs/LogUserBehavior.md @@ -0,0 +1,32 @@ +# LogUserBehavior + +The result of the user behavior detection models associated with the event + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**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] +**id** | **str** | The unique identifier of the user behavior detection model | [optional] [readonly] +**result** | **str** | The result of the user behavior analysis | [optional] [readonly] + +## Example + +```python +from okta.models.log_user_behavior import LogUserBehavior + +# TODO update the JSON string below +json = "{}" +# create an instance of LogUserBehavior from a JSON string +log_user_behavior_instance = LogUserBehavior.from_json(json) +# print the JSON string representation of the object +print(LogUserBehavior.to_json()) + +# convert the object into a dict +log_user_behavior_dict = log_user_behavior_instance.to_dict() +# create an instance of LogUserBehavior from a dict +log_user_behavior_from_dict = LogUserBehavior.from_dict(log_user_behavior_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/okta/__init__.py b/okta/__init__.py index 0c29ec3d..a301df4b 100644 --- a/okta/__init__.py +++ b/okta/__init__.py @@ -1046,6 +1046,7 @@ "LogTargetChangeDetails": "okta.models.log_target_change_details", "LogTransaction": "okta.models.log_transaction", "LogUserAgent": "okta.models.log_user_agent", + "LogUserBehavior": "okta.models.log_user_behavior", "MDMEnrollmentPolicyEnrollment": "okta.models.mdm_enrollment_policy_enrollment", "MDMEnrollmentPolicyRuleCondition": "okta.models.mdm_enrollment_policy_rule_condition", "ManagedConnection": "okta.models.managed_connection", diff --git a/okta/models/__init__.py b/okta/models/__init__.py index 386695b9..1a3ed8b6 100644 --- a/okta/models/__init__.py +++ b/okta/models/__init__.py @@ -1246,6 +1246,7 @@ "LogTargetChangeDetails": "okta.models.log_target_change_details", "LogTransaction": "okta.models.log_transaction", "LogUserAgent": "okta.models.log_user_agent", + "LogUserBehavior": "okta.models.log_user_behavior", "MDMEnrollmentPolicyEnrollment": "okta.models.mdm_enrollment_policy_enrollment", "MDMEnrollmentPolicyRuleCondition": "okta.models.mdm_enrollment_policy_rule_condition", "ManagedConnection": "okta.models.managed_connection", @@ -2135,6 +2136,8 @@ "ZscalerbyzApplicationSettings": "okta.models.zscalerbyz_application_settings", "ZscalerbyzApplicationSettingsApplication": "okta.models.zscalerbyz_application_settings_application", } + + def __getattr__(name): if name in _LAZY_IMPORT_MAP: # Use lock to ensure thread-safe importing and caching diff --git a/okta/models/log_security_context.py b/okta/models/log_security_context.py index a9167b4a..5877ca41 100644 --- a/okta/models/log_security_context.py +++ b/okta/models/log_security_context.py @@ -31,6 +31,8 @@ from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr from typing_extensions import Self +from okta.models.log_user_behavior import LogUserBehavior + class LogSecurityContext(BaseModel): """ @@ -64,7 +66,7 @@ class LogSecurityContext(BaseModel): description="Specifies whether an event's request is from a known proxy", alias="isProxy", ) - user_behaviors: Optional[List[StrictStr]] = Field( + user_behaviors: Optional[List[LogUserBehavior]] = Field( default=None, description="The result of the user behavior detection models associated with the event", alias="userBehaviors", @@ -130,6 +132,13 @@ def to_dict(self) -> Dict[str, Any]: exclude=excluded_fields, exclude_none=True, ) + # override the default output from pydantic by calling `to_dict()` of each item in user_behaviors (list) + _items = [] + if self.user_behaviors: + for _item in self.user_behaviors: + if _item: + _items.append(_item.to_dict()) + _dict["userBehaviors"] = _items # set to None if as_number (nullable) is None # and model_fields_set contains the field 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]: if self.is_proxy is None and "is_proxy" in self.model_fields_set: _dict["isProxy"] = None - # set to None if user_behaviors (nullable) is None - # and model_fields_set contains the field - if self.user_behaviors is None and "user_behaviors" in self.model_fields_set: - _dict["userBehaviors"] = None - return _dict @classmethod @@ -178,7 +182,11 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "domain": obj.get("domain"), "isp": obj.get("isp"), "isProxy": obj.get("isProxy"), - "userBehaviors": obj.get("userBehaviors"), + "userBehaviors": ( + [LogUserBehavior.from_dict(_item) for _item in obj["userBehaviors"]] + if obj.get("userBehaviors") is not None + else None + ), } ) return _obj diff --git a/okta/models/log_user_behavior.py b/okta/models/log_user_behavior.py new file mode 100644 index 00000000..971b2364 --- /dev/null +++ b/okta/models/log_user_behavior.py @@ -0,0 +1,141 @@ +# The Okta software accompanied by this notice is provided pursuant to the following terms: +# Copyright © 2025-Present, Okta, Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the +# License. +# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. +# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS +# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and limitations under the License. +# coding: utf-8 + +""" +Okta Admin Management + +Allows customers to easily access the Okta Management APIs + +The version of the OpenAPI document: 5.1.0 +Contact: devex-public@okta.com +Generated by OpenAPI Generator (https://openapi-generator.tech) + +Do not edit the class manually. +""" # noqa: E501 + +from __future__ import annotations + +import json +import pprint +import re # noqa: F401 +from typing import Any, ClassVar, Dict, List +from typing import Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator +from typing_extensions import Self + + +class LogUserBehavior(BaseModel): + """ + The result of the user behavior detection models associated with the event + """ # noqa: E501 + + name: Optional[StrictStr] = Field( + default=None, + description="The name of the user behavior detection model [configured by admins](" + "https://developer.okta.com/docs/api/openapi/okta-management/management/tag/Behavior/)", + ) + id: Optional[StrictStr] = Field( + default=None, + description="The unique identifier of the user behavior detection model", + ) + result: Optional[StrictStr] = Field( + default=None, description="The result of the user behavior analysis" + ) + __properties: ClassVar[List[str]] = ["name", "id", "result"] + + @field_validator("result") + def result_validate_enum(cls, value): + """Validates the enum""" + if value is None: + return value + + if value not in set(["UNKNOWN", "POSITIVE", "NEGATIVE", "BAD_REQUEST"]): + raise ValueError( + "must be one of enum values ('UNKNOWN', 'POSITIVE', 'NEGATIVE', 'BAD_REQUEST')" + ) + return value + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of LogUserBehavior from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + * OpenAPI `readOnly` fields are excluded. + * OpenAPI `readOnly` fields are excluded. + * OpenAPI `readOnly` fields are excluded. + """ + excluded_fields: Set[str] = set( + [ + "name", + "id", + "result", + ] + ) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # set to None if name (nullable) is None + # and model_fields_set contains the field + if self.name is None and "name" in self.model_fields_set: + _dict["name"] = None + + # set to None if id (nullable) is None + # and model_fields_set contains the field + if self.id is None and "id" in self.model_fields_set: + _dict["id"] = None + + # set to None if result (nullable) is None + # and model_fields_set contains the field + if self.result is None and "result" in self.model_fields_set: + _dict["result"] = None + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of LogUserBehavior from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + {"name": obj.get("name"), "id": obj.get("id"), "result": obj.get("result")} + ) + return _obj diff --git a/openapi/api.yaml b/openapi/api.yaml index 57396744..2fe8bda9 100644 --- a/openapi/api.yaml +++ b/openapi/api.yaml @@ -68783,6 +68783,33 @@ components: - COUNTRY - LAT_LONG - SUBDIVISION + LogUserBehavior: + x-okta-lifecycle: + features: + - SECURITY_CONTEXT_AND_IP_CHAIN_SYSLOG_IMPROVEMENT + description: The result of the user behavior detection models associated with the event + type: object + properties: + name: + description: The name of the user behavior detection model [configured by admins](https://developer.okta.com/docs/api/openapi/okta-management/management/tag/Behavior/) + type: string + readOnly: true + nullable: true + id: + description: The unique identifier of the user behavior detection model + type: string + readOnly: true + nullable: true + result: + description: The result of the user behavior analysis + type: string + readOnly: true + nullable: true + enum: + - UNKNOWN + - POSITIVE + - NEGATIVE + - BAD_REQUEST LogActor: 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. type: object @@ -69185,7 +69212,8 @@ components: description: The result of the user behavior detection models associated with the event type: array readOnly: true - nullable: true + items: + $ref: '#/components/schemas/LogUserBehavior' LogSeverity: description: Indicates how severe the event is type: string