Artem Goncharov 7eb8b00b61 Drop overloaded federation service provider schema
Fix docstring processing which might be list already (why?)

Change-Id: Ia8f88085e00d53815a68565526ca0a387d5d4dbc
2025-01-31 20:51:26 +01:00

390 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.
#
from typing import Any
from jsonref import replace_refs
from keystone.federation import schema as federation_schema
from keystone.federation import utils as federation_mapping_schema
from codegenerator.common.schema import ParameterSchema
from codegenerator.common.schema import TypeSchema
from codegenerator.openapi.keystone_schemas import auth
_identity_provider_properties = {
"enabled": {
"type": "boolean",
"description": "Whether the identity provider is enabled or not",
},
"description": {
"type": ["string", "null"],
"description": "The identity provider description",
},
"authorization_ttl": {
"type": ["integer", "null"],
"minimum": 0,
"description": (
"The length of validity in minutes for group memberships "
"carried over through mapping and persisted in the database. "
"If left unset, the default value configured in keystone will "
"be used, if enabled."
),
},
"remote_ids": {
"type": ["array", "null"],
"description": "List of the unique identity provider's remote IDs",
"items": {"type": "string"},
"uniqueItems": True,
},
}
IDENTITY_PROVIDER_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The Identity Provider unique ID",
},
"description": {
"type": "string",
"description": "The Identity Provider description",
},
"domain_id": {
"type": "string",
"format": "uuid",
"description": "The ID of a domain that is associated with the Identity Provider.",
},
"authorization_ttl": {
"type": "integer",
"description": "The length of validity in minutes for group memberships carried over through mapping and persisted in the database.",
},
"enabled": {
"type": "boolean",
"description": "Whether the Identity Provider is enabled or not",
},
"remote_ids": {
"type": "array",
"description": "List of the unique Identity Providers remote IDs",
"items": {"type": "string"},
},
},
}
IDENTITY_PROVIDER_CONTAINER_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {"identity_provider": IDENTITY_PROVIDER_SCHEMA},
}
IDENTITY_PROVIDER_CREATE_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {
"identity_provider": {
"type": "object",
"projecties": {
**_identity_provider_properties,
"domain_id": {
"type": ["string", "null"],
"minLength": 1,
"maxLength": 64,
"pattern": r"^[a-zA-Z0-9-]+$",
"description": (
"The ID of a domain that is associated with the "
"identity provider. Federated users that "
"authenticate with the identity provider will be "
"created under the domain specified."
),
},
},
}
},
}
IDENTITY_PROVIDER_UPDATE_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {
"identity_provider": {
"type": "object",
"properties": _identity_provider_properties,
"additionalProperties": False,
"minProperties": 1,
}
},
}
IDENTITY_PROVIDERS_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {
"identity_providers": {
"type": "array",
"items": IDENTITY_PROVIDER_SCHEMA,
}
},
}
IDENTITY_PROVIDERS_LIST_PARAMETERS: dict[str, Any] = {
"OS_FEDERATION_identity_providers_id": {
"in": "query",
"name": "id",
"description": "Filter for Identity Providers ID attribute",
"schema": {"type": "string"},
},
"OS_FEDERATION_identity_providers_enabled": {
"in": "query",
"name": "enabled",
"description": "Filter for Identity Providers enabled attribute",
"schema": {"type": "boolean"},
},
}
IDENTITY_PROVIDER_PROTOCOL_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"description": "The federation protocol ID",
},
"mapping_id": {"type": "string"},
"remote_id_attribute": {"type": "string", "maxLength": 64},
},
}
IDENTITY_PROVIDER_PROTOCOL_CONTAINER_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {"protocol": IDENTITY_PROVIDER_PROTOCOL_SCHEMA},
}
IDENTITY_PROVIDER_PROTOCOLS_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {
"protocols": {
"type": "array",
"items": IDENTITY_PROVIDER_PROTOCOL_SCHEMA,
}
},
}
IDENTITY_PROVIDER_PROTOCOL_CREATE_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {"protocol": federation_schema.protocol_create},
}
IDENTITY_PROVIDER_PROTOCOL_UPDATE_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {"protocol": federation_schema.protocol_update},
}
MAPPING_PROPERTIES = replace_refs(
federation_mapping_schema.IDP_ATTRIBUTE_MAPPING_SCHEMA_2_0, proxies=False
)
MAPPING_PROPERTIES.pop("definitions", None)
MAPPING_PROPERTIES["properties"]["schema_version"] = {
"type": "string",
"description": "Mapping schema version",
}
MAPPING_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The Federation Mapping unique ID",
},
**MAPPING_PROPERTIES["properties"],
},
}
MAPPING_CONTAINER_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {"mapping": MAPPING_SCHEMA},
}
MAPPINGS_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {"mappings": {"type": "array", "items": MAPPING_SCHEMA}},
}
MAPPING_CREATE_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {"mapping": MAPPING_PROPERTIES},
}
def _post_process_operation_hook(
openapi_spec, operation_spec, path: str | None = None
):
"""Hook to allow service specific generator to modify details"""
operationId = operation_spec.operationId
if operationId == "OS-FEDERATION/identity_providers:get":
for key, val in IDENTITY_PROVIDERS_LIST_PARAMETERS.items():
openapi_spec.components.parameters.setdefault(
key, ParameterSchema(**val)
)
ref = f"#/components/parameters/{key}"
if ref not in [x.ref for x in operation_spec.parameters]:
operation_spec.parameters.append(ParameterSchema(ref=ref))
elif operationId in [
"OS-FEDERATION/projects:get",
"OS-FEDERATION/projects:head",
"OS-FEDERATION/domains:get",
"OS-FEDERATION/domains:head",
"endpoints/endpoint_id/OS-ENDPOINT-POLICY/policy:get",
]:
operation_spec.deprecated = True
def _get_schema_ref(
openapi_spec, name, description=None, schema_def=None, action_name=None
) -> tuple[str | None, str | None, bool]:
mime_type: str = "application/json"
ref: str | None
if name == "Os_FederationProjectsGetResponse":
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**auth.AUTH_PROJECTS_SCHEMA)
)
ref = f"#/components/schemas/{name}"
elif name in ["Os_FederationDomainsGetResponse"]:
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**auth.AUTH_DOMAINS_SCHEMA)
)
ref = f"#/components/schemas/{name}"
elif name in [
"AuthOs_FederationSaml2PostRequest",
"AuthOs_FederationSaml2EcpPostRequest",
]:
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**auth.AUTH_TOKEN_ISSUE_SCHEMA)
)
ref = f"#/components/schemas/{name}"
elif name in [
"AuthOs_FederationSaml2PostResponse",
"AuthOs_FederationSaml2EcpPostResponse",
]:
mime_type = "text/xml"
openapi_spec.components.schemas.setdefault(
name,
TypeSchema(
type="string",
format="xml",
descripion="SAML assertion in XML format",
),
)
ref = f"#/components/schemas/{name}"
elif name in [
"AuthOs_FederationWebssoGetResponse",
"AuthOs_FederationWebssoPostResponse",
"AuthOs_FederationIdentity_ProvidersProtocolsWebssoGetResponse",
"AuthOs_FederationIdentity_ProvidersProtocolsWebssoPostResponse",
"Os_FederationIdentity_ProvidersProtocolsAuthGetResponse",
"Os_FederationIdentity_ProvidersProtocolsAuthPostResponse",
]:
# Federation based auth returns unscoped token even it is not
# described explicitly in apiref
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**auth.AUTH_TOKEN_SCHEMA)
)
ref = f"#/components/schemas/{name}"
elif name in [
"AuthOs_FederationWebssoPostRequest",
"AuthOs_FederationIdentity_ProvidersProtocolsWebssoPostRequest",
]:
ref = None
# ### Identity provider
elif name == "Os_FederationIdentity_ProvidersGetResponse":
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**IDENTITY_PROVIDERS_SCHEMA)
)
ref = f"#/components/schemas/{name}"
elif name in [
"Os_FederationIdentity_ProviderGetResponse",
"Os_FederationIdentity_ProviderPutResponse",
"Os_FederationIdentity_ProviderPatchResponse",
]:
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**IDENTITY_PROVIDER_CONTAINER_SCHEMA)
)
ref = f"#/components/schemas/{name}"
elif name == "Os_FederationIdentity_ProviderPutRequest":
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**IDENTITY_PROVIDER_CREATE_SCHEMA)
)
ref = f"#/components/schemas/{name}"
elif name == "Os_FederationIdentity_ProviderPatchRequest":
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**IDENTITY_PROVIDER_UPDATE_SCHEMA)
)
ref = f"#/components/schemas/{name}"
# ### Identity provider protocols
elif name == "Os_FederationIdentity_ProvidersProtocolsGetResponse":
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**IDENTITY_PROVIDER_PROTOCOLS_SCHEMA)
)
ref = f"#/components/schemas/{name}"
elif name in [
"Os_FederationIdentity_ProvidersProtocolGetResponse",
"Os_FederationIdentity_ProvidersProtocolPutResponse",
"Os_FederationIdentity_ProvidersProtocolPatchResponse",
]:
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**IDENTITY_PROVIDER_PROTOCOL_CONTAINER_SCHEMA)
)
ref = f"#/components/schemas/{name}"
elif name == "Os_FederationIdentity_ProvidersProtocolPutRequest":
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**IDENTITY_PROVIDER_PROTOCOL_CREATE_SCHEMA)
)
ref = f"#/components/schemas/{name}"
elif name == "Os_FederationIdentity_ProvidersProtocolPatchRequest":
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**IDENTITY_PROVIDER_PROTOCOL_UPDATE_SCHEMA)
)
ref = f"#/components/schemas/{name}"
# ### Identity provider mapping
elif name == "Os_FederationMappingsGetResponse":
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**MAPPINGS_SCHEMA)
)
ref = f"#/components/schemas/{name}"
elif name in [
"Os_FederationMappingGetResponse",
"Os_FederationMappingPutResponse",
"Os_FederationMappingPatchResponse",
]:
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**MAPPING_CONTAINER_SCHEMA)
)
ref = f"#/components/schemas/{name}"
elif name in [
"Os_FederationMappingPutRequest",
"Os_FederationMappingPatchRequest",
]:
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**MAPPING_CREATE_SCHEMA)
)
ref = f"#/components/schemas/{name}"
# SAML2 Metadata
elif name == "Os_FederationSaml2MetadataGetResponse":
mime_type = "text/xml"
openapi_spec.components.schemas.setdefault(
name,
TypeSchema(
type="string",
format="xml",
descripion="Identity Provider metadata information in XML format",
),
)
ref = f"#/components/schemas/{name}"
else:
return (None, None, False)
return (ref, mime_type, True)