From dbf59474bb89b2999f36239889b51aa5715fa667 Mon Sep 17 00:00:00 2001 From: James Hodgkinson Date: Fri, 1 Mar 2024 16:57:36 +1000 Subject: [PATCH] OpenAPI schema fixes (#2590) * OpenAPI schema fixes * Adding OpenAPI schema checks to the release script --- proto/src/internal/mod.rs | 8 +- scripts/openapi_tests/check_openapi_spec.sh | 12 +- scripts/test_run_release_server.sh | 12 +- server/core/src/https/apidocs/mod.rs | 73 ++++---- server/core/src/https/generic.rs | 1 + server/core/src/https/oauth2.rs | 1 + server/core/src/https/v1.rs | 174 ++++++++++++++------ server/core/src/https/v1_oauth2.rs | 18 +- server/core/src/https/v1_scim.rs | 19 ++- 9 files changed, 225 insertions(+), 93 deletions(-) diff --git a/proto/src/internal/mod.rs b/proto/src/internal/mod.rs index 3dc314cbd..b10c4da64 100644 --- a/proto/src/internal/mod.rs +++ b/proto/src/internal/mod.rs @@ -24,7 +24,7 @@ pub use self::error::*; pub use self::raw::*; pub use self::token::*; -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, ToSchema)] /// This is a description of a linked or connected application for a user. This is /// used in the UI to render applications on the dashboard for a user to access. pub enum AppLink { @@ -37,7 +37,9 @@ pub enum AppLink { }, } -#[derive(Debug, Serialize, Deserialize, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +#[derive( + Debug, Serialize, Deserialize, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, ToSchema, +)] #[serde(rename_all = "lowercase")] #[derive(TryFromPrimitive)] #[repr(u16)] @@ -81,7 +83,7 @@ pub enum IdentifyUserRequest { DisplayCode, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, ToSchema)] pub enum IdentifyUserResponse { IdentityVerificationUnavailable, IdentityVerificationAvailable, diff --git a/scripts/openapi_tests/check_openapi_spec.sh b/scripts/openapi_tests/check_openapi_spec.sh index 62336a9ed..a8a548823 100755 --- a/scripts/openapi_tests/check_openapi_spec.sh +++ b/scripts/openapi_tests/check_openapi_spec.sh @@ -27,15 +27,21 @@ if [ ! -s "${WORKDIR}/openapi.json" ]; then exit 1 fi +echo "Running pythonopenapi/openapi-spec-validator" + docker run \ --mount "type=bind,src=${WORKDIR}/openapi.json,target=/openapi.json" \ --rm pythonopenapi/openapi-spec-validator /openapi.json && \ echo "openapi-spec-validator passed" -docker run --rm -it \ +echo "Running openapitools/openapi-generator-cli" +docker run --rm \ --mount "type=bind,src=${WORKDIR},target=/spec" \ - openapitools/openapi-generator-cli generate \ - -i /spec/openapi.json -g rust + openapitools/openapi-generator-cli validate \ + -i /spec/openapi.json + cleanup "${WORKDIR}" + +echo "It looks to have passed OK!" \ No newline at end of file diff --git a/scripts/test_run_release_server.sh b/scripts/test_run_release_server.sh index c8783ccd5..f7ac3c52d 100755 --- a/scripts/test_run_release_server.sh +++ b/scripts/test_run_release_server.sh @@ -66,12 +66,16 @@ done ../../scripts/setup_dev_environment.sh +if [ -n "$CURRENT_DIR" ]; then + cd "$CURRENT_DIR" || exit 1 +fi + +echo "Running the OpenAPI schema checks" + +bash -c ./scripts/openapi_tests/check_openapi_spec.sh || exit 1 + echo "Waiting ${WAIT_TIMER} seconds and terminating Kanidmd" sleep "${WAIT_TIMER}" if [ "$(pgrep kanidmd | wc -l)" -gt 0 ]; then kill $(pgrep kanidmd) fi - -if [ -n "$CURRENT_DIR" ]; then - cd "$CURRENT_DIR" || exit 1 -fi diff --git a/server/core/src/https/apidocs/mod.rs b/server/core/src/https/apidocs/mod.rs index 11b6c860f..4b9722099 100644 --- a/server/core/src/https/apidocs/mod.rs +++ b/server/core/src/https/apidocs/mod.rs @@ -34,6 +34,16 @@ impl Modify for SecurityAddon { // docs for the derive macro are here: #[derive(OpenApi)] #[openapi( + servers( + (url="https://{host}:{port}", + variables( + ("host" = (default="localhost", description="Server's hostname")), + ("port" = (default="8443", description="Server HTTPS port")), + ) + ) + ), + external_docs(url = "https://kanidm.com/docs", description = "Kanidm documentation page"), + paths( super::generic::status, super::generic::robots_txt, @@ -188,55 +198,60 @@ impl Modify for SecurityAddon { scim_v1::ScimSyncRetentionMode, // TODO: can't add Entry/ProtoEntry to schema as this was only recently supported utoipa v3.5.0 doesn't support it - ref // v1::Entry, - v1::AccountUnixExtend, internal::ApiToken, - v1::ApiTokenGenerate, - v1::AuthRequest, - v1::AuthResponse, - v1::AuthState, + internal::ApiTokenPurpose, internal::BackupCodesView, internal::CreateRequest, internal::CredentialDetail, + internal::CredentialDetailType, internal::CredentialStatus, + internal::CUExtPortal, internal::CUIntentToken, + internal::CURegState, internal::CUSessionToken, internal::CUStatus, internal::DeleteRequest, + internal::Filter, internal::Group, - v1::GroupUnixExtend, + internal::Modify, internal::ModifyList, internal::ModifyRequest, + internal::OperationError, internal::PasskeyDetail, + internal::PasswordFeedback, + internal::PluginError, internal::RadiusAuthToken, + internal::SchemaError, internal::SearchRequest, internal::SearchResponse, - v1::SingleStringRequest, - internal::TotpSecret, internal::TotpAlgo, - v1::UatStatus, - v1::UnixGroupToken, - v1::UnixUserToken, + internal::TotpSecret, + internal::UatPurpose, internal::UserAuthToken, - v1::WhoamiResponse, - internal::ApiTokenPurpose, - v1::AuthStep, + v1::AccountUnixExtend, + v1::ApiTokenGenerate, + v1::AuthAllowed, + v1::AuthCredential, v1::AuthIssueSession, v1::AuthMech, - v1::AuthCredential, - v1::AuthAllowed, - internal::CUExtPortal, - internal::CURegState, - internal::CredentialDetailType, + v1::AuthRequest, + v1::AuthResponse, + v1::AuthState, + v1::AuthStep, v1::Entry, - internal::Filter, - internal::Modify, - v1::UatStatusState, + v1::GroupUnixExtend, + v1::SingleStringRequest, + internal::UiHint, v1::UatPurposeStatus, - internal::UatPurpose, - internal::OperationError, - internal::SchemaError, - internal::PluginError, - internal::PasswordFeedback, + v1::UatStatus, + v1::UatStatusState, + v1::UnixGroupToken, + v1::UnixUserToken, + v1::WhoamiResponse, + internal::CUCredState, + internal::CURegWarning, + internal::IdentifyUserResponse, + internal::AppLink, internal::IdentifyUserRequest, // terrible workaround for other things @@ -266,9 +281,9 @@ impl Modify for SecurityAddon { ), info( title = "Kanidm", - description = "API for interacting with the Kanidm system. This is a work in progress", + description = "API for interacting with the Kanidm system. This is a work in progress.", contact( // - name="Kanidm", + name="Kanidm Github", url="https://github.com/kanidm/kanidm", ) ) diff --git a/server/core/src/https/generic.rs b/server/core/src/https/generic.rs index e8e5f95c9..d33fbdbc4 100644 --- a/server/core/src/https/generic.rs +++ b/server/core/src/https/generic.rs @@ -38,6 +38,7 @@ pub async fn status( (status = 200, description = "Ok"), ), tag = "ui", + operation_id = "robots_txt", )] pub async fn robots_txt() -> impl IntoResponse { diff --git a/server/core/src/https/oauth2.rs b/server/core/src/https/oauth2.rs index 84339c23b..99aa275f5 100644 --- a/server/core/src/https/oauth2.rs +++ b/server/core/src/https/oauth2.rs @@ -82,6 +82,7 @@ pub(crate) fn oauth2_id(rs_name: &str) -> Filter { #[utoipa::path( get, path = "/ui/images/oauth2/{rs_name}", + operation_id = "oauth2_image_get", responses( (status = 200, description = "Ok", body=&[u8]), (status = 403, description = "Authorization refused"), diff --git a/server/core/src/https/v1.rs b/server/core/src/https/v1.rs index b35d0a2db..42283e355 100644 --- a/server/core/src/https/v1.rs +++ b/server/core/src/https/v1.rs @@ -49,6 +49,7 @@ pub(crate) struct SessionId { request_body=CreateRequest, security(("token_jwt" = [])), tag = "v1/raw", + operation_id="raw_create" )] /// Raw request to the system, be warned this can be dangerous! pub async fn raw_create( @@ -74,6 +75,7 @@ pub async fn raw_create( request_body=ModifyRequest, security(("token_jwt" = [])), tag = "v1/raw", + operation_id="raw_modify" )] /// Raw request to the system, be warned this can be dangerous! pub async fn raw_modify( @@ -99,6 +101,7 @@ pub async fn raw_modify( request_body=DeleteRequest, security(("token_jwt" = [])), tag = "v1/raw", + operation_id = "raw_delete" )] /// Raw request to the system, be warned this can be dangerous! pub async fn raw_delete( @@ -119,12 +122,13 @@ pub async fn raw_delete( post, path = "/v1/raw/search", responses( - (status = 200), // TODO: response content + (status = 200, body=SearchResponse, content_type="application/json"), ApiResponseWithout200, ), request_body=SearchRequest, security(("token_jwt" = [])), tag = "v1/raw", + operation_id="raw_search" )] /// Raw request to the system, be warned this can be dangerous! pub async fn raw_search( @@ -145,11 +149,12 @@ pub async fn raw_search( get, path = "/v1/self", responses( - (status = 200), // TODO: response content + (status = 200, body=WhoamiResponse, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/self", + operation_id="whoami" )] // Whoami? pub async fn whoami( @@ -170,11 +175,12 @@ pub async fn whoami( get, path = "/v1/self/_uat", responses( - (status = 200, description = "Ok"), + (status = 200, description = "Ok", body=UserAuthToken, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/self", + operation_id="whoami_uat" )] pub async fn whoami_uat( State(state): State, @@ -197,6 +203,7 @@ pub async fn whoami_uat( ), security(("token_jwt" = [])), tag = "v1/auth", + operation_id="logout" )] pub async fn logout( State(state): State, @@ -441,11 +448,12 @@ pub async fn json_rest_event_delete_attr( get, path = "/v1/schema", responses( - (status=200), // TODO: define response + (status=200, content_type="application/json", body=Vec), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/schema", + operation_id = "schema_get", )] // Whoami? pub async fn schema_get( @@ -468,11 +476,12 @@ pub async fn schema_get( get, path = "/v1/schema/attributetype", responses( - (status=200), // TODO: define response + (status=200, content_type="application/json", body=Vec), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/schema", + operation_id = "schema_attributetype_get", )] pub async fn schema_attributetype_get( State(state): State, @@ -487,11 +496,12 @@ pub async fn schema_attributetype_get( get, path = "/v1/schema/attributetype/{id}", responses( - (status=200), // TODO: define response + (status=200, body=Option, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/schema", + operation_id = "schema_attributetype_get_id", )] pub async fn schema_attributetype_get_id( State(state): State, @@ -521,11 +531,12 @@ pub async fn schema_attributetype_get_id( get, path = "/v1/schema/classtype", responses( - (status=200), // TODO: define response + (status=200, body=Vec, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/schema", + operation_id="schema_classtype_get", )] pub async fn schema_classtype_get( State(state): State, @@ -540,11 +551,12 @@ pub async fn schema_classtype_get( get, path = "/v1/schema/classtype/{id}", responses( - (status=200), // TODO: define response + (status=200, body=Option, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/schema", + operation_id="schema_classtype_get_id", )] pub async fn schema_classtype_get_id( State(state): State, @@ -570,11 +582,12 @@ pub async fn schema_classtype_get_id( get, path = "/v1/person", responses( - (status=200), // TODO: define response + (status=200, body=Vec, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/person", + operation_id = "person_get", )] pub async fn person_get( State(state): State, @@ -591,9 +604,10 @@ pub async fn person_get( responses( DefaultApiResponse, ), - // request_body=ProtoEntry, // TODO: ProtoEntry can't be serialized, so we need to do this manually + request_body=ProtoEntry, security(("token_jwt" = [])), tag = "v1/person", + operation_id = "person_post", )] /// Expects the following fields in the attrs field of the req: [name, displayname] pub async fn person_post( @@ -614,11 +628,12 @@ pub async fn person_post( get, path = "/v1/person/{id}", responses( - (status=200), // TODO: define response + (status=200, body=Option, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/person", + operation_id = "person_id_get", )] pub async fn person_id_get( State(state): State, @@ -638,6 +653,7 @@ pub async fn person_id_get( ), security(("token_jwt" = [])), tag = "v1/person", + operation_id = "person_id_delete", )] pub async fn person_id_delete( State(state): State, @@ -655,11 +671,12 @@ pub async fn person_id_delete( get, path = "/v1/service_account", responses( - (status=200), // TODO: define response + (status=200, body=Vec, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/service_account", + operation_id = "service_account_get", )] pub async fn service_account_get( State(state): State, @@ -673,12 +690,13 @@ pub async fn service_account_get( #[utoipa::path( post, path = "/v1/service_account", - // request_body=Json, // TODO ProtoEntry can't be serialized, so we need to do this manually + request_body=ProtoEntry, responses( DefaultApiResponse, ), security(("token_jwt" = [])), tag = "v1/service_account", + operation_id = "service_account_post", )] pub async fn service_account_post( State(state): State, @@ -700,9 +718,10 @@ pub async fn service_account_post( responses( DefaultApiResponse, ), - // request_body=ProtoEntry, // TODO: can't deal with a HashMap in the attr + request_body=ProtoEntry, security(("token_jwt" = [])), tag = "v1/service_account", + operation_id = "service_account_id_patch", )] pub async fn service_account_id_patch( State(state): State, @@ -726,11 +745,12 @@ pub async fn service_account_id_patch( get, path = "/v1/service_account/{id}", responses( - (status=200), // TODO: define response + (status=200, body=Option, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/service_account", + operation_id = "service_account_id_get", )] pub async fn service_account_id_get( State(state): State, @@ -818,11 +838,12 @@ pub async fn service_account_into_person( get, path = "/v1/service_account/{id}/_spi_token", responses( - (status=200), // TODO: define response + (status=200, body=Vec, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/service_account", + operation_id = "service_account_api_token_get", )] pub async fn service_account_api_token_get( State(state): State, @@ -843,11 +864,12 @@ pub async fn service_account_api_token_get( path = "/v1/service_account/{id}/_spi_token", request_body = ApiTokenGenerate, responses( - (status=200), // TODO: define response + (status=200, body=String, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/service_account", + operation_id = "service_account_api_token_post", )] pub async fn service_account_api_token_post( State(state): State, @@ -879,6 +901,7 @@ pub async fn service_account_api_token_post( ), security(("token_jwt" = [])), tag = "v1/service_account", + operation_id = "service_account_api_token_delete", )] pub async fn service_account_api_token_delete( State(state): State, @@ -898,12 +921,13 @@ pub async fn service_account_api_token_delete( get, path = "/v1/person/{id}/_attr/{attr}", responses( - (status=200), // TODO: define response + (status=200, body=Option>, content_type="application/json"), ApiResponseWithout200, (status = 403, description = "Authorzation refused"), ), security(("token_jwt" = [])), tag = "v1/person/attr", + operation_id = "person_id_get_attr", )] pub async fn person_id_get_attr( State(state): State, @@ -919,11 +943,12 @@ pub async fn person_id_get_attr( get, path = "/v1/service_account/{id}/_attr/{attr}", responses( - (status=200), // TODO: define response + (status=200, body=Option>, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/service_account", + operation_id = "service_account_id_get_attr", )] pub async fn service_account_id_get_attr( State(state): State, @@ -944,6 +969,7 @@ pub async fn service_account_id_get_attr( ), security(("token_jwt" = [])), tag = "v1/person/attr", + operation_id = "person_id_post_attr", )] pub async fn person_id_post_attr( State(state): State, @@ -965,6 +991,7 @@ pub async fn person_id_post_attr( ), security(("token_jwt" = [])), tag = "v1/service_account", + operation_id = "service_account_id_post_attr", )] pub async fn service_account_id_post_attr( State(state): State, @@ -985,6 +1012,7 @@ pub async fn service_account_id_post_attr( ), security(("token_jwt" = [])), tag = "v1/person/attr", + operation_id = "person_id_delete_attr", )] pub async fn person_id_delete_attr( State(state): State, @@ -1004,6 +1032,7 @@ pub async fn person_id_delete_attr( ), security(("token_jwt" = [])), tag = "v1/service_account", + operation_id = "service_account_id_delete_attr", )] pub async fn service_account_id_delete_attr( State(state): State, @@ -1023,6 +1052,7 @@ pub async fn service_account_id_delete_attr( ), security(("token_jwt" = [])), tag = "v1/person/attr", + operation_id = "person_id_put_attr", )] pub async fn person_id_put_attr( State(state): State, @@ -1044,6 +1074,7 @@ pub async fn person_id_put_attr( ), security(("token_jwt" = [])), tag = "v1/service_account", + operation_id = "service_account_id_put_attr", )] pub async fn service_account_id_put_attr( State(state): State, @@ -1062,9 +1093,10 @@ pub async fn service_account_id_put_attr( responses( DefaultApiResponse, ), - // request_body=ProtoEntry, // TODO: can't deal with a HashMap in the attr + request_body=ProtoEntry, security(("token_jwt" = [])), tag = "v1/person", + operation_id = "person_id_patch", )] pub async fn person_id_patch( State(state): State, @@ -1426,6 +1458,7 @@ pub async fn person_get_id_credential_status( ), security(("token_jwt" = [])), tag = "v1/person/ssh_pubkeys", + operation_id = "person_id_ssh_pubkeys_get", )] pub async fn person_id_ssh_pubkeys_get( State(state): State, @@ -1450,6 +1483,7 @@ pub async fn person_id_ssh_pubkeys_get( ), security(("token_jwt" = [])), tag = "v1/account", + operation_id = "account_id_ssh_pubkeys_get", )] #[deprecated] pub async fn account_id_ssh_pubkeys_get( @@ -1475,6 +1509,7 @@ pub async fn account_id_ssh_pubkeys_get( ), security(("token_jwt" = [])), tag = "v1/service_account", + operation_id = "service_account_id_ssh_pubkeys_get", )] pub async fn service_account_id_ssh_pubkeys_get( State(state): State, @@ -1498,6 +1533,7 @@ pub async fn service_account_id_ssh_pubkeys_get( ), security(("token_jwt" = [])), tag = "v1/person/ssh_pubkeys", + operation_id = "person_id_ssh_pubkeys_post", )] pub async fn person_id_ssh_pubkeys_post( State(state): State, @@ -1525,6 +1561,7 @@ pub async fn person_id_ssh_pubkeys_post( ), security(("token_jwt" = [])), tag = "v1/service_account", + operation_id = "service_account_id_ssh_pubkeys_post", )] pub async fn service_account_id_ssh_pubkeys_post( State(state): State, @@ -1552,6 +1589,7 @@ pub async fn service_account_id_ssh_pubkeys_post( ), security(("token_jwt" = [])), tag = "v1/person/ssh_pubkeys/tag", + operation_id = "person_id_ssh_pubkeys_tag_get", )] pub async fn person_id_ssh_pubkeys_tag_get( State(state): State, @@ -1575,6 +1613,7 @@ pub async fn person_id_ssh_pubkeys_tag_get( ), security(("token_jwt" = [])), tag = "v1/account", + operation_id = "account_id_ssh_pubkeys_tag_get", )] pub async fn account_id_ssh_pubkeys_tag_get( State(state): State, @@ -1599,6 +1638,7 @@ pub async fn account_id_ssh_pubkeys_tag_get( ), security(("token_jwt" = [])), tag = "v1/service_account", + operation_id = "service_account_id_ssh_pubkeys_tag_get", )] pub async fn service_account_id_ssh_pubkeys_tag_get( State(state): State, @@ -1625,6 +1665,7 @@ pub async fn service_account_id_ssh_pubkeys_tag_get( ), security(("token_jwt" = [])), tag = "v1/person/ssh_pubkeys/tag", + operation_id = "person_id_ssh_pubkeys_tag_delete", )] pub async fn person_id_ssh_pubkeys_tag_delete( State(state): State, @@ -1660,6 +1701,7 @@ pub async fn person_id_ssh_pubkeys_tag_delete( ), security(("token_jwt" = [])), tag = "v1/person", + operation_id = "service_account_id_ssh_pubkeys_tag_delete", )] pub async fn service_account_id_ssh_pubkeys_tag_delete( State(state): State, @@ -1693,6 +1735,7 @@ pub async fn service_account_id_ssh_pubkeys_tag_delete( ), security(("token_jwt" = [])), tag = "v1/person/radius", + operation_id = "person_id_radius_get" )] /// Get and return a single str pub async fn person_id_radius_get( @@ -1719,8 +1762,8 @@ pub async fn person_id_radius_get( ), security(("token_jwt" = [])), tag = "v1/person/radius", + operation_id = "person_id_radius_post" )] -// TODO: what body do we take here? pub async fn person_id_radius_post( State(state): State, Extension(kopid): Extension, @@ -1744,6 +1787,7 @@ pub async fn person_id_radius_post( ), security(("token_jwt" = [])), tag = "v1/person", + operation_id = "person_id_radius_delete" )] pub async fn person_id_radius_delete( State(state): State, @@ -1756,16 +1800,16 @@ pub async fn person_id_radius_delete( json_rest_event_delete_id_attr(state, id, attr, filter, None, kopid, client_auth_info).await } -// /v1/person/:id/_radius/_token #[utoipa::path( get, path = "/v1/person/{id}/_radius/_token", responses( - (status=200), // TODO: define response + (status=200, body=RadiusAuthToken, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/person/radius", + operation_id = "person_id_radius_token_get" )] pub async fn person_id_radius_token_get( State(state): State, @@ -1781,11 +1825,12 @@ pub async fn person_id_radius_token_get( get, path = "/v1/account/{id}/_radius/_token", responses( - (status=200), // TODO: define response + (status=200, body=RadiusAuthToken, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/account", + operation_id = "account_id_radius_token_get" )] pub async fn account_id_radius_token_get( State(state): State, @@ -1800,12 +1845,13 @@ pub async fn account_id_radius_token_get( post, path = "/v1/account/{id}/_radius/_token", responses( - (status=200), // TODO: define response + (status=200, body=RadiusAuthToken, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/person", -)] // TODO: what body do we expect here? + operation_id = "account_id_radius_token_post" +)] pub async fn account_id_radius_token_post( State(state): State, Path(id): Path, @@ -1912,12 +1958,13 @@ pub async fn account_id_unix_post( get,post, path = "/v1/account/{id}/_unix/_token", responses( - (status=200), // TODO: define response + (status=200, body=UnixUserToken, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/account", -)] // TODO: what body do we expect here? + operation_id = "account_id_unix_token" +)] #[instrument(level = "INFO", skip_all)] pub async fn account_id_unix_token( State(state): State, @@ -1953,12 +2000,13 @@ pub async fn account_id_unix_token( post, path = "/v1/account/{id}/_unix/_auth", responses( - (status=200), // TODO: define response + (status=200, body=Option, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/account", -)] // TODO: what body do we expect here? + operation_id = "account_id_unix_auth_post" +)] pub async fn account_id_unix_auth_post( State(state): State, Extension(kopid): Extension, @@ -1983,7 +2031,8 @@ pub async fn account_id_unix_auth_post( ), security(("token_jwt" = [])), tag = "v1/person/unix", -)] // TODO: what body do we expect here? + operation_id = "person_id_unix_credential_put" +)] pub async fn person_id_unix_credential_put( State(state): State, Extension(kopid): Extension, @@ -2007,6 +2056,7 @@ pub async fn person_id_unix_credential_put( ), security(("token_jwt" = [])), tag = "v1/person/unix", + operation_id = "person_id_unix_credential_delete" )] pub async fn person_id_unix_credential_delete( State(state): State, @@ -2033,12 +2083,13 @@ pub async fn person_id_unix_credential_delete( post, path = "/v1/person/{id}/_identify/_user", responses( - (status=200), // TODO: define response + (status=200, body=IdentifyUserResponse, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/person", -)] // TODO: what body do we expect here? + operation_id = "person_identify_user_post" +)] pub async fn person_identify_user_post( State(state): State, Extension(kopid): Extension, @@ -2058,11 +2109,12 @@ pub async fn person_identify_user_post( get, path = "/v1/group", responses( - (status=200), // TODO: define response + (status=200,body=Vec, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/group", + operation_id = "group_get", )] /// Returns all groups visible to the user pub async fn group_get( @@ -2085,7 +2137,8 @@ pub async fn group_get( ), security(("token_jwt" = [])), tag = "v1/group", -)] // TODO: post body + operation_id = "group_post", +)] pub async fn group_post( State(state): State, Extension(kopid): Extension, @@ -2100,11 +2153,12 @@ pub async fn group_post( get, path = "/v1/group/{id}", responses( - (status=200), // TODO: define response + (status=200, body=Option, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/group", + operation_id = "group_id_get", )] pub async fn group_id_get( State(state): State, @@ -2124,6 +2178,7 @@ pub async fn group_id_get( ), security(("token_jwt" = [])), tag = "v1/group", + operation_id = "group_id_delete", )] pub async fn group_id_delete( State(state): State, @@ -2139,11 +2194,12 @@ pub async fn group_id_delete( get, path = "/v1/group/{id}/_attr/{attr}", responses( - (status=200), // TODO: define response + (status=200, body=Vec, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/group/attr", + operation_id = "group_id_attr_get", )] pub async fn group_id_attr_get( State(state): State, @@ -2164,6 +2220,7 @@ pub async fn group_id_attr_get( ), security(("token_jwt" = [])), tag = "v1/group/attr", + operation_id = "group_id_attr_post", )] pub async fn group_id_attr_post( Path((id, attr)): Path<(String, String)>, @@ -2185,6 +2242,7 @@ pub async fn group_id_attr_post( ), security(("token_jwt" = [])), tag = "v1/group/attr", + operation_id = "group_id_attr_delete", )] pub async fn group_id_attr_delete( Path((id, attr)): Path<(String, String)>, @@ -2207,6 +2265,7 @@ pub async fn group_id_attr_delete( ), security(("token_jwt" = [])), tag = "v1/group/attr", + operation_id = "group_id_attr_put", )] pub async fn group_id_attr_put( Path((id, attr)): Path<(String, String)>, @@ -2228,6 +2287,7 @@ pub async fn group_id_attr_put( ), security(("token_jwt" = [])), tag = "v1/group/unix", + operation_id = "group_id_unix_put", )] pub async fn group_id_unix_post( State(state): State, @@ -2248,11 +2308,12 @@ pub async fn group_id_unix_post( get, path = "/v1/group/{id}/_unix/_token", responses( - (status=200), // TODO: define response + (status=200, body=UnixGroupToken, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/group/unix", + operation_id = "group_id_unix_token_get", )] pub async fn group_id_unix_token_get( State(state): State, @@ -2272,11 +2333,12 @@ pub async fn group_id_unix_token_get( get, path = "/v1/domain", responses( - (status=200), // TODO: define response + (status=200, body=Vec, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/domain", + operation_id = "domain_get", )] pub async fn domain_get( State(state): State, @@ -2291,11 +2353,12 @@ pub async fn domain_get( get, path = "/v1/domain/_attr/{attr}", responses( - (status=200), // TODO: define response + (status=200, body=Option>, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/domain", + operation_id = "domain_attr_get", )] pub async fn domain_attr_get( State(state): State, @@ -2324,6 +2387,7 @@ pub async fn domain_attr_get( ), security(("token_jwt" = [])), tag = "v1/domain", + operation_id = "domain_attr_put", )] pub async fn domain_attr_put( State(state): State, @@ -2354,6 +2418,7 @@ pub async fn domain_attr_put( ), security(("token_jwt" = [])), tag = "v1/domain", + operation_id = "domain_attr_delete", )] pub async fn domain_attr_delete( State(state): State, @@ -2379,11 +2444,12 @@ pub async fn domain_attr_delete( get, path = "/v1/system", responses( - (status=200), // TODO: define response + (status=200,body=Vec, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/system", + operation_id = "system_get", )] pub async fn system_get( State(state): State, @@ -2401,11 +2467,12 @@ pub async fn system_get( get, path = "/v1/system/_attr/{attr}", responses( - (status=200), // TODO: define response + (status=200, body=Option>, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/system", + operation_id = "system_attr_get", )] pub async fn system_attr_get( State(state): State, @@ -2434,6 +2501,7 @@ pub async fn system_attr_get( ), security(("token_jwt" = [])), tag = "v1/system", + operation_id = "system_attr_post", )] pub async fn system_attr_post( State(state): State, @@ -2464,6 +2532,7 @@ pub async fn system_attr_post( ), security(("token_jwt" = [])), tag = "v1/system", + operation_id = "system_attr_delete", )] pub async fn system_attr_delete( State(state): State, @@ -2494,6 +2563,7 @@ pub async fn system_attr_delete( ), security(("token_jwt" = [])), tag = "v1/system", + operation_id = "system_attr_put", )] pub async fn system_attr_put( State(state): State, @@ -2519,11 +2589,12 @@ pub async fn system_attr_put( post, path = "/v1/recycle_bin", responses( - (status=200), // TODO: define response + (status=200,body=Vec, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/recycle_bin", + operation_id="recycle_bin_get", )] pub async fn recycle_bin_get( State(state): State, @@ -2544,11 +2615,12 @@ pub async fn recycle_bin_get( get, path = "/v1/recycle_bin/{id}", responses( - (status=200), // TODO: define response + (status=200, body=Option, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/recycle_bin", + operation_id = "recycle_bin_id_get", )] pub async fn recycle_bin_id_get( State(state): State, @@ -2576,6 +2648,7 @@ pub async fn recycle_bin_id_get( ), security(("token_jwt" = [])), tag = "v1/recycle_bin", + operation_id = "recycle_bin_revive_id_post", )] pub async fn recycle_bin_revive_id_post( State(state): State, @@ -2596,11 +2669,12 @@ pub async fn recycle_bin_revive_id_post( get, path = "/v1/self/_applinks", responses( - (status=200), // TODO: define response + (status=200, body=Vec, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/self", + operation_id = "self_applinks_get", )] /// Returns your OAuth2 app links for the Web UI pub async fn applinks_get( @@ -2620,12 +2694,13 @@ pub async fn applinks_get( post, path = "/v1/reauth", responses( - (status=200), // TODO: define response + (status=200, content_type="application/json"), // TODO: define response ApiResponseWithout200, ), request_body = AuthIssueSession, security(("token_jwt" = [])), tag = "v1/auth", + operation_id = "reauth_post", )] // TODO: post body stuff pub async fn reauth( State(state): State, @@ -2646,12 +2721,13 @@ pub async fn reauth( post, path = "/v1/auth", responses( - (status=200), // TODO: define response + (status=200, content_type="application/json"), // TODO: define response ApiResponseWithout200, ), request_body = AuthRequest, security(("token_jwt" = [])), tag = "v1/auth", + operation_id = "auth_post", )] pub async fn auth( State(state): State, @@ -2775,6 +2851,7 @@ fn auth_session_state_management( ), security(("token_jwt" = [])), tag = "v1/auth", + operation_id = "auth_valid", )] pub async fn auth_valid( State(state): State, @@ -2793,10 +2870,11 @@ pub async fn auth_valid( get, path = "/v1/debug/ipinfo", responses( - (status = 200, description = "Ok"), + (status = 200, description = "Ok", body=Vec, content_type="application/json"), ), security(("token_jwt" = [])), tag = "v1/debug", + operation_id = "debug_ipinfo", )] pub async fn debug_ipinfo( State(_state): State, diff --git a/server/core/src/https/v1_oauth2.rs b/server/core/src/https/v1_oauth2.rs index 5cf44f864..b221b0169 100644 --- a/server/core/src/https/v1_oauth2.rs +++ b/server/core/src/https/v1_oauth2.rs @@ -23,6 +23,7 @@ use sketching::admin_error; ), security(("token_jwt" = [])), tag = "v1/oauth2", + operation_id = "oauth2_get" )] /// Lists all the OAuth2 Resource Servers pub(crate) async fn oauth2_get( @@ -46,6 +47,7 @@ pub(crate) async fn oauth2_get( ), security(("token_jwt" = [])), tag = "v1/oauth2", + operation_id = "oauth2_basic_post" )] // TODO: what does this actually do? :D pub(crate) async fn oauth2_basic_post( @@ -72,6 +74,7 @@ pub(crate) async fn oauth2_basic_post( ), security(("token_jwt" = [])), tag = "v1/oauth2", + operation_id = "oauth2_public_post" )] // TODO: what does this actually do? :D pub(crate) async fn oauth2_public_post( @@ -93,11 +96,12 @@ pub(crate) async fn oauth2_public_post( get, path = "/v1/oauth2/{rs_name}", responses( - (status = 200, /* TODO response=Option*/), + (status = 200, body=Option, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/oauth2", + operation_id = "oauth2_id_get" )] /// Get the details of a given OAuth2 Resource Server. pub(crate) async fn oauth2_id_get( @@ -125,6 +129,7 @@ pub(crate) async fn oauth2_id_get( ), security(("token_jwt" = [])), tag = "v1/oauth2", + operation_id = "oauth2_id_get_basic_secret" )] /// Get the basic secret for a given OAuth2 Resource Server. This is used for authentication. #[instrument(level = "info", skip(state))] @@ -152,6 +157,7 @@ pub(crate) async fn oauth2_id_get_basic_secret( ), security(("token_jwt" = [])), tag = "v1/oauth2", + operation_id = "oauth2_id_patch" )] /// Modify an OAuth2 Resource Server pub(crate) async fn oauth2_id_patch( @@ -180,6 +186,7 @@ pub(crate) async fn oauth2_id_patch( ), security(("token_jwt" = [])), tag = "v1/oauth2", + operation_id = "oauth2_id_scopemap_post" )] /// Modify the scope map for a given OAuth2 Resource Server pub(crate) async fn oauth2_id_scopemap_post( @@ -206,6 +213,7 @@ pub(crate) async fn oauth2_id_scopemap_post( ), security(("token_jwt" = [])), tag = "v1/oauth2", + operation_id = "oauth2_id_scopemap_delete" )] // Delete a scope map for a given OAuth2 Resource Server pub(crate) async fn oauth2_id_scopemap_delete( @@ -232,6 +240,7 @@ pub(crate) async fn oauth2_id_scopemap_delete( ), security(("token_jwt" = [])), tag = "v1/oauth2", + operation_id = "oauth2_id_claimmap_post" )] /// Modify the claim map for a given OAuth2 Resource Server pub(crate) async fn oauth2_id_claimmap_post( @@ -266,6 +275,7 @@ pub(crate) async fn oauth2_id_claimmap_post( ), security(("token_jwt" = [])), tag = "v1/oauth2", + operation_id = "oauth2_id_claimmap_join_post" )] /// Modify the claim map join strategy for a given OAuth2 Resource Server pub(crate) async fn oauth2_id_claimmap_join_post( @@ -298,6 +308,7 @@ pub(crate) async fn oauth2_id_claimmap_join_post( ), security(("token_jwt" = [])), tag = "v1/oauth2", + operation_id = "oauth2_id_claimmap_delete" )] // Delete a claim map for a given OAuth2 Resource Server pub(crate) async fn oauth2_id_claimmap_delete( @@ -323,6 +334,7 @@ pub(crate) async fn oauth2_id_claimmap_delete( ), security(("token_jwt" = [])), tag = "v1/oauth2", + operation_id = "oauth2_id_sup_scopemap_post" )] /// Create a supplemental scope map for a given OAuth2 Resource Server pub(crate) async fn oauth2_id_sup_scopemap_post( @@ -349,6 +361,7 @@ pub(crate) async fn oauth2_id_sup_scopemap_post( ), security(("token_jwt" = [])), tag = "v1/oauth2", + operation_id = "oauth2_id_sup_scopemap_delete" )] // Delete a supplemental scope map configuration. pub(crate) async fn oauth2_id_sup_scopemap_delete( @@ -375,6 +388,7 @@ pub(crate) async fn oauth2_id_sup_scopemap_delete( ), security(("token_jwt" = [])), tag = "v1/oauth2", + operation_id = "oauth2_id_delete" )] /// Delete an OAuth2 Resource Server pub(crate) async fn oauth2_id_delete( @@ -400,6 +414,7 @@ pub(crate) async fn oauth2_id_delete( ), security(("token_jwt" = [])), tag = "v1/oauth2", + operation_id = "oauth2_id_image_delete" )] // API endpoint for deleting the image associated with an OAuth2 Resource Server. pub(crate) async fn oauth2_id_image_delete( @@ -423,6 +438,7 @@ pub(crate) async fn oauth2_id_image_delete( ), security(("token_jwt" = [])), tag = "v1/oauth2", + operation_id = "oauth2_id_image_post" )] /// API endpoint for creating/replacing the image associated with an OAuth2 Resource Server. /// diff --git a/server/core/src/https/v1_scim.rs b/server/core/src/https/v1_scim.rs index c92e61e1e..2b932aa5b 100644 --- a/server/core/src/https/v1_scim.rs +++ b/server/core/src/https/v1_scim.rs @@ -25,6 +25,7 @@ use kanidmd_lib::prelude::*; ), security(("token_jwt" = [])), tag = "v1/sync_account", + operation_id = "sync_account_get" )] /// Get all? the sync accounts. pub async fn sync_account_get( @@ -45,6 +46,7 @@ pub async fn sync_account_get( ), security(("token_jwt" = [])), tag = "v1/sync_account", + operation_id = "sync_account_post" )] pub async fn sync_account_post( State(state): State, @@ -86,6 +88,7 @@ pub async fn sync_account_id_get( ), security(("token_jwt" = [])), tag = "v1/sync_account", + operation_id = "sync_account_id_patch" )] /// Modify a sync account in-place pub async fn sync_account_id_patch( @@ -114,8 +117,8 @@ pub async fn sync_account_id_patch( ), security(("token_jwt" = [])), tag = "v1/sync_account", + operation_id = "sync_account_id_finalise_get" )] -// TODO: why is this a get and not a post? pub async fn sync_account_id_finalise_get( State(state): State, Path(id): Path, @@ -138,8 +141,8 @@ pub async fn sync_account_id_finalise_get( ), security(("token_jwt" = [])), tag = "v1/sync_account", + operation_id = "sync_account_id_terminate_get" )] -// TODO: why is this a get if it's a terminate? pub async fn sync_account_id_terminate_get( State(state): State, Path(id): Path, @@ -158,11 +161,12 @@ pub async fn sync_account_id_terminate_get( post, path = "/v1/sync_account/{id}/_sync_token", responses( - (status = 200), // TODO: response content + (status = 200, body=String, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/sync_account", + operation_id = "sync_account_token_post" )] pub async fn sync_account_token_post( State(state): State, @@ -187,6 +191,7 @@ pub async fn sync_account_token_post( ), security(("token_jwt" = [])), tag = "v1/sync_account", + operation_id = "sync_account_token_delete" )] pub async fn sync_account_token_delete( State(state): State, @@ -211,6 +216,7 @@ pub async fn sync_account_token_delete( ), security(("token_jwt" = [])), tag = "scim", + operation_id = "scim_sync_post" )] async fn scim_sync_post( State(state): State, @@ -230,11 +236,12 @@ async fn scim_sync_post( get, path = "/scim/v1/Sync", responses( - (status = 200), // TODO: response content + (status = 200, content_type="application/json", body=ScimSyncState), // TODO: response content ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "scim", + operation_id = "scim_sync_get" )] async fn scim_sync_get( State(state): State, @@ -255,11 +262,12 @@ async fn scim_sync_get( get, path = "/v1/sync_account/{id}/_attr/{attr}", responses( - (status = 200), // TODO: response content + (status = 200, body=Option>, content_type="application/json"), ApiResponseWithout200, ), security(("token_jwt" = [])), tag = "v1/sync_account", + operation_id = "sync_account_id_attr_get" )] pub async fn sync_account_id_attr_get( State(state): State, @@ -280,6 +288,7 @@ pub async fn sync_account_id_attr_get( ), security(("token_jwt" = [])), tag = "v1/sync_account", + operation_id = "sync_account_id_attr_put" )] pub async fn sync_account_id_attr_put( State(state): State,