Skip to content

Commit add115e

Browse files
committed
- Removed MFA_AS_SERVICE sign on mode as we have added the support for handling unknown signOnModes.
- Updated application_json_converter.mustache for flake8 issues.
1 parent e7172d7 commit add115e

File tree

6 files changed

+62
-81
lines changed

6 files changed

+62
-81
lines changed

docs/ApplicationSignOnMode.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# ApplicationSignOnMode
22

3-
Authentication mode for the app | signOnMode | Description | | ---------- | ----------- | | AUTO_LOGIN | Secure Web Authentication (SWA) | | BASIC_AUTH | HTTP Basic Authentication with Okta Browser Plugin | | BOOKMARK | Just a bookmark (no-authentication) | | BROWSER_PLUGIN | Secure Web Authentication (SWA) with Okta Browser Plugin | | OPENID_CONNECT | Federated Authentication with OpenID Connect (OIDC) | | SAML_1_1 | Federated Authentication with SAML 1.1 WebSSO (not supported for custom apps) | | SAML_2_0 | Federated Authentication with SAML 2.0 WebSSO | | SECURE_PASSWORD_STORE | Secure Web Authentication (SWA) with POST (plugin not required) | | WS_FEDERATION | Federated Authentication with WS-Federation Passive Requestor Profile | | MFA_AS_SERVICE | Application to use Okta's MFA as a service for RDP | Select the `signOnMode` for your custom app:
3+
Authentication mode for the app | signOnMode | Description | | ---------- | ----------- | | AUTO_LOGIN | Secure Web Authentication (SWA) | | BASIC_AUTH | HTTP Basic Authentication with Okta Browser Plugin | | BOOKMARK | Just a bookmark (no-authentication) | | BROWSER_PLUGIN | Secure Web Authentication (SWA) with Okta Browser Plugin | | OPENID_CONNECT | Federated Authentication with OpenID Connect (OIDC) | | SAML_1_1 | Federated Authentication with SAML 1.1 WebSSO (not supported for custom apps) | | SAML_2_0 | Federated Authentication with SAML 2.0 WebSSO | | SECURE_PASSWORD_STORE | Secure Web Authentication (SWA) with POST (plugin not required) | | WS_FEDERATION | Federated Authentication with WS-Federation Passive Requestor Profile | Select the `signOnMode` for your custom app:
44

55
## Properties
66

okta/models/application.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
from okta.models.basic_auth_application import BasicAuthApplication
5050
from okta.models.bookmark_application import BookmarkApplication
5151
from okta.models.browser_plugin_application import BrowserPluginApplication
52-
from okta.models.application import Application
5352
from okta.models.open_id_connect_application import OpenIdConnectApplication
5453
from okta.models.saml11_application import Saml11Application
5554
from okta.models.saml_application import SamlApplication
@@ -60,7 +59,7 @@
6059
from okta.models.active_directory_application import ActiveDirectoryApplication
6160

6261

63-
class Application(BaseModel): # noqa: F811
62+
class Application(BaseModel):
6463
"""
6564
Application
6665
""" # noqa: E501
@@ -212,7 +211,6 @@ def features_validate_enum(cls, value):
212211
"BASIC_AUTH": "BasicAuthApplication",
213212
"BOOKMARK": "BookmarkApplication",
214213
"BROWSER_PLUGIN": "BrowserPluginApplication",
215-
"MFA_AS_SERVICE": "Application",
216214
"OPENID_CONNECT": "OpenIdConnectApplication",
217215
"SAML_1_1": "Saml11Application",
218216
"SAML_2_0": "SamlApplication",
@@ -246,7 +244,6 @@ def from_json(cls, json_str: str) -> Optional[
246244
BasicAuthApplication,
247245
BookmarkApplication,
248246
BrowserPluginApplication,
249-
Application,
250247
OpenIdConnectApplication,
251248
Saml11Application,
252249
SamlApplication,
@@ -284,7 +281,6 @@ def from_dict(cls, obj: Dict[str, Any]) -> Optional[
284281
BasicAuthApplication,
285282
BookmarkApplication,
286283
BrowserPluginApplication,
287-
Application,
288284
OpenIdConnectApplication,
289285
Saml11Application,
290286
SamlApplication,

okta/models/application_json_converter.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
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+
111
"""
212
Okta Admin Management
313
@@ -10,7 +20,6 @@
1020
Do not edit the class manually.
1121
""" # noqa: E501
1222
import logging
13-
logger = logging.getLogger(__name__)
1423

1524
from typing import Dict, Any, Optional
1625

@@ -27,6 +36,8 @@
2736
from okta.models.secure_password_store_application import SecurePasswordStoreApplication
2837
from okta.models.ws_federation_application import WsFederationApplication
2938

39+
logger = logging.getLogger(__name__)
40+
3041

3142
class ApplicationJsonConverter:
3243
"""
@@ -60,7 +71,6 @@ class ApplicationJsonConverter:
6071
"SAML_2_0",
6172
"SECURE_PASSWORD_STORE",
6273
"WS_FEDERATION",
63-
"MFA_AS_SERVICE", # Maps to base Application class
6474
}
6575

6676
SIGN_ON_MODE_MAPPING = {
@@ -73,7 +83,6 @@ class ApplicationJsonConverter:
7383
"SAML_2_0": SamlApplication,
7484
"SECURE_PASSWORD_STORE": SecurePasswordStoreApplication,
7585
"WS_FEDERATION": WsFederationApplication,
76-
"MFA_AS_SERVICE": Application, # Explicitly map to base Application
7786
}
7887

7988
@classmethod
@@ -151,8 +160,6 @@ def to_dict(cls, value: Application) -> Optional[Dict[str, Any]]:
151160
if value is None:
152161
return None
153162

154-
# Use Pydantic's model_dump to serialize the instance
155-
# This avoids calling to_dict() which would recurse back to this converter
156163
# Derive from model configuration
157164
excluded_fields = {
158165
field_name

okta/models/application_sign_on_mode.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ class ApplicationSignOnMode(str, Enum):
3636
Federated Authentication with OpenID Connect (OIDC) | | SAML_1_1 | Federated Authentication with SAML 1.1 WebSSO (not
3737
supported for custom apps) | | SAML_2_0 | Federated Authentication with SAML 2.0 WebSSO | | SECURE_PASSWORD_STORE |
3838
Secure Web Authentication (SWA) with POST (plugin not required) | | WS_FEDERATION | Federated Authentication with
39-
WS-Federation Passive Requestor Profile | | MFA_AS_SERVICE | Application to use Okta's MFA as a service for RDP |
40-
Select the `signOnMode` for your custom app:
39+
WS-Federation Passive Requestor Profile | Select the `signOnMode` for your custom app:
4140
"""
4241

4342
"""
@@ -52,7 +51,6 @@ class ApplicationSignOnMode(str, Enum):
5251
SAML_2_0 = "SAML_2_0"
5352
SECURE_PASSWORD_STORE = "SECURE_PASSWORD_STORE"
5453
WS_FEDERATION = "WS_FEDERATION"
55-
MFA_AS_SERVICE = "MFA_AS_SERVICE"
5654

5755
@classmethod
5856
def from_json(cls, json_str: str) -> Self:

openapi/api.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59325,7 +59325,6 @@ components:
5932559325
SAML_2_0: '#/components/schemas/SamlApplication'
5932659326
SECURE_PASSWORD_STORE: '#/components/schemas/SecurePasswordStoreApplication'
5932759327
WS_FEDERATION: '#/components/schemas/WsFederationApplication'
59328-
MFA_AS_SERVICE: '#/components/schemas/Application'
5932959328
ApplicationAccessibility:
5933059329
description: Specifies access settings for the app
5933159330
type: object
@@ -59788,7 +59787,6 @@ components:
5978859787
| SAML_2_0 | Federated Authentication with SAML 2.0 WebSSO |
5978959788
| SECURE_PASSWORD_STORE | Secure Web Authentication (SWA) with POST (plugin not required) |
5979059789
| WS_FEDERATION | Federated Authentication with WS-Federation Passive Requestor Profile |
59791-
| MFA_AS_SERVICE | Application to use Okta's MFA as a service for RDP |
5979259790

5979359791
Select the `signOnMode` for your custom app:
5979459792
type: string
@@ -59802,7 +59800,6 @@ components:
5980259800
- SAML_2_0
5980359801
- SECURE_PASSWORD_STORE
5980459802
- WS_FEDERATION
59805-
- MFA_AS_SERVICE
5980659803
ApplicationType:
5980759804
description: 'The type of client application. Default value: `web`.'
5980859805
type: string

openapi/templates/application_json_converter.mustache

Lines changed: 47 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
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+
111
{{>partial_header}}
212

13+
import logging
14+
315
import json
416
from typing import Dict, Any, Optional
517

@@ -16,6 +28,9 @@ from {{packageName}}.models.saml_application import SamlApplication
1628
from {{packageName}}.models.secure_password_store_application import SecurePasswordStoreApplication
1729
from {{packageName}}.models.ws_federation_application import WsFederationApplication
1830

31+
logger = logging.getLogger(__name__)
32+
33+
1934
class ApplicationJsonConverter:
2035
"""
2136
Custom JSON converter/factory for Application that handles null, empty, and unknown signOnMode values.
@@ -48,7 +63,6 @@ class ApplicationJsonConverter:
4863
"SAML_2_0",
4964
"SECURE_PASSWORD_STORE",
5065
"WS_FEDERATION",
51-
"MFA_AS_SERVICE", # Maps to base Application class
5266
}
5367

5468
SIGN_ON_MODE_MAPPING = {
@@ -61,7 +75,6 @@ class ApplicationJsonConverter:
6175
"SAML_2_0": SamlApplication,
6276
"SECURE_PASSWORD_STORE": SecurePasswordStoreApplication,
6377
"WS_FEDERATION": WsFederationApplication,
64-
"MFA_AS_SERVICE": Application, # Explicitly map to base Application
6578
}
6679

6780
@classmethod
@@ -93,10 +106,12 @@ class ApplicationJsonConverter:
93106
elif str(sign_on_mode).upper() in cls.KNOWN_SIGN_ON_MODES:
94107
# Known sign-on mode - map to specific class (or base Application for MFA_AS_SERVICE)
95108
target_type = cls.SIGN_ON_MODE_MAPPING[str(sign_on_mode).upper()]
96-
obj_copy["signOnMode"] = str(sign_on_mode).upper() # Normalize for validation
109+
obj_copy["signOnMode"] = str(
110+
sign_on_mode
111+
).upper() # Normalize for validation
97112
else:
98113
# Unknown sign-on mode - preserve original value and set to None for validation
99-
logger.info(
114+
logger.debug(
100115
f"Unknown signOnMode '{sign_on_mode}' encountered, "
101116
f"routing to base Application class"
102117
)
@@ -109,17 +124,21 @@ class ApplicationJsonConverter:
109124
instance = target_type.model_validate(obj_copy)
110125

111126
# Validate consistency (in dev/test mode)
112-
if isinstance(instance, Application) and not isinstance(instance, type(instance).__bases__[0]):
127+
if isinstance(instance, Application) and not isinstance(
128+
instance, type(instance).__bases__[0]
129+
):
113130
# Log warning if subclass instantiated but fields seem inconsistent
114131
logger.debug(f"Routed {sign_on_mode} to {type(instance).__name__}")
115132

116133
# Store the original unknown sign-on mode if present
117134
# For known modes, set to None to indicate no preservation needed
118135
if original_sign_on_mode is not None:
119136
# Use object.__setattr__ to bypass Pydantic's validation
120-
object.__setattr__(instance, '_original_sign_on_mode', original_sign_on_mode)
137+
object.__setattr__(
138+
instance, "_original_sign_on_mode", original_sign_on_mode
139+
)
121140
else:
122-
object.__setattr__(instance, '_original_sign_on_mode', None)
141+
object.__setattr__(instance, "_original_sign_on_mode", None)
123142

124143
return instance
125144

@@ -133,89 +152,53 @@ class ApplicationJsonConverter:
133152
if value is None:
134153
return None
135154

136-
# Use Pydantic's model_dump to serialize the instance
137-
# This avoids calling to_dict() which would recurse back to this converter
138155
# Derive from model configuration
139156
excluded_fields = {
140-
field_name for field_name, field_info in Application.model_fields.items()
141-
if field_info.exclude or (field_info.json_schema_extra and field_info.json_schema_extra.get('readOnly'))
157+
field_name
158+
for field_name, field_info in Application.model_fields.items()
159+
if field_info.exclude
160+
or (
161+
field_info.json_schema_extra
162+
and field_info.json_schema_extra.get("readOnly")
163+
)
142164
}
143165

144166
_dict = value.model_dump(
145167
by_alias=True,
146168
exclude=excluded_fields,
147169
exclude_none=True,
148-
mode='json', # Serialize enums to their values
170+
mode="json", # Serialize enums to their values
149171
)
150172

151173
# Restore original unknown signOnMode if it was preserved
152-
if hasattr(value, '_original_sign_on_mode') and value._original_sign_on_mode is not None:
174+
if (
175+
hasattr(value, "_original_sign_on_mode")
176+
and value._original_sign_on_mode is not None
177+
):
153178
_dict["signOnMode"] = value._original_sign_on_mode
154179
# Ensure signOnMode is serialized as string (in case mode='json' didn't handle it)
155-
elif "signOnMode" in _dict and hasattr(_dict["signOnMode"], 'value'):
180+
elif "signOnMode" in _dict and hasattr(_dict["signOnMode"], "value"):
156181
_dict["signOnMode"] = _dict["signOnMode"].value
157182

158-
# Handle nested model serialization manually
159-
# (Pydantic will handle most of this, but we need to ensure proper to_dict() calls for nested models)
160-
if value.accessibility:
161-
if not isinstance(value.accessibility, dict):
162-
_dict["accessibility"] = value.accessibility.to_dict()
163-
else:
164-
_dict["accessibility"] = value.accessibility
165-
166-
if value.express_configuration:
167-
if not isinstance(value.express_configuration, dict):
168-
_dict["expressConfiguration"] = value.express_configuration.to_dict()
169-
else:
170-
_dict["expressConfiguration"] = value.express_configuration
171-
172-
if value.licensing:
173-
if not isinstance(value.licensing, dict):
174-
_dict["licensing"] = value.licensing.to_dict()
175-
else:
176-
_dict["licensing"] = value.licensing
177-
178-
if value.universal_logout:
179-
if not isinstance(value.universal_logout, dict):
180-
_dict["universalLogout"] = value.universal_logout.to_dict()
181-
else:
182-
_dict["universalLogout"] = value.universal_logout
183-
184-
if value.visibility:
185-
if not isinstance(value.visibility, dict):
186-
_dict["visibility"] = value.visibility.to_dict()
187-
else:
188-
_dict["visibility"] = value.visibility
189-
190-
if value.embedded:
191-
if not isinstance(value.embedded, dict):
192-
_dict["_embedded"] = value.embedded.to_dict()
193-
else:
194-
_dict["_embedded"] = value.embedded
195-
196-
if value.links:
197-
if not isinstance(value.links, dict):
198-
_dict["_links"] = value.links.to_dict()
199-
else:
200-
_dict["_links"] = value.links
183+
# NOTE: Pydantic's model_dump(mode='json') handles most nested BaseModel serialization.
184+
# However, subclass-specific fields (settings, credentials, name) need manual handling
185+
# because they're not in the base Application schema and model_dump doesn't call
186+
# their custom to_dict() methods which may have additional logic.
201187

202-
# Handle subclass-specific fields
203-
# Check if instance has settings (for subclasses like ActiveDirectoryApplication)
204-
if hasattr(value, 'settings') and value.settings:
188+
# Handle subclass-specific fields that may have custom serialization logic
189+
if hasattr(value, "settings") and value.settings:
205190
if not isinstance(value.settings, dict):
206191
_dict["settings"] = value.settings.to_dict()
207192
else:
208193
_dict["settings"] = value.settings
209194

210-
# Check if instance has credentials (for subclasses like AutoLoginApplication)
211-
if hasattr(value, 'credentials') and value.credentials:
195+
if hasattr(value, "credentials") and value.credentials:
212196
if not isinstance(value.credentials, dict):
213197
_dict["credentials"] = value.credentials.to_dict()
214198
else:
215199
_dict["credentials"] = value.credentials
216200

217-
# Check if instance has name (for various subclasses)
218-
if hasattr(value, 'name') and value.name:
201+
if hasattr(value, "name") and value.name:
219202
_dict["name"] = value.name
220203

221204
return _dict

0 commit comments

Comments
 (0)