From 78d5b208fec32fbf500283ad24829be2a941cd21 Mon Sep 17 00:00:00 2001 From: BinoyOza-okta Date: Sun, 7 Jun 2026 19:08:35 +0530 Subject: [PATCH] fix: Align AccessPolicyConstraint methods/types enums with actual API casing This commit fixes Pydantic deserialization failures on `PolicyApi.list_policy_rules()` (GET `/api/v1/policies/{policyId}/rules`) when an access policy rule's `constraints[]` contains lowercase `methods` or `types` values (e.g. `"password"`, `"push"`, `"webauthn"`). Problem: - The Okta API returns `methods` and `types` constraint values in lowercase (e.g. `"types": ["password"]`, `"methods": ["push"]`), but the OpenAPI spec defined the corresponding enums as UPPERCASE-only (`PASSWORD`, `PUSH`, `WEBAUTHN`, ...). - Generated Pydantic validators rejected the real API payload with: each list item must be one of ('PASSWORD', 'SECURITY_QUESTION', 'SMS', 'VOICE', 'EMAIL', 'PUSH', 'SIGNED_NONCE', 'OTP', 'TOTP', 'WEBAUTHN', 'DUO', 'IDP', 'CERT') - This broke `list_policy_rules()` for any access policy whose rules carry `KnowledgeConstraint` / `PossessionConstraint` / base `AccessPolicyConstraint` blocks (i.e. most modern authentication policies). Root Cause: - Enum case mismatch between the OAS3 spec and the live API response for `AccessPolicyConstraint.methods[]` and `AccessPolicyConstraint.types[]` (inherited by `KnowledgeConstraint` and `PossessionConstraint`). Solution: 1. Updated `openapi/api.yaml` to redefine both enums in lowercase to match what the API actually returns: - `methods[]`: password, security_question, sms, voice, email, push, signed_nonce, otp, totp, webauthn, duo, idp, cert - `types[]`: security_key, phone, email, password, security_question, app, federated 2. Regenerated the affected models so their `field_validator` allow-lists and error messages reflect the lowercase values: - `okta/models/access_policy_constraint.py` - `okta/models/knowledge_constraint.py` - `okta/models/possession_constraint.py` Testing: - Verified against a live Okta org with an access policy whose knowledge constraint contains `"types": ["password"]`. `client.list_policy_rules(policy_id)` now returns the full rule list without raising `ValidationError`, and `constraints[].knowledge.types` deserializes cleanly. - All three regenerated models accept the lowercase values; no other factor / policy code paths were touched. Backward Compatibility: - This is a wire-format alignment fix: previously the SDK could not parse real API responses at all, so no existing successful call is affected. Callers constructing constraints client-side must now use lowercase values (matching API behavior). Fixes: OKTA-1172239 --- okta/models/access_policy_constraint.py | 48 ++++++++++++------------- okta/models/knowledge_constraint.py | 48 ++++++++++++------------- okta/models/possession_constraint.py | 48 ++++++++++++------------- openapi/api.yaml | 40 ++++++++++----------- 4 files changed, 92 insertions(+), 92 deletions(-) diff --git a/okta/models/access_policy_constraint.py b/okta/models/access_policy_constraint.py index ccbd38c6..62b4c537 100644 --- a/okta/models/access_policy_constraint.py +++ b/okta/models/access_policy_constraint.py @@ -99,24 +99,24 @@ def methods_validate_enum(cls, value): for i in value: if i not in set( [ - "PASSWORD", - "SECURITY_QUESTION", - "SMS", - "VOICE", - "EMAIL", - "PUSH", - "SIGNED_NONCE", - "OTP", - "TOTP", - "WEBAUTHN", - "DUO", - "IDP", - "CERT", + "password", + "security_question", + "sms", + "voice", + "email", + "push", + "signed_nonce", + "otp", + "totp", + "webauthn", + "duo", + "idp", + "cert", ] ): raise ValueError( - "each list item must be one of ('PASSWORD', 'SECURITY_QUESTION', 'SMS', 'VOICE', 'EMAIL', 'PUSH', " - "'SIGNED_NONCE', 'OTP', 'TOTP', 'WEBAUTHN', 'DUO', 'IDP', 'CERT')" + "each list item must be one of ('password', 'security_question', 'sms', 'voice', 'email', 'push', " + "'signed_nonce', 'otp', 'totp', 'webauthn', 'duo', 'idp', 'cert')" ) return value @@ -129,18 +129,18 @@ def types_validate_enum(cls, value): for i in value: if i not in set( [ - "SECURITY_KEY", - "PHONE", - "EMAIL", - "PASSWORD", - "SECURITY_QUESTION", - "APP", - "FEDERATED", + "security_key", + "phone", + "email", + "password", + "security_question", + "app", + "federated", ] ): raise ValueError( - "each list item must be one of ('SECURITY_KEY', 'PHONE', 'EMAIL', 'PASSWORD', 'SECURITY_QUESTION', " - "'APP', 'FEDERATED')" + "each list item must be one of ('security_key', 'phone', 'email', 'password', 'security_question', " + "'app', 'federated')" ) return value diff --git a/okta/models/knowledge_constraint.py b/okta/models/knowledge_constraint.py index c14c8e76..d3cfbb6e 100644 --- a/okta/models/knowledge_constraint.py +++ b/okta/models/knowledge_constraint.py @@ -96,24 +96,24 @@ def methods_validate_enum(cls, value): for i in value: if i not in set( [ - "PASSWORD", - "SECURITY_QUESTION", - "SMS", - "VOICE", - "EMAIL", - "PUSH", - "SIGNED_NONCE", - "OTP", - "TOTP", - "WEBAUTHN", - "DUO", - "IDP", - "CERT", + "password", + "security_question", + "sms", + "voice", + "email", + "push", + "signed_nonce", + "otp", + "totp", + "webauthn", + "duo", + "idp", + "cert", ] ): raise ValueError( - "each list item must be one of ('PASSWORD', 'SECURITY_QUESTION', 'SMS', 'VOICE', 'EMAIL', 'PUSH', " - "'SIGNED_NONCE', 'OTP', 'TOTP', 'WEBAUTHN', 'DUO', 'IDP', 'CERT')" + "each list item must be one of ('password', 'security_question', 'sms', 'voice', 'email', 'push', " + "'signed_nonce', 'otp', 'totp', 'webauthn', 'duo', 'idp', 'cert')" ) return value @@ -126,18 +126,18 @@ def types_validate_enum(cls, value): for i in value: if i not in set( [ - "SECURITY_KEY", - "PHONE", - "EMAIL", - "PASSWORD", - "SECURITY_QUESTION", - "APP", - "FEDERATED", + "security_key", + "phone", + "email", + "password", + "security_question", + "app", + "federated", ] ): raise ValueError( - "each list item must be one of ('SECURITY_KEY', 'PHONE', 'EMAIL', 'PASSWORD', 'SECURITY_QUESTION', " - "'APP', 'FEDERATED')" + "each list item must be one of ('security_key', 'phone', 'email', 'password', 'security_question', " + "'app', 'federated')" ) return value diff --git a/okta/models/possession_constraint.py b/okta/models/possession_constraint.py index b8ca7eec..3c611bab 100644 --- a/okta/models/possession_constraint.py +++ b/okta/models/possession_constraint.py @@ -137,24 +137,24 @@ def methods_validate_enum(cls, value): for i in value: if i not in set( [ - "PASSWORD", - "SECURITY_QUESTION", - "SMS", - "VOICE", - "EMAIL", - "PUSH", - "SIGNED_NONCE", - "OTP", - "TOTP", - "WEBAUTHN", - "DUO", - "IDP", - "CERT", + "password", + "security_question", + "sms", + "voice", + "email", + "push", + "signed_nonce", + "otp", + "totp", + "webauthn", + "duo", + "idp", + "cert", ] ): raise ValueError( - "each list item must be one of ('PASSWORD', 'SECURITY_QUESTION', 'SMS', 'VOICE', 'EMAIL', 'PUSH', " - "'SIGNED_NONCE', 'OTP', 'TOTP', 'WEBAUTHN', 'DUO', 'IDP', 'CERT')" + "each list item must be one of ('password', 'security_question', 'sms', 'voice', 'email', 'push', " + "'signed_nonce', 'otp', 'totp', 'webauthn', 'duo', 'idp', 'cert')" ) return value @@ -167,18 +167,18 @@ def types_validate_enum(cls, value): for i in value: if i not in set( [ - "SECURITY_KEY", - "PHONE", - "EMAIL", - "PASSWORD", - "SECURITY_QUESTION", - "APP", - "FEDERATED", + "security_key", + "phone", + "email", + "password", + "security_question", + "app", + "federated", ] ): raise ValueError( - "each list item must be one of ('SECURITY_KEY', 'PHONE', 'EMAIL', 'PASSWORD', 'SECURITY_QUESTION', " - "'APP', 'FEDERATED')" + "each list item must be one of ('security_key', 'phone', 'email', 'password', 'security_question', " + "'app', 'federated')" ) return value diff --git a/openapi/api.yaml b/openapi/api.yaml index d07ef21e..050b0fbb 100644 --- a/openapi/api.yaml +++ b/openapi/api.yaml @@ -57789,19 +57789,19 @@ components: items: type: string enum: - - PASSWORD - - SECURITY_QUESTION - - SMS - - VOICE - - EMAIL - - PUSH - - SIGNED_NONCE - - OTP - - TOTP - - WEBAUTHN - - DUO - - IDP - - CERT + - password + - security_question + - sms + - voice + - email + - push + - signed_nonce + - otp + - totp + - webauthn + - duo + - idp + - cert type: array reauthenticateIn: description: The duration after which the user must re-authenticate regardless of user activity. This re-authentication interval overrides the Verification Method object's `reauthenticateIn` interval. The supported values use ISO 8601 period format for recurring time intervals (for example, `PT1H`). @@ -57814,13 +57814,13 @@ components: items: type: string enum: - - SECURITY_KEY - - PHONE - - EMAIL - - PASSWORD - - SECURITY_QUESTION - - APP - - FEDERATED + - security_key + - phone + - email + - password + - security_question + - app + - federated type: array AccessPolicyConstraints: description: Specifies constraints for the authenticator. Constraints are logically evaluated such that only one constraint object needs to be satisfied. But, within a constraint object, each constraint property must be satisfied.