use crate::common::helpers::{
Context, PushError, ValidateWithContext, validate_optional_url, validate_required_string,
validate_required_url,
};
use crate::v3_1::spec::Spec;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fmt::{Display, Formatter};
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(tag = "type")]
pub enum SecurityScheme {
#[serde(rename = "http")]
HTTP(Box<HttpSecurityScheme>),
#[serde(rename = "apiKey")]
ApiKey(Box<ApiKeySecurityScheme>),
#[serde(rename = "oauth2")]
OAuth2(Box<OAuth2SecurityScheme>),
#[serde(rename = "openIdConnect")]
OpenIdConnect(Box<OpenIdConnectSecurityScheme>),
}
impl Display for SecurityScheme {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
SecurityScheme::HTTP(_) => write!(f, "http"),
SecurityScheme::ApiKey(_) => write!(f, "apiKey"),
SecurityScheme::OAuth2(_) => write!(f, "oauth2"),
SecurityScheme::OpenIdConnect(_) => write!(f, "openIdConnect"),
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct HttpSecurityScheme {
pub scheme: HttpScheme,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "bearerFormat")]
pub bearer_format: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(flatten)]
#[serde(with = "crate::common::extensions")]
#[serde(skip_serializing_if = "Option::is_none")]
pub extensions: Option<BTreeMap<String, serde_json::Value>>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub enum HttpScheme {
#[default]
#[serde(alias = "basic")]
Basic,
#[serde(alias = "bearer")]
Bearer,
#[serde(alias = "digest")]
Digest,
#[serde(alias = "dpop")]
DPoP,
#[serde(alias = "hoba")]
HOBA,
#[serde(alias = "mutual")]
Mutual,
#[serde(alias = "negotiate")]
Negotiate,
#[serde(alias = "oauth")]
OAuth,
#[serde(alias = "scram-sha-1")]
#[serde(rename = "SCRAM-SHA-1")]
SCRAMSHA1,
#[serde(alias = "scram-sha-256")]
#[serde(rename = "SCRAM-SHA-256")]
SCRAMSHA256,
#[serde(rename = "vapid")]
Vapid,
}
impl Display for HttpScheme {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
HttpScheme::Basic => write!(f, "Basic"),
HttpScheme::Bearer => write!(f, "Bearer"),
HttpScheme::Digest => write!(f, "Digest"),
HttpScheme::DPoP => write!(f, "DPoP"),
HttpScheme::HOBA => write!(f, "HOBA"),
HttpScheme::Mutual => write!(f, "Mutual"),
HttpScheme::Negotiate => write!(f, "Negotiate"),
HttpScheme::OAuth => write!(f, "OAuth"),
HttpScheme::SCRAMSHA1 => write!(f, "SCRAM-SHA-1"),
HttpScheme::SCRAMSHA256 => write!(f, "SCRAM-SHA-256"),
HttpScheme::Vapid => write!(f, "vapid"),
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct ApiKeySecurityScheme {
pub name: String,
#[serde(rename = "in")]
pub location: ApiKeyLocation,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(flatten)]
#[serde(with = "crate::common::extensions")]
#[serde(skip_serializing_if = "Option::is_none")]
pub extensions: Option<BTreeMap<String, serde_json::Value>>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub enum ApiKeyLocation {
#[default]
#[serde(rename = "query")]
Query,
#[serde(rename = "header")]
Header,
#[serde(rename = "cookie")]
Cookie,
}
impl Display for ApiKeyLocation {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ApiKeyLocation::Query => write!(f, "query"),
ApiKeyLocation::Header => write!(f, "header"),
ApiKeyLocation::Cookie => write!(f, "cookie"),
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct OAuth2SecurityScheme {
pub flows: OAuth2Flows,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(flatten)]
#[serde(with = "crate::common::extensions")]
#[serde(skip_serializing_if = "Option::is_none")]
pub extensions: Option<BTreeMap<String, serde_json::Value>>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct OAuth2Flows {
#[serde(skip_serializing_if = "Option::is_none")]
pub implicit: Option<ImplicitOAuth2Flow>,
#[serde(skip_serializing_if = "Option::is_none")]
pub password: Option<PasswordOAuth2Flow>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "clientCredentials")]
pub client_credentials: Option<ClientCredentialsOAuth2Flow>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "authorizationCode")]
pub authorization_code: Option<AuthorizationCodeOAuth2Flow>,
#[serde(flatten)]
#[serde(with = "crate::common::extensions")]
#[serde(skip_serializing_if = "Option::is_none")]
pub extensions: Option<BTreeMap<String, serde_json::Value>>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct ImplicitOAuth2Flow {
#[serde(rename = "authorizationUrl")]
pub authorization_url: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "refreshUrl")]
pub refresh_url: Option<String>,
pub scopes: BTreeMap<String, String>,
#[serde(flatten)]
#[serde(with = "crate::common::extensions")]
#[serde(skip_serializing_if = "Option::is_none")]
pub extensions: Option<BTreeMap<String, serde_json::Value>>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct PasswordOAuth2Flow {
#[serde(rename = "tokenUrl")]
pub token_url: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "refreshUrl")]
pub refresh_url: Option<String>,
pub scopes: BTreeMap<String, String>,
#[serde(flatten)]
#[serde(with = "crate::common::extensions")]
#[serde(skip_serializing_if = "Option::is_none")]
pub extensions: Option<BTreeMap<String, serde_json::Value>>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct ClientCredentialsOAuth2Flow {
#[serde(rename = "tokenUrl")]
pub token_url: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "refreshUrl")]
pub refresh_url: Option<String>,
pub scopes: BTreeMap<String, String>,
#[serde(flatten)]
#[serde(with = "crate::common::extensions")]
#[serde(skip_serializing_if = "Option::is_none")]
pub extensions: Option<BTreeMap<String, serde_json::Value>>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct AuthorizationCodeOAuth2Flow {
#[serde(rename = "authorizationUrl")]
pub authorization_url: String,
#[serde(rename = "tokenUrl")]
pub token_url: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "refreshUrl")]
pub refresh_url: Option<String>,
pub scopes: BTreeMap<String, String>,
#[serde(flatten)]
#[serde(with = "crate::common::extensions")]
#[serde(skip_serializing_if = "Option::is_none")]
pub extensions: Option<BTreeMap<String, serde_json::Value>>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct OpenIdConnectSecurityScheme {
#[serde(rename = "openIdConnectUrl")]
pub open_id_connect_url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(flatten)]
#[serde(with = "crate::common::extensions")]
#[serde(skip_serializing_if = "Option::is_none")]
pub extensions: Option<BTreeMap<String, serde_json::Value>>,
}
impl ValidateWithContext<Spec> for SecurityScheme {
fn validate_with_context(&self, ctx: &mut Context<Spec>, path: String) {
match self {
SecurityScheme::HTTP(http) => http.validate_with_context(ctx, path),
SecurityScheme::ApiKey(api_key) => api_key.validate_with_context(ctx, path),
SecurityScheme::OAuth2(oauth2) => oauth2.validate_with_context(ctx, path),
SecurityScheme::OpenIdConnect(open_id_connect) => {
open_id_connect.validate_with_context(ctx, path)
}
}
}
}
impl ValidateWithContext<Spec> for HttpSecurityScheme {
fn validate_with_context(&self, ctx: &mut Context<Spec>, path: String) {
if let Some(bearer_format) = &self.bearer_format
&& !bearer_format.is_empty()
&& self.scheme != HttpScheme::Bearer
{
ctx.error(
path,
format_args!(".bearerFormat: must be empty for scheme `{}`", self.scheme,),
);
}
}
}
impl ValidateWithContext<Spec> for ApiKeySecurityScheme {
fn validate_with_context(&self, ctx: &mut Context<Spec>, path: String) {
validate_required_string(&self.name, ctx, format!("{path}.name"));
}
}
impl ValidateWithContext<Spec> for OAuth2SecurityScheme {
fn validate_with_context(&self, ctx: &mut Context<Spec>, path: String) {
self.flows
.validate_with_context(ctx, format!("{path}.flow"));
}
}
impl ValidateWithContext<Spec> for OAuth2Flows {
fn validate_with_context(&self, ctx: &mut Context<Spec>, path: String) {
if let Some(flow) = &self.implicit {
flow.validate_with_context(ctx, format!("{path}.implicit"));
}
if let Some(flow) = &self.password {
flow.validate_with_context(ctx, format!("{path}.password"));
}
if let Some(flow) = &self.client_credentials {
flow.validate_with_context(ctx, format!("{path}.clientCredentials"));
}
if let Some(flow) = &self.authorization_code {
flow.validate_with_context(ctx, format!("{path}.authorizationCode"));
}
}
}
impl ValidateWithContext<Spec> for ImplicitOAuth2Flow {
fn validate_with_context(&self, ctx: &mut Context<Spec>, path: String) {
validate_required_url(
&self.authorization_url,
ctx,
format!("{path}.authorizationUrl"),
);
validate_optional_url(&self.refresh_url, ctx, format!("{path}.refreshUrl"));
}
}
impl ValidateWithContext<Spec> for PasswordOAuth2Flow {
fn validate_with_context(&self, ctx: &mut Context<Spec>, path: String) {
validate_required_url(&self.token_url, ctx, format!("{path}.tokenUrl"));
validate_optional_url(&self.refresh_url, ctx, format!("{path}.refreshUrl"));
}
}
impl ValidateWithContext<Spec> for ClientCredentialsOAuth2Flow {
fn validate_with_context(&self, ctx: &mut Context<Spec>, path: String) {
validate_required_url(&self.token_url, ctx, format!("{path}.tokenUrl"));
validate_optional_url(&self.refresh_url, ctx, format!("{path}.refreshUrl"));
}
}
impl ValidateWithContext<Spec> for AuthorizationCodeOAuth2Flow {
fn validate_with_context(&self, ctx: &mut Context<Spec>, path: String) {
validate_required_url(
&self.authorization_url,
ctx,
format!("{path}.authorizationUrl"),
);
validate_required_url(&self.token_url, ctx, format!("{path}.tokenUrl"));
validate_optional_url(&self.refresh_url, ctx, format!("{path}.refreshUrl"));
}
}
impl ValidateWithContext<Spec> for OpenIdConnectSecurityScheme {
fn validate_with_context(&self, ctx: &mut Context<Spec>, path: String) {
validate_required_url(
&self.open_id_connect_url,
ctx,
format!("{path}.openIdConnectUrl"),
);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::validation::Options;
use serde_json::json;
#[test]
fn test_security_scheme_http_deserialize() {
assert_eq!(
serde_json::from_value::<SecurityScheme>(json!({
"type": "http",
"scheme": "Basic",
"description": "A short description for security scheme.",
}))
.unwrap(),
SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::Basic,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})),
"deserialize scheme = basic",
);
assert_eq!(
serde_json::from_value::<SecurityScheme>(json!({
"type": "http",
"scheme": "Bearer",
"description": "A short description for security scheme.",
}))
.unwrap(),
SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::Bearer,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})),
"deserialize scheme = bearer",
);
assert_eq!(
serde_json::from_value::<SecurityScheme>(json!({
"type": "http",
"scheme": "Digest",
"description": "A short description for security scheme.",
}))
.unwrap(),
SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::Digest,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})),
"deserialize scheme = digest",
);
assert_eq!(
serde_json::from_value::<SecurityScheme>(json!({
"type": "http",
"scheme": "DPoP",
"description": "A short description for security scheme.",
}))
.unwrap(),
SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::DPoP,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})),
"deserialize scheme = dpop",
);
assert_eq!(
serde_json::from_value::<SecurityScheme>(json!({
"type": "http",
"scheme": "HOBA",
"description": "A short description for security scheme.",
}))
.unwrap(),
SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::HOBA,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})),
"deserialize scheme = hoba",
);
assert_eq!(
serde_json::from_value::<SecurityScheme>(json!({
"type": "http",
"scheme": "Mutual",
"description": "A short description for security scheme.",
}))
.unwrap(),
SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::Mutual,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})),
"deserialize scheme = mutual",
);
assert_eq!(
serde_json::from_value::<SecurityScheme>(json!({
"type": "http",
"scheme": "Negotiate",
"description": "A short description for security scheme.",
}))
.unwrap(),
SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::Negotiate,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})),
"deserialize scheme = negotiate",
);
assert_eq!(
serde_json::from_value::<SecurityScheme>(json!({
"type": "http",
"scheme": "OAuth",
"description": "A short description for security scheme.",
}))
.unwrap(),
SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::OAuth,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})),
"deserialize scheme = oauth",
);
assert_eq!(
serde_json::from_value::<SecurityScheme>(json!({
"type": "http",
"scheme": "SCRAM-SHA-1",
"description": "A short description for security scheme.",
}))
.unwrap(),
SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::SCRAMSHA1,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})),
"deserialize scheme = scram-sha-1",
);
assert_eq!(
serde_json::from_value::<SecurityScheme>(json!({
"type": "http",
"scheme": "SCRAM-SHA-256",
"description": "A short description for security scheme.",
}))
.unwrap(),
SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::SCRAMSHA256,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})),
"deserialize scheme = scram-sha-2256",
);
assert_eq!(
serde_json::from_value::<SecurityScheme>(json!({
"type": "http",
"scheme": "vapid",
"description": "A short description for security scheme.",
}))
.unwrap(),
SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::Vapid,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})),
"deserialize scheme = vapid",
);
}
#[test]
fn test_security_scheme_http_serialize() {
assert_eq!(
serde_json::to_value(SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::Basic,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})))
.unwrap(),
json!({
"type": "http",
"scheme": "Basic",
"description": "A short description for security scheme.",
}),
"serialize scheme = basic",
);
assert_eq!(
serde_json::to_value(SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::Bearer,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})))
.unwrap(),
json!({
"type": "http",
"scheme": "Bearer",
"description": "A short description for security scheme.",
}),
"serialize scheme = bearer",
);
assert_eq!(
serde_json::to_value(SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::Digest,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})))
.unwrap(),
json!({
"type": "http",
"scheme": "Digest",
"description": "A short description for security scheme.",
}),
"serialize scheme = digest",
);
assert_eq!(
serde_json::to_value(SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::DPoP,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})))
.unwrap(),
json!({
"type": "http",
"scheme": "DPoP",
"description": "A short description for security scheme.",
}),
"serialize scheme = dpop",
);
assert_eq!(
serde_json::to_value(SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::HOBA,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})))
.unwrap(),
json!({
"type": "http",
"scheme": "HOBA",
"description": "A short description for security scheme.",
}),
"serialize scheme = hoba",
);
assert_eq!(
serde_json::to_value(SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::Mutual,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})))
.unwrap(),
json!({
"type": "http",
"scheme": "Mutual",
"description": "A short description for security scheme.",
}),
"serialize scheme = mutual",
);
assert_eq!(
serde_json::to_value(SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::Negotiate,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})))
.unwrap(),
json!({
"type": "http",
"scheme": "Negotiate",
"description": "A short description for security scheme.",
}),
"serialize scheme = negotiate",
);
assert_eq!(
serde_json::to_value(SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::OAuth,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})))
.unwrap(),
json!({
"type": "http",
"scheme": "OAuth",
"description": "A short description for security scheme.",
}),
"serialize scheme = oauth",
);
assert_eq!(
serde_json::to_value(SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::SCRAMSHA1,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})))
.unwrap(),
json!({
"type": "http",
"scheme": "SCRAM-SHA-1",
"description": "A short description for security scheme.",
}),
"serialize scheme = scram-sha-1",
);
assert_eq!(
serde_json::to_value(SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::SCRAMSHA256,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})))
.unwrap(),
json!({
"type": "http",
"scheme": "SCRAM-SHA-256",
"description": "A short description for security scheme.",
}),
"serialize scheme = scram-sha-256",
);
assert_eq!(
serde_json::to_value(SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::Vapid,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})))
.unwrap(),
json!({
"type": "http",
"scheme": "vapid",
"description": "A short description for security scheme.",
}),
"serialize scheme = vapid",
);
}
#[test]
fn test_security_scheme_api_key_deserialize() {
assert_eq!(
serde_json::from_value::<SecurityScheme>(json!({
"type": "apiKey",
"name": "api_key",
"in": "header",
"description": "A short description for security scheme.",
}))
.unwrap(),
SecurityScheme::ApiKey(Box::new(ApiKeySecurityScheme {
name: String::from("api_key"),
location: ApiKeyLocation::Header,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})),
"deserialize in = header",
);
assert_eq!(
serde_json::from_value::<SecurityScheme>(json!({
"type": "apiKey",
"name": "api_key",
"in": "query",
"description": "A short description for security scheme.",
}))
.unwrap(),
SecurityScheme::ApiKey(Box::new(ApiKeySecurityScheme {
name: String::from("api_key"),
location: ApiKeyLocation::Query,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})),
"deserialize in = query",
);
assert_eq!(
serde_json::from_value::<SecurityScheme>(json!({
"type": "apiKey",
"name": "api_key",
"in": "cookie",
"description": "A short description for security scheme.",
}))
.unwrap(),
SecurityScheme::ApiKey(Box::new(ApiKeySecurityScheme {
name: String::from("api_key"),
location: ApiKeyLocation::Cookie,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})),
"deserialize in = cookie",
);
}
#[test]
fn test_security_scheme_api_key_serialize() {
assert_eq!(
serde_json::to_value(SecurityScheme::ApiKey(Box::new(ApiKeySecurityScheme {
name: String::from("api_key"),
location: ApiKeyLocation::Header,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})))
.unwrap(),
json!({
"type": "apiKey",
"name": "api_key",
"in": "header",
"description": "A short description for security scheme.",
}),
"serialize location = header",
);
assert_eq!(
serde_json::to_value(SecurityScheme::ApiKey(Box::new(ApiKeySecurityScheme {
name: String::from("api_key"),
location: ApiKeyLocation::Query,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})))
.unwrap(),
json!({
"type": "apiKey",
"name": "api_key",
"in": "query",
"description": "A short description for security scheme.",
}),
"serialize location = query",
);
assert_eq!(
serde_json::to_value(SecurityScheme::ApiKey(Box::new(ApiKeySecurityScheme {
name: String::from("api_key"),
location: ApiKeyLocation::Cookie,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})))
.unwrap(),
json!({
"type": "apiKey",
"name": "api_key",
"in": "cookie",
"description": "A short description for security scheme.",
}),
"serialize location = query",
);
}
#[test]
fn test_security_scheme_oauth2_deserialize() {
assert_eq!(
serde_json::from_value::<SecurityScheme>(json!({
"type": "oauth2",
"flows": {
"implicit": {
"authorizationUrl": "https://example.com/api/oauth/dialog",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets",
},
},
"password": {
"tokenUrl": "https://example.com/api/oauth/dialog",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets",
},
},
"clientCredentials": {
"tokenUrl": "https://example.com/api/oauth/dialog",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets",
},
},
"authorizationCode": {
"authorizationUrl": "https://example.com/api/oauth/dialog",
"tokenUrl": "https://example.com/api/oauth/dialog",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets",
},
},
},
"description": "A short description for security scheme.",
"x-tra": "custom",
}))
.unwrap(),
SecurityScheme::OAuth2(Box::new(OAuth2SecurityScheme {
flows: OAuth2Flows {
implicit: Some(ImplicitOAuth2Flow {
authorization_url: String::from("https://example.com/api/oauth/dialog"),
scopes: BTreeMap::from_iter(vec![
(
String::from("write:pets"),
String::from("modify pets in your account"),
),
(String::from("read:pets"), String::from("read your pets"),),
]),
..Default::default()
}),
password: Some(PasswordOAuth2Flow {
token_url: String::from("https://example.com/api/oauth/dialog"),
scopes: BTreeMap::from_iter(vec![
(
String::from("write:pets"),
String::from("modify pets in your account"),
),
(String::from("read:pets"), String::from("read your pets"),),
]),
..Default::default()
}),
client_credentials: Some(ClientCredentialsOAuth2Flow {
token_url: String::from("https://example.com/api/oauth/dialog"),
scopes: BTreeMap::from_iter(vec![
(
String::from("write:pets"),
String::from("modify pets in your account"),
),
(String::from("read:pets"), String::from("read your pets"),),
]),
..Default::default()
}),
authorization_code: Some(AuthorizationCodeOAuth2Flow {
authorization_url: String::from("https://example.com/api/oauth/dialog"),
token_url: String::from("https://example.com/api/oauth/dialog"),
scopes: BTreeMap::from_iter(vec![
(
String::from("write:pets"),
String::from("modify pets in your account"),
),
(String::from("read:pets"), String::from("read your pets"),),
]),
..Default::default()
}),
..Default::default()
},
description: Some(String::from("A short description for security scheme.")),
extensions: Some({
let mut map = BTreeMap::new();
map.insert(
String::from("x-tra"),
serde_json::Value::String(String::from("custom")),
);
map
}),
})),
"deserialize",
);
}
#[test]
fn test_security_scheme_oauth2_serialize() {
assert_eq!(
serde_json::to_value(SecurityScheme::OAuth2(Box::new(OAuth2SecurityScheme {
flows: OAuth2Flows {
implicit: Some(ImplicitOAuth2Flow {
authorization_url: String::from("https://example.com/api/oauth/dialog"),
scopes: BTreeMap::from_iter(vec![
(
String::from("write:pets"),
String::from("modify pets in your account"),
),
(String::from("read:pets"), String::from("read your pets"),),
]),
..Default::default()
}),
password: Some(PasswordOAuth2Flow {
token_url: String::from("https://example.com/api/oauth/dialog"),
scopes: BTreeMap::from_iter(vec![
(
String::from("write:pets"),
String::from("modify pets in your account"),
),
(String::from("read:pets"), String::from("read your pets"),),
]),
..Default::default()
}),
client_credentials: Some(ClientCredentialsOAuth2Flow {
token_url: String::from("https://example.com/api/oauth/dialog"),
scopes: BTreeMap::from_iter(vec![
(
String::from("write:pets"),
String::from("modify pets in your account"),
),
(String::from("read:pets"), String::from("read your pets"),),
]),
..Default::default()
}),
authorization_code: Some(AuthorizationCodeOAuth2Flow {
authorization_url: String::from("https://example.com/api/oauth/dialog"),
token_url: String::from("https://example.com/api/oauth/dialog"),
scopes: BTreeMap::from_iter(vec![
(
String::from("write:pets"),
String::from("modify pets in your account"),
),
(String::from("read:pets"), String::from("read your pets"),),
]),
..Default::default()
}),
..Default::default()
},
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})))
.unwrap(),
json!({
"type": "oauth2",
"flows": {
"implicit": {
"authorizationUrl": "https://example.com/api/oauth/dialog",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets",
},
},
"password": {
"tokenUrl": "https://example.com/api/oauth/dialog",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets",
},
},
"clientCredentials": {
"tokenUrl": "https://example.com/api/oauth/dialog",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets",
},
},
"authorizationCode": {
"authorizationUrl": "https://example.com/api/oauth/dialog",
"tokenUrl": "https://example.com/api/oauth/dialog",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets",
},
},
},
"description": "A short description for security scheme.",
}),
"serialize",
);
}
#[test]
fn test_security_scheme_open_id_connect_deserialize() {
assert_eq!(
serde_json::from_value::<SecurityScheme>(json!({
"type": "openIdConnect",
"openIdConnectUrl": "https://example.com/.well-known/openid-configuration",
"description": "A short description for security scheme.",
}))
.unwrap(),
SecurityScheme::OpenIdConnect(Box::new(OpenIdConnectSecurityScheme {
open_id_connect_url: String::from(
"https://example.com/.well-known/openid-configuration"
),
description: Some(String::from("A short description for security scheme.")),
..Default::default()
})),
"deserialize",
);
}
#[test]
fn test_security_scheme_open_id_connect_serialize() {
assert_eq!(
serde_json::to_value(SecurityScheme::OpenIdConnect(Box::new(
OpenIdConnectSecurityScheme {
open_id_connect_url: String::from(
"https://example.com/.well-known/openid-configuration"
),
description: Some(String::from("A short description for security scheme.")),
..Default::default()
}
)))
.unwrap(),
json!({
"type": "openIdConnect",
"openIdConnectUrl": "https://example.com/.well-known/openid-configuration",
"description": "A short description for security scheme.",
}),
"serialize",
);
}
#[test]
fn test_security_scheme_validation() {
let spec = Spec::default();
let mut ctx = Context::new(&spec, Options::new());
SecurityScheme::OpenIdConnect(Box::new(OpenIdConnectSecurityScheme {
open_id_connect_url: String::from(
"https://example.com/.well-known/openid-configuration",
),
description: Some(String::from("A short description for security scheme.")),
..Default::default()
}))
.validate_with_context(&mut ctx, String::from("securityScheme"));
assert!(
ctx.errors.is_empty(),
"OpenIdConnect: no errors: {:?}",
ctx.errors
);
SecurityScheme::OpenIdConnect(Box::new(OpenIdConnectSecurityScheme {
open_id_connect_url: String::from(""),
description: Some(String::from("A short description for security scheme.")),
..Default::default()
}))
.validate_with_context(&mut ctx, String::from("securityScheme"));
assert_eq!(
ctx.errors.len(),
1,
"OpenIdConnect: one error: {:?}",
ctx.errors
);
ctx = Context::new(&spec, Options::new());
SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::Basic,
description: Some(String::from("A short description for security scheme.")),
..Default::default()
}))
.validate_with_context(&mut ctx, String::from("securityScheme"));
assert!(
ctx.errors.is_empty(),
"HTTP::Basic: no errors: {:?}",
ctx.errors
);
SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::Bearer,
bearer_format: Some(String::from("fooo")),
description: Some(String::from("A short description for security scheme.")),
..Default::default()
}))
.validate_with_context(&mut ctx, String::from("securityScheme"));
assert!(
ctx.errors.is_empty(),
"HTTP::Bearer with format: no errors: {:?}",
ctx.errors
);
SecurityScheme::HTTP(Box::new(HttpSecurityScheme {
scheme: HttpScheme::Basic,
bearer_format: Some(String::from("fooo")),
description: Some(String::from("A short description for security scheme.")),
..Default::default()
}))
.validate_with_context(&mut ctx, String::from("securityScheme"));
assert_eq!(
ctx.errors.len(),
1,
"HTTP::Basic with format: one error: {:?}",
ctx.errors
);
ctx = Context::new(&spec, Options::new());
SecurityScheme::ApiKey(Box::new(ApiKeySecurityScheme {
name: String::from("api_key"),
description: Some(String::from("A short description for security scheme.")),
..Default::default()
}))
.validate_with_context(&mut ctx, String::from("securityScheme"));
assert!(ctx.errors.is_empty(), "ApiKey: no errors: {:?}", ctx.errors);
SecurityScheme::ApiKey(Box::new(ApiKeySecurityScheme {
name: String::from(""),
description: Some(String::from("A short description for security scheme.")),
..Default::default()
}))
.validate_with_context(&mut ctx, String::from("securityScheme"));
assert_eq!(ctx.errors.len(), 1, "ApiKey: one error: {:?}", ctx.errors);
ctx = Context::new(&spec, Options::new());
SecurityScheme::OAuth2(Box::new(OAuth2SecurityScheme {
flows: OAuth2Flows {
..Default::default()
},
description: Some(String::from("A short description for security scheme.")),
..Default::default()
}))
.validate_with_context(&mut ctx, String::from("securityScheme"));
assert!(ctx.errors.is_empty(), "OAuth2: no errors: {:?}", ctx.errors);
SecurityScheme::OAuth2(Box::new(OAuth2SecurityScheme {
flows: OAuth2Flows {
implicit: Some(ImplicitOAuth2Flow {
authorization_url: String::from("foo"),
refresh_url: Some(String::from("bar")),
..Default::default()
}),
..Default::default()
},
description: Some(String::from("A short description for security scheme.")),
..Default::default()
}))
.validate_with_context(&mut ctx, String::from("securityScheme"));
assert_eq!(
ctx.errors.len(),
2,
"OAuth2.implicit.authorization_url: two errors: {:?}",
ctx.errors
);
ctx = Context::new(&spec, Options::new());
SecurityScheme::OAuth2(Box::new(OAuth2SecurityScheme {
flows: OAuth2Flows {
password: Some(PasswordOAuth2Flow {
token_url: String::from("foo"),
refresh_url: Some(String::from("bar")),
..Default::default()
}),
..Default::default()
},
description: Some(String::from("A short description for security scheme.")),
..Default::default()
}))
.validate_with_context(&mut ctx, String::from("securityScheme"));
assert_eq!(
ctx.errors.len(),
2,
"OAuth2.password.(token_url, refresh_url): two errors: {:?}",
ctx.errors
);
ctx = Context::new(&spec, Options::new());
SecurityScheme::OAuth2(Box::new(OAuth2SecurityScheme {
flows: OAuth2Flows {
client_credentials: Some(ClientCredentialsOAuth2Flow {
token_url: String::from("foo"),
refresh_url: Some(String::from("bar")),
..Default::default()
}),
..Default::default()
},
description: Some(String::from("A short description for security scheme.")),
..Default::default()
}))
.validate_with_context(&mut ctx, String::from("securityScheme"));
assert_eq!(
ctx.errors.len(),
2,
"OAuth2.client_credentials.(token_url, refresh_url): two errors: {:?}",
ctx.errors
);
ctx = Context::new(&spec, Options::new());
SecurityScheme::OAuth2(Box::new(OAuth2SecurityScheme {
flows: OAuth2Flows {
authorization_code: Some(AuthorizationCodeOAuth2Flow {
authorization_url: String::from("xyz"),
token_url: String::from("foo"),
refresh_url: Some(String::from("bar")),
..Default::default()
}),
..Default::default()
},
description: Some(String::from("A short description for security scheme.")),
..Default::default()
}))
.validate_with_context(&mut ctx, String::from("securityScheme"));
assert_eq!(
ctx.errors.len(),
3,
"OAuth2.authorization_code.(authorization_url, token_url, refresh_url): three errors: {:?}",
ctx.errors
);
}
}