From 3a9984330fa1695f55c5a0c98f2fe3359d20dd09 Mon Sep 17 00:00:00 2001 From: marcelbuesing Date: Wed, 31 Oct 2018 16:40:43 +0100 Subject: [PATCH] Migrate to openapi-generator --- Cargo.toml | 2 +- vault-api/.cargo/config | 2 + ...degen-ignore => .openapi-generator-ignore} | 0 vault-api/.openapi-generator/FILES | 33 + vault-api/.openapi-generator/VERSION | 1 + vault-api/Cargo.toml | 94 +- vault-api/Makefile | 15 +- vault-api/api/{swagger.yaml => openapi.yaml} | 0 vault-api/docs/AuthCertLoginParameters.md | 2 +- vault-api/docs/AuthResponse.md | 10 +- vault-api/docs/AuthResponseAllOf.md | 10 + vault-api/docs/AuthResponseAllOfAuth.md | 14 + vault-api/docs/CertificateResponse.md | 10 +- vault-api/docs/CertificateResponseAllOf.md | 10 + .../docs/CertificateResponseAllOfData.md | 10 + vault-api/docs/CommonResponse.md | 8 +- vault-api/docs/CreateTokenParameters.md | 20 +- .../docs/GenerateCertificateParameters.md | 12 +- vault-api/docs/GenerateCertificateResponse.md | 10 +- .../docs/GenerateCertificateResponseAllOf.md | 10 + .../GenerateCertificateResponseAllOfData.md | 15 + vault-api/docs/RenewSelfParameters.md | 2 +- vault-api/docs/RevokeLeaseParameters.md | 2 +- vault-api/docs/leases_api.md | 37 + vault-api/docs/pki_backend_api.md | 68 + vault-api/docs/token_backend_api.md | 130 + vault-api/examples/client.rs | 4 + vault-api/examples/client/main.rs | 145 ++ vault-api/examples/server/main.rs | 25 + vault-api/examples/server/server.rs | 199 ++ vault-api/src/apis/client.rs | 38 - vault-api/src/apis/configuration.rs | 25 - vault-api/src/apis/leases_api.rs | 71 - vault-api/src/apis/mod.rs | 32 - vault-api/src/apis/pki_backend_api.rs | 102 - vault-api/src/apis/token_backend_api.rs | 178 -- vault-api/src/base64_format.rs | 24 - vault-api/src/client.rs | 617 ----- vault-api/src/client/mod.rs | 1041 ++++++++ vault-api/src/context.rs | 113 + vault-api/src/header.rs | 180 ++ vault-api/src/lib.rs | 270 +- vault-api/src/mimetypes.rs | 57 - vault-api/src/models.rs | 2230 +++++++++++++++-- vault-api/src/server.rs | 605 ----- vault-api/src/server/mod.rs | 904 +++++++ 46 files changed, 5278 insertions(+), 2109 deletions(-) rename vault-api/{.swagger-codegen-ignore => .openapi-generator-ignore} (100%) create mode 100644 vault-api/.openapi-generator/FILES create mode 100644 vault-api/.openapi-generator/VERSION rename vault-api/api/{swagger.yaml => openapi.yaml} (100%) create mode 100644 vault-api/docs/AuthResponseAllOf.md create mode 100644 vault-api/docs/AuthResponseAllOfAuth.md create mode 100644 vault-api/docs/CertificateResponseAllOf.md create mode 100644 vault-api/docs/CertificateResponseAllOfData.md create mode 100644 vault-api/docs/GenerateCertificateResponseAllOf.md create mode 100644 vault-api/docs/GenerateCertificateResponseAllOfData.md create mode 100644 vault-api/docs/leases_api.md create mode 100644 vault-api/docs/pki_backend_api.md create mode 100644 vault-api/docs/token_backend_api.md create mode 100644 vault-api/examples/client/main.rs create mode 100644 vault-api/examples/server/main.rs create mode 100644 vault-api/examples/server/server.rs delete mode 100644 vault-api/src/apis/client.rs delete mode 100644 vault-api/src/apis/configuration.rs delete mode 100644 vault-api/src/apis/leases_api.rs delete mode 100644 vault-api/src/apis/mod.rs delete mode 100644 vault-api/src/apis/pki_backend_api.rs delete mode 100644 vault-api/src/apis/token_backend_api.rs delete mode 100644 vault-api/src/base64_format.rs delete mode 100644 vault-api/src/client.rs create mode 100644 vault-api/src/client/mod.rs create mode 100644 vault-api/src/context.rs create mode 100644 vault-api/src/header.rs delete mode 100644 vault-api/src/mimetypes.rs delete mode 100644 vault-api/src/server.rs create mode 100644 vault-api/src/server/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 5a1a0c0..051f7d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,4 +30,4 @@ vault-api = "0.7.2" [dev-dependencies] tempfile = "3.0.5" -[workspace] +[workspace] \ No newline at end of file diff --git a/vault-api/.cargo/config b/vault-api/.cargo/config index 23056bb..b8acc9c 100644 --- a/vault-api/.cargo/config +++ b/vault-api/.cargo/config @@ -13,4 +13,6 @@ rustflags = [ "-W", "unused_extern_crates", # extern crates that are never used "-W", "unused_import_braces", # unnecessary braces around an imported item + + "-D", "warnings", # all warnings should be denied ] diff --git a/vault-api/.swagger-codegen-ignore b/vault-api/.openapi-generator-ignore similarity index 100% rename from vault-api/.swagger-codegen-ignore rename to vault-api/.openapi-generator-ignore diff --git a/vault-api/.openapi-generator/FILES b/vault-api/.openapi-generator/FILES new file mode 100644 index 0000000..9c61281 --- /dev/null +++ b/vault-api/.openapi-generator/FILES @@ -0,0 +1,33 @@ +.cargo/config +.gitignore +Cargo.toml +docs/AuthCertLoginParameters.md +docs/AuthResponse.md +docs/AuthResponseAllOf.md +docs/AuthResponseAllOfAuth.md +docs/CertificateResponse.md +docs/CertificateResponseAllOf.md +docs/CertificateResponseAllOfData.md +docs/CommonResponse.md +docs/CreateTokenParameters.md +docs/GenerateCertificateParameters.md +docs/GenerateCertificateResponse.md +docs/GenerateCertificateResponseAllOf.md +docs/GenerateCertificateResponseAllOfData.md +docs/RenewSelfParameters.md +docs/RevokeLeaseParameters.md +docs/leases_api.md +docs/pki_backend_api.md +docs/token_backend_api.md +examples/ca.pem +examples/client/main.rs +examples/server-chain.pem +examples/server-key.pem +examples/server/main.rs +examples/server/server.rs +src/client/mod.rs +src/context.rs +src/header.rs +src/lib.rs +src/models.rs +src/server/mod.rs diff --git a/vault-api/.openapi-generator/VERSION b/vault-api/.openapi-generator/VERSION new file mode 100644 index 0000000..d99e716 --- /dev/null +++ b/vault-api/.openapi-generator/VERSION @@ -0,0 +1 @@ +5.0.0-SNAPSHOT \ No newline at end of file diff --git a/vault-api/Cargo.toml b/vault-api/Cargo.toml index c73cdfb..c706da1 100644 --- a/vault-api/Cargo.toml +++ b/vault-api/Cargo.toml @@ -1,43 +1,81 @@ [package] name = "vault-api" -version = "0.7.2" +version = "1.0.0" authors = ["Metaswitch Networks Ltd"] license = "Apache-2.0/MIT" description = "Vault API library" +edition = "2018" [features] default = ["client", "server"] -client = ["serde_json", "serde_ignored", "hyper", "hyper-openssl", "uuid"] -server = ["serde_json", "serde_ignored", "hyper", "iron", "router", "bodyparser", "urlencoded", "uuid"] +client = [ + "hyper", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url" +] +server = [ + "serde_ignored", "hyper", "regex", "percent-encoding", "url", "lazy_static" +] +conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"] + +[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies] +native-tls = { version = "0.2", optional = true } +hyper-tls = { version = "0.4", optional = true } + +[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies] +hyper-openssl = { version = "0.8", optional = true } +openssl = {version = "0.10", optional = true } [dependencies] -# Required by example server. -# +# Common +async-trait = "0.1.24" chrono = { version = "0.4", features = ["serde"] } -futures = "0.1" -hyper = {version = "0.10", optional = true} -hyper-openssl = {version = "0.2", optional = true } -iron = {version = "0.5", optional = true} -swagger = "0.7" - -# Not required by example server. -# -bodyparser = {version = "0.7", optional = true} -url = "1.5" -lazy_static = "0.2" -log = "0.3.0" -multipart = {version = "0.13", optional = true} -router = {version = "0.5", optional = true} -serde = "1.0" -serde_derive = "1.0" -serde_ignored = {version = "0.0.4", optional = true} -serde_json = {version = "1.0", optional = true} -urlencoded = {version = "0.5", optional = true} -uuid = {version = "0.5", optional = true, features = ["serde", "v4"]} -# ToDo: this should be updated to point at the official crate once -# https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream +futures = "0.3" +swagger = "5.0.0-alpha-1" +log = "0.4.0" +mime = "0.3" + +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" + +# Crates included if required by the API definition + +# Common between server and client features +hyper = {version = "0.13", optional = true} +serde_ignored = {version = "0.1.1", optional = true} +url = {version = "2.1", optional = true} + +# Client-specific +# Server, and client callback-specific +lazy_static = { version = "1.4", optional = true } +percent-encoding = {version = "2.1.0", optional = true} +regex = {version = "1.3", optional = true} + +# Conversion +frunk = { version = "0.3.0", optional = true } +frunk_derives = { version = "0.3.0", optional = true } +frunk_core = { version = "0.3.0", optional = true } +frunk-enum-derive = { version = "0.2.0", optional = true } +frunk-enum-core = { version = "0.2.0", optional = true } [dev-dependencies] clap = "2.25" -error-chain = "0.11" +env_logger = "0.7" +tokio = { version = "0.2", features = ["rt-threaded", "macros", "stream"] } +native-tls = "0.2" +tokio-tls = "0.3" + +[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies] +tokio-openssl = "0.4" +openssl = "0.10" + +[[example]] +name = "client" +path = "./examples/client/main.rs" +required-features = ["client"] + +[[example]] +name = "server" +path = "./examples/server/main.rs" +required-features = ["server"] + +[workspace] \ No newline at end of file diff --git a/vault-api/Makefile b/vault-api/Makefile index 1937142..498ec97 100644 --- a/vault-api/Makefile +++ b/vault-api/Makefile @@ -1,5 +1,5 @@ PACKAGE_NAME=vault-api -SWAGGER_CODEGEN_IMAGE := jimschubert/swagger-codegen-cli +OPENAPI_GENERATOR_IMAGE := openapitools/openapi-generator-cli .FORCE: .PHONY: codegen @@ -8,10 +8,11 @@ clean: -rm -r output Cargo.toml: .FORCE - @echo "Running swagger-codegen for $*..." - @docker pull ${SWAGGER_CODEGEN_IMAGE} - @docker run --rm -u $$(id -u $$USER) -v=${CURDIR}:/src ${SWAGGER_CODEGEN_IMAGE} generate \ - -i /src/api/swagger.yaml \ - -l rust-server \ + @echo "Running openapi-generator for $*..." + @docker pull ${OPENAPI_GENERATOR_IMAGE} + @docker run --rm -u $$(id -u $$USER) -v=${CURDIR}:/src ${OPENAPI_GENERATOR_IMAGE} generate \ + -i /src/api/openapi.yaml \ + -g rust-server \ -o /src \ - --additional-properties packageName=${PACKAGE_NAME} + --additional-properties packageName=${PACKAGE_NAME} \ + --skip-validate-spec diff --git a/vault-api/api/swagger.yaml b/vault-api/api/openapi.yaml similarity index 100% rename from vault-api/api/swagger.yaml rename to vault-api/api/openapi.yaml diff --git a/vault-api/docs/AuthCertLoginParameters.md b/vault-api/docs/AuthCertLoginParameters.md index 1066001..68f4ae8 100644 --- a/vault-api/docs/AuthCertLoginParameters.md +++ b/vault-api/docs/AuthCertLoginParameters.md @@ -3,7 +3,7 @@ ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**name** | **String** | | [optional] [default to null] +**name** | **String** | | [optional] [default to None] [[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/vault-api/docs/AuthResponse.md b/vault-api/docs/AuthResponse.md index c3693eb..4c0ae7d 100644 --- a/vault-api/docs/AuthResponse.md +++ b/vault-api/docs/AuthResponse.md @@ -3,11 +3,11 @@ ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**request_id** | **String** | | [default to null] -**lease_duration** | **i32** | | [default to null] -**lease_id** | **String** | | [default to null] -**renewable** | **bool** | | [default to null] -**auth** | [***::models::AuthResponseAuth**](AuthResponse_auth.md) | | [optional] [default to null] +**request_id** | **String** | | +**lease_duration** | **isize** | | +**lease_id** | **String** | | +**renewable** | **bool** | | +**auth** | [***models::AuthResponseAllOfAuth**](AuthResponse_allOf_auth.md) | | [[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/vault-api/docs/AuthResponseAllOf.md b/vault-api/docs/AuthResponseAllOf.md new file mode 100644 index 0000000..f03708c --- /dev/null +++ b/vault-api/docs/AuthResponseAllOf.md @@ -0,0 +1,10 @@ +# AuthResponseAllOf + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**auth** | [***models::AuthResponseAllOfAuth**](AuthResponse_allOf_auth.md) | | + +[[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/vault-api/docs/AuthResponseAllOfAuth.md b/vault-api/docs/AuthResponseAllOfAuth.md new file mode 100644 index 0000000..10e3f27 --- /dev/null +++ b/vault-api/docs/AuthResponseAllOfAuth.md @@ -0,0 +1,14 @@ +# AuthResponseAllOfAuth + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**renewable** | **bool** | | +**lease_duration** | **isize** | | +**policies** | **Vec** | | +**accessor** | **String** | | +**client_token** | **String** | | + +[[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/vault-api/docs/CertificateResponse.md b/vault-api/docs/CertificateResponse.md index 54140f8..c01fb8b 100644 --- a/vault-api/docs/CertificateResponse.md +++ b/vault-api/docs/CertificateResponse.md @@ -3,11 +3,11 @@ ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**request_id** | **String** | | [default to null] -**lease_duration** | **i32** | | [default to null] -**lease_id** | **String** | | [default to null] -**renewable** | **bool** | | [default to null] -**data** | [***::models::CertificateResponseData**](CertificateResponse_data.md) | | [optional] [default to null] +**request_id** | **String** | | +**lease_duration** | **isize** | | +**lease_id** | **String** | | +**renewable** | **bool** | | +**data** | [***models::CertificateResponseAllOfData**](CertificateResponse_allOf_data.md) | | [[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/vault-api/docs/CertificateResponseAllOf.md b/vault-api/docs/CertificateResponseAllOf.md new file mode 100644 index 0000000..a40e934 --- /dev/null +++ b/vault-api/docs/CertificateResponseAllOf.md @@ -0,0 +1,10 @@ +# CertificateResponseAllOf + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**data** | [***models::CertificateResponseAllOfData**](CertificateResponse_allOf_data.md) | | + +[[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/vault-api/docs/CertificateResponseAllOfData.md b/vault-api/docs/CertificateResponseAllOfData.md new file mode 100644 index 0000000..929a7dc --- /dev/null +++ b/vault-api/docs/CertificateResponseAllOfData.md @@ -0,0 +1,10 @@ +# CertificateResponseAllOfData + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**certificate** | **String** | | + +[[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/vault-api/docs/CommonResponse.md b/vault-api/docs/CommonResponse.md index 5c53bba..722acb5 100644 --- a/vault-api/docs/CommonResponse.md +++ b/vault-api/docs/CommonResponse.md @@ -3,10 +3,10 @@ ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**request_id** | **String** | | [default to null] -**lease_duration** | **i32** | | [default to null] -**lease_id** | **String** | | [default to null] -**renewable** | **bool** | | [default to null] +**request_id** | **String** | | +**lease_duration** | **isize** | | +**lease_id** | **String** | | +**renewable** | **bool** | | [[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/vault-api/docs/CreateTokenParameters.md b/vault-api/docs/CreateTokenParameters.md index 1cbe840..025fc70 100644 --- a/vault-api/docs/CreateTokenParameters.md +++ b/vault-api/docs/CreateTokenParameters.md @@ -3,16 +3,16 @@ ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**id** | **String** | | [optional] [default to null] -**policies** | **Vec** | | [optional] [default to null] -**no_parent** | **bool** | | [optional] [default to null] -**no_default_policy** | **bool** | | [optional] [default to null] -**renewable** | **bool** | | [optional] [default to null] -**ttl** | **String** | | [optional] [default to null] -**explicit_max_ttl** | **bool** | | [optional] [default to null] -**display_name** | **String** | | [optional] [default to null] -**num_uses** | **i32** | | [optional] [default to null] -**period** | **String** | | [optional] [default to null] +**id** | **String** | | [optional] [default to None] +**policies** | **Vec** | | [optional] [default to None] +**no_parent** | **bool** | | [optional] [default to None] +**no_default_policy** | **bool** | | [optional] [default to None] +**renewable** | **bool** | | [optional] [default to None] +**ttl** | **String** | | [optional] [default to None] +**explicit_max_ttl** | **bool** | | [optional] [default to None] +**display_name** | **String** | | [optional] [default to None] +**num_uses** | **isize** | | [optional] [default to None] +**period** | **String** | | [optional] [default to None] [[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/vault-api/docs/GenerateCertificateParameters.md b/vault-api/docs/GenerateCertificateParameters.md index 990fddd..67e0787 100644 --- a/vault-api/docs/GenerateCertificateParameters.md +++ b/vault-api/docs/GenerateCertificateParameters.md @@ -3,12 +3,12 @@ ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**common_name** | **String** | | [default to null] -**alt_names** | **String** | | [optional] [default to null] -**ip_sans** | **String** | | [optional] [default to null] -**ttl** | **String** | | [optional] [default to null] -**format** | **String** | | [optional] [default to null] -**exclude_cn_from_sans** | **bool** | | [optional] [default to null] +**common_name** | **String** | | +**alt_names** | **String** | | [optional] [default to None] +**ip_sans** | **String** | | [optional] [default to None] +**ttl** | **String** | | [optional] [default to None] +**format** | **String** | | [optional] [default to None] +**exclude_cn_from_sans** | **bool** | | [optional] [default to Some(false)] [[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/vault-api/docs/GenerateCertificateResponse.md b/vault-api/docs/GenerateCertificateResponse.md index cf0d3f4..4728a4a 100644 --- a/vault-api/docs/GenerateCertificateResponse.md +++ b/vault-api/docs/GenerateCertificateResponse.md @@ -3,11 +3,11 @@ ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**request_id** | **String** | | [default to null] -**lease_duration** | **i32** | | [default to null] -**lease_id** | **String** | | [default to null] -**renewable** | **bool** | | [default to null] -**data** | [***::models::GenerateCertificateResponseData**](GenerateCertificateResponse_data.md) | | [optional] [default to null] +**request_id** | **String** | | +**lease_duration** | **isize** | | +**lease_id** | **String** | | +**renewable** | **bool** | | +**data** | [***models::GenerateCertificateResponseAllOfData**](GenerateCertificateResponse_allOf_data.md) | | [[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/vault-api/docs/GenerateCertificateResponseAllOf.md b/vault-api/docs/GenerateCertificateResponseAllOf.md new file mode 100644 index 0000000..b956198 --- /dev/null +++ b/vault-api/docs/GenerateCertificateResponseAllOf.md @@ -0,0 +1,10 @@ +# GenerateCertificateResponseAllOf + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**data** | [***models::GenerateCertificateResponseAllOfData**](GenerateCertificateResponse_allOf_data.md) | | + +[[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/vault-api/docs/GenerateCertificateResponseAllOfData.md b/vault-api/docs/GenerateCertificateResponseAllOfData.md new file mode 100644 index 0000000..617114e --- /dev/null +++ b/vault-api/docs/GenerateCertificateResponseAllOfData.md @@ -0,0 +1,15 @@ +# GenerateCertificateResponseAllOfData + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**certificate** | **String** | | +**issuing_ca** | **String** | | +**ca_chain** | **Vec** | | [optional] [default to None] +**private_key** | **String** | | +**private_key_type** | **String** | | +**serial_number** | **String** | | + +[[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/vault-api/docs/RenewSelfParameters.md b/vault-api/docs/RenewSelfParameters.md index 104ac8b..3cbf370 100644 --- a/vault-api/docs/RenewSelfParameters.md +++ b/vault-api/docs/RenewSelfParameters.md @@ -3,7 +3,7 @@ ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**increment** | **String** | | [optional] [default to null] +**increment** | **String** | | [optional] [default to None] [[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/vault-api/docs/RevokeLeaseParameters.md b/vault-api/docs/RevokeLeaseParameters.md index 422c1c5..8bf28b6 100644 --- a/vault-api/docs/RevokeLeaseParameters.md +++ b/vault-api/docs/RevokeLeaseParameters.md @@ -3,7 +3,7 @@ ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**lease_id** | **String** | | [default to null] +**lease_id** | **String** | | [[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/vault-api/docs/leases_api.md b/vault-api/docs/leases_api.md new file mode 100644 index 0000000..7b8eebe --- /dev/null +++ b/vault-api/docs/leases_api.md @@ -0,0 +1,37 @@ +# leases_api + +All URIs are relative to *http://localhost/v1* + +Method | HTTP request | Description +------------- | ------------- | ------------- +**revoke_lease**](leases_api.md#revoke_lease) | **PUT** /sys/leases/revoke | Revoke lease + + +# **revoke_lease** +> revoke_lease(x_vault_token, body) +Revoke lease + +Revoke a lease + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **x_vault_token** | **String**| Vault token for authorization | + **body** | [**RevokeLeaseParameters**](RevokeLeaseParameters.md)| Parameters | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/vault-api/docs/pki_backend_api.md b/vault-api/docs/pki_backend_api.md new file mode 100644 index 0000000..a39d5b5 --- /dev/null +++ b/vault-api/docs/pki_backend_api.md @@ -0,0 +1,68 @@ +# pki_backend_api + +All URIs are relative to *http://localhost/v1* + +Method | HTTP request | Description +------------- | ------------- | ------------- +**generate_cert**](pki_backend_api.md#generate_cert) | **POST** /{mount}/issue/{name} | Generate certificate +**read_cert**](pki_backend_api.md#read_cert) | **GET** /{mount}/cert/{serial} | Read certificate + + +# **generate_cert** +> models::GenerateCertificateResponse generate_cert(x_vault_token, mount, name, body) +Generate certificate + +Generate a new certificate based on a role. The private key is not stored and must be retained by the client. + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **x_vault_token** | **String**| Vault token for authorization | + **mount** | **String**| Name of the mount - commonly \"pki\". | + **name** | **String**| Name of the role to create this certificate against | + **body** | [**GenerateCertificateParameters**](GenerateCertificateParameters.md)| Parameters | + +### Return type + +[**models::GenerateCertificateResponse**](GenerateCertificateResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json, + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **read_cert** +> models::CertificateResponse read_cert(mount, serial) +Read certificate + +Read a certificate in PEM format (within JSON). This is an unauthenticated endpoint. + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **mount** | **String**| Name of the mount - commonly \"pki\". | + **serial** | **String**| Name of the certificate | + +### Return type + +[**models::CertificateResponse**](CertificateResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/vault-api/docs/token_backend_api.md b/vault-api/docs/token_backend_api.md new file mode 100644 index 0000000..b5ea4cd --- /dev/null +++ b/vault-api/docs/token_backend_api.md @@ -0,0 +1,130 @@ +# token_backend_api + +All URIs are relative to *http://localhost/v1* + +Method | HTTP request | Description +------------- | ------------- | ------------- +**create_orphan_token**](token_backend_api.md#create_orphan_token) | **POST** /auth/token/create-orphan | Create an orphan token +**create_token**](token_backend_api.md#create_token) | **POST** /auth/token/create | Create token +**Log_in_with_TLS_certificate**](token_backend_api.md#Log_in_with_TLS_certificate) | **POST** /auth/cert/login | Log in +**renew_own_token**](token_backend_api.md#renew_own_token) | **POST** /auth/token/renew-self | Renew own token + + +# **create_orphan_token** +> models::AuthResponse create_orphan_token(x_vault_token, body) +Create an orphan token + +Create a new token without basing it off of a role. + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **x_vault_token** | **String**| Vault token for authorization | + **body** | [**CreateTokenParameters**](CreateTokenParameters.md)| Parameters | + +### Return type + +[**models::AuthResponse**](AuthResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json, + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **create_token** +> models::AuthResponse create_token(x_vault_token, body) +Create token + +Create a new token without basing it off of a role. + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **x_vault_token** | **String**| Vault token for authorization | + **body** | [**CreateTokenParameters**](CreateTokenParameters.md)| Parameters | + +### Return type + +[**models::AuthResponse**](AuthResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json, + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **Log_in_with_TLS_certificate** +> models::AuthResponse Log_in_with_TLS_certificate(optional) +Log in + +Log in with a TLS certificate + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **optional** | **map[string]interface{}** | optional parameters | nil if no parameters + +### Optional Parameters +Optional parameters are passed through a map[string]interface{}. + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **body** | [**AuthCertLoginParameters**](AuthCertLoginParameters.md)| Parameters | + +### Return type + +[**models::AuthResponse**](AuthResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: */*, + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **renew_own_token** +> models::AuthResponse renew_own_token(x_vault_token, body) +Renew own token + +Renews the token used to make this request. + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **x_vault_token** | **String**| Vault token for authorization | + **body** | [**RenewSelfParameters**](RenewSelfParameters.md)| Parameters | + +### Return type + +[**models::AuthResponse**](AuthResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/vault-api/examples/client.rs b/vault-api/examples/client.rs index 1ec64f1..339cb42 100644 --- a/vault-api/examples/client.rs +++ b/vault-api/examples/client.rs @@ -8,6 +8,7 @@ extern crate swagger; #[allow(unused_extern_crates)] extern crate uuid; extern crate clap; +extern crate url; #[allow(unused_imports)] use futures::{Future, future, Stream, stream}; @@ -23,6 +24,7 @@ use vault_api::{ApiNoContext, ContextWrapperExt, RenewOwnTokenResponse }; use clap::{App, Arg}; +use url::Url; fn main() { let matches = App::new("client") @@ -54,6 +56,8 @@ fn main() { if is_https { "https" } else { "http" }, matches.value_of("host").unwrap(), matches.value_of("port").unwrap()); + let base_url = Url::parse(&base_url).expect("Invalid base url"); + let client = if is_https { // Using Simple HTTPS vault_api::Client::try_new_https(&base_url, "examples/ca.pem") diff --git a/vault-api/examples/client/main.rs b/vault-api/examples/client/main.rs new file mode 100644 index 0000000..75632d7 --- /dev/null +++ b/vault-api/examples/client/main.rs @@ -0,0 +1,145 @@ +#![allow(missing_docs, unused_variables, trivial_casts)] + + +#[allow(unused_imports)] +use futures::{future, Stream, stream}; +#[allow(unused_imports)] +use vault_api::{Api, ApiNoContext, Client, ContextWrapperExt, models, + RevokeLeaseResponse, + GenerateCertResponse, + ReadCertResponse, + CreateOrphanTokenResponse, + CreateTokenResponse, + LogInWithTLSCertificateResponse, + RenewOwnTokenResponse, + }; +use clap::{App, Arg}; + +#[allow(unused_imports)] +use log::info; + +// swagger::Has may be unused if there are no examples +#[allow(unused_imports)] +use swagger::{AuthData, ContextBuilder, EmptyContext, Has, Push, XSpanIdString}; + +type ClientContext = swagger::make_context_ty!(ContextBuilder, EmptyContext, Option, XSpanIdString); + +// rt may be unused if there are no examples +#[allow(unused_mut)] +fn main() { + env_logger::init(); + + let matches = App::new("client") + .arg(Arg::with_name("operation") + .help("Sets the operation to run") + .possible_values(&[ + "ReadCert", + "LogInWithTLSCertificate", + ]) + .required(true) + .index(1)) + .arg(Arg::with_name("https") + .long("https") + .help("Whether to use HTTPS or not")) + .arg(Arg::with_name("host") + .long("host") + .takes_value(true) + .default_value("localhost") + .help("Hostname to contact")) + .arg(Arg::with_name("port") + .long("port") + .takes_value(true) + .default_value("8080") + .help("Port to contact")) + .get_matches(); + + let is_https = matches.is_present("https"); + let base_url = format!("{}://{}:{}", + if is_https { "https" } else { "http" }, + matches.value_of("host").unwrap(), + matches.value_of("port").unwrap()); + + let context: ClientContext = + swagger::make_context!(ContextBuilder, EmptyContext, None as Option, XSpanIdString::default()); + + let mut client : Box> = if matches.is_present("https") { + // Using Simple HTTPS + let client = Box::new(Client::try_new_https(&base_url) + .expect("Failed to create HTTPS client")); + Box::new(client.with_context(context)) + } else { + // Using HTTP + let client = Box::new(Client::try_new_http( + &base_url) + .expect("Failed to create HTTP client")); + Box::new(client.with_context(context)) + }; + + let mut rt = tokio::runtime::Runtime::new().unwrap(); + + match matches.value_of("operation") { + /* Disabled because there's no example. + Some("RevokeLease") => { + let result = rt.block_on(client.revoke_lease( + "x_vault_token_example".to_string(), + ??? + )); + info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); + }, + */ + /* Disabled because there's no example. + Some("GenerateCert") => { + let result = rt.block_on(client.generate_cert( + "x_vault_token_example".to_string(), + "mount_example".to_string(), + "name_example".to_string(), + ??? + )); + info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); + }, + */ + Some("ReadCert") => { + let result = rt.block_on(client.read_cert( + "mount_example".to_string(), + "serial_example".to_string() + )); + info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); + }, + /* Disabled because there's no example. + Some("CreateOrphanToken") => { + let result = rt.block_on(client.create_orphan_token( + "x_vault_token_example".to_string(), + ??? + )); + info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); + }, + */ + /* Disabled because there's no example. + Some("CreateToken") => { + let result = rt.block_on(client.create_token( + "x_vault_token_example".to_string(), + ??? + )); + info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); + }, + */ + Some("LogInWithTLSCertificate") => { + let result = rt.block_on(client.log_in_with_tls_certificate( + None + )); + info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); + }, + /* Disabled because there's no example. + Some("RenewOwnToken") => { + let result = rt.block_on(client.renew_own_token( + "x_vault_token_example".to_string(), + ??? + )); + info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); + }, + */ + _ => { + panic!("Invalid operation provided") + } + } +} diff --git a/vault-api/examples/server/main.rs b/vault-api/examples/server/main.rs new file mode 100644 index 0000000..07ebf04 --- /dev/null +++ b/vault-api/examples/server/main.rs @@ -0,0 +1,25 @@ +//! Main binary entry point for vault_api implementation. + +#![allow(missing_docs)] + +use clap::{App, Arg}; + +mod server; + + +/// Create custom server, wire it to the autogenerated router, +/// and pass it to the web server. +#[tokio::main] +async fn main() { + env_logger::init(); + + let matches = App::new("server") + .arg(Arg::with_name("https") + .long("https") + .help("Whether to use HTTPS or not")) + .get_matches(); + + let addr = "127.0.0.1:8080"; + + server::create(addr, matches.is_present("https")).await; +} diff --git a/vault-api/examples/server/server.rs b/vault-api/examples/server/server.rs new file mode 100644 index 0000000..ab5deef --- /dev/null +++ b/vault-api/examples/server/server.rs @@ -0,0 +1,199 @@ +//! Main library entry point for vault_api implementation. + +#![allow(unused_imports)] + +use async_trait::async_trait; +use futures::{future, Stream, StreamExt, TryFutureExt, TryStreamExt}; +use hyper::server::conn::Http; +use hyper::service::Service; +use log::info; +use openssl::ssl::SslAcceptorBuilder; +use std::future::Future; +use std::marker::PhantomData; +use std::net::SocketAddr; +use std::sync::{Arc, Mutex}; +use std::task::{Context, Poll}; +use swagger::{Has, XSpanIdString}; +use swagger::auth::MakeAllowAllAuthenticator; +use swagger::EmptyContext; +use tokio::net::TcpListener; + +#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] +use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; + +use vault_api::models; + +#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] +/// Builds an SSL implementation for Simple HTTPS from some hard-coded file names +pub async fn create(addr: &str, https: bool) { + let addr = addr.parse().expect("Failed to parse bind address"); + + let server = Server::new(); + + let service = MakeService::new(server); + + let service = MakeAllowAllAuthenticator::new(service, "cosmo"); + + let mut service = + vault_api::server::context::MakeAddContext::<_, EmptyContext>::new( + service + ); + + if https { + #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] + { + unimplemented!("SSL is not implemented for the examples on MacOS, Windows or iOS"); + } + + #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] + { + let mut ssl = SslAcceptor::mozilla_intermediate_v5(SslMethod::tls()).expect("Failed to create SSL Acceptor"); + + // Server authentication + ssl.set_private_key_file("examples/server-key.pem", SslFiletype::PEM).expect("Failed to set private key"); + ssl.set_certificate_chain_file("examples/server-chain.pem").expect("Failed to set cerificate chain"); + ssl.check_private_key().expect("Failed to check private key"); + + let tls_acceptor = Arc::new(ssl.build()); + let mut tcp_listener = TcpListener::bind(&addr).await.unwrap(); + let mut incoming = tcp_listener.incoming(); + + while let (Some(tcp), rest) = incoming.into_future().await { + if let Ok(tcp) = tcp { + let addr = tcp.peer_addr().expect("Unable to get remote address"); + let service = service.call(addr); + let tls_acceptor = Arc::clone(&tls_acceptor); + + tokio::spawn(async move { + let tls = tokio_openssl::accept(&*tls_acceptor, tcp).await.map_err(|_| ())?; + + let service = service.await.map_err(|_| ())?; + + Http::new().serve_connection(tls, service).await.map_err(|_| ()) + }); + } + + incoming = rest; + } + } + } else { + // Using HTTP + hyper::server::Server::bind(&addr).serve(service).await.unwrap() + } +} + +#[derive(Copy, Clone)] +pub struct Server { + marker: PhantomData, +} + +impl Server { + pub fn new() -> Self { + Server{marker: PhantomData} + } +} + + +use vault_api::{ + Api, + RevokeLeaseResponse, + GenerateCertResponse, + ReadCertResponse, + CreateOrphanTokenResponse, + CreateTokenResponse, + LogInWithTLSCertificateResponse, + RenewOwnTokenResponse, +}; +use vault_api::server::MakeService; +use std::error::Error; +use swagger::ApiError; + +#[async_trait] +impl Api for Server where C: Has + Send + Sync +{ + /// Revoke lease + async fn revoke_lease( + &self, + x_vault_token: String, + body: models::RevokeLeaseParameters, + context: &C) -> Result + { + let context = context.clone(); + info!("revoke_lease(\"{}\", {:?}) - X-Span-ID: {:?}", x_vault_token, body, context.get().0.clone()); + Err("Generic failuare".into()) + } + + /// Generate certificate + async fn generate_cert( + &self, + x_vault_token: String, + mount: String, + name: String, + body: models::GenerateCertificateParameters, + context: &C) -> Result + { + let context = context.clone(); + info!("generate_cert(\"{}\", \"{}\", \"{}\", {:?}) - X-Span-ID: {:?}", x_vault_token, mount, name, body, context.get().0.clone()); + Err("Generic failuare".into()) + } + + /// Read certificate + async fn read_cert( + &self, + mount: String, + serial: String, + context: &C) -> Result + { + let context = context.clone(); + info!("read_cert(\"{}\", \"{}\") - X-Span-ID: {:?}", mount, serial, context.get().0.clone()); + Err("Generic failuare".into()) + } + + /// Create an orphan token + async fn create_orphan_token( + &self, + x_vault_token: String, + body: models::CreateTokenParameters, + context: &C) -> Result + { + let context = context.clone(); + info!("create_orphan_token(\"{}\", {:?}) - X-Span-ID: {:?}", x_vault_token, body, context.get().0.clone()); + Err("Generic failuare".into()) + } + + /// Create token + async fn create_token( + &self, + x_vault_token: String, + body: models::CreateTokenParameters, + context: &C) -> Result + { + let context = context.clone(); + info!("create_token(\"{}\", {:?}) - X-Span-ID: {:?}", x_vault_token, body, context.get().0.clone()); + Err("Generic failuare".into()) + } + + /// Log in + async fn log_in_with_tls_certificate( + &self, + body: Option, + context: &C) -> Result + { + let context = context.clone(); + info!("log_in_with_tls_certificate({:?}) - X-Span-ID: {:?}", body, context.get().0.clone()); + Err("Generic failuare".into()) + } + + /// Renew own token + async fn renew_own_token( + &self, + x_vault_token: String, + body: models::RenewSelfParameters, + context: &C) -> Result + { + let context = context.clone(); + info!("renew_own_token(\"{}\", {:?}) - X-Span-ID: {:?}", x_vault_token, body, context.get().0.clone()); + Err("Generic failuare".into()) + } + +} diff --git a/vault-api/src/apis/client.rs b/vault-api/src/apis/client.rs deleted file mode 100644 index d69e012..0000000 --- a/vault-api/src/apis/client.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::rc::Rc; - -use hyper; -use super::configuration::Configuration; - -pub struct APIClient { - configuration: Rc>, - leases_api: Box<::apis::LeasesApi>, - pki_backend_api: Box<::apis::PkiBackendApi>, - token_backend_api: Box<::apis::TokenBackendApi>, -} - -impl APIClient { - pub fn new(configuration: Configuration) -> APIClient { - let rc = Rc::new(configuration); - - APIClient { - configuration: rc.clone(), - leases_api: Box::new(::apis::LeasesApiClient::new(rc.clone())), - pki_backend_api: Box::new(::apis::PkiBackendApiClient::new(rc.clone())), - token_backend_api: Box::new(::apis::TokenBackendApiClient::new(rc.clone())), - } - } - - pub fn leases_api(&self) -> &::apis::LeasesApi{ - self.leases_api.as_ref() - } - - pub fn pki_backend_api(&self) -> &::apis::PkiBackendApi{ - self.pki_backend_api.as_ref() - } - - pub fn token_backend_api(&self) -> &::apis::TokenBackendApi{ - self.token_backend_api.as_ref() - } - - -} diff --git a/vault-api/src/apis/configuration.rs b/vault-api/src/apis/configuration.rs deleted file mode 100644 index 16cd408..0000000 --- a/vault-api/src/apis/configuration.rs +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Vault - * - * Hashicorp Vault API - * - * OpenAPI spec version: 0.7.2 - * - * Generated by: https://github.com/swagger-api/swagger-codegen.git - */ - -use hyper; - -pub struct Configuration { - pub base_path: String, - pub client: hyper::client::Client, -} - -impl Configuration { - pub fn new(client: hyper::client::Client) -> Configuration { - Configuration { - base_path: "http://localhost/v1".to_owned(), - client: client, - } - } -} diff --git a/vault-api/src/apis/leases_api.rs b/vault-api/src/apis/leases_api.rs deleted file mode 100644 index 0ab02b0..0000000 --- a/vault-api/src/apis/leases_api.rs +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Vault - * - * Hashicorp Vault API - * - * OpenAPI spec version: 0.7.2 - * - * Generated by: https://github.com/swagger-api/swagger-codegen.git - */ - -use std::rc::Rc; -use std::borrow::Borrow; - -use hyper; -use serde_json; -use futures; -use futures::{Future, Stream}; - -use super::{Error, configuration}; - -pub struct LeasesApiClient { - configuration: Rc>, -} - -impl LeasesApiClient { - pub fn new(configuration: Rc>) -> LeasesApiClient { - LeasesApiClient { - configuration: configuration, - } - } -} - -pub trait LeasesApi { - fn revoke_lease(&self, x_vault_token: &str, body: ::models::RevokeLeaseParameters) -> Box>; -} - - -implLeasesApi for LeasesApiClient { - fn revoke_lease(&self, x_vault_token: &str, body: ::models::RevokeLeaseParameters) -> Box> { - let configuration: &configuration::Configuration = self.configuration.borrow(); - - let method = hyper::Method::Put; - - let uri_str = format!("{}/sys/leases/revoke", configuration.base_path); - - let uri = uri_str.parse(); - // TODO(farcaller): handle error - // if let Err(e) = uri { - // return Box::new(futures::future::err(e)); - // } - let mut req = hyper::Request::new(method, uri.unwrap()); - - { - let mut headers = req.headers_mut(); - headers.set_raw("X-Vault-Token", x_vault_token); - } - - let serialized = serde_json::to_string(&body).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); - req.headers_mut().set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); - - // send request - Box::new( - configuration.client.request(req).and_then(|res| { res.body().concat2() }) - .map_err(|e| Error::from(e)) - .and_then(|_| futures::future::ok(())) - ) - } - -} diff --git a/vault-api/src/apis/mod.rs b/vault-api/src/apis/mod.rs deleted file mode 100644 index 117b0c3..0000000 --- a/vault-api/src/apis/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -use hyper; -use serde_json; - -#[derive(Debug)] -pub enum Error { - Hyper(hyper::Error), - Serde(serde_json::Error), -} - -impl From for Error { - fn from(e: hyper::Error) -> Self { - return Error::Hyper(e) - } -} - -impl From for Error { - fn from(e: serde_json::Error) -> Self { - return Error::Serde(e) - } -} - -use super::models::*; - -mod leases_api; -pub use self::leases_api::{ LeasesApi, LeasesApiClient }; -mod pki_backend_api; -pub use self::pki_backend_api::{ PkiBackendApi, PkiBackendApiClient }; -mod token_backend_api; -pub use self::token_backend_api::{ TokenBackendApi, TokenBackendApiClient }; - -pub mod configuration; -pub mod client; diff --git a/vault-api/src/apis/pki_backend_api.rs b/vault-api/src/apis/pki_backend_api.rs deleted file mode 100644 index 3a53ed0..0000000 --- a/vault-api/src/apis/pki_backend_api.rs +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Vault - * - * Hashicorp Vault API - * - * OpenAPI spec version: 0.7.2 - * - * Generated by: https://github.com/swagger-api/swagger-codegen.git - */ - -use std::rc::Rc; -use std::borrow::Borrow; - -use hyper; -use serde_json; -use futures; -use futures::{Future, Stream}; - -use super::{Error, configuration}; - -pub struct PkiBackendApiClient { - configuration: Rc>, -} - -impl PkiBackendApiClient { - pub fn new(configuration: Rc>) -> PkiBackendApiClient { - PkiBackendApiClient { - configuration: configuration, - } - } -} - -pub trait PkiBackendApi { - fn generate_cert(&self, x_vault_token: &str, mount: &str, name: &str, body: ::models::GenerateCertificateParameters) -> Box>; - fn read_cert(&self, mount: &str, serial: &str) -> Box>; -} - - -implPkiBackendApi for PkiBackendApiClient { - fn generate_cert(&self, x_vault_token: &str, mount: &str, name: &str, body: ::models::GenerateCertificateParameters) -> Box> { - let configuration: &configuration::Configuration = self.configuration.borrow(); - - let method = hyper::Method::Post; - - let uri_str = format!("{}/{mount}/issue/{name}", configuration.base_path, mount=mount, name=name); - - let uri = uri_str.parse(); - // TODO(farcaller): handle error - // if let Err(e) = uri { - // return Box::new(futures::future::err(e)); - // } - let mut req = hyper::Request::new(method, uri.unwrap()); - - { - let mut headers = req.headers_mut(); - headers.set_raw("X-Vault-Token", x_vault_token); - } - - let serialized = serde_json::to_string(&body).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); - req.headers_mut().set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); - - // send request - Box::new( - configuration.client.request(req).and_then(|res| { res.body().concat2() }) - .map_err(|e| Error::from(e)) - .and_then(|body| { - let parsed: Result<::models::GenerateCertificateResponse, _> = serde_json::from_slice(&body); - parsed.map_err(|e| Error::from(e)) - }).map_err(|e| Error::from(e)) - ) - } - - fn read_cert(&self, mount: &str, serial: &str) -> Box> { - let configuration: &configuration::Configuration = self.configuration.borrow(); - - let method = hyper::Method::Get; - - let uri_str = format!("{}/{mount}/cert/{serial}", configuration.base_path, mount=mount, serial=serial); - - let uri = uri_str.parse(); - // TODO(farcaller): handle error - // if let Err(e) = uri { - // return Box::new(futures::future::err(e)); - // } - let mut req = hyper::Request::new(method, uri.unwrap()); - - - - // send request - Box::new( - configuration.client.request(req).and_then(|res| { res.body().concat2() }) - .map_err(|e| Error::from(e)) - .and_then(|body| { - let parsed: Result<::models::CertificateResponse, _> = serde_json::from_slice(&body); - parsed.map_err(|e| Error::from(e)) - }).map_err(|e| Error::from(e)) - ) - } - -} diff --git a/vault-api/src/apis/token_backend_api.rs b/vault-api/src/apis/token_backend_api.rs deleted file mode 100644 index 61322a4..0000000 --- a/vault-api/src/apis/token_backend_api.rs +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Vault - * - * Hashicorp Vault API - * - * OpenAPI spec version: 0.7.2 - * - * Generated by: https://github.com/swagger-api/swagger-codegen.git - */ - -use std::rc::Rc; -use std::borrow::Borrow; - -use hyper; -use serde_json; -use futures; -use futures::{Future, Stream}; - -use super::{Error, configuration}; - -pub struct TokenBackendApiClient { - configuration: Rc>, -} - -impl TokenBackendApiClient { - pub fn new(configuration: Rc>) -> TokenBackendApiClient { - TokenBackendApiClient { - configuration: configuration, - } - } -} - -pub trait TokenBackendApi { - fn create_orphan_token(&self, x_vault_token: &str, body: ::models::CreateTokenParameters) -> Box>; - fn create_token(&self, x_vault_token: &str, body: ::models::CreateTokenParameters) -> Box>; - fn log_in_with_tls_certificate(&self, body: ::models::AuthCertLoginParameters) -> Box>; - fn renew_own_token(&self, x_vault_token: &str, body: ::models::RenewSelfParameters) -> Box>; -} - - -implTokenBackendApi for TokenBackendApiClient { - fn create_orphan_token(&self, x_vault_token: &str, body: ::models::CreateTokenParameters) -> Box> { - let configuration: &configuration::Configuration = self.configuration.borrow(); - - let method = hyper::Method::Post; - - let uri_str = format!("{}/auth/token/create-orphan", configuration.base_path); - - let uri = uri_str.parse(); - // TODO(farcaller): handle error - // if let Err(e) = uri { - // return Box::new(futures::future::err(e)); - // } - let mut req = hyper::Request::new(method, uri.unwrap()); - - { - let mut headers = req.headers_mut(); - headers.set_raw("X-Vault-Token", x_vault_token); - } - - let serialized = serde_json::to_string(&body).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); - req.headers_mut().set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); - - // send request - Box::new( - configuration.client.request(req).and_then(|res| { res.body().concat2() }) - .map_err(|e| Error::from(e)) - .and_then(|body| { - let parsed: Result<::models::AuthResponse, _> = serde_json::from_slice(&body); - parsed.map_err(|e| Error::from(e)) - }).map_err(|e| Error::from(e)) - ) - } - - fn create_token(&self, x_vault_token: &str, body: ::models::CreateTokenParameters) -> Box> { - let configuration: &configuration::Configuration = self.configuration.borrow(); - - let method = hyper::Method::Post; - - let uri_str = format!("{}/auth/token/create", configuration.base_path); - - let uri = uri_str.parse(); - // TODO(farcaller): handle error - // if let Err(e) = uri { - // return Box::new(futures::future::err(e)); - // } - let mut req = hyper::Request::new(method, uri.unwrap()); - - { - let mut headers = req.headers_mut(); - headers.set_raw("X-Vault-Token", x_vault_token); - } - - let serialized = serde_json::to_string(&body).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); - req.headers_mut().set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); - - // send request - Box::new( - configuration.client.request(req).and_then(|res| { res.body().concat2() }) - .map_err(|e| Error::from(e)) - .and_then(|body| { - let parsed: Result<::models::AuthResponse, _> = serde_json::from_slice(&body); - parsed.map_err(|e| Error::from(e)) - }).map_err(|e| Error::from(e)) - ) - } - - fn log_in_with_tls_certificate(&self, body: ::models::AuthCertLoginParameters) -> Box> { - let configuration: &configuration::Configuration = self.configuration.borrow(); - - let method = hyper::Method::Post; - - let uri_str = format!("{}/auth/cert/login", configuration.base_path); - - let uri = uri_str.parse(); - // TODO(farcaller): handle error - // if let Err(e) = uri { - // return Box::new(futures::future::err(e)); - // } - let mut req = hyper::Request::new(method, uri.unwrap()); - - - let serialized = serde_json::to_string(&body).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); - req.headers_mut().set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); - - // send request - Box::new( - configuration.client.request(req).and_then(|res| { res.body().concat2() }) - .map_err(|e| Error::from(e)) - .and_then(|body| { - let parsed: Result<::models::AuthResponse, _> = serde_json::from_slice(&body); - parsed.map_err(|e| Error::from(e)) - }).map_err(|e| Error::from(e)) - ) - } - - fn renew_own_token(&self, x_vault_token: &str, body: ::models::RenewSelfParameters) -> Box> { - let configuration: &configuration::Configuration = self.configuration.borrow(); - - let method = hyper::Method::Post; - - let uri_str = format!("{}/auth/token/renew-self", configuration.base_path); - - let uri = uri_str.parse(); - // TODO(farcaller): handle error - // if let Err(e) = uri { - // return Box::new(futures::future::err(e)); - // } - let mut req = hyper::Request::new(method, uri.unwrap()); - - { - let mut headers = req.headers_mut(); - headers.set_raw("X-Vault-Token", x_vault_token); - } - - let serialized = serde_json::to_string(&body).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); - req.headers_mut().set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); - - // send request - Box::new( - configuration.client.request(req).and_then(|res| { res.body().concat2() }) - .map_err(|e| Error::from(e)) - .and_then(|body| { - let parsed: Result<::models::AuthResponse, _> = serde_json::from_slice(&body); - parsed.map_err(|e| Error::from(e)) - }).map_err(|e| Error::from(e)) - ) - } - -} diff --git a/vault-api/src/base64_format.rs b/vault-api/src/base64_format.rs deleted file mode 100644 index 6a3719a..0000000 --- a/vault-api/src/base64_format.rs +++ /dev/null @@ -1,24 +0,0 @@ -use serde::ser::Serializer; -use serde::de::{Deserialize, Deserializer, Error}; -use base64::{encode, decode}; - -// These functions are only used if the API uses base64-encoded properties, so allow them to be -// dead code. - -#[allow(dead_code)] -pub fn serialize_with(obj: &Vec, serializer: S) -> Result - where S: Serializer -{ - serializer.serialize_str(&encode(obj)) -} - -#[allow(dead_code)] -pub fn deserialize_with<'de, D>(deserializer: D) -> Result, D::Error> - where D: Deserializer<'de> -{ - let s = try!(String::deserialize(deserializer)); - match decode(&s) { - Ok(bin) => Ok(bin), - _ => Err(D::Error::custom("invalid base64")), - } -} diff --git a/vault-api/src/client.rs b/vault-api/src/client.rs deleted file mode 100644 index 0766590..0000000 --- a/vault-api/src/client.rs +++ /dev/null @@ -1,617 +0,0 @@ -#![allow(unused_extern_crates)] -extern crate hyper_openssl; -extern crate chrono; -extern crate url; - - - -use hyper; -use hyper::client::IntoUrl; -use hyper::mime; -use hyper::header::{Headers, ContentType}; -use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value}; -use hyper::Url; -use self::hyper_openssl::openssl; -use self::url::percent_encoding::{utf8_percent_encode, PATH_SEGMENT_ENCODE_SET, QUERY_ENCODE_SET}; -use futures; -use futures::{Future, Stream}; -use futures::{future, stream}; -use std::borrow::Cow; -use std::io::{Read, Error}; -use std::error; -use std::fmt; -use std::path::Path; -use std::sync::Arc; -use std::str; - -use mimetypes; - -use serde_json; - - -#[allow(unused_imports)] -use std::collections::{HashMap, BTreeMap}; -#[allow(unused_imports)] -use swagger; - -use swagger::{Context, ApiError, XSpanId}; - -use {Api, - SysLeasesRevokePutResponse, - GenerateCertResponse, - ReadCertResponse, - CreateOrphanTokenResponse, - CreateTokenResponse, - LogInWithTLSCertificateResponse, - RenewOwnTokenResponse - }; -use models; - -/// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes. -fn into_base_path(input: T, correct_scheme: Option<&'static str>) -> Result { - // First convert to Url, since a base path is a subset of Url. - let url = input.into_url()?; - - let scheme = url.scheme(); - - // Check the scheme if necessary - if let Some(correct_scheme) = correct_scheme { - if scheme != correct_scheme { - return Err(ClientInitError::InvalidScheme); - } - } - - let host = url.host().ok_or_else(|| ClientInitError::MissingHost)?; - let port = url.port().map(|x| format!(":{}", x)).unwrap_or_default(); - Ok(format!("{}://{}{}", scheme, host, port)) -} - -/// A client that implements the API by making HTTP calls out to a server. -#[derive(Clone)] -pub struct Client { - base_path: String, - hyper_client: Arc hyper::client::Client + Sync + Send>, -} - -impl fmt::Debug for Client { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Client {{ base_path: {} }}", self.base_path) - } -} - -impl Client { - pub fn try_new_http(base_path: T) -> Result - where T: IntoUrl - { - Ok(Client { - base_path: into_base_path(base_path, Some("http"))?, - hyper_client: Arc::new(hyper::client::Client::new), - }) - } - - pub fn try_new_https(base_path: T, - ca_certificate: CA) - -> Result - where T: IntoUrl, - CA: AsRef - { - let ca_certificate = ca_certificate.as_ref().to_owned(); - - let https_hyper_client = move || { - // SSL implementation - let mut ssl = openssl::ssl::SslConnectorBuilder::new(openssl::ssl::SslMethod::tls()).unwrap(); - - // Server authentication - ssl.builder_mut().set_ca_file(ca_certificate.clone()).unwrap(); - - let ssl = hyper_openssl::OpensslClient::from(ssl.build()); - let connector = hyper::net::HttpsConnector::new(ssl); - hyper::client::Client::with_connector(connector) - }; - - Ok(Client { - base_path: into_base_path(base_path, Some("https"))?, - hyper_client: Arc::new(https_hyper_client), - }) - } - - pub fn try_new_https_mutual(base_path: T, - ca_certificate: CA, - client_key: K, - client_certificate: C) - -> Result - where T: IntoUrl, - CA: AsRef, - K: AsRef, - C: AsRef - { - let ca_certificate = ca_certificate.as_ref().to_owned(); - let client_key = client_key.as_ref().to_owned(); - let client_certificate = client_certificate.as_ref().to_owned(); - - let https_mutual_hyper_client = move || { - // SSL implementation - let mut ssl = openssl::ssl::SslConnectorBuilder::new(openssl::ssl::SslMethod::tls()).unwrap(); - - // Server authentication - ssl.builder_mut().set_ca_file(ca_certificate.clone()).unwrap(); - - // Client authentication - ssl.builder_mut().set_private_key_file(client_key.clone(), openssl::x509::X509_FILETYPE_PEM).unwrap(); - ssl.builder_mut().set_certificate_chain_file(client_certificate.clone()).unwrap(); - ssl.builder_mut().check_private_key().unwrap(); - - let ssl = hyper_openssl::OpensslClient::from(ssl.build()); - let connector = hyper::net::HttpsConnector::new(ssl); - hyper::client::Client::with_connector(connector) - }; - - Ok(Client { - base_path: into_base_path(base_path, Some("https"))?, - hyper_client: Arc::new(https_mutual_hyper_client) - }) - } - - /// Constructor for creating a `Client` by passing in a pre-made `hyper` client. - /// - /// One should avoid relying on this function if possible, since it adds a dependency on the underlying transport - /// implementation, which it would be better to abstract away. Therefore, using this function may lead to a loss of - /// code generality, which may make it harder to move the application to a serverless environment, for example. - /// - /// The reason for this function's existence is to support legacy test code, which did mocking at the hyper layer. - /// This is not a recommended way to write new tests. If other reasons are found for using this function, they - /// should be mentioned here. - pub fn try_new_with_hyper_client(base_path: T, - hyper_client: Arc hyper::client::Client + Sync + Send>) - -> Result - where T: IntoUrl - { - Ok(Client { - base_path: into_base_path(base_path, None)?, - hyper_client: hyper_client - }) - } -} - -impl Api for Client { - - fn sys_leases_revoke_put(&self, param_x_vault_token: String, param_body: models::RevokeLeaseParameters, context: &Context) -> Box + Send> { - - - let url = format!( - "{}/v1/sys/leases/revoke", - self.base_path - ); - - - let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - - let hyper_client = (self.hyper_client)(); - let request = hyper_client.request(hyper::method::Method::Put, &url); - let mut custom_headers = hyper::header::Headers::new(); - - let request = request.body(&body); - - custom_headers.set(ContentType(mimetypes::requests::SYS_LEASES_REVOKE_PUT.clone())); - context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); - - // Header parameters - header! { (RequestXVaultToken, "X-Vault-Token") => [String] } - custom_headers.set(RequestXVaultToken(param_x_vault_token)); - - - let request = request.headers(custom_headers); - - // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). - fn parse_response(mut response: hyper::client::response::Response) -> Result { - match response.status.to_u16() { - 204 => { - - - Ok(SysLeasesRevokePutResponse::Success) - }, - code => { - let mut buf = [0; 100]; - let debug_body = match response.read(&mut buf) { - Ok(len) => match str::from_utf8(&buf[..len]) { - Ok(body) => Cow::from(body), - Err(_) => Cow::from(format!("", &buf[..len].to_vec())), - }, - Err(e) => Cow::from(format!("", e)), - }; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - response.headers, - debug_body))) - } - } - } - - let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); - Box::new(futures::done(result)) - } - - fn generate_cert(&self, param_x_vault_token: String, param_mount: String, param_name: String, param_body: models::GenerateCertificateParameters, context: &Context) -> Box + Send> { - - - let url = format!( - "{}/v1/{mount}/issue/{name}", - self.base_path, mount=utf8_percent_encode(¶m_mount.to_string(), PATH_SEGMENT_ENCODE_SET), name=utf8_percent_encode(¶m_name.to_string(), PATH_SEGMENT_ENCODE_SET) - ); - - - let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - - let hyper_client = (self.hyper_client)(); - let request = hyper_client.request(hyper::method::Method::Post, &url); - let mut custom_headers = hyper::header::Headers::new(); - - let request = request.body(&body); - - custom_headers.set(ContentType(mimetypes::requests::GENERATE_CERT.clone())); - context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); - - // Header parameters - header! { (RequestXVaultToken, "X-Vault-Token") => [String] } - custom_headers.set(RequestXVaultToken(param_x_vault_token)); - - - let request = request.headers(custom_headers); - - // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). - fn parse_response(mut response: hyper::client::response::Response) -> Result { - match response.status.to_u16() { - 200 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - - - - Ok(GenerateCertResponse::Success(body)) - }, - code => { - let mut buf = [0; 100]; - let debug_body = match response.read(&mut buf) { - Ok(len) => match str::from_utf8(&buf[..len]) { - Ok(body) => Cow::from(body), - Err(_) => Cow::from(format!("", &buf[..len].to_vec())), - }, - Err(e) => Cow::from(format!("", e)), - }; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - response.headers, - debug_body))) - } - } - } - - let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); - Box::new(futures::done(result)) - } - - fn read_cert(&self, param_mount: String, param_serial: String, context: &Context) -> Box + Send> { - - - let url = format!( - "{}/v1/{mount}/cert/{serial}", - self.base_path, mount=utf8_percent_encode(¶m_mount.to_string(), PATH_SEGMENT_ENCODE_SET), serial=utf8_percent_encode(¶m_serial.to_string(), PATH_SEGMENT_ENCODE_SET) - ); - - - let hyper_client = (self.hyper_client)(); - let request = hyper_client.request(hyper::method::Method::Get, &url); - let mut custom_headers = hyper::header::Headers::new(); - - context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); - - - let request = request.headers(custom_headers); - - // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). - fn parse_response(mut response: hyper::client::response::Response) -> Result { - match response.status.to_u16() { - 200 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - - - - Ok(ReadCertResponse::Success(body)) - }, - code => { - let mut buf = [0; 100]; - let debug_body = match response.read(&mut buf) { - Ok(len) => match str::from_utf8(&buf[..len]) { - Ok(body) => Cow::from(body), - Err(_) => Cow::from(format!("", &buf[..len].to_vec())), - }, - Err(e) => Cow::from(format!("", e)), - }; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - response.headers, - debug_body))) - } - } - } - - let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); - Box::new(futures::done(result)) - } - - fn create_orphan_token(&self, param_x_vault_token: String, param_body: models::CreateTokenParameters, context: &Context) -> Box + Send> { - - - let url = format!( - "{}/v1/auth/token/create-orphan", - self.base_path - ); - - - let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - - let hyper_client = (self.hyper_client)(); - let request = hyper_client.request(hyper::method::Method::Post, &url); - let mut custom_headers = hyper::header::Headers::new(); - - let request = request.body(&body); - - custom_headers.set(ContentType(mimetypes::requests::CREATE_ORPHAN_TOKEN.clone())); - context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); - - // Header parameters - header! { (RequestXVaultToken, "X-Vault-Token") => [String] } - custom_headers.set(RequestXVaultToken(param_x_vault_token)); - - - let request = request.headers(custom_headers); - - // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). - fn parse_response(mut response: hyper::client::response::Response) -> Result { - match response.status.to_u16() { - 200 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - - - - Ok(CreateOrphanTokenResponse::Success(body)) - }, - code => { - let mut buf = [0; 100]; - let debug_body = match response.read(&mut buf) { - Ok(len) => match str::from_utf8(&buf[..len]) { - Ok(body) => Cow::from(body), - Err(_) => Cow::from(format!("", &buf[..len].to_vec())), - }, - Err(e) => Cow::from(format!("", e)), - }; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - response.headers, - debug_body))) - } - } - } - - let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); - Box::new(futures::done(result)) - } - - fn create_token(&self, param_x_vault_token: String, param_body: models::CreateTokenParameters, context: &Context) -> Box + Send> { - - - let url = format!( - "{}/v1/auth/token/create", - self.base_path - ); - - - let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - - let hyper_client = (self.hyper_client)(); - let request = hyper_client.request(hyper::method::Method::Post, &url); - let mut custom_headers = hyper::header::Headers::new(); - - let request = request.body(&body); - - custom_headers.set(ContentType(mimetypes::requests::CREATE_TOKEN.clone())); - context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); - - // Header parameters - header! { (RequestXVaultToken, "X-Vault-Token") => [String] } - custom_headers.set(RequestXVaultToken(param_x_vault_token)); - - - let request = request.headers(custom_headers); - - // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). - fn parse_response(mut response: hyper::client::response::Response) -> Result { - match response.status.to_u16() { - 200 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - - - - Ok(CreateTokenResponse::Success(body)) - }, - code => { - let mut buf = [0; 100]; - let debug_body = match response.read(&mut buf) { - Ok(len) => match str::from_utf8(&buf[..len]) { - Ok(body) => Cow::from(body), - Err(_) => Cow::from(format!("", &buf[..len].to_vec())), - }, - Err(e) => Cow::from(format!("", e)), - }; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - response.headers, - debug_body))) - } - } - } - - let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); - Box::new(futures::done(result)) - } - - fn log_in_with_tls_certificate(&self, param_body: Option, context: &Context) -> Box + Send> { - - - let url = format!( - "{}/v1/auth/cert/login", - self.base_path - ); - - let body = param_body.map(|ref body| { - - serde_json::to_string(body).expect("impossible to fail to serialize") - }); - let hyper_client = (self.hyper_client)(); - let request = hyper_client.request(hyper::method::Method::Post, &url); - let mut custom_headers = hyper::header::Headers::new(); - - let request = match body { - Some(ref body) => request.body(body), - None => request, - }; - - custom_headers.set(ContentType(mimetypes::requests::LOG_IN_WITH_TLS_CERTIFICATE.clone())); - context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); - - - let request = request.headers(custom_headers); - - // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). - fn parse_response(mut response: hyper::client::response::Response) -> Result { - match response.status.to_u16() { - 200 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - - - - Ok(LogInWithTLSCertificateResponse::Success(body)) - }, - code => { - let mut buf = [0; 100]; - let debug_body = match response.read(&mut buf) { - Ok(len) => match str::from_utf8(&buf[..len]) { - Ok(body) => Cow::from(body), - Err(_) => Cow::from(format!("", &buf[..len].to_vec())), - }, - Err(e) => Cow::from(format!("", e)), - }; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - response.headers, - debug_body))) - } - } - } - - let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); - Box::new(futures::done(result)) - } - - fn renew_own_token(&self, param_x_vault_token: String, param_body: models::RenewSelfParameters, context: &Context) -> Box + Send> { - - - let url = format!( - "{}/v1/auth/token/renew-self", - self.base_path - ); - - - let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - - let hyper_client = (self.hyper_client)(); - let request = hyper_client.request(hyper::method::Method::Post, &url); - let mut custom_headers = hyper::header::Headers::new(); - - let request = request.body(&body); - - custom_headers.set(ContentType(mimetypes::requests::RENEW_OWN_TOKEN.clone())); - context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); - - // Header parameters - header! { (RequestXVaultToken, "X-Vault-Token") => [String] } - custom_headers.set(RequestXVaultToken(param_x_vault_token)); - - - let request = request.headers(custom_headers); - - // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). - fn parse_response(mut response: hyper::client::response::Response) -> Result { - match response.status.to_u16() { - 200 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - - - - Ok(RenewOwnTokenResponse::Success(body)) - }, - code => { - let mut buf = [0; 100]; - let debug_body = match response.read(&mut buf) { - Ok(len) => match str::from_utf8(&buf[..len]) { - Ok(body) => Cow::from(body), - Err(_) => Cow::from(format!("", &buf[..len].to_vec())), - }, - Err(e) => Cow::from(format!("", e)), - }; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - response.headers, - debug_body))) - } - } - } - - let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); - Box::new(futures::done(result)) - } - -} - -#[derive(Debug)] -pub enum ClientInitError { - InvalidScheme, - InvalidUrl(hyper::error::ParseError), - MissingHost, - SslError(openssl::error::ErrorStack) -} - -impl From for ClientInitError { - fn from(err: hyper::error::ParseError) -> ClientInitError { - ClientInitError::InvalidUrl(err) - } -} - -impl From for ClientInitError { - fn from(err: openssl::error::ErrorStack) -> ClientInitError { - ClientInitError::SslError(err) - } -} - -impl fmt::Display for ClientInitError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - (self as &fmt::Debug).fmt(f) - } -} - -impl error::Error for ClientInitError { - fn description(&self) -> &str { - "Failed to produce a hyper client." - } -} diff --git a/vault-api/src/client/mod.rs b/vault-api/src/client/mod.rs new file mode 100644 index 0000000..f806f52 --- /dev/null +++ b/vault-api/src/client/mod.rs @@ -0,0 +1,1041 @@ +use async_trait::async_trait; +use futures::{Stream, future, future::BoxFuture, stream, future::TryFutureExt, future::FutureExt, stream::StreamExt}; +use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; +use hyper::{Body, Request, Response, service::Service, Uri}; +use percent_encoding::{utf8_percent_encode, AsciiSet}; +use std::borrow::Cow; +use std::convert::TryInto; +use std::io::{ErrorKind, Read}; +use std::error::Error; +use std::future::Future; +use std::fmt; +use std::marker::PhantomData; +use std::path::Path; +use std::sync::{Arc, Mutex}; +use std::str; +use std::str::FromStr; +use std::string::ToString; +use std::task::{Context, Poll}; +use swagger::{ApiError, AuthData, BodyExt, Connector, DropContextService, Has, XSpanIdString}; +use url::form_urlencoded; + + +use crate::models; +use crate::header; + +/// https://url.spec.whatwg.org/#fragment-percent-encode-set +#[allow(dead_code)] +const FRAGMENT_ENCODE_SET: &AsciiSet = &percent_encoding::CONTROLS + .add(b' ').add(b'"').add(b'<').add(b'>').add(b'`'); + +/// This encode set is used for object IDs +/// +/// Aside from the special characters defined in the `PATH_SEGMENT_ENCODE_SET`, +/// the vertical bar (|) is encoded. +#[allow(dead_code)] +const ID_ENCODE_SET: &AsciiSet = &FRAGMENT_ENCODE_SET.add(b'|'); + +use crate::{Api, + RevokeLeaseResponse, + GenerateCertResponse, + ReadCertResponse, + CreateOrphanTokenResponse, + CreateTokenResponse, + LogInWithTLSCertificateResponse, + RenewOwnTokenResponse + }; + +/// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes. +fn into_base_path(input: impl TryInto, correct_scheme: Option<&'static str>) -> Result { + // First convert to Uri, since a base path is a subset of Uri. + let uri = input.try_into()?; + + let scheme = uri.scheme_str().ok_or(ClientInitError::InvalidScheme)?; + + // Check the scheme if necessary + if let Some(correct_scheme) = correct_scheme { + if scheme != correct_scheme { + return Err(ClientInitError::InvalidScheme); + } + } + + let host = uri.host().ok_or_else(|| ClientInitError::MissingHost)?; + let port = uri.port_u16().map(|x| format!(":{}", x)).unwrap_or_default(); + Ok(format!("{}://{}{}{}", scheme, host, port, uri.path().trim_end_matches('/'))) +} + +/// A client that implements the API by making HTTP calls out to a server. +pub struct Client where + S: Service< + (Request, C), + Response=Response> + Clone + Sync + Send + 'static, + S::Future: Send + 'static, + S::Error: Into + fmt::Display, + C: Clone + Send + Sync + 'static +{ + /// Inner service + client_service: S, + + /// Base path of the API + base_path: String, + + /// Marker + marker: PhantomData, +} + +impl fmt::Debug for Client where + S: Service< + (Request, C), + Response=Response> + Clone + Sync + Send + 'static, + S::Future: Send + 'static, + S::Error: Into + fmt::Display, + C: Clone + Send + Sync + 'static +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Client {{ base_path: {} }}", self.base_path) + } +} + +impl Clone for Client where + S: Service< + (Request, C), + Response=Response> + Clone + Sync + Send + 'static, + S::Future: Send + 'static, + S::Error: Into + fmt::Display, + C: Clone + Send + Sync + 'static +{ + fn clone(&self) -> Self { + Self { + client_service: self.client_service.clone(), + base_path: self.base_path.clone(), + marker: PhantomData, + } + } +} + +impl Client, C>, C> where + Connector: hyper::client::connect::Connect + Clone + Send + Sync + 'static, + C: Clone + Send + Sync + 'static, +{ + /// Create a client with a custom implementation of hyper::client::Connect. + /// + /// Intended for use with custom implementations of connect for e.g. protocol logging + /// or similar functionality which requires wrapping the transport layer. When wrapping a TCP connection, + /// this function should be used in conjunction with `swagger::Connector::builder()`. + /// + /// For ordinary tcp connections, prefer the use of `try_new_http`, `try_new_https` + /// and `try_new_https_mutual`, to avoid introducing a dependency on the underlying transport layer. + /// + /// # Arguments + /// + /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + /// * `protocol` - Which protocol to use when constructing the request url, e.g. `Some("http")` + /// * `connector` - Implementation of `hyper::client::Connect` to use for the client + pub fn try_new_with_connector( + base_path: &str, + protocol: Option<&'static str>, + connector: Connector, + ) -> Result + { + let client_service = hyper::client::Client::builder().build(connector); + let client_service = DropContextService::new(client_service); + + Ok(Self { + client_service, + base_path: into_base_path(base_path, protocol)?, + marker: PhantomData, + }) + } +} + +#[derive(Debug, Clone)] +pub enum HyperClient { + Http(hyper::client::Client), + Https(hyper::client::Client), +} + +impl Service> for HyperClient { + type Response = Response; + type Error = hyper::Error; + type Future = hyper::client::ResponseFuture; + + fn poll_ready(&mut self, cx: &mut Context) -> Poll> { + match self { + HyperClient::Http(client) => client.poll_ready(cx), + HyperClient::Https(client) => client.poll_ready(cx), + } + } + + fn call(&mut self, req: Request) -> Self::Future { + match self { + HyperClient::Http(client) => client.call(req), + HyperClient::Https(client) => client.call(req) + } + } +} + +impl Client, C> where + C: Clone + Send + Sync + 'static, +{ + /// Create an HTTP client. + /// + /// # Arguments + /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + pub fn try_new( + base_path: &str, + ) -> Result { + let uri = Uri::from_str(base_path)?; + + let scheme = uri.scheme_str().ok_or(ClientInitError::InvalidScheme)?; + let scheme = scheme.to_ascii_lowercase(); + + let connector = Connector::builder(); + + let client_service = match scheme.as_str() { + "http" => { + HyperClient::Http(hyper::client::Client::builder().build(connector.build())) + }, + "https" => { + let connector = connector.https() + .build() + .map_err(|e| ClientInitError::SslError(e))?; + HyperClient::Https(hyper::client::Client::builder().build(connector)) + }, + _ => { + return Err(ClientInitError::InvalidScheme); + } + }; + + let client_service = DropContextService::new(client_service); + + Ok(Self { + client_service, + base_path: into_base_path(base_path, None)?, + marker: PhantomData, + }) + } +} + +impl Client, C>, C> where + C: Clone + Send + Sync + 'static +{ + /// Create an HTTP client. + /// + /// # Arguments + /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + pub fn try_new_http( + base_path: &str, + ) -> Result { + let http_connector = Connector::builder().build(); + + Self::try_new_with_connector(base_path, Some("http"), http_connector) + } +} + +#[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] +type HttpsConnector = hyper_tls::HttpsConnector; + +#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] +type HttpsConnector = hyper_openssl::HttpsConnector; + +impl Client, C>, C> where + C: Clone + Send + Sync + 'static +{ + /// Create a client with a TLS connection to the server + /// + /// # Arguments + /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + pub fn try_new_https(base_path: &str) -> Result + { + let https_connector = Connector::builder() + .https() + .build() + .map_err(|e| ClientInitError::SslError(e))?; + Self::try_new_with_connector(base_path, Some("https"), https_connector) + } + + /// Create a client with a TLS connection to the server using a pinned certificate + /// + /// # Arguments + /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `ca_certificate` - Path to CA certificate used to authenticate the server + #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] + pub fn try_new_https_pinned( + base_path: &str, + ca_certificate: CA, + ) -> Result + where + CA: AsRef, + { + let https_connector = Connector::builder() + .https() + .pin_server_certificate(ca_certificate) + .build() + .map_err(|e| ClientInitError::SslError(e))?; + Self::try_new_with_connector(base_path, Some("https"), https_connector) + } + + /// Create a client with a mutually authenticated TLS connection to the server. + /// + /// # Arguments + /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `ca_certificate` - Path to CA certificate used to authenticate the server + /// * `client_key` - Path to the client private key + /// * `client_certificate` - Path to the client's public certificate associated with the private key + #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] + pub fn try_new_https_mutual( + base_path: &str, + ca_certificate: CA, + client_key: K, + client_certificate: D, + ) -> Result + where + CA: AsRef, + K: AsRef, + D: AsRef, + { + let https_connector = Connector::builder() + .https() + .pin_server_certificate(ca_certificate) + .client_authentication(client_key, client_certificate) + .build() + .map_err(|e| ClientInitError::SslError(e))?; + Self::try_new_with_connector(base_path, Some("https"), https_connector) + } +} + +impl Client where + S: Service< + (Request, C), + Response=Response> + Clone + Sync + Send + 'static, + S::Future: Send + 'static, + S::Error: Into + fmt::Display, + C: Clone + Send + Sync + 'static +{ + /// Constructor for creating a `Client` by passing in a pre-made `hyper::service::Service` / + /// `tower::Service` + /// + /// This allows adding custom wrappers around the underlying transport, for example for logging. + pub fn try_new_with_client_service( + client_service: S, + base_path: &str, + ) -> Result + { + Ok(Self { + client_service, + base_path: into_base_path(base_path, None)?, + marker: PhantomData, + }) + } +} + +/// Error type failing to create a Client +#[derive(Debug)] +pub enum ClientInitError { + /// Invalid URL Scheme + InvalidScheme, + + /// Invalid URI + InvalidUri(hyper::http::uri::InvalidUri), + + /// Missing Hostname + MissingHost, + + /// SSL Connection Error + #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] + SslError(native_tls::Error), + + /// SSL Connection Error + #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] + SslError(openssl::error::ErrorStack), +} + +impl From for ClientInitError { + fn from(err: hyper::http::uri::InvalidUri) -> ClientInitError { + ClientInitError::InvalidUri(err) + } +} + +impl fmt::Display for ClientInitError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s: &dyn fmt::Debug = self; + s.fmt(f) + } +} + +impl Error for ClientInitError { + fn description(&self) -> &str { + "Failed to produce a hyper client." + } +} + +#[async_trait] +impl Api for Client where + S: Service< + (Request, C), + Response=Response> + Clone + Sync + Send + 'static, + S::Future: Send + 'static, + S::Error: Into + fmt::Display, + C: Has + Clone + Send + Sync + 'static, +{ + fn poll_ready(&self, cx: &mut Context) -> Poll> { + match self.client_service.clone().poll_ready(cx) { + Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())), + Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)), + Poll::Pending => Poll::Pending, + } + } + + async fn revoke_lease( + &self, + param_x_vault_token: String, + param_body: models::RevokeLeaseParameters, + context: &C) -> Result + { + let mut client_service = self.client_service.clone(); + let mut uri = format!( + "{}/v1/sys/leases/revoke", + self.base_path + ); + + // Query parameters + let query_string = { + let mut query_string = form_urlencoded::Serializer::new("".to_owned()); + query_string.finish() + }; + if !query_string.is_empty() { + uri += "?"; + uri += &query_string; + } + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + }; + + let mut request = match Request::builder() + .method("PUT") + .uri(uri) + .body(Body::empty()) { + Ok(req) => req, + Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + }; + + // Body parameter + let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); + + *request.body_mut() = Body::from(body); + + let header = "application/json"; + request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) + }); + + let header = HeaderValue::from_str(Has::::get(context).0.clone().to_string().as_str()); + request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + }); + + // Header parameters + request.headers_mut().append( + HeaderName::from_static("x-vault-token"), + match header::IntoHeaderValue(param_x_vault_token.clone()).try_into() { + Ok(header) => header, + Err(e) => { + return Err(ApiError(format!( + "Invalid header x_vault_token - {}", e))); + }, + }); + + let mut response = client_service.call((request, context.clone())) + .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + + match response.status().as_u16() { + 204 => { + let body = response.into_body(); + Ok( + RevokeLeaseResponse::Success + ) + } + code => { + let headers = response.headers().clone(); + let body = response.into_body() + .take(100) + .to_raw().await; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(body) => match String::from_utf8(body) { + Ok(body) => body, + Err(e) => format!("", e), + }, + Err(e) => format!("", e), + } + ))) + } + } + } + + async fn generate_cert( + &self, + param_x_vault_token: String, + param_mount: String, + param_name: String, + param_body: models::GenerateCertificateParameters, + context: &C) -> Result + { + let mut client_service = self.client_service.clone(); + let mut uri = format!( + "{}/v1/{mount}/issue/{name}", + self.base_path + ,mount=utf8_percent_encode(¶m_mount.to_string(), ID_ENCODE_SET) + ,name=utf8_percent_encode(¶m_name.to_string(), ID_ENCODE_SET) + ); + + // Query parameters + let query_string = { + let mut query_string = form_urlencoded::Serializer::new("".to_owned()); + query_string.finish() + }; + if !query_string.is_empty() { + uri += "?"; + uri += &query_string; + } + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + }; + + let mut request = match Request::builder() + .method("POST") + .uri(uri) + .body(Body::empty()) { + Ok(req) => req, + Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + }; + + // Body parameter + let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); + *request.body_mut() = Body::from(body); + + let header = "application/json"; + request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) + }); + let header = HeaderValue::from_str(Has::::get(context).0.clone().to_string().as_str()); + request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + }); + + // Header parameters + request.headers_mut().append( + HeaderName::from_static("x-vault-token"), + match header::IntoHeaderValue(param_x_vault_token.clone()).try_into() { + Ok(header) => header, + Err(e) => { + return Err(ApiError(format!( + "Invalid header x_vault_token - {}", e))); + }, + }); + + let mut response = client_service.call((request, context.clone())) + .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + + match response.status().as_u16() { + 200 => { + let body = response.into_body(); + let body = body + .to_raw() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = str::from_utf8(&body) + .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(body)?; + Ok(GenerateCertResponse::Success + (body) + ) + } + code => { + let headers = response.headers().clone(); + let body = response.into_body() + .take(100) + .to_raw().await; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(body) => match String::from_utf8(body) { + Ok(body) => body, + Err(e) => format!("", e), + }, + Err(e) => format!("", e), + } + ))) + } + } + } + + async fn read_cert( + &self, + param_mount: String, + param_serial: String, + context: &C) -> Result + { + let mut client_service = self.client_service.clone(); + let mut uri = format!( + "{}/v1/{mount}/cert/{serial}", + self.base_path + ,mount=utf8_percent_encode(¶m_mount.to_string(), ID_ENCODE_SET) + ,serial=utf8_percent_encode(¶m_serial.to_string(), ID_ENCODE_SET) + ); + + // Query parameters + let query_string = { + let mut query_string = form_urlencoded::Serializer::new("".to_owned()); + query_string.finish() + }; + if !query_string.is_empty() { + uri += "?"; + uri += &query_string; + } + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + }; + + let mut request = match Request::builder() + .method("GET") + .uri(uri) + .body(Body::empty()) { + Ok(req) => req, + Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + }; + + let header = HeaderValue::from_str(Has::::get(context).0.clone().to_string().as_str()); + request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + }); + + let mut response = client_service.call((request, context.clone())) + .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + + match response.status().as_u16() { + 200 => { + let body = response.into_body(); + let body = body + .to_raw() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = str::from_utf8(&body) + .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(body)?; + Ok(ReadCertResponse::Success + (body) + ) + } + code => { + let headers = response.headers().clone(); + let body = response.into_body() + .take(100) + .to_raw().await; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(body) => match String::from_utf8(body) { + Ok(body) => body, + Err(e) => format!("", e), + }, + Err(e) => format!("", e), + } + ))) + } + } + } + + async fn create_orphan_token( + &self, + param_x_vault_token: String, + param_body: models::CreateTokenParameters, + context: &C) -> Result + { + let mut client_service = self.client_service.clone(); + let mut uri = format!( + "{}/v1/auth/token/create-orphan", + self.base_path + ); + + // Query parameters + let query_string = { + let mut query_string = form_urlencoded::Serializer::new("".to_owned()); + query_string.finish() + }; + if !query_string.is_empty() { + uri += "?"; + uri += &query_string; + } + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + }; + + let mut request = match Request::builder() + .method("POST") + .uri(uri) + .body(Body::empty()) { + Ok(req) => req, + Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + }; + + // Body parameter + let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); + *request.body_mut() = Body::from(body); + + let header = "application/json"; + request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) + }); + let header = HeaderValue::from_str(Has::::get(context).0.clone().to_string().as_str()); + request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + }); + + // Header parameters + request.headers_mut().append( + HeaderName::from_static("x-vault-token"), + match header::IntoHeaderValue(param_x_vault_token.clone()).try_into() { + Ok(header) => header, + Err(e) => { + return Err(ApiError(format!( + "Invalid header x_vault_token - {}", e))); + }, + }); + + let mut response = client_service.call((request, context.clone())) + .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + + match response.status().as_u16() { + 200 => { + let body = response.into_body(); + let body = body + .to_raw() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = str::from_utf8(&body) + .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(body)?; + Ok(CreateOrphanTokenResponse::Success + (body) + ) + } + code => { + let headers = response.headers().clone(); + let body = response.into_body() + .take(100) + .to_raw().await; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(body) => match String::from_utf8(body) { + Ok(body) => body, + Err(e) => format!("", e), + }, + Err(e) => format!("", e), + } + ))) + } + } + } + + async fn create_token( + &self, + param_x_vault_token: String, + param_body: models::CreateTokenParameters, + context: &C) -> Result + { + let mut client_service = self.client_service.clone(); + let mut uri = format!( + "{}/v1/auth/token/create", + self.base_path + ); + + // Query parameters + let query_string = { + let mut query_string = form_urlencoded::Serializer::new("".to_owned()); + query_string.finish() + }; + if !query_string.is_empty() { + uri += "?"; + uri += &query_string; + } + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + }; + + let mut request = match Request::builder() + .method("POST") + .uri(uri) + .body(Body::empty()) { + Ok(req) => req, + Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + }; + + let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); + *request.body_mut() = Body::from(body); + + let header = "application/json"; + request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) + }); + let header = HeaderValue::from_str(Has::::get(context).0.clone().to_string().as_str()); + request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + }); + + // Header parameters + request.headers_mut().append( + HeaderName::from_static("x-vault-token"), + match header::IntoHeaderValue(param_x_vault_token.clone()).try_into() { + Ok(header) => header, + Err(e) => { + return Err(ApiError(format!( + "Invalid header x_vault_token - {}", e))); + }, + }); + + let mut response = client_service.call((request, context.clone())) + .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + + match response.status().as_u16() { + 200 => { + let body = response.into_body(); + let body = body + .to_raw() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = str::from_utf8(&body) + .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(body)?; + Ok(CreateTokenResponse::Success + (body) + ) + } + code => { + let headers = response.headers().clone(); + let body = response.into_body() + .take(100) + .to_raw().await; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(body) => match String::from_utf8(body) { + Ok(body) => body, + Err(e) => format!("", e), + }, + Err(e) => format!("", e), + } + ))) + } + } + } + + async fn log_in_with_tls_certificate( + &self, + param_body: Option, + context: &C) -> Result + { + let mut client_service = self.client_service.clone(); + let mut uri = format!( + "{}/v1/auth/cert/login", + self.base_path + ); + + // Query parameters + let query_string = { + let mut query_string = form_urlencoded::Serializer::new("".to_owned()); + query_string.finish() + }; + if !query_string.is_empty() { + uri += "?"; + uri += &query_string; + } + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + }; + + let mut request = match Request::builder() + .method("POST") + .uri(uri) + .body(Body::empty()) { + Ok(req) => req, + Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + }; + + let body = param_body.map(|ref body| { + serde_json::to_string(body).expect("impossible to fail to serialize") + }); + if let Some(body) = body { + *request.body_mut() = Body::from(body); + } + + let header = "application/json"; + request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) + }); + let header = HeaderValue::from_str(Has::::get(context).0.clone().to_string().as_str()); + request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + }); + + let mut response = client_service.call((request, context.clone())) + .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + + match response.status().as_u16() { + 200 => { + let body = response.into_body(); + let body = body + .to_raw() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = str::from_utf8(&body) + .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(body)?; + Ok(LogInWithTLSCertificateResponse::Success + (body) + ) + } + code => { + let headers = response.headers().clone(); + let body = response.into_body() + .take(100) + .to_raw().await; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(body) => match String::from_utf8(body) { + Ok(body) => body, + Err(e) => format!("", e), + }, + Err(e) => format!("", e), + } + ))) + } + } + } + + async fn renew_own_token( + &self, + param_x_vault_token: String, + param_body: models::RenewSelfParameters, + context: &C) -> Result + { + let mut client_service = self.client_service.clone(); + let mut uri = format!( + "{}/v1/auth/token/renew-self", + self.base_path + ); + + // Query parameters + let query_string = { + let mut query_string = form_urlencoded::Serializer::new("".to_owned()); + query_string.finish() + }; + if !query_string.is_empty() { + uri += "?"; + uri += &query_string; + } + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + }; + + let mut request = match Request::builder() + .method("POST") + .uri(uri) + .body(Body::empty()) { + Ok(req) => req, + Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + }; + + let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); + + *request.body_mut() = Body::from(body); + + let header = "application/json"; + request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) + }); + + let header = HeaderValue::from_str(Has::::get(context).0.clone().to_string().as_str()); + request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + }); + + // Header parameters + request.headers_mut().append( + HeaderName::from_static("x-vault-token"), + match header::IntoHeaderValue(param_x_vault_token.clone()).try_into() { + Ok(header) => header, + Err(e) => { + return Err(ApiError(format!( + "Invalid header x_vault_token - {}", e))); + }, + }); + + let mut response = client_service.call((request, context.clone())) + .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + + match response.status().as_u16() { + 200 => { + let body = response.into_body(); + let body = body + .to_raw() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = str::from_utf8(&body) + .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(body)?; + Ok(RenewOwnTokenResponse::Success + (body) + ) + } + code => { + let headers = response.headers().clone(); + let body = response.into_body() + .take(100) + .to_raw().await; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(body) => match String::from_utf8(body) { + Ok(body) => body, + Err(e) => format!("", e), + }, + Err(e) => format!("", e), + } + ))) + } + } + } + +} diff --git a/vault-api/src/context.rs b/vault-api/src/context.rs new file mode 100644 index 0000000..fadd880 --- /dev/null +++ b/vault-api/src/context.rs @@ -0,0 +1,113 @@ +use futures::future::BoxFuture; +use hyper::header::HeaderName; +use hyper::{Error, Request, Response, StatusCode, service::Service}; +use url::form_urlencoded; +use std::default::Default; +use std::io; +use std::marker::PhantomData; +use std::task::{Poll, Context}; +use swagger::auth::{AuthData, Authorization, Bearer, Scopes}; +use swagger::{EmptyContext, Has, Pop, Push, XSpanIdString}; +use crate::Api; + +pub struct MakeAddContext { + inner: T, + marker: PhantomData, +} + +impl MakeAddContext +where + A: Default + Push, + B: Push, Result = C>, + C: Push, Result = D>, +{ + pub fn new(inner: T) -> MakeAddContext { + MakeAddContext { + inner, + marker: PhantomData, + } + } +} + +// Make a service that adds context. +impl Service for + MakeAddContext +where + Target: Send, + A: Default + Push + Send, + B: Push, Result = C>, + C: Push, Result = D>, + D: Send + 'static, + T: Service + Send, + T::Future: Send + 'static +{ + type Error = T::Error; + type Response = AddContext; + type Future = BoxFuture<'static, Result>; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_ready(cx) + } + + fn call(&mut self, target: Target) -> Self::Future { + let service = self.inner.call(target); + + Box::pin(async move { + Ok(AddContext::new(service.await?)) + }) + } +} + +/// Middleware to add context data from the request +pub struct AddContext +where + A: Default + Push, + B: Push, Result = C>, + C: Push, Result = D> +{ + inner: T, + marker: PhantomData, +} + +impl AddContext +where + A: Default + Push, + B: Push, Result = C>, + C: Push, Result = D>, +{ + pub fn new(inner: T) -> Self { + AddContext { + inner, + marker: PhantomData, + } + } +} + +impl Service> for AddContext + where + A: Default + Push, + B: Push, Result=C>, + C: Push, Result=D>, + D: Send + 'static, + T: Service<(Request, D)> +{ + type Error = T::Error; + type Future = T::Future; + type Response = T::Response; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_ready(cx) + } + + + fn call(&mut self, request: Request) -> Self::Future { + let context = A::default().push(XSpanIdString::get_or_generate(&request)); + let headers = request.headers(); + + + let context = context.push(None::); + let context = context.push(None::); + + self.inner.call((request, context)) + } +} diff --git a/vault-api/src/header.rs b/vault-api/src/header.rs new file mode 100644 index 0000000..5bc6ebe --- /dev/null +++ b/vault-api/src/header.rs @@ -0,0 +1,180 @@ +use chrono::{DateTime, Utc}; +use hyper::header::HeaderValue; +use std::convert::TryFrom; +use std::fmt; +use std::ops::Deref; + +/// A struct to allow homogeneous conversion into a HeaderValue. We can't +/// implement the From/Into trait on HeaderValue because we don't own +/// either of the types. +#[derive(Debug, Clone)] +pub(crate) struct IntoHeaderValue(pub T); + +// Generic implementations + +impl Deref for IntoHeaderValue { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} + +// Derive for each TryFrom in hyper::header::HeaderValue + +macro_rules! ihv_generate { + ($t:ident) => { + impl TryFrom for IntoHeaderValue<$t> { + type Error = String; + + fn try_from(hdr_value: HeaderValue) -> Result { + match hdr_value.to_str() { + Ok(hdr_value) => match hdr_value.parse::<$t>() { + Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), + Err(e) => Err(format!("Unable to parse {} as a string: {}", + stringify!($t), e)), + }, + Err(e) => Err(format!("Unable to parse header {:?} as a string - {}", + hdr_value, e)), + } + } + } + + impl TryFrom> for HeaderValue { + type Error = String; + + fn try_from(hdr_value: IntoHeaderValue<$t>) -> Result { + Ok(hdr_value.0.into()) + } + } + }; +} + +ihv_generate!(u64); +ihv_generate!(i64); +ihv_generate!(i16); +ihv_generate!(u16); +ihv_generate!(u32); +ihv_generate!(usize); +ihv_generate!(isize); +ihv_generate!(i32); + +// Custom derivations + +// Vec + +impl TryFrom for IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_value: HeaderValue) -> Result { + match hdr_value.to_str() { + Ok(hdr_value) => Ok(IntoHeaderValue( + hdr_value + .split(',') + .filter_map(|x| match x.trim() { + "" => None, + y => Some(y.to_string()), + }) + .collect())), + Err(e) => Err(format!("Unable to parse header: {:?} as a string - {}", + hdr_value, e)), + } + } +} + +impl TryFrom>> for HeaderValue { + type Error = String; + + fn try_from(hdr_value: IntoHeaderValue>) -> Result { + match HeaderValue::from_str(&hdr_value.0.join(", ")) { + Ok(hdr_value) => Ok(hdr_value), + Err(e) => Err(format!("Unable to convert {:?} into a header - {}", + hdr_value, e)) + } + } +} + +// String + +impl TryFrom for IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: HeaderValue) -> Result { + match hdr_value.to_str() { + Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value.to_string())), + Err(e) => Err(format!("Unable to convert header {:?} to {}", + hdr_value, e)), + } + } +} + +impl TryFrom> for HeaderValue { + type Error = String; + + fn try_from(hdr_value: IntoHeaderValue) -> Result { + match HeaderValue::from_str(&hdr_value.0) { + Ok(hdr_value) => Ok(hdr_value), + Err(e) => Err(format!("Unable to convert {:?} from a header {}", + hdr_value, e)) + } + } +} + +// bool +impl TryFrom for IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: HeaderValue) -> Result { + match hdr_value.to_str() { + Ok(hdr_value) => match hdr_value.parse() { + Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), + Err(e) => Err(format!("Unable to parse bool from {} - {}", + hdr_value, e)), + }, + Err(e) => Err(format!("Unable to convert {:?} from a header {}", + hdr_value, e)), + } + } +} + +impl TryFrom> for HeaderValue { + type Error = String; + + fn try_from(hdr_value: IntoHeaderValue) -> Result { + match HeaderValue::from_str(&hdr_value.0.to_string()) { + Ok(hdr_value) => Ok(hdr_value), + Err(e) => Err(format!("Unable to convert: {:?} into a header: {}", + hdr_value, e)) + } + } +} + +// DateTime + +impl TryFrom for IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_value: HeaderValue) -> Result { + match hdr_value.to_str() { + Ok(hdr_value) => match DateTime::parse_from_rfc3339(hdr_value) { + Ok(date) => Ok(IntoHeaderValue(date.with_timezone(&Utc))), + Err(e) => Err(format!("Unable to parse: {} as date - {}", + hdr_value, e)), + }, + Err(e) => Err(format!("Unable to convert header {:?} to string {}", + hdr_value, e)), + } + } +} + +impl TryFrom>> for HeaderValue { + type Error = String; + + fn try_from(hdr_value: IntoHeaderValue>) -> Result { + match HeaderValue::from_str(hdr_value.0.to_rfc3339().as_str()) { + Ok(hdr_value) => Ok(hdr_value), + Err(e) => Err(format!("Unable to convert {:?} to a header: {}", + hdr_value, e)), + } + } +} diff --git a/vault-api/src/lib.rs b/vault-api/src/lib.rs index a83785b..998b4c7 100644 --- a/vault-api/src/lib.rs +++ b/vault-api/src/lib.rs @@ -1,189 +1,305 @@ #![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)] -extern crate serde; -#[macro_use] -extern crate serde_derive; -extern crate serde_json; - -extern crate futures; -extern crate chrono; - -#[macro_use] -extern crate lazy_static; -#[macro_use] -extern crate log; - -// Logically this should be in the client and server modules, but rust doesn't allow `macro_use` from a module. -#[cfg(any(feature = "client", feature = "server"))] -#[macro_use] -extern crate hyper; - -extern crate swagger; +use async_trait::async_trait; use futures::Stream; -use std::io::Error; +use std::error::Error; +use std::task::{Poll, Context}; +use swagger::{ApiError, ContextWrapper}; -#[allow(unused_imports)] -use std::collections::HashMap; - -pub use futures::Future; - -#[cfg(any(feature = "client", feature = "server"))] -mod mimetypes; - -pub use swagger::{ApiError, Context, ContextWrapper}; +type ServiceError = Box; +pub const BASE_PATH: &'static str = "/v1"; +pub const API_VERSION: &'static str = "0.7.2"; #[derive(Debug, PartialEq)] -pub enum SysLeasesRevokePutResponse { - Success , +pub enum RevokeLeaseResponse { + /// Success + Success } #[derive(Debug, PartialEq)] pub enum GenerateCertResponse { - Success ( models::GenerateCertificateResponse ) , + /// Success + Success + (models::GenerateCertificateResponse) } #[derive(Debug, PartialEq)] pub enum ReadCertResponse { - Success ( models::CertificateResponse ) , + /// Success + Success + (models::CertificateResponse) } #[derive(Debug, PartialEq)] pub enum CreateOrphanTokenResponse { - Success ( models::AuthResponse ) , + /// Success + Success + (models::AuthResponse) } #[derive(Debug, PartialEq)] pub enum CreateTokenResponse { - Success ( models::AuthResponse ) , + /// Success + Success + (models::AuthResponse) } #[derive(Debug, PartialEq)] pub enum LogInWithTLSCertificateResponse { - Success ( models::AuthResponse ) , + /// Success + Success + (models::AuthResponse) } #[derive(Debug, PartialEq)] pub enum RenewOwnTokenResponse { - Success ( models::AuthResponse ) , + /// Success + Success + (models::AuthResponse) } - /// API -pub trait Api { +#[async_trait] +pub trait Api { + fn poll_ready(&self, _cx: &mut Context) -> Poll>> { + Poll::Ready(Ok(())) + } /// Revoke lease - fn sys_leases_revoke_put(&self, x_vault_token: String, body: models::RevokeLeaseParameters, context: &Context) -> Box + Send>; + async fn revoke_lease( + &self, + x_vault_token: String, + body: models::RevokeLeaseParameters, + context: &C) -> Result; /// Generate certificate - fn generate_cert(&self, x_vault_token: String, mount: String, name: String, body: models::GenerateCertificateParameters, context: &Context) -> Box + Send>; + async fn generate_cert( + &self, + x_vault_token: String, + mount: String, + name: String, + body: models::GenerateCertificateParameters, + context: &C) -> Result; /// Read certificate - fn read_cert(&self, mount: String, serial: String, context: &Context) -> Box + Send>; + async fn read_cert( + &self, + mount: String, + serial: String, + context: &C) -> Result; /// Create an orphan token - fn create_orphan_token(&self, x_vault_token: String, body: models::CreateTokenParameters, context: &Context) -> Box + Send>; + async fn create_orphan_token( + &self, + x_vault_token: String, + body: models::CreateTokenParameters, + context: &C) -> Result; /// Create token - fn create_token(&self, x_vault_token: String, body: models::CreateTokenParameters, context: &Context) -> Box + Send>; + async fn create_token( + &self, + x_vault_token: String, + body: models::CreateTokenParameters, + context: &C) -> Result; /// Log in - fn log_in_with_tls_certificate(&self, body: Option, context: &Context) -> Box + Send>; + async fn log_in_with_tls_certificate( + &self, + body: Option, + context: &C) -> Result; /// Renew own token - fn renew_own_token(&self, x_vault_token: String, body: models::RenewSelfParameters, context: &Context) -> Box + Send>; + async fn renew_own_token( + &self, + x_vault_token: String, + body: models::RenewSelfParameters, + context: &C) -> Result; } -/// API without a `Context` -pub trait ApiNoContext { +/// API where `Context` isn't passed on every API call +#[async_trait] +pub trait ApiNoContext { + + fn poll_ready(&self, _cx: &mut Context) -> Poll>>; + + fn context(&self) -> &C; /// Revoke lease - fn sys_leases_revoke_put(&self, x_vault_token: String, body: models::RevokeLeaseParameters) -> Box + Send>; + async fn revoke_lease( + &self, + x_vault_token: String, + body: models::RevokeLeaseParameters, + ) -> Result; /// Generate certificate - fn generate_cert(&self, x_vault_token: String, mount: String, name: String, body: models::GenerateCertificateParameters) -> Box + Send>; + async fn generate_cert( + &self, + x_vault_token: String, + mount: String, + name: String, + body: models::GenerateCertificateParameters, + ) -> Result; /// Read certificate - fn read_cert(&self, mount: String, serial: String) -> Box + Send>; + async fn read_cert( + &self, + mount: String, + serial: String, + ) -> Result; /// Create an orphan token - fn create_orphan_token(&self, x_vault_token: String, body: models::CreateTokenParameters) -> Box + Send>; + async fn create_orphan_token( + &self, + x_vault_token: String, + body: models::CreateTokenParameters, + ) -> Result; /// Create token - fn create_token(&self, x_vault_token: String, body: models::CreateTokenParameters) -> Box + Send>; + async fn create_token( + &self, + x_vault_token: String, + body: models::CreateTokenParameters, + ) -> Result; /// Log in - fn log_in_with_tls_certificate(&self, body: Option) -> Box + Send>; + async fn log_in_with_tls_certificate( + &self, + body: Option, + ) -> Result; /// Renew own token - fn renew_own_token(&self, x_vault_token: String, body: models::RenewSelfParameters) -> Box + Send>; + async fn renew_own_token( + &self, + x_vault_token: String, + body: models::RenewSelfParameters, + ) -> Result; } /// Trait to extend an API to make it easy to bind it to a context. -pub trait ContextWrapperExt<'a> where Self: Sized { +pub trait ContextWrapperExt where Self: Sized +{ /// Binds this API to a context. - fn with_context(self: &'a Self, context: Context) -> ContextWrapper<'a, Self>; + fn with_context(self: Self, context: C) -> ContextWrapper; } -impl<'a, T: Api + Sized> ContextWrapperExt<'a> for T { - fn with_context(self: &'a T, context: Context) -> ContextWrapper<'a, T> { - ContextWrapper::::new(self, context) +impl + Send + Sync, C: Clone + Send + Sync> ContextWrapperExt for T { + fn with_context(self: T, context: C) -> ContextWrapper { + ContextWrapper::::new(self, context) } } -impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { +#[async_trait] +impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for ContextWrapper { + fn poll_ready(&self, cx: &mut Context) -> Poll> { + self.api().poll_ready(cx) + } + + fn context(&self) -> &C { + ContextWrapper::context(self) + } /// Revoke lease - fn sys_leases_revoke_put(&self, x_vault_token: String, body: models::RevokeLeaseParameters) -> Box + Send> { - self.api().sys_leases_revoke_put(x_vault_token, body, &self.context()) + async fn revoke_lease( + &self, + x_vault_token: String, + body: models::RevokeLeaseParameters, + ) -> Result + { + let context = self.context().clone(); + self.api().revoke_lease(x_vault_token, body, &context).await } /// Generate certificate - fn generate_cert(&self, x_vault_token: String, mount: String, name: String, body: models::GenerateCertificateParameters) -> Box + Send> { - self.api().generate_cert(x_vault_token, mount, name, body, &self.context()) + async fn generate_cert( + &self, + x_vault_token: String, + mount: String, + name: String, + body: models::GenerateCertificateParameters, + ) -> Result + { + let context = self.context().clone(); + self.api().generate_cert(x_vault_token, mount, name, body, &context).await } /// Read certificate - fn read_cert(&self, mount: String, serial: String) -> Box + Send> { - self.api().read_cert(mount, serial, &self.context()) + async fn read_cert( + &self, + mount: String, + serial: String, + ) -> Result + { + let context = self.context().clone(); + self.api().read_cert(mount, serial, &context).await } /// Create an orphan token - fn create_orphan_token(&self, x_vault_token: String, body: models::CreateTokenParameters) -> Box + Send> { - self.api().create_orphan_token(x_vault_token, body, &self.context()) + async fn create_orphan_token( + &self, + x_vault_token: String, + body: models::CreateTokenParameters, + ) -> Result + { + let context = self.context().clone(); + self.api().create_orphan_token(x_vault_token, body, &context).await } /// Create token - fn create_token(&self, x_vault_token: String, body: models::CreateTokenParameters) -> Box + Send> { - self.api().create_token(x_vault_token, body, &self.context()) + async fn create_token( + &self, + x_vault_token: String, + body: models::CreateTokenParameters, + ) -> Result + { + let context = self.context().clone(); + self.api().create_token(x_vault_token, body, &context).await } /// Log in - fn log_in_with_tls_certificate(&self, body: Option) -> Box + Send> { - self.api().log_in_with_tls_certificate(body, &self.context()) + async fn log_in_with_tls_certificate( + &self, + body: Option, + ) -> Result + { + let context = self.context().clone(); + self.api().log_in_with_tls_certificate(body, &context).await } /// Renew own token - fn renew_own_token(&self, x_vault_token: String, body: models::RenewSelfParameters) -> Box + Send> { - self.api().renew_own_token(x_vault_token, body, &self.context()) + async fn renew_own_token( + &self, + x_vault_token: String, + body: models::RenewSelfParameters, + ) -> Result + { + let context = self.context().clone(); + self.api().renew_own_token(x_vault_token, body, &context).await } } + #[cfg(feature = "client")] pub mod client; // Re-export Client as a top-level name #[cfg(feature = "client")] -pub use self::client::Client; +pub use client::Client; #[cfg(feature = "server")] pub mod server; // Re-export router() as a top-level name #[cfg(feature = "server")] -pub use self::server::router; +pub use self::server::Service; + +#[cfg(feature = "server")] +pub mod context; pub mod models; + +#[cfg(any(feature = "client", feature = "server"))] +pub(crate) mod header; diff --git a/vault-api/src/mimetypes.rs b/vault-api/src/mimetypes.rs deleted file mode 100644 index 282e924..0000000 --- a/vault-api/src/mimetypes.rs +++ /dev/null @@ -1,57 +0,0 @@ -/// mime types for requests and responses - -pub mod responses { - use hyper::mime::*; - - // The macro is called per-operation to beat the recursion limit - /// Create Mime objects for the response content types for GenerateCert - lazy_static! { - pub static ref GENERATE_CERT_SUCCESS: Mime = mime!(Application/Json); - } - /// Create Mime objects for the response content types for ReadCert - lazy_static! { - pub static ref READ_CERT_SUCCESS: Mime = mime!(Application/Json); - } - /// Create Mime objects for the response content types for CreateOrphanToken - lazy_static! { - pub static ref CREATE_ORPHAN_TOKEN_SUCCESS: Mime = mime!(Application/Json); - } - /// Create Mime objects for the response content types for CreateToken - lazy_static! { - pub static ref CREATE_TOKEN_SUCCESS: Mime = mime!(Application/Json); - } - /// Create Mime objects for the response content types for RenewOwnToken - lazy_static! { - pub static ref RENEW_OWN_TOKEN_SUCCESS: Mime = mime!(Application/Json); - } - -} - -pub mod requests { - use hyper::mime::*; - /// Create Mime objects for the request content types for SysLeasesRevokePut - lazy_static! { - pub static ref SYS_LEASES_REVOKE_PUT: Mime = mime!(Application/Json); - } - /// Create Mime objects for the request content types for GenerateCert - lazy_static! { - pub static ref GENERATE_CERT: Mime = mime!(Application/Json); - } - /// Create Mime objects for the request content types for CreateOrphanToken - lazy_static! { - pub static ref CREATE_ORPHAN_TOKEN: Mime = mime!(Application/Json); - } - /// Create Mime objects for the request content types for CreateToken - lazy_static! { - pub static ref CREATE_TOKEN: Mime = mime!(Application/Json); - } - /// Create Mime objects for the request content types for LogInWithTLSCertificate - lazy_static! { - pub static ref LOG_IN_WITH_TLS_CERTIFICATE: Mime = mime!(Application/Json); - } - /// Create Mime objects for the request content types for RenewOwnToken - lazy_static! { - pub static ref RENEW_OWN_TOKEN: Mime = mime!(Application/Json); - } - -} diff --git a/vault-api/src/models.rs b/vault-api/src/models.rs index aced2f8..743dd9c 100644 --- a/vault-api/src/models.rs +++ b/vault-api/src/models.rs @@ -1,16 +1,51 @@ -#![allow(unused_imports, unused_qualifications, unused_extern_crates)] -extern crate chrono; -extern crate uuid; +#![allow(unused_qualifications)] +use crate::models; +#[cfg(any(feature = "client", feature = "server"))] +use crate::header; -use serde::ser::Serializer; -use std::collections::HashMap; -use models; -use swagger; +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for AuthCertLoginParameters - value: {} is invalid {}", + hdr_value, e)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into AuthCertLoginParameters - {}", + value, err)) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {:?} to string: {}", + hdr_value, e)) + } + } +} + + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct AuthCertLoginParameters { #[serde(rename = "name")] #[serde(skip_serializing_if="Option::is_none")] @@ -26,59 +61,114 @@ impl AuthCertLoginParameters { } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct AuthResponseAuth { - #[serde(rename = "renewable")] - pub renewable: bool, +/// Converts the AuthCertLoginParameters value to the Query Parameters representation (style=form, explode=false) +/// specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde serializer +impl std::string::ToString for AuthCertLoginParameters { + fn to_string(&self) -> String { + let mut params: Vec = vec![]; - #[serde(rename = "lease_duration")] - pub lease_duration: i32, + if let Some(ref name) = self.name { + params.push("name".to_string()); + params.push(name.to_string()); + } - #[serde(rename = "policies")] - pub policies: Vec, + params.join(",").to_string() + } +} - #[serde(rename = "accessor")] - pub accessor: String, +/// Converts Query Parameters representation (style=form, explode=false) to a AuthCertLoginParameters value +/// as specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde deserializer +impl std::str::FromStr for AuthCertLoginParameters { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + #[derive(Default)] + // An intermediate representation of the struct to use for parsing. + struct IntermediateRep { + pub name: Vec, + } - #[serde(rename = "client_token")] - pub client_token: String, + let mut intermediate_rep = IntermediateRep::default(); -} + // Parse into intermediate representation + let mut string_iter = s.split(',').into_iter(); + let mut key_result = string_iter.next(); -impl AuthResponseAuth { - pub fn new(renewable: bool, lease_duration: i32, policies: Vec, accessor: String, client_token: String, ) -> AuthResponseAuth { - AuthResponseAuth { - renewable: renewable, - lease_duration: lease_duration, - policies: policies, - accessor: accessor, - client_token: client_token, + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing AuthCertLoginParameters".to_string()) + }; + + if let Some(key) = key_result { + match key { + "name" => intermediate_rep.name.push(String::from_str(val).map_err(|x| format!("{}", x))?), + _ => return std::result::Result::Err("Unexpected key while parsing AuthCertLoginParameters".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(AuthCertLoginParameters { + name: intermediate_rep.name.into_iter().next(), + }) } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct CertificateResponseData { - #[serde(rename = "certificate")] - pub certificate: String, + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for AuthResponse - value: {} is invalid {}", + hdr_value, e)) + } + } } -impl CertificateResponseData { - pub fn new(certificate: String, ) -> CertificateResponseData { - CertificateResponseData { - certificate: certificate, +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into AuthResponse - {}", + value, err)) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {:?} to string: {}", + hdr_value, e)) } } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct CommonResponse { + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct AuthResponse { #[serde(rename = "request_id")] pub request_id: String, #[serde(rename = "lease_duration")] - pub lease_duration: i32, + pub lease_duration: isize, #[serde(rename = "lease_id")] pub lease_id: String, @@ -86,226 +176,425 @@ pub struct CommonResponse { #[serde(rename = "renewable")] pub renewable: bool, + #[serde(rename = "auth")] + pub auth: models::AuthResponseAllOfAuth, + } -impl CommonResponse { - pub fn new(request_id: String, lease_duration: i32, lease_id: String, renewable: bool, ) -> CommonResponse { - CommonResponse { +impl AuthResponse { + pub fn new(request_id: String, lease_duration: isize, lease_id: String, renewable: bool, auth: models::AuthResponseAllOfAuth, ) -> AuthResponse { + AuthResponse { request_id: request_id, lease_duration: lease_duration, lease_id: lease_id, renewable: renewable, + auth: auth, } } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct CreateTokenParameters { - #[serde(rename = "id")] - #[serde(skip_serializing_if="Option::is_none")] - pub id: Option, - - #[serde(rename = "policies")] - #[serde(skip_serializing_if="Option::is_none")] - pub policies: Option>, +/// Converts the AuthResponse value to the Query Parameters representation (style=form, explode=false) +/// specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde serializer +impl std::string::ToString for AuthResponse { + fn to_string(&self) -> String { + let mut params: Vec = vec![]; - #[serde(rename = "no_parent")] - #[serde(skip_serializing_if="Option::is_none")] - pub no_parent: Option, + params.push("request_id".to_string()); + params.push(self.request_id.to_string()); - #[serde(rename = "no_default_policy")] - #[serde(skip_serializing_if="Option::is_none")] - pub no_default_policy: Option, - #[serde(rename = "renewable")] - #[serde(skip_serializing_if="Option::is_none")] - pub renewable: Option, + params.push("lease_duration".to_string()); + params.push(self.lease_duration.to_string()); - #[serde(rename = "ttl")] - #[serde(skip_serializing_if="Option::is_none")] - pub ttl: Option, - #[serde(rename = "explicit_max_ttl")] - #[serde(skip_serializing_if="Option::is_none")] - pub explicit_max_ttl: Option, + params.push("lease_id".to_string()); + params.push(self.lease_id.to_string()); - #[serde(rename = "display_name")] - #[serde(skip_serializing_if="Option::is_none")] - pub display_name: Option, - #[serde(rename = "num_uses")] - #[serde(skip_serializing_if="Option::is_none")] - pub num_uses: Option, + params.push("renewable".to_string()); + params.push(self.renewable.to_string()); - #[serde(rename = "period")] - #[serde(skip_serializing_if="Option::is_none")] - pub period: Option, + // Skipping auth in query parameter serialization + params.join(",").to_string() + } } -impl CreateTokenParameters { - pub fn new() -> CreateTokenParameters { - CreateTokenParameters { - id: None, - policies: None, - no_parent: None, - no_default_policy: None, - renewable: None, - ttl: None, - explicit_max_ttl: None, - display_name: None, - num_uses: None, - period: None, +/// Converts Query Parameters representation (style=form, explode=false) to a AuthResponse value +/// as specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde deserializer +impl std::str::FromStr for AuthResponse { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + #[derive(Default)] + // An intermediate representation of the struct to use for parsing. + struct IntermediateRep { + pub request_id: Vec, + pub lease_duration: Vec, + pub lease_id: Vec, + pub renewable: Vec, + pub auth: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(',').into_iter(); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing AuthResponse".to_string()) + }; + + if let Some(key) = key_result { + match key { + "request_id" => intermediate_rep.request_id.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "lease_duration" => intermediate_rep.lease_duration.push(isize::from_str(val).map_err(|x| format!("{}", x))?), + "lease_id" => intermediate_rep.lease_id.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "renewable" => intermediate_rep.renewable.push(bool::from_str(val).map_err(|x| format!("{}", x))?), + "auth" => intermediate_rep.auth.push(models::AuthResponseAllOfAuth::from_str(val).map_err(|x| format!("{}", x))?), + _ => return std::result::Result::Err("Unexpected key while parsing AuthResponse".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(AuthResponse { + request_id: intermediate_rep.request_id.into_iter().next().ok_or("request_id missing in AuthResponse".to_string())?, + lease_duration: intermediate_rep.lease_duration.into_iter().next().ok_or("lease_duration missing in AuthResponse".to_string())?, + lease_id: intermediate_rep.lease_id.into_iter().next().ok_or("lease_id missing in AuthResponse".to_string())?, + renewable: intermediate_rep.renewable.into_iter().next().ok_or("renewable missing in AuthResponse".to_string())?, + auth: intermediate_rep.auth.into_iter().next().ok_or("auth missing in AuthResponse".to_string())?, + }) } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct GenerateCertificateParameters { - #[serde(rename = "common_name")] - pub common_name: String, - #[serde(rename = "alt_names")] - #[serde(skip_serializing_if="Option::is_none")] - pub alt_names: Option, - #[serde(rename = "ip_sans")] - #[serde(skip_serializing_if="Option::is_none")] - pub ip_sans: Option, +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue - #[serde(rename = "ttl")] - #[serde(skip_serializing_if="Option::is_none")] - pub ttl: Option, +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; - #[serde(rename = "format")] - #[serde(skip_serializing_if="Option::is_none")] - pub format: Option, + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for AuthResponseAllOf - value: {} is invalid {}", + hdr_value, e)) + } + } +} - #[serde(rename = "exclude_cn_from_sans")] - #[serde(skip_serializing_if="Option::is_none")] - pub exclude_cn_from_sans: Option, +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into AuthResponseAllOf - {}", + value, err)) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {:?} to string: {}", + hdr_value, e)) + } + } +} + + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct AuthResponseAllOf { + #[serde(rename = "auth")] + pub auth: models::AuthResponseAllOfAuth, } -impl GenerateCertificateParameters { - pub fn new(common_name: String, ) -> GenerateCertificateParameters { - GenerateCertificateParameters { - common_name: common_name, - alt_names: None, - ip_sans: None, - ttl: None, - format: None, - exclude_cn_from_sans: Some(false), +impl AuthResponseAllOf { + pub fn new(auth: models::AuthResponseAllOfAuth, ) -> AuthResponseAllOf { + AuthResponseAllOf { + auth: auth, } } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct GenerateCertificateResponseData { - #[serde(rename = "certificate")] - pub certificate: String, +/// Converts the AuthResponseAllOf value to the Query Parameters representation (style=form, explode=false) +/// specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde serializer +impl std::string::ToString for AuthResponseAllOf { + fn to_string(&self) -> String { + let mut params: Vec = vec![]; + // Skipping auth in query parameter serialization - #[serde(rename = "issuing_ca")] - pub issuing_ca: String, + params.join(",").to_string() + } +} - #[serde(rename = "ca_chain")] - #[serde(skip_serializing_if="Option::is_none")] - pub ca_chain: Option>, +/// Converts Query Parameters representation (style=form, explode=false) to a AuthResponseAllOf value +/// as specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde deserializer +impl std::str::FromStr for AuthResponseAllOf { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + #[derive(Default)] + // An intermediate representation of the struct to use for parsing. + struct IntermediateRep { + pub auth: Vec, + } - #[serde(rename = "private_key")] - pub private_key: String, + let mut intermediate_rep = IntermediateRep::default(); - #[serde(rename = "private_key_type")] - pub private_key_type: String, + // Parse into intermediate representation + let mut string_iter = s.split(',').into_iter(); + let mut key_result = string_iter.next(); - #[serde(rename = "serial_number")] - pub serial_number: String, + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing AuthResponseAllOf".to_string()) + }; -} + if let Some(key) = key_result { + match key { + "auth" => intermediate_rep.auth.push(models::AuthResponseAllOfAuth::from_str(val).map_err(|x| format!("{}", x))?), + _ => return std::result::Result::Err("Unexpected key while parsing AuthResponseAllOf".to_string()) + } + } -impl GenerateCertificateResponseData { - pub fn new(certificate: String, issuing_ca: String, private_key: String, private_key_type: String, serial_number: String, ) -> GenerateCertificateResponseData { - GenerateCertificateResponseData { - certificate: certificate, - issuing_ca: issuing_ca, - ca_chain: None, - private_key: private_key, - private_key_type: private_key_type, - serial_number: serial_number, + // Get the next key + key_result = string_iter.next(); } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(AuthResponseAllOf { + auth: intermediate_rep.auth.into_iter().next().ok_or("auth missing in AuthResponseAllOf".to_string())?, + }) } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct RenewSelfParameters { - #[serde(rename = "increment")] - #[serde(skip_serializing_if="Option::is_none")] - pub increment: Option, + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for AuthResponseAllOfAuth - value: {} is invalid {}", + hdr_value, e)) + } + } } -impl RenewSelfParameters { - pub fn new() -> RenewSelfParameters { - RenewSelfParameters { - increment: None, +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into AuthResponseAllOfAuth - {}", + value, err)) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {:?} to string: {}", + hdr_value, e)) } } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct RevokeLeaseParameters { - #[serde(rename = "lease_id")] - pub lease_id: String, + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct AuthResponseAllOfAuth { + #[serde(rename = "renewable")] + pub renewable: bool, + + #[serde(rename = "lease_duration")] + pub lease_duration: isize, + + #[serde(rename = "policies")] + pub policies: Vec, + + #[serde(rename = "accessor")] + pub accessor: String, + + #[serde(rename = "client_token")] + pub client_token: String, } -impl RevokeLeaseParameters { - pub fn new(lease_id: String, ) -> RevokeLeaseParameters { - RevokeLeaseParameters { - lease_id: lease_id, +impl AuthResponseAllOfAuth { + pub fn new(renewable: bool, lease_duration: isize, policies: Vec, accessor: String, client_token: String, ) -> AuthResponseAllOfAuth { + AuthResponseAllOfAuth { + renewable: renewable, + lease_duration: lease_duration, + policies: policies, + accessor: accessor, + client_token: client_token, } } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct AuthResponse { - #[serde(rename = "request_id")] - pub request_id: String, +/// Converts the AuthResponseAllOfAuth value to the Query Parameters representation (style=form, explode=false) +/// specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde serializer +impl std::string::ToString for AuthResponseAllOfAuth { + fn to_string(&self) -> String { + let mut params: Vec = vec![]; - #[serde(rename = "lease_duration")] - pub lease_duration: i32, + params.push("renewable".to_string()); + params.push(self.renewable.to_string()); - #[serde(rename = "lease_id")] - pub lease_id: String, - #[serde(rename = "renewable")] - pub renewable: bool, + params.push("lease_duration".to_string()); + params.push(self.lease_duration.to_string()); - #[serde(rename = "auth")] - #[serde(skip_serializing_if="Option::is_none")] - pub auth: Option, + params.push("policies".to_string()); + params.push(self.policies.iter().map(|x| x.to_string()).collect::>().join(",").to_string()); + + + params.push("accessor".to_string()); + params.push(self.accessor.to_string()); + + + params.push("client_token".to_string()); + params.push(self.client_token.to_string()); + + params.join(",").to_string() + } } -impl AuthResponse { - pub fn new(request_id: String, lease_duration: i32, lease_id: String, renewable: bool, ) -> AuthResponse { - AuthResponse { - request_id: request_id, - lease_duration: lease_duration, - lease_id: lease_id, - renewable: renewable, - auth: None, +/// Converts Query Parameters representation (style=form, explode=false) to a AuthResponseAllOfAuth value +/// as specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde deserializer +impl std::str::FromStr for AuthResponseAllOfAuth { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + #[derive(Default)] + // An intermediate representation of the struct to use for parsing. + struct IntermediateRep { + pub renewable: Vec, + pub lease_duration: Vec, + pub policies: Vec>, + pub accessor: Vec, + pub client_token: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(',').into_iter(); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing AuthResponseAllOfAuth".to_string()) + }; + + if let Some(key) = key_result { + match key { + "renewable" => intermediate_rep.renewable.push(bool::from_str(val).map_err(|x| format!("{}", x))?), + "lease_duration" => intermediate_rep.lease_duration.push(isize::from_str(val).map_err(|x| format!("{}", x))?), + "policies" => return std::result::Result::Err("Parsing a container in this style is not supported in AuthResponseAllOfAuth".to_string()), + "accessor" => intermediate_rep.accessor.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "client_token" => intermediate_rep.client_token.push(String::from_str(val).map_err(|x| format!("{}", x))?), + _ => return std::result::Result::Err("Unexpected key while parsing AuthResponseAllOfAuth".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(AuthResponseAllOfAuth { + renewable: intermediate_rep.renewable.into_iter().next().ok_or("renewable missing in AuthResponseAllOfAuth".to_string())?, + lease_duration: intermediate_rep.lease_duration.into_iter().next().ok_or("lease_duration missing in AuthResponseAllOfAuth".to_string())?, + policies: intermediate_rep.policies.into_iter().next().ok_or("policies missing in AuthResponseAllOfAuth".to_string())?, + accessor: intermediate_rep.accessor.into_iter().next().ok_or("accessor missing in AuthResponseAllOfAuth".to_string())?, + client_token: intermediate_rep.client_token.into_iter().next().ok_or("client_token missing in AuthResponseAllOfAuth".to_string())?, + }) + } +} + + + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for CertificateResponse - value: {} is invalid {}", + hdr_value, e)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into CertificateResponse - {}", + value, err)) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {:?} to string: {}", + hdr_value, e)) } } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct CertificateResponse { #[serde(rename = "request_id")] pub request_id: String, #[serde(rename = "lease_duration")] - pub lease_duration: i32, + pub lease_duration: isize, #[serde(rename = "lease_id")] pub lease_id: String, @@ -314,51 +603,1574 @@ pub struct CertificateResponse { pub renewable: bool, #[serde(rename = "data")] - #[serde(skip_serializing_if="Option::is_none")] - pub data: Option, + pub data: models::CertificateResponseAllOfData, } impl CertificateResponse { - pub fn new(request_id: String, lease_duration: i32, lease_id: String, renewable: bool, ) -> CertificateResponse { + pub fn new(request_id: String, lease_duration: isize, lease_id: String, renewable: bool, data: models::CertificateResponseAllOfData, ) -> CertificateResponse { CertificateResponse { request_id: request_id, lease_duration: lease_duration, lease_id: lease_id, renewable: renewable, - data: None, + data: data, } } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct GenerateCertificateResponse { - #[serde(rename = "request_id")] - pub request_id: String, +/// Converts the CertificateResponse value to the Query Parameters representation (style=form, explode=false) +/// specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde serializer +impl std::string::ToString for CertificateResponse { + fn to_string(&self) -> String { + let mut params: Vec = vec![]; - #[serde(rename = "lease_duration")] - pub lease_duration: i32, + params.push("request_id".to_string()); + params.push(self.request_id.to_string()); - #[serde(rename = "lease_id")] - pub lease_id: String, - #[serde(rename = "renewable")] - pub renewable: bool, + params.push("lease_duration".to_string()); + params.push(self.lease_duration.to_string()); - #[serde(rename = "data")] - #[serde(skip_serializing_if="Option::is_none")] - pub data: Option, -} + params.push("lease_id".to_string()); + params.push(self.lease_id.to_string()); -impl GenerateCertificateResponse { - pub fn new(request_id: String, lease_duration: i32, lease_id: String, renewable: bool, ) -> GenerateCertificateResponse { - GenerateCertificateResponse { - request_id: request_id, - lease_duration: lease_duration, - lease_id: lease_id, - renewable: renewable, - data: None, - } + + params.push("renewable".to_string()); + params.push(self.renewable.to_string()); + + // Skipping data in query parameter serialization + + params.join(",").to_string() } } + +/// Converts Query Parameters representation (style=form, explode=false) to a CertificateResponse value +/// as specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde deserializer +impl std::str::FromStr for CertificateResponse { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + #[derive(Default)] + // An intermediate representation of the struct to use for parsing. + struct IntermediateRep { + pub request_id: Vec, + pub lease_duration: Vec, + pub lease_id: Vec, + pub renewable: Vec, + pub data: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(',').into_iter(); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing CertificateResponse".to_string()) + }; + + if let Some(key) = key_result { + match key { + "request_id" => intermediate_rep.request_id.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "lease_duration" => intermediate_rep.lease_duration.push(isize::from_str(val).map_err(|x| format!("{}", x))?), + "lease_id" => intermediate_rep.lease_id.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "renewable" => intermediate_rep.renewable.push(bool::from_str(val).map_err(|x| format!("{}", x))?), + "data" => intermediate_rep.data.push(models::CertificateResponseAllOfData::from_str(val).map_err(|x| format!("{}", x))?), + _ => return std::result::Result::Err("Unexpected key while parsing CertificateResponse".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(CertificateResponse { + request_id: intermediate_rep.request_id.into_iter().next().ok_or("request_id missing in CertificateResponse".to_string())?, + lease_duration: intermediate_rep.lease_duration.into_iter().next().ok_or("lease_duration missing in CertificateResponse".to_string())?, + lease_id: intermediate_rep.lease_id.into_iter().next().ok_or("lease_id missing in CertificateResponse".to_string())?, + renewable: intermediate_rep.renewable.into_iter().next().ok_or("renewable missing in CertificateResponse".to_string())?, + data: intermediate_rep.data.into_iter().next().ok_or("data missing in CertificateResponse".to_string())?, + }) + } +} + + + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for CertificateResponseAllOf - value: {} is invalid {}", + hdr_value, e)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into CertificateResponseAllOf - {}", + value, err)) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {:?} to string: {}", + hdr_value, e)) + } + } +} + + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct CertificateResponseAllOf { + #[serde(rename = "data")] + pub data: models::CertificateResponseAllOfData, + +} + +impl CertificateResponseAllOf { + pub fn new(data: models::CertificateResponseAllOfData, ) -> CertificateResponseAllOf { + CertificateResponseAllOf { + data: data, + } + } +} + +/// Converts the CertificateResponseAllOf value to the Query Parameters representation (style=form, explode=false) +/// specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde serializer +impl std::string::ToString for CertificateResponseAllOf { + fn to_string(&self) -> String { + let mut params: Vec = vec![]; + // Skipping data in query parameter serialization + + params.join(",").to_string() + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a CertificateResponseAllOf value +/// as specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde deserializer +impl std::str::FromStr for CertificateResponseAllOf { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + #[derive(Default)] + // An intermediate representation of the struct to use for parsing. + struct IntermediateRep { + pub data: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(',').into_iter(); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing CertificateResponseAllOf".to_string()) + }; + + if let Some(key) = key_result { + match key { + "data" => intermediate_rep.data.push(models::CertificateResponseAllOfData::from_str(val).map_err(|x| format!("{}", x))?), + _ => return std::result::Result::Err("Unexpected key while parsing CertificateResponseAllOf".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(CertificateResponseAllOf { + data: intermediate_rep.data.into_iter().next().ok_or("data missing in CertificateResponseAllOf".to_string())?, + }) + } +} + + + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for CertificateResponseAllOfData - value: {} is invalid {}", + hdr_value, e)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into CertificateResponseAllOfData - {}", + value, err)) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {:?} to string: {}", + hdr_value, e)) + } + } +} + + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct CertificateResponseAllOfData { + #[serde(rename = "certificate")] + pub certificate: String, + +} + +impl CertificateResponseAllOfData { + pub fn new(certificate: String, ) -> CertificateResponseAllOfData { + CertificateResponseAllOfData { + certificate: certificate, + } + } +} + +/// Converts the CertificateResponseAllOfData value to the Query Parameters representation (style=form, explode=false) +/// specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde serializer +impl std::string::ToString for CertificateResponseAllOfData { + fn to_string(&self) -> String { + let mut params: Vec = vec![]; + + params.push("certificate".to_string()); + params.push(self.certificate.to_string()); + + params.join(",").to_string() + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a CertificateResponseAllOfData value +/// as specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde deserializer +impl std::str::FromStr for CertificateResponseAllOfData { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + #[derive(Default)] + // An intermediate representation of the struct to use for parsing. + struct IntermediateRep { + pub certificate: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(',').into_iter(); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing CertificateResponseAllOfData".to_string()) + }; + + if let Some(key) = key_result { + match key { + "certificate" => intermediate_rep.certificate.push(String::from_str(val).map_err(|x| format!("{}", x))?), + _ => return std::result::Result::Err("Unexpected key while parsing CertificateResponseAllOfData".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(CertificateResponseAllOfData { + certificate: intermediate_rep.certificate.into_iter().next().ok_or("certificate missing in CertificateResponseAllOfData".to_string())?, + }) + } +} + + + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for CommonResponse - value: {} is invalid {}", + hdr_value, e)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into CommonResponse - {}", + value, err)) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {:?} to string: {}", + hdr_value, e)) + } + } +} + + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct CommonResponse { + #[serde(rename = "request_id")] + pub request_id: String, + + #[serde(rename = "lease_duration")] + pub lease_duration: isize, + + #[serde(rename = "lease_id")] + pub lease_id: String, + + #[serde(rename = "renewable")] + pub renewable: bool, + +} + +impl CommonResponse { + pub fn new(request_id: String, lease_duration: isize, lease_id: String, renewable: bool, ) -> CommonResponse { + CommonResponse { + request_id: request_id, + lease_duration: lease_duration, + lease_id: lease_id, + renewable: renewable, + } + } +} + +/// Converts the CommonResponse value to the Query Parameters representation (style=form, explode=false) +/// specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde serializer +impl std::string::ToString for CommonResponse { + fn to_string(&self) -> String { + let mut params: Vec = vec![]; + + params.push("request_id".to_string()); + params.push(self.request_id.to_string()); + + + params.push("lease_duration".to_string()); + params.push(self.lease_duration.to_string()); + + + params.push("lease_id".to_string()); + params.push(self.lease_id.to_string()); + + + params.push("renewable".to_string()); + params.push(self.renewable.to_string()); + + params.join(",").to_string() + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a CommonResponse value +/// as specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde deserializer +impl std::str::FromStr for CommonResponse { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + #[derive(Default)] + // An intermediate representation of the struct to use for parsing. + struct IntermediateRep { + pub request_id: Vec, + pub lease_duration: Vec, + pub lease_id: Vec, + pub renewable: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(',').into_iter(); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing CommonResponse".to_string()) + }; + + if let Some(key) = key_result { + match key { + "request_id" => intermediate_rep.request_id.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "lease_duration" => intermediate_rep.lease_duration.push(isize::from_str(val).map_err(|x| format!("{}", x))?), + "lease_id" => intermediate_rep.lease_id.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "renewable" => intermediate_rep.renewable.push(bool::from_str(val).map_err(|x| format!("{}", x))?), + _ => return std::result::Result::Err("Unexpected key while parsing CommonResponse".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(CommonResponse { + request_id: intermediate_rep.request_id.into_iter().next().ok_or("request_id missing in CommonResponse".to_string())?, + lease_duration: intermediate_rep.lease_duration.into_iter().next().ok_or("lease_duration missing in CommonResponse".to_string())?, + lease_id: intermediate_rep.lease_id.into_iter().next().ok_or("lease_id missing in CommonResponse".to_string())?, + renewable: intermediate_rep.renewable.into_iter().next().ok_or("renewable missing in CommonResponse".to_string())?, + }) + } +} + + + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for CreateTokenParameters - value: {} is invalid {}", + hdr_value, e)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into CreateTokenParameters - {}", + value, err)) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {:?} to string: {}", + hdr_value, e)) + } + } +} + + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct CreateTokenParameters { + #[serde(rename = "id")] + #[serde(skip_serializing_if="Option::is_none")] + pub id: Option, + + #[serde(rename = "policies")] + #[serde(skip_serializing_if="Option::is_none")] + pub policies: Option>, + + #[serde(rename = "no_parent")] + #[serde(skip_serializing_if="Option::is_none")] + pub no_parent: Option, + + #[serde(rename = "no_default_policy")] + #[serde(skip_serializing_if="Option::is_none")] + pub no_default_policy: Option, + + #[serde(rename = "renewable")] + #[serde(skip_serializing_if="Option::is_none")] + pub renewable: Option, + + #[serde(rename = "ttl")] + #[serde(skip_serializing_if="Option::is_none")] + pub ttl: Option, + + #[serde(rename = "explicit_max_ttl")] + #[serde(skip_serializing_if="Option::is_none")] + pub explicit_max_ttl: Option, + + #[serde(rename = "display_name")] + #[serde(skip_serializing_if="Option::is_none")] + pub display_name: Option, + + #[serde(rename = "num_uses")] + #[serde(skip_serializing_if="Option::is_none")] + pub num_uses: Option, + + #[serde(rename = "period")] + #[serde(skip_serializing_if="Option::is_none")] + pub period: Option, + +} + +impl CreateTokenParameters { + pub fn new() -> CreateTokenParameters { + CreateTokenParameters { + id: None, + policies: None, + no_parent: None, + no_default_policy: None, + renewable: None, + ttl: None, + explicit_max_ttl: None, + display_name: None, + num_uses: None, + period: None, + } + } +} + +/// Converts the CreateTokenParameters value to the Query Parameters representation (style=form, explode=false) +/// specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde serializer +impl std::string::ToString for CreateTokenParameters { + fn to_string(&self) -> String { + let mut params: Vec = vec![]; + + if let Some(ref id) = self.id { + params.push("id".to_string()); + params.push(id.to_string()); + } + + + if let Some(ref policies) = self.policies { + params.push("policies".to_string()); + params.push(policies.iter().map(|x| x.to_string()).collect::>().join(",").to_string()); + } + + + if let Some(ref no_parent) = self.no_parent { + params.push("no_parent".to_string()); + params.push(no_parent.to_string()); + } + + + if let Some(ref no_default_policy) = self.no_default_policy { + params.push("no_default_policy".to_string()); + params.push(no_default_policy.to_string()); + } + + + if let Some(ref renewable) = self.renewable { + params.push("renewable".to_string()); + params.push(renewable.to_string()); + } + + + if let Some(ref ttl) = self.ttl { + params.push("ttl".to_string()); + params.push(ttl.to_string()); + } + + + if let Some(ref explicit_max_ttl) = self.explicit_max_ttl { + params.push("explicit_max_ttl".to_string()); + params.push(explicit_max_ttl.to_string()); + } + + + if let Some(ref display_name) = self.display_name { + params.push("display_name".to_string()); + params.push(display_name.to_string()); + } + + + if let Some(ref num_uses) = self.num_uses { + params.push("num_uses".to_string()); + params.push(num_uses.to_string()); + } + + + if let Some(ref period) = self.period { + params.push("period".to_string()); + params.push(period.to_string()); + } + + params.join(",").to_string() + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a CreateTokenParameters value +/// as specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde deserializer +impl std::str::FromStr for CreateTokenParameters { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + #[derive(Default)] + // An intermediate representation of the struct to use for parsing. + struct IntermediateRep { + pub id: Vec, + pub policies: Vec>, + pub no_parent: Vec, + pub no_default_policy: Vec, + pub renewable: Vec, + pub ttl: Vec, + pub explicit_max_ttl: Vec, + pub display_name: Vec, + pub num_uses: Vec, + pub period: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(',').into_iter(); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing CreateTokenParameters".to_string()) + }; + + if let Some(key) = key_result { + match key { + "id" => intermediate_rep.id.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "policies" => return std::result::Result::Err("Parsing a container in this style is not supported in CreateTokenParameters".to_string()), + "no_parent" => intermediate_rep.no_parent.push(bool::from_str(val).map_err(|x| format!("{}", x))?), + "no_default_policy" => intermediate_rep.no_default_policy.push(bool::from_str(val).map_err(|x| format!("{}", x))?), + "renewable" => intermediate_rep.renewable.push(bool::from_str(val).map_err(|x| format!("{}", x))?), + "ttl" => intermediate_rep.ttl.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "explicit_max_ttl" => intermediate_rep.explicit_max_ttl.push(bool::from_str(val).map_err(|x| format!("{}", x))?), + "display_name" => intermediate_rep.display_name.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "num_uses" => intermediate_rep.num_uses.push(isize::from_str(val).map_err(|x| format!("{}", x))?), + "period" => intermediate_rep.period.push(String::from_str(val).map_err(|x| format!("{}", x))?), + _ => return std::result::Result::Err("Unexpected key while parsing CreateTokenParameters".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(CreateTokenParameters { + id: intermediate_rep.id.into_iter().next(), + policies: intermediate_rep.policies.into_iter().next(), + no_parent: intermediate_rep.no_parent.into_iter().next(), + no_default_policy: intermediate_rep.no_default_policy.into_iter().next(), + renewable: intermediate_rep.renewable.into_iter().next(), + ttl: intermediate_rep.ttl.into_iter().next(), + explicit_max_ttl: intermediate_rep.explicit_max_ttl.into_iter().next(), + display_name: intermediate_rep.display_name.into_iter().next(), + num_uses: intermediate_rep.num_uses.into_iter().next(), + period: intermediate_rep.period.into_iter().next(), + }) + } +} + + + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for GenerateCertificateParameters - value: {} is invalid {}", + hdr_value, e)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into GenerateCertificateParameters - {}", + value, err)) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {:?} to string: {}", + hdr_value, e)) + } + } +} + + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct GenerateCertificateParameters { + #[serde(rename = "common_name")] + pub common_name: String, + + #[serde(rename = "alt_names")] + #[serde(skip_serializing_if="Option::is_none")] + pub alt_names: Option, + + #[serde(rename = "ip_sans")] + #[serde(skip_serializing_if="Option::is_none")] + pub ip_sans: Option, + + #[serde(rename = "ttl")] + #[serde(skip_serializing_if="Option::is_none")] + pub ttl: Option, + + #[serde(rename = "format")] + #[serde(skip_serializing_if="Option::is_none")] + pub format: Option, + + #[serde(rename = "exclude_cn_from_sans")] + #[serde(skip_serializing_if="Option::is_none")] + pub exclude_cn_from_sans: Option, + +} + +impl GenerateCertificateParameters { + pub fn new(common_name: String, ) -> GenerateCertificateParameters { + GenerateCertificateParameters { + common_name: common_name, + alt_names: None, + ip_sans: None, + ttl: None, + format: None, + exclude_cn_from_sans: Some(false), + } + } +} + +/// Converts the GenerateCertificateParameters value to the Query Parameters representation (style=form, explode=false) +/// specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde serializer +impl std::string::ToString for GenerateCertificateParameters { + fn to_string(&self) -> String { + let mut params: Vec = vec![]; + + params.push("common_name".to_string()); + params.push(self.common_name.to_string()); + + + if let Some(ref alt_names) = self.alt_names { + params.push("alt_names".to_string()); + params.push(alt_names.to_string()); + } + + + if let Some(ref ip_sans) = self.ip_sans { + params.push("ip_sans".to_string()); + params.push(ip_sans.to_string()); + } + + + if let Some(ref ttl) = self.ttl { + params.push("ttl".to_string()); + params.push(ttl.to_string()); + } + + + if let Some(ref format) = self.format { + params.push("format".to_string()); + params.push(format.to_string()); + } + + + if let Some(ref exclude_cn_from_sans) = self.exclude_cn_from_sans { + params.push("exclude_cn_from_sans".to_string()); + params.push(exclude_cn_from_sans.to_string()); + } + + params.join(",").to_string() + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a GenerateCertificateParameters value +/// as specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde deserializer +impl std::str::FromStr for GenerateCertificateParameters { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + #[derive(Default)] + // An intermediate representation of the struct to use for parsing. + struct IntermediateRep { + pub common_name: Vec, + pub alt_names: Vec, + pub ip_sans: Vec, + pub ttl: Vec, + pub format: Vec, + pub exclude_cn_from_sans: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(',').into_iter(); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing GenerateCertificateParameters".to_string()) + }; + + if let Some(key) = key_result { + match key { + "common_name" => intermediate_rep.common_name.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "alt_names" => intermediate_rep.alt_names.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "ip_sans" => intermediate_rep.ip_sans.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "ttl" => intermediate_rep.ttl.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "format" => intermediate_rep.format.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "exclude_cn_from_sans" => intermediate_rep.exclude_cn_from_sans.push(bool::from_str(val).map_err(|x| format!("{}", x))?), + _ => return std::result::Result::Err("Unexpected key while parsing GenerateCertificateParameters".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(GenerateCertificateParameters { + common_name: intermediate_rep.common_name.into_iter().next().ok_or("common_name missing in GenerateCertificateParameters".to_string())?, + alt_names: intermediate_rep.alt_names.into_iter().next(), + ip_sans: intermediate_rep.ip_sans.into_iter().next(), + ttl: intermediate_rep.ttl.into_iter().next(), + format: intermediate_rep.format.into_iter().next(), + exclude_cn_from_sans: intermediate_rep.exclude_cn_from_sans.into_iter().next(), + }) + } +} + + + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for GenerateCertificateResponse - value: {} is invalid {}", + hdr_value, e)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into GenerateCertificateResponse - {}", + value, err)) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {:?} to string: {}", + hdr_value, e)) + } + } +} + + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct GenerateCertificateResponse { + #[serde(rename = "request_id")] + pub request_id: String, + + #[serde(rename = "lease_duration")] + pub lease_duration: isize, + + #[serde(rename = "lease_id")] + pub lease_id: String, + + #[serde(rename = "renewable")] + pub renewable: bool, + + #[serde(rename = "data")] + pub data: models::GenerateCertificateResponseAllOfData, + +} + +impl GenerateCertificateResponse { + pub fn new(request_id: String, lease_duration: isize, lease_id: String, renewable: bool, data: models::GenerateCertificateResponseAllOfData, ) -> GenerateCertificateResponse { + GenerateCertificateResponse { + request_id: request_id, + lease_duration: lease_duration, + lease_id: lease_id, + renewable: renewable, + data: data, + } + } +} + +/// Converts the GenerateCertificateResponse value to the Query Parameters representation (style=form, explode=false) +/// specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde serializer +impl std::string::ToString for GenerateCertificateResponse { + fn to_string(&self) -> String { + let mut params: Vec = vec![]; + + params.push("request_id".to_string()); + params.push(self.request_id.to_string()); + + + params.push("lease_duration".to_string()); + params.push(self.lease_duration.to_string()); + + + params.push("lease_id".to_string()); + params.push(self.lease_id.to_string()); + + + params.push("renewable".to_string()); + params.push(self.renewable.to_string()); + + // Skipping data in query parameter serialization + + params.join(",").to_string() + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a GenerateCertificateResponse value +/// as specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde deserializer +impl std::str::FromStr for GenerateCertificateResponse { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + #[derive(Default)] + // An intermediate representation of the struct to use for parsing. + struct IntermediateRep { + pub request_id: Vec, + pub lease_duration: Vec, + pub lease_id: Vec, + pub renewable: Vec, + pub data: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(',').into_iter(); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing GenerateCertificateResponse".to_string()) + }; + + if let Some(key) = key_result { + match key { + "request_id" => intermediate_rep.request_id.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "lease_duration" => intermediate_rep.lease_duration.push(isize::from_str(val).map_err(|x| format!("{}", x))?), + "lease_id" => intermediate_rep.lease_id.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "renewable" => intermediate_rep.renewable.push(bool::from_str(val).map_err(|x| format!("{}", x))?), + "data" => intermediate_rep.data.push(models::GenerateCertificateResponseAllOfData::from_str(val).map_err(|x| format!("{}", x))?), + _ => return std::result::Result::Err("Unexpected key while parsing GenerateCertificateResponse".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(GenerateCertificateResponse { + request_id: intermediate_rep.request_id.into_iter().next().ok_or("request_id missing in GenerateCertificateResponse".to_string())?, + lease_duration: intermediate_rep.lease_duration.into_iter().next().ok_or("lease_duration missing in GenerateCertificateResponse".to_string())?, + lease_id: intermediate_rep.lease_id.into_iter().next().ok_or("lease_id missing in GenerateCertificateResponse".to_string())?, + renewable: intermediate_rep.renewable.into_iter().next().ok_or("renewable missing in GenerateCertificateResponse".to_string())?, + data: intermediate_rep.data.into_iter().next().ok_or("data missing in GenerateCertificateResponse".to_string())?, + }) + } +} + + + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for GenerateCertificateResponseAllOf - value: {} is invalid {}", + hdr_value, e)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into GenerateCertificateResponseAllOf - {}", + value, err)) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {:?} to string: {}", + hdr_value, e)) + } + } +} + + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct GenerateCertificateResponseAllOf { + #[serde(rename = "data")] + pub data: models::GenerateCertificateResponseAllOfData, + +} + +impl GenerateCertificateResponseAllOf { + pub fn new(data: models::GenerateCertificateResponseAllOfData, ) -> GenerateCertificateResponseAllOf { + GenerateCertificateResponseAllOf { + data: data, + } + } +} + +/// Converts the GenerateCertificateResponseAllOf value to the Query Parameters representation (style=form, explode=false) +/// specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde serializer +impl std::string::ToString for GenerateCertificateResponseAllOf { + fn to_string(&self) -> String { + let mut params: Vec = vec![]; + // Skipping data in query parameter serialization + + params.join(",").to_string() + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a GenerateCertificateResponseAllOf value +/// as specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde deserializer +impl std::str::FromStr for GenerateCertificateResponseAllOf { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + #[derive(Default)] + // An intermediate representation of the struct to use for parsing. + struct IntermediateRep { + pub data: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(',').into_iter(); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing GenerateCertificateResponseAllOf".to_string()) + }; + + if let Some(key) = key_result { + match key { + "data" => intermediate_rep.data.push(models::GenerateCertificateResponseAllOfData::from_str(val).map_err(|x| format!("{}", x))?), + _ => return std::result::Result::Err("Unexpected key while parsing GenerateCertificateResponseAllOf".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(GenerateCertificateResponseAllOf { + data: intermediate_rep.data.into_iter().next().ok_or("data missing in GenerateCertificateResponseAllOf".to_string())?, + }) + } +} + + + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for GenerateCertificateResponseAllOfData - value: {} is invalid {}", + hdr_value, e)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into GenerateCertificateResponseAllOfData - {}", + value, err)) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {:?} to string: {}", + hdr_value, e)) + } + } +} + + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct GenerateCertificateResponseAllOfData { + #[serde(rename = "certificate")] + pub certificate: String, + + #[serde(rename = "issuing_ca")] + pub issuing_ca: String, + + #[serde(rename = "ca_chain")] + #[serde(skip_serializing_if="Option::is_none")] + pub ca_chain: Option>, + + #[serde(rename = "private_key")] + pub private_key: String, + + #[serde(rename = "private_key_type")] + pub private_key_type: String, + + #[serde(rename = "serial_number")] + pub serial_number: String, + +} + +impl GenerateCertificateResponseAllOfData { + pub fn new(certificate: String, issuing_ca: String, private_key: String, private_key_type: String, serial_number: String, ) -> GenerateCertificateResponseAllOfData { + GenerateCertificateResponseAllOfData { + certificate: certificate, + issuing_ca: issuing_ca, + ca_chain: None, + private_key: private_key, + private_key_type: private_key_type, + serial_number: serial_number, + } + } +} + +/// Converts the GenerateCertificateResponseAllOfData value to the Query Parameters representation (style=form, explode=false) +/// specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde serializer +impl std::string::ToString for GenerateCertificateResponseAllOfData { + fn to_string(&self) -> String { + let mut params: Vec = vec![]; + + params.push("certificate".to_string()); + params.push(self.certificate.to_string()); + + + params.push("issuing_ca".to_string()); + params.push(self.issuing_ca.to_string()); + + + if let Some(ref ca_chain) = self.ca_chain { + params.push("ca_chain".to_string()); + params.push(ca_chain.iter().map(|x| x.to_string()).collect::>().join(",").to_string()); + } + + + params.push("private_key".to_string()); + params.push(self.private_key.to_string()); + + + params.push("private_key_type".to_string()); + params.push(self.private_key_type.to_string()); + + + params.push("serial_number".to_string()); + params.push(self.serial_number.to_string()); + + params.join(",").to_string() + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a GenerateCertificateResponseAllOfData value +/// as specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde deserializer +impl std::str::FromStr for GenerateCertificateResponseAllOfData { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + #[derive(Default)] + // An intermediate representation of the struct to use for parsing. + struct IntermediateRep { + pub certificate: Vec, + pub issuing_ca: Vec, + pub ca_chain: Vec>, + pub private_key: Vec, + pub private_key_type: Vec, + pub serial_number: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(',').into_iter(); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing GenerateCertificateResponseAllOfData".to_string()) + }; + + if let Some(key) = key_result { + match key { + "certificate" => intermediate_rep.certificate.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "issuing_ca" => intermediate_rep.issuing_ca.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "ca_chain" => return std::result::Result::Err("Parsing a container in this style is not supported in GenerateCertificateResponseAllOfData".to_string()), + "private_key" => intermediate_rep.private_key.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "private_key_type" => intermediate_rep.private_key_type.push(String::from_str(val).map_err(|x| format!("{}", x))?), + "serial_number" => intermediate_rep.serial_number.push(String::from_str(val).map_err(|x| format!("{}", x))?), + _ => return std::result::Result::Err("Unexpected key while parsing GenerateCertificateResponseAllOfData".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(GenerateCertificateResponseAllOfData { + certificate: intermediate_rep.certificate.into_iter().next().ok_or("certificate missing in GenerateCertificateResponseAllOfData".to_string())?, + issuing_ca: intermediate_rep.issuing_ca.into_iter().next().ok_or("issuing_ca missing in GenerateCertificateResponseAllOfData".to_string())?, + ca_chain: intermediate_rep.ca_chain.into_iter().next(), + private_key: intermediate_rep.private_key.into_iter().next().ok_or("private_key missing in GenerateCertificateResponseAllOfData".to_string())?, + private_key_type: intermediate_rep.private_key_type.into_iter().next().ok_or("private_key_type missing in GenerateCertificateResponseAllOfData".to_string())?, + serial_number: intermediate_rep.serial_number.into_iter().next().ok_or("serial_number missing in GenerateCertificateResponseAllOfData".to_string())?, + }) + } +} + + + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for RenewSelfParameters - value: {} is invalid {}", + hdr_value, e)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into RenewSelfParameters - {}", + value, err)) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {:?} to string: {}", + hdr_value, e)) + } + } +} + + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct RenewSelfParameters { + #[serde(rename = "increment")] + #[serde(skip_serializing_if="Option::is_none")] + pub increment: Option, + +} + +impl RenewSelfParameters { + pub fn new() -> RenewSelfParameters { + RenewSelfParameters { + increment: None, + } + } +} + +/// Converts the RenewSelfParameters value to the Query Parameters representation (style=form, explode=false) +/// specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde serializer +impl std::string::ToString for RenewSelfParameters { + fn to_string(&self) -> String { + let mut params: Vec = vec![]; + + if let Some(ref increment) = self.increment { + params.push("increment".to_string()); + params.push(increment.to_string()); + } + + params.join(",").to_string() + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a RenewSelfParameters value +/// as specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde deserializer +impl std::str::FromStr for RenewSelfParameters { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + #[derive(Default)] + // An intermediate representation of the struct to use for parsing. + struct IntermediateRep { + pub increment: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(',').into_iter(); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing RenewSelfParameters".to_string()) + }; + + if let Some(key) = key_result { + match key { + "increment" => intermediate_rep.increment.push(String::from_str(val).map_err(|x| format!("{}", x))?), + _ => return std::result::Result::Err("Unexpected key while parsing RenewSelfParameters".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(RenewSelfParameters { + increment: intermediate_rep.increment.into_iter().next(), + }) + } +} + + + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for RevokeLeaseParameters - value: {} is invalid {}", + hdr_value, e)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into RevokeLeaseParameters - {}", + value, err)) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {:?} to string: {}", + hdr_value, e)) + } + } +} + + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct RevokeLeaseParameters { + #[serde(rename = "lease_id")] + pub lease_id: String, + +} + +impl RevokeLeaseParameters { + pub fn new(lease_id: String, ) -> RevokeLeaseParameters { + RevokeLeaseParameters { + lease_id: lease_id, + } + } +} + +/// Converts the RevokeLeaseParameters value to the Query Parameters representation (style=form, explode=false) +/// specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde serializer +impl std::string::ToString for RevokeLeaseParameters { + fn to_string(&self) -> String { + let mut params: Vec = vec![]; + + params.push("lease_id".to_string()); + params.push(self.lease_id.to_string()); + + params.join(",").to_string() + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a RevokeLeaseParameters value +/// as specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde deserializer +impl std::str::FromStr for RevokeLeaseParameters { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + #[derive(Default)] + // An intermediate representation of the struct to use for parsing. + struct IntermediateRep { + pub lease_id: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(',').into_iter(); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing RevokeLeaseParameters".to_string()) + }; + + if let Some(key) = key_result { + match key { + "lease_id" => intermediate_rep.lease_id.push(String::from_str(val).map_err(|x| format!("{}", x))?), + _ => return std::result::Result::Err("Unexpected key while parsing RevokeLeaseParameters".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(RevokeLeaseParameters { + lease_id: intermediate_rep.lease_id.into_iter().next().ok_or("lease_id missing in RevokeLeaseParameters".to_string())?, + }) + } +} + + diff --git a/vault-api/src/server.rs b/vault-api/src/server.rs deleted file mode 100644 index d8f7bc8..0000000 --- a/vault-api/src/server.rs +++ /dev/null @@ -1,605 +0,0 @@ -#![allow(unused_extern_crates)] -extern crate serde_ignored; -extern crate iron; -extern crate router; -extern crate bodyparser; -extern crate urlencoded; -extern crate uuid; -extern crate chrono; - - -use futures::Future; -use futures::future; -use futures::{stream, Stream}; -use hyper; -use hyper::header::{Headers, ContentType}; -use self::iron::prelude::*; -use self::iron::{status, modifiers, BeforeMiddleware}; -use self::iron::url::percent_encoding::percent_decode; -use self::router::Router; -use self::urlencoded::UrlEncodedQuery; -use mimetypes; - - -use serde_json; - - -#[allow(unused_imports)] -use std::collections::{HashMap, BTreeMap}; -#[allow(unused_imports)] -use swagger; -use std::io::Error; - -#[allow(unused_imports)] -use std::collections::BTreeSet; - -pub use swagger::auth::Authorization; -use swagger::auth::{AuthData, Scopes}; -use swagger::{ApiError, Context, XSpanId}; - -use {Api, - SysLeasesRevokePutResponse, - GenerateCertResponse, - ReadCertResponse, - CreateOrphanTokenResponse, - CreateTokenResponse, - LogInWithTLSCertificateResponse, - RenewOwnTokenResponse - }; -#[allow(unused_imports)] -use models; - -header! { (Warning, "Warning") => [String] } - -/// Create a new router for `Api` -pub fn router(api: T) -> Router where T: Api + Send + Sync + Clone + 'static { - let mut router = Router::new(); - add_routes(&mut router, api); - router -} - -/// Add routes for `Api` to a provided router. -/// -/// Note that these routes are added straight onto the router. This means that if the router -/// already has a route for an endpoint which clashes with those provided by this API, then the -/// old route will be lost. -/// -/// It is generally a bad idea to add routes in this way to an existing router, which may have -/// routes on it for other APIs. Distinct APIs should be behind distinct paths to encourage -/// separation of interfaces, which this function does not enforce. APIs should not overlap. -/// -/// Alternative approaches include: -/// -/// - generate an `iron::middleware::Handler` (usually a `router::Router` or -/// `iron::middleware::chain`) for each interface, and add those handlers inside an existing -/// router, mounted at different paths - so the interfaces are separated by path -/// - use a different instance of `iron::Iron` for each interface - so the interfaces are -/// separated by the address/port they listen on -/// -/// This function exists to allow legacy code, which doesn't separate its APIs properly, to make -/// use of this crate. -#[deprecated(note="APIs should not overlap - only for use in legacy code.")] -pub fn route(router: &mut Router, api: T) where T: Api + Send + Sync + Clone + 'static { - add_routes(router, api) -} - -/// Add routes for `Api` to a provided router -fn add_routes(router: &mut Router, api: T) where T: Api + Send + Sync + Clone + 'static { - - let api_clone = api.clone(); - router.put( - "/v1/sys/leases/revoke", - move |req: &mut Request| { - let mut context = Context::default(); - - // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). - fn handle_request(req: &mut Request, api: &T, context: &mut Context) -> Result where T: Api { - - context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); - context.auth_data = req.extensions.remove::(); - context.authorization = req.extensions.remove::(); - - - - // Header parameters - header! { (RequestXVaultToken, "X-Vault-Token") => [String] } - let param_x_vault_token = req.headers.get::().ok_or_else(|| Response::with((status::BadRequest, "Missing or invalid required header X-Vault-Token".to_string())))?.0.clone(); - - - // Body parameters (note that non-required body parameters will ignore garbage - // values, rather than causing a 400 response). Produce warning header and logs for - // any unused fields. - - let param_body_raw = req.get::().map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter body - not valid UTF-8: {}", e))))?; - let mut unused_elements = Vec::new(); - - let param_body = if let Some(param_body_raw) = param_body_raw { - let deserializer = &mut serde_json::Deserializer::from_str(¶m_body_raw); - - let param_body: Option = serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }).map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter body - doesn't match schema: {}", e))))?; - - param_body - } else { - None - }; - let param_body = param_body.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter body".to_string())))?; - - - match api.sys_leases_revoke_put(param_x_vault_token, param_body, context).wait() { - Ok(rsp) => match rsp { - SysLeasesRevokePutResponse::Success => { - - - let mut response = Response::with((status::Status::from_u16(204))); - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } - Ok(response) - }, - }, - Err(_) => { - // Application code returned an error. This should not happen, as the implementation should - // return a valid response. - Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) - } - } - } - - handle_request(req, &api_clone, &mut context).or_else(|mut response| { - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - Ok(response) - }) - }, - "SysLeasesRevokePut"); - - let api_clone = api.clone(); - router.post( - "/v1/:mount/issue/:name", - move |req: &mut Request| { - let mut context = Context::default(); - - // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). - fn handle_request(req: &mut Request, api: &T, context: &mut Context) -> Result where T: Api { - - context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); - context.auth_data = req.extensions.remove::(); - context.authorization = req.extensions.remove::(); - - - - // Path parameters - let param_mount = { - let param = req.extensions.get::().ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? - .find("mount").ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter mount".to_string())))?; - percent_decode(param.as_bytes()).decode_utf8() - .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? - .parse().map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter mount: {}", e))))? - }; - let param_name = { - let param = req.extensions.get::().ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? - .find("name").ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter name".to_string())))?; - percent_decode(param.as_bytes()).decode_utf8() - .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? - .parse().map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter name: {}", e))))? - }; - - // Header parameters - header! { (RequestXVaultToken, "X-Vault-Token") => [String] } - let param_x_vault_token = req.headers.get::().ok_or_else(|| Response::with((status::BadRequest, "Missing or invalid required header X-Vault-Token".to_string())))?.0.clone(); - - - // Body parameters (note that non-required body parameters will ignore garbage - // values, rather than causing a 400 response). Produce warning header and logs for - // any unused fields. - - let param_body_raw = req.get::().map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter body - not valid UTF-8: {}", e))))?; - let mut unused_elements = Vec::new(); - - let param_body = if let Some(param_body_raw) = param_body_raw { - let deserializer = &mut serde_json::Deserializer::from_str(¶m_body_raw); - - let param_body: Option = serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }).map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter body - doesn't match schema: {}", e))))?; - - param_body - } else { - None - }; - let param_body = param_body.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter body".to_string())))?; - - - match api.generate_cert(param_x_vault_token, param_mount, param_name, param_body, context).wait() { - Ok(rsp) => match rsp { - GenerateCertResponse::Success(body) => { - - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::GENERATE_CERT_SUCCESS.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } - Ok(response) - }, - }, - Err(_) => { - // Application code returned an error. This should not happen, as the implementation should - // return a valid response. - Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) - } - } - } - - handle_request(req, &api_clone, &mut context).or_else(|mut response| { - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - Ok(response) - }) - }, - "GenerateCert"); - - let api_clone = api.clone(); - router.get( - "/v1/:mount/cert/:serial", - move |req: &mut Request| { - let mut context = Context::default(); - - // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). - fn handle_request(req: &mut Request, api: &T, context: &mut Context) -> Result where T: Api { - - context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); - context.auth_data = req.extensions.remove::(); - context.authorization = req.extensions.remove::(); - - - - // Path parameters - let param_mount = { - let param = req.extensions.get::().ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? - .find("mount").ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter mount".to_string())))?; - percent_decode(param.as_bytes()).decode_utf8() - .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? - .parse().map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter mount: {}", e))))? - }; - let param_serial = { - let param = req.extensions.get::().ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? - .find("serial").ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter serial".to_string())))?; - percent_decode(param.as_bytes()).decode_utf8() - .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? - .parse().map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter serial: {}", e))))? - }; - - - - match api.read_cert(param_mount, param_serial, context).wait() { - Ok(rsp) => match rsp { - ReadCertResponse::Success(body) => { - - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::READ_CERT_SUCCESS.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - }, - }, - Err(_) => { - // Application code returned an error. This should not happen, as the implementation should - // return a valid response. - Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) - } - } - } - - handle_request(req, &api_clone, &mut context).or_else(|mut response| { - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - Ok(response) - }) - }, - "ReadCert"); - - let api_clone = api.clone(); - router.post( - "/v1/auth/token/create-orphan", - move |req: &mut Request| { - let mut context = Context::default(); - - // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). - fn handle_request(req: &mut Request, api: &T, context: &mut Context) -> Result where T: Api { - - context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); - context.auth_data = req.extensions.remove::(); - context.authorization = req.extensions.remove::(); - - - - // Header parameters - header! { (RequestXVaultToken, "X-Vault-Token") => [String] } - let param_x_vault_token = req.headers.get::().ok_or_else(|| Response::with((status::BadRequest, "Missing or invalid required header X-Vault-Token".to_string())))?.0.clone(); - - - // Body parameters (note that non-required body parameters will ignore garbage - // values, rather than causing a 400 response). Produce warning header and logs for - // any unused fields. - - let param_body_raw = req.get::().map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter body - not valid UTF-8: {}", e))))?; - let mut unused_elements = Vec::new(); - - let param_body = if let Some(param_body_raw) = param_body_raw { - let deserializer = &mut serde_json::Deserializer::from_str(¶m_body_raw); - - let param_body: Option = serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }).map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter body - doesn't match schema: {}", e))))?; - - param_body - } else { - None - }; - let param_body = param_body.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter body".to_string())))?; - - - match api.create_orphan_token(param_x_vault_token, param_body, context).wait() { - Ok(rsp) => match rsp { - CreateOrphanTokenResponse::Success(body) => { - - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::CREATE_ORPHAN_TOKEN_SUCCESS.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } - Ok(response) - }, - }, - Err(_) => { - // Application code returned an error. This should not happen, as the implementation should - // return a valid response. - Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) - } - } - } - - handle_request(req, &api_clone, &mut context).or_else(|mut response| { - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - Ok(response) - }) - }, - "CreateOrphanToken"); - - let api_clone = api.clone(); - router.post( - "/v1/auth/token/create", - move |req: &mut Request| { - let mut context = Context::default(); - - // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). - fn handle_request(req: &mut Request, api: &T, context: &mut Context) -> Result where T: Api { - - context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); - context.auth_data = req.extensions.remove::(); - context.authorization = req.extensions.remove::(); - - - - // Header parameters - header! { (RequestXVaultToken, "X-Vault-Token") => [String] } - let param_x_vault_token = req.headers.get::().ok_or_else(|| Response::with((status::BadRequest, "Missing or invalid required header X-Vault-Token".to_string())))?.0.clone(); - - - // Body parameters (note that non-required body parameters will ignore garbage - // values, rather than causing a 400 response). Produce warning header and logs for - // any unused fields. - - let param_body_raw = req.get::().map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter body - not valid UTF-8: {}", e))))?; - let mut unused_elements = Vec::new(); - - let param_body = if let Some(param_body_raw) = param_body_raw { - let deserializer = &mut serde_json::Deserializer::from_str(¶m_body_raw); - - let param_body: Option = serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }).map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter body - doesn't match schema: {}", e))))?; - - param_body - } else { - None - }; - let param_body = param_body.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter body".to_string())))?; - - - match api.create_token(param_x_vault_token, param_body, context).wait() { - Ok(rsp) => match rsp { - CreateTokenResponse::Success(body) => { - - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::CREATE_TOKEN_SUCCESS.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } - Ok(response) - }, - }, - Err(_) => { - // Application code returned an error. This should not happen, as the implementation should - // return a valid response. - Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) - } - } - } - - handle_request(req, &api_clone, &mut context).or_else(|mut response| { - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - Ok(response) - }) - }, - "CreateToken"); - - let api_clone = api.clone(); - router.post( - "/v1/auth/cert/login", - move |req: &mut Request| { - let mut context = Context::default(); - - // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). - fn handle_request(req: &mut Request, api: &T, context: &mut Context) -> Result where T: Api { - - context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); - context.auth_data = req.extensions.remove::(); - context.authorization = req.extensions.remove::(); - - - - - // Body parameters (note that non-required body parameters will ignore garbage - // values, rather than causing a 400 response). Produce warning header and logs for - // any unused fields. - - let param_body_raw = req.get::().unwrap_or(None); - let mut unused_elements = Vec::new(); - - let param_body = if let Some(param_body_raw) = param_body_raw { - let deserializer = &mut serde_json::Deserializer::from_str(¶m_body_raw); - - let param_body: Option = serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }).unwrap_or(None); - - param_body - } else { - None - };; - - - match api.log_in_with_tls_certificate(param_body, context).wait() { - Ok(rsp) => match rsp { - LogInWithTLSCertificateResponse::Success(body) => { - - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(200), body_string)); - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } - Ok(response) - }, - }, - Err(_) => { - // Application code returned an error. This should not happen, as the implementation should - // return a valid response. - Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) - } - } - } - - handle_request(req, &api_clone, &mut context).or_else(|mut response| { - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - Ok(response) - }) - }, - "LogInWithTLSCertificate"); - - let api_clone = api.clone(); - router.post( - "/v1/auth/token/renew-self", - move |req: &mut Request| { - let mut context = Context::default(); - - // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). - fn handle_request(req: &mut Request, api: &T, context: &mut Context) -> Result where T: Api { - - context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); - context.auth_data = req.extensions.remove::(); - context.authorization = req.extensions.remove::(); - - - - // Header parameters - header! { (RequestXVaultToken, "X-Vault-Token") => [String] } - let param_x_vault_token = req.headers.get::().ok_or_else(|| Response::with((status::BadRequest, "Missing or invalid required header X-Vault-Token".to_string())))?.0.clone(); - - - // Body parameters (note that non-required body parameters will ignore garbage - // values, rather than causing a 400 response). Produce warning header and logs for - // any unused fields. - - let param_body_raw = req.get::().map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter body - not valid UTF-8: {}", e))))?; - let mut unused_elements = Vec::new(); - - let param_body = if let Some(param_body_raw) = param_body_raw { - let deserializer = &mut serde_json::Deserializer::from_str(¶m_body_raw); - - let param_body: Option = serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }).map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter body - doesn't match schema: {}", e))))?; - - param_body - } else { - None - }; - let param_body = param_body.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter body".to_string())))?; - - - match api.renew_own_token(param_x_vault_token, param_body, context).wait() { - Ok(rsp) => match rsp { - RenewOwnTokenResponse::Success(body) => { - - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::RENEW_OWN_TOKEN_SUCCESS.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } - Ok(response) - }, - }, - Err(_) => { - // Application code returned an error. This should not happen, as the implementation should - // return a valid response. - Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) - } - } - } - - handle_request(req, &api_clone, &mut context).or_else(|mut response| { - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - Ok(response) - }) - }, - "RenewOwnToken"); - -} - -/// Middleware to extract authentication data from request -pub struct ExtractAuthData; - -impl BeforeMiddleware for ExtractAuthData { - fn before(&self, req: &mut Request) -> IronResult<()> { - - Ok(()) - } -} diff --git a/vault-api/src/server/mod.rs b/vault-api/src/server/mod.rs new file mode 100644 index 0000000..40dea3e --- /dev/null +++ b/vault-api/src/server/mod.rs @@ -0,0 +1,904 @@ +use futures::{future, future::BoxFuture, Stream, stream, future::FutureExt, stream::TryStreamExt}; +use hyper::{Request, Response, StatusCode, Body, HeaderMap}; +use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; +use log::warn; +#[allow(unused_imports)] +use std::convert::{TryFrom, TryInto}; +use std::error::Error; +use std::future::Future; +use std::marker::PhantomData; +use std::task::{Context, Poll}; +use swagger::{ApiError, BodyExt, Has, RequestParser, XSpanIdString}; +pub use swagger::auth::Authorization; +use swagger::auth::Scopes; +use url::form_urlencoded; + +#[allow(unused_imports)] +use crate::models; +use crate::header; + +pub use crate::context; + +type ServiceFuture = BoxFuture<'static, Result, crate::ServiceError>>; + +use crate::{Api, + RevokeLeaseResponse, + GenerateCertResponse, + ReadCertResponse, + CreateOrphanTokenResponse, + CreateTokenResponse, + LogInWithTLSCertificateResponse, + RenewOwnTokenResponse +}; + +mod paths { + use lazy_static::lazy_static; + + lazy_static! { + pub static ref GLOBAL_REGEX_SET: regex::RegexSet = regex::RegexSet::new(vec![ + r"^/v1/auth/cert/login$", + r"^/v1/auth/token/create$", + r"^/v1/auth/token/create-orphan$", + r"^/v1/auth/token/renew-self$", + r"^/v1/sys/leases/revoke$", + r"^/v1/(?P[^/?#]*)/cert/(?P[^/?#]*)$", + r"^/v1/(?P[^/?#]*)/issue/(?P[^/?#]*)$" + ]) + .expect("Unable to create global regex set"); + } + pub(crate) static ID_AUTH_CERT_LOGIN: usize = 0; + pub(crate) static ID_AUTH_TOKEN_CREATE: usize = 1; + pub(crate) static ID_AUTH_TOKEN_CREATE_ORPHAN: usize = 2; + pub(crate) static ID_AUTH_TOKEN_RENEW_SELF: usize = 3; + pub(crate) static ID_SYS_LEASES_REVOKE: usize = 4; + pub(crate) static ID_MOUNT_CERT_SERIAL: usize = 5; + lazy_static! { + pub static ref REGEX_MOUNT_CERT_SERIAL: regex::Regex = + regex::Regex::new(r"^/v1/(?P[^/?#]*)/cert/(?P[^/?#]*)$") + .expect("Unable to create regex for MOUNT_CERT_SERIAL"); + } + pub(crate) static ID_MOUNT_ISSUE_NAME: usize = 6; + lazy_static! { + pub static ref REGEX_MOUNT_ISSUE_NAME: regex::Regex = + regex::Regex::new(r"^/v1/(?P[^/?#]*)/issue/(?P[^/?#]*)$") + .expect("Unable to create regex for MOUNT_ISSUE_NAME"); + } +} + +pub struct MakeService where + T: Api + Clone + Send + 'static, + C: Has + Send + Sync + 'static +{ + api_impl: T, + marker: PhantomData, +} + +impl MakeService where + T: Api + Clone + Send + 'static, + C: Has + Send + Sync + 'static +{ + pub fn new(api_impl: T) -> Self { + MakeService { + api_impl, + marker: PhantomData + } + } +} + +impl hyper::service::Service for MakeService where + T: Api + Clone + Send + 'static, + C: Has + Send + Sync + 'static +{ + type Response = Service; + type Error = crate::ServiceError; + type Future = future::Ready>; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn call(&mut self, target: Target) -> Self::Future { + futures::future::ok(Service::new( + self.api_impl.clone(), + )) + } +} + +fn method_not_allowed() -> Result, crate::ServiceError> { + Ok( + Response::builder().status(StatusCode::METHOD_NOT_ALLOWED) + .body(Body::empty()) + .expect("Unable to create Method Not Allowed response") + ) +} + +pub struct Service where + T: Api + Clone + Send + 'static, + C: Has + Send + Sync + 'static +{ + api_impl: T, + marker: PhantomData, +} + +impl Service where + T: Api + Clone + Send + 'static, + C: Has + Send + Sync + 'static +{ + pub fn new(api_impl: T) -> Self { + Service { + api_impl: api_impl, + marker: PhantomData + } + } +} + +impl Clone for Service where + T: Api + Clone + Send + 'static, + C: Has + Send + Sync + 'static +{ + fn clone(&self) -> Self { + Service { + api_impl: self.api_impl.clone(), + marker: self.marker.clone(), + } + } +} + +impl hyper::service::Service<(Request, C)> for Service where + T: Api + Clone + Send + Sync + 'static, + C: Has + Send + Sync + 'static +{ + type Response = Response; + type Error = crate::ServiceError; + type Future = ServiceFuture; + + fn poll_ready(&mut self, cx: &mut Context) -> Poll> { + self.api_impl.poll_ready(cx) + } + + fn call(&mut self, req: (Request, C)) -> Self::Future { async fn run(mut api_impl: T, req: (Request, C)) -> Result, crate::ServiceError> where + T: Api + Clone + Send + 'static, + C: Has + Send + Sync + 'static + { + let (request, context) = req; + let (parts, body) = request.into_parts(); + let (method, uri, headers) = (parts.method, parts.uri, parts.headers); + let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); + + match &method { + + // RevokeLease - PUT /sys/leases/revoke + &hyper::Method::PUT if path.matched(paths::ID_SYS_LEASES_REVOKE) => { + // Header parameters + let param_x_vault_token = headers.get(HeaderName::from_static("x-vault-token")); + + let param_x_vault_token = match param_x_vault_token { + Some(v) => match header::IntoHeaderValue::::try_from((*v).clone()) { + Ok(result) => + result.0, + Err(err) => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Invalid header X-Vault-Token - {}", err))) + .expect("Unable to create Bad Request response for invalid header X-Vault-Token")); + + }, + }, + None => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from("Missing required header X-Vault-Token")) + .expect("Unable to create Bad Request response for missing required header X-Vault-Token")); + } + }; + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + let result = body.to_raw().await; + match result { + Ok(body) => { + let mut unused_elements = Vec::new(); + let param_body: Option = if !body.is_empty() { + let deserializer = &mut serde_json::Deserializer::from_slice(&*body); + match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }) { + Ok(param_body) => param_body, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't parse body parameter body - doesn't match schema: {}", e))) + .expect("Unable to create Bad Request response for invalid body parameter body due to schema")), + } + } else { + None + }; + let param_body = match param_body { + Some(param_body) => param_body, + None => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from("Missing required body parameter body")) + .expect("Unable to create Bad Request response for missing body parameter body")), + }; + + let result = api_impl.revoke_lease( + param_x_vault_token, + param_body, + &context + ).await; + let mut response = Response::new(Body::empty()); + response.headers_mut().insert( + HeaderName::from_static("x-span-id"), + HeaderValue::from_str((&context as &dyn Has).get().0.clone().to_string().as_str()) + .expect("Unable to create X-Span-ID header value")); + + if !unused_elements.is_empty() { + response.headers_mut().insert( + HeaderName::from_static("warning"), + HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + .expect("Unable to create Warning header value")); + } + + match result { + Ok(rsp) => match rsp { + RevokeLeaseResponse::Success + => { + *response.status_mut() = StatusCode::from_u16(204).expect("Unable to turn 204 into a StatusCode"); + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + *response.body_mut() = Body::from("An internal error occurred"); + }, + } + + Ok(response) + }, + Err(e) => Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't read body parameter body: {}", e))) + .expect("Unable to create Bad Request response due to unable to read body parameter body")), + } + }, + + // GenerateCert - POST /{mount}/issue/{name} + &hyper::Method::POST if path.matched(paths::ID_MOUNT_ISSUE_NAME) => { + // Path parameters + let path: &str = &uri.path().to_string(); + let path_params = + paths::REGEX_MOUNT_ISSUE_NAME + .captures(&path) + .unwrap_or_else(|| + panic!("Path {} matched RE MOUNT_ISSUE_NAME in set but failed match against \"{}\"", path, paths::REGEX_MOUNT_ISSUE_NAME.as_str()) + ); + + let param_mount = match percent_encoding::percent_decode(path_params["mount"].as_bytes()).decode_utf8() { + Ok(param_mount) => match param_mount.parse::() { + Ok(param_mount) => param_mount, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't parse path parameter mount: {}", e))) + .expect("Unable to create Bad Request response for invalid path parameter")), + }, + Err(_) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["mount"]))) + .expect("Unable to create Bad Request response for invalid percent decode")) + }; + + let param_name = match percent_encoding::percent_decode(path_params["name"].as_bytes()).decode_utf8() { + Ok(param_name) => match param_name.parse::() { + Ok(param_name) => param_name, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't parse path parameter name: {}", e))) + .expect("Unable to create Bad Request response for invalid path parameter")), + }, + Err(_) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["name"]))) + .expect("Unable to create Bad Request response for invalid percent decode")) + }; + + // Header parameters + let param_x_vault_token = headers.get(HeaderName::from_static("x-vault-token")); + + let param_x_vault_token = match param_x_vault_token { + Some(v) => match header::IntoHeaderValue::::try_from((*v).clone()) { + Ok(result) => + result.0, + Err(err) => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Invalid header X-Vault-Token - {}", err))) + .expect("Unable to create Bad Request response for invalid header X-Vault-Token")); + + }, + }, + None => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from("Missing required header X-Vault-Token")) + .expect("Unable to create Bad Request response for missing required header X-Vault-Token")); + } + }; + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + let result = body.to_raw().await; + match result { + Ok(body) => { + let mut unused_elements = Vec::new(); + let param_body: Option = if !body.is_empty() { + let deserializer = &mut serde_json::Deserializer::from_slice(&*body); + match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }) { + Ok(param_body) => param_body, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't parse body parameter body - doesn't match schema: {}", e))) + .expect("Unable to create Bad Request response for invalid body parameter body due to schema")), + } + } else { + None + }; + let param_body = match param_body { + Some(param_body) => param_body, + None => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from("Missing required body parameter body")) + .expect("Unable to create Bad Request response for missing body parameter body")), + }; + + let result = api_impl.generate_cert( + param_x_vault_token, + param_mount, + param_name, + param_body, + &context + ).await; + let mut response = Response::new(Body::empty()); + response.headers_mut().insert( + HeaderName::from_static("x-span-id"), + HeaderValue::from_str((&context as &dyn Has).get().0.clone().to_string().as_str()) + .expect("Unable to create X-Span-ID header value")); + + if !unused_elements.is_empty() { + response.headers_mut().insert( + HeaderName::from_static("warning"), + HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + .expect("Unable to create Warning header value")); + } + + match result { + Ok(rsp) => match rsp { + GenerateCertResponse::Success + (body) + => { + *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + response.headers_mut().insert( + CONTENT_TYPE, + HeaderValue::from_str("application/json") + .expect("Unable to create Content-Type header for GENERATE_CERT_SUCCESS")); + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = Body::from(body); + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + *response.body_mut() = Body::from("An internal error occurred"); + }, + } + + Ok(response) + }, + Err(e) => Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't read body parameter body: {}", e))) + .expect("Unable to create Bad Request response due to unable to read body parameter body")), + } + }, + + // ReadCert - GET /{mount}/cert/{serial} + &hyper::Method::GET if path.matched(paths::ID_MOUNT_CERT_SERIAL) => { + // Path parameters + let path: &str = &uri.path().to_string(); + let path_params = + paths::REGEX_MOUNT_CERT_SERIAL + .captures(&path) + .unwrap_or_else(|| + panic!("Path {} matched RE MOUNT_CERT_SERIAL in set but failed match against \"{}\"", path, paths::REGEX_MOUNT_CERT_SERIAL.as_str()) + ); + + let param_mount = match percent_encoding::percent_decode(path_params["mount"].as_bytes()).decode_utf8() { + Ok(param_mount) => match param_mount.parse::() { + Ok(param_mount) => param_mount, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't parse path parameter mount: {}", e))) + .expect("Unable to create Bad Request response for invalid path parameter")), + }, + Err(_) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["mount"]))) + .expect("Unable to create Bad Request response for invalid percent decode")) + }; + + let param_serial = match percent_encoding::percent_decode(path_params["serial"].as_bytes()).decode_utf8() { + Ok(param_serial) => match param_serial.parse::() { + Ok(param_serial) => param_serial, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't parse path parameter serial: {}", e))) + .expect("Unable to create Bad Request response for invalid path parameter")), + }, + Err(_) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["serial"]))) + .expect("Unable to create Bad Request response for invalid percent decode")) + }; + + let result = api_impl.read_cert( + param_mount, + param_serial, + &context + ).await; + let mut response = Response::new(Body::empty()); + response.headers_mut().insert( + HeaderName::from_static("x-span-id"), + HeaderValue::from_str((&context as &dyn Has).get().0.clone().to_string().as_str()) + .expect("Unable to create X-Span-ID header value")); + + match result { + Ok(rsp) => match rsp { + ReadCertResponse::Success + (body) + => { + *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + response.headers_mut().insert( + CONTENT_TYPE, + HeaderValue::from_str("application/json") + .expect("Unable to create Content-Type header for READ_CERT_SUCCESS")); + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = Body::from(body); + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + *response.body_mut() = Body::from("An internal error occurred"); + }, + } + + Ok(response) + }, + + // CreateOrphanToken - POST /auth/token/create-orphan + &hyper::Method::POST if path.matched(paths::ID_AUTH_TOKEN_CREATE_ORPHAN) => { + // Header parameters + let param_x_vault_token = headers.get(HeaderName::from_static("x-vault-token")); + + let param_x_vault_token = match param_x_vault_token { + Some(v) => match header::IntoHeaderValue::::try_from((*v).clone()) { + Ok(result) => + result.0, + Err(err) => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Invalid header X-Vault-Token - {}", err))) + .expect("Unable to create Bad Request response for invalid header X-Vault-Token")); + + }, + }, + None => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from("Missing required header X-Vault-Token")) + .expect("Unable to create Bad Request response for missing required header X-Vault-Token")); + } + }; + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + let result = body.to_raw().await; + match result { + Ok(body) => { + let mut unused_elements = Vec::new(); + let param_body: Option = if !body.is_empty() { + let deserializer = &mut serde_json::Deserializer::from_slice(&*body); + match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }) { + Ok(param_body) => param_body, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't parse body parameter body - doesn't match schema: {}", e))) + .expect("Unable to create Bad Request response for invalid body parameter body due to schema")), + } + } else { + None + }; + let param_body = match param_body { + Some(param_body) => param_body, + None => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from("Missing required body parameter body")) + .expect("Unable to create Bad Request response for missing body parameter body")), + }; + + let result = api_impl.create_orphan_token( + param_x_vault_token, + param_body, + &context + ).await; + let mut response = Response::new(Body::empty()); + response.headers_mut().insert( + HeaderName::from_static("x-span-id"), + HeaderValue::from_str((&context as &dyn Has).get().0.clone().to_string().as_str()) + .expect("Unable to create X-Span-ID header value")); + + if !unused_elements.is_empty() { + response.headers_mut().insert( + HeaderName::from_static("warning"), + HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + .expect("Unable to create Warning header value")); + } + + match result { + Ok(rsp) => match rsp { + CreateOrphanTokenResponse::Success + (body) + => { + *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + response.headers_mut().insert( + CONTENT_TYPE, + HeaderValue::from_str("application/json") + .expect("Unable to create Content-Type header for CREATE_ORPHAN_TOKEN_SUCCESS")); + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = Body::from(body); + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + *response.body_mut() = Body::from("An internal error occurred"); + }, + } + + Ok(response) + }, + Err(e) => Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't read body parameter body: {}", e))) + .expect("Unable to create Bad Request response due to unable to read body parameter body")), + } + }, + + // CreateToken - POST /auth/token/create + &hyper::Method::POST if path.matched(paths::ID_AUTH_TOKEN_CREATE) => { + // Header parameters + let param_x_vault_token = headers.get(HeaderName::from_static("x-vault-token")); + + let param_x_vault_token = match param_x_vault_token { + Some(v) => match header::IntoHeaderValue::::try_from((*v).clone()) { + Ok(result) => + result.0, + Err(err) => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Invalid header X-Vault-Token - {}", err))) + .expect("Unable to create Bad Request response for invalid header X-Vault-Token")); + + }, + }, + None => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from("Missing required header X-Vault-Token")) + .expect("Unable to create Bad Request response for missing required header X-Vault-Token")); + } + }; + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + let result = body.to_raw().await; + match result { + Ok(body) => { + let mut unused_elements = Vec::new(); + let param_body: Option = if !body.is_empty() { + let deserializer = &mut serde_json::Deserializer::from_slice(&*body); + match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }) { + Ok(param_body) => param_body, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't parse body parameter body - doesn't match schema: {}", e))) + .expect("Unable to create Bad Request response for invalid body parameter body due to schema")), + } + } else { + None + }; + let param_body = match param_body { + Some(param_body) => param_body, + None => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from("Missing required body parameter body")) + .expect("Unable to create Bad Request response for missing body parameter body")), + }; + + let result = api_impl.create_token( + param_x_vault_token, + param_body, + &context + ).await; + let mut response = Response::new(Body::empty()); + response.headers_mut().insert( + HeaderName::from_static("x-span-id"), + HeaderValue::from_str((&context as &dyn Has).get().0.clone().to_string().as_str()) + .expect("Unable to create X-Span-ID header value")); + + if !unused_elements.is_empty() { + response.headers_mut().insert( + HeaderName::from_static("warning"), + HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + .expect("Unable to create Warning header value")); + } + + match result { + Ok(rsp) => match rsp { + CreateTokenResponse::Success + (body) + => { + *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + response.headers_mut().insert( + CONTENT_TYPE, + HeaderValue::from_str("application/json") + .expect("Unable to create Content-Type header for CREATE_TOKEN_SUCCESS")); + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = Body::from(body); + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + *response.body_mut() = Body::from("An internal error occurred"); + }, + } + + Ok(response) + }, + Err(e) => Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't read body parameter body: {}", e))) + .expect("Unable to create Bad Request response due to unable to read body parameter body")), + } + }, + + // LogInWithTLSCertificate - POST /auth/cert/login + &hyper::Method::POST if path.matched(paths::ID_AUTH_CERT_LOGIN) => { + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + let result = body.to_raw().await; + match result { + Ok(body) => { + let mut unused_elements = Vec::new(); + let param_body: Option = if !body.is_empty() { + let deserializer = &mut serde_json::Deserializer::from_slice(&*body); + match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }) { + Ok(param_body) => param_body, + Err(_) => None, + } + } else { + None + }; + + let result = api_impl.log_in_with_tls_certificate( + param_body, + &context + ).await; + let mut response = Response::new(Body::empty()); + response.headers_mut().insert( + HeaderName::from_static("x-span-id"), + HeaderValue::from_str((&context as &dyn Has).get().0.clone().to_string().as_str()) + .expect("Unable to create X-Span-ID header value")); + + if !unused_elements.is_empty() { + response.headers_mut().insert( + HeaderName::from_static("warning"), + HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + .expect("Unable to create Warning header value")); + } + + match result { + Ok(rsp) => match rsp { + LogInWithTLSCertificateResponse::Success + (body) + => { + *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + response.headers_mut().insert( + CONTENT_TYPE, + HeaderValue::from_str("*/*") + .expect("Unable to create Content-Type header for LOG_IN_WITH_TLS_CERTIFICATE_SUCCESS")); + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = Body::from(body); + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + *response.body_mut() = Body::from("An internal error occurred"); + }, + } + + Ok(response) + }, + Err(e) => Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't read body parameter body: {}", e))) + .expect("Unable to create Bad Request response due to unable to read body parameter body")), + } + }, + + // RenewOwnToken - POST /auth/token/renew-self + &hyper::Method::POST if path.matched(paths::ID_AUTH_TOKEN_RENEW_SELF) => { + // Header parameters + let param_x_vault_token = headers.get(HeaderName::from_static("x-vault-token")); + + let param_x_vault_token = match param_x_vault_token { + Some(v) => match header::IntoHeaderValue::::try_from((*v).clone()) { + Ok(result) => + result.0, + Err(err) => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Invalid header X-Vault-Token - {}", err))) + .expect("Unable to create Bad Request response for invalid header X-Vault-Token")); + + }, + }, + None => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from("Missing required header X-Vault-Token")) + .expect("Unable to create Bad Request response for missing required header X-Vault-Token")); + } + }; + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + let result = body.to_raw().await; + match result { + Ok(body) => { + let mut unused_elements = Vec::new(); + let param_body: Option = if !body.is_empty() { + let deserializer = &mut serde_json::Deserializer::from_slice(&*body); + match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }) { + Ok(param_body) => param_body, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't parse body parameter body - doesn't match schema: {}", e))) + .expect("Unable to create Bad Request response for invalid body parameter body due to schema")), + } + } else { + None + }; + let param_body = match param_body { + Some(param_body) => param_body, + None => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from("Missing required body parameter body")) + .expect("Unable to create Bad Request response for missing body parameter body")), + }; + + let result = api_impl.renew_own_token( + param_x_vault_token, + param_body, + &context + ).await; + let mut response = Response::new(Body::empty()); + response.headers_mut().insert( + HeaderName::from_static("x-span-id"), + HeaderValue::from_str((&context as &dyn Has).get().0.clone().to_string().as_str()) + .expect("Unable to create X-Span-ID header value")); + + if !unused_elements.is_empty() { + response.headers_mut().insert( + HeaderName::from_static("warning"), + HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + .expect("Unable to create Warning header value")); + } + + match result { + Ok(rsp) => match rsp { + RenewOwnTokenResponse::Success + (body) + => { + *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + response.headers_mut().insert( + CONTENT_TYPE, + HeaderValue::from_str("application/json") + .expect("Unable to create Content-Type header for RENEW_OWN_TOKEN_SUCCESS")); + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = Body::from(body); + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + *response.body_mut() = Body::from("An internal error occurred"); + }, + } + + Ok(response) + }, + Err(e) => Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't read body parameter body: {}", e))) + .expect("Unable to create Bad Request response due to unable to read body parameter body")), + } + }, + + _ if path.matched(paths::ID_AUTH_CERT_LOGIN) => method_not_allowed(), + _ if path.matched(paths::ID_AUTH_TOKEN_CREATE) => method_not_allowed(), + _ if path.matched(paths::ID_AUTH_TOKEN_CREATE_ORPHAN) => method_not_allowed(), + _ if path.matched(paths::ID_AUTH_TOKEN_RENEW_SELF) => method_not_allowed(), + _ if path.matched(paths::ID_SYS_LEASES_REVOKE) => method_not_allowed(), + _ if path.matched(paths::ID_MOUNT_CERT_SERIAL) => method_not_allowed(), + _ if path.matched(paths::ID_MOUNT_ISSUE_NAME) => method_not_allowed(), + _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) + .body(Body::empty()) + .expect("Unable to create Not Found response")) + } + } Box::pin(run(self.api_impl.clone(), req)) } +} + +/// Request parser for `Api`. +pub struct ApiRequestParser; +impl RequestParser for ApiRequestParser { + fn parse_operation_id(request: &Request) -> Result<&'static str, ()> { + let path = paths::GLOBAL_REGEX_SET.matches(request.uri().path()); + match request.method() { + // RevokeLease - PUT /sys/leases/revoke + &hyper::Method::PUT if path.matched(paths::ID_SYS_LEASES_REVOKE) => Ok("RevokeLease"), + // GenerateCert - POST /{mount}/issue/{name} + &hyper::Method::POST if path.matched(paths::ID_MOUNT_ISSUE_NAME) => Ok("GenerateCert"), + // ReadCert - GET /{mount}/cert/{serial} + &hyper::Method::GET if path.matched(paths::ID_MOUNT_CERT_SERIAL) => Ok("ReadCert"), + // CreateOrphanToken - POST /auth/token/create-orphan + &hyper::Method::POST if path.matched(paths::ID_AUTH_TOKEN_CREATE_ORPHAN) => Ok("CreateOrphanToken"), + // CreateToken - POST /auth/token/create + &hyper::Method::POST if path.matched(paths::ID_AUTH_TOKEN_CREATE) => Ok("CreateToken"), + // LogInWithTLSCertificate - POST /auth/cert/login + &hyper::Method::POST if path.matched(paths::ID_AUTH_CERT_LOGIN) => Ok("LogInWithTLSCertificate"), + // RenewOwnToken - POST /auth/token/renew-self + &hyper::Method::POST if path.matched(paths::ID_AUTH_TOKEN_RENEW_SELF) => Ok("RenewOwnToken"), + _ => Err(()), + } + } +}