Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement schemars::JsonSchema for new types. #177

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ reqwest-blocking = ["oauth2/reqwest-blocking"]
rustls-tls = ["oauth2/rustls-tls"]
timing-resistant-secret-traits = ["oauth2/timing-resistant-secret-traits"]
ureq = ["oauth2/ureq"]
schemars = ["dep:schemars", "oauth2/schemars"]

[[example]]
name = "gitlab"
Expand Down Expand Up @@ -70,10 +71,17 @@ url = { version = "2.4", features = ["serde"] }
subtle = "2.4"
ed25519-dalek = { version = "2.0.0", features = ["pem"] }

# Feature: schemars
schemars = { version = "0.8", optional = true}

[dev-dependencies]
color-backtrace = { version = "0.5" }
env_logger = "0.9"
pretty_assertions = "1.0"
reqwest = { version = "0.12", features = ["blocking", "rustls-tls"], default-features = false }
retry = "1.0"
anyhow = "1.0"

# TEMP: https://github.com/ramosbugs/oauth2-rs/pull/279
[patch.crates-io]
oauth2 = { git = "https://github.com/gibbz00/oauth2-rs", branch = "schemars" }
2 changes: 2 additions & 0 deletions src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ impl Display for CoreAuthPrompt {
new_type![
/// OpenID Connect Core claim name.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
CoreClaimName(String)
];
impl ClaimName for CoreClaimName {}
Expand Down Expand Up @@ -447,6 +448,7 @@ impl ClientAuthMethod for CoreClientAuthMethod {}
new_type![
/// OpenID Connect Core gender claim.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
CoreGenderClaim(String)
];
impl GenderClaim for CoreGenderClaim {}
Expand Down
2 changes: 2 additions & 0 deletions src/jwt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub(crate) mod tests;

new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
JsonWebTokenContentType(String)
];

Expand All @@ -34,6 +35,7 @@ new_type![
///
/// To compare two different JSON Web Token types, please use the normalized version via [`JsonWebTokenType::normalize`].
#[derive(Deserialize, Hash, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
JsonWebTokenType(String)

impl {
Expand Down
53 changes: 53 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ macro_rules! new_secret_type {
#[$attr]
)*
#[cfg_attr(feature = "timing-resistant-secret-traits", derive(Eq))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct $name($type);
impl $name {
$($item)*
Expand Down Expand Up @@ -424,6 +425,22 @@ macro_rules! new_url_type {
}
}
impl Eq for $name {}

#[cfg(feature = "schemars")]
impl schemars::JsonSchema for $name {
fn schema_name() -> String {
stringify!($name).to_owned()
}

fn schema_id() -> std::borrow::Cow<'static, str> {
std::borrow::Cow::Borrowed(concat!("openidconnect::", stringify!($name)))
}

fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
// HELP(gibbz00): do we want to generate the schema for a URL or a String?
gen.subschema_for::<String>()
}
}
};
}

Expand Down Expand Up @@ -951,3 +968,39 @@ macro_rules! serialize_as_str {
}
};
}

#[cfg(test)]
mod tests {
#[cfg(feature = "schemars")]
mod json_schema {
use schemars::schema_for;
use serde_json::json;

#[test]
fn generates_new_url_type_json_schema() {
let expected_schema = json!({
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ClientUrl",
"type": "string"
});

let schema = schema_for!(crate::ClientUrl);
let actual_schema = serde_json::to_value(&schema).unwrap();
assert_eq!(expected_schema, actual_schema);
}

#[test]
fn generates_new_secret_type_json_schema() {
let expected_schema = json!({
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Nonce",
"description": "String value used to associate a client session with an ID Token, and to mitigate replay attacks.",
"type": "string"
});

let schema = schema_for!(crate::Nonce);
let actual_schema = serde_json::to_value(&schema).unwrap();
assert_eq!(expected_schema, actual_schema);
}
}
}
1 change: 1 addition & 0 deletions src/types/jwk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::hash::Hash;
new_type![
/// ID of a JSON Web Key.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
JsonWebKeyId(String)
];

Expand Down
1 change: 1 addition & 0 deletions src/types/localized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::collections::HashMap;
new_type![
/// Language tag adhering to RFC 5646 (e.g., `fr` or `fr-CA`).
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
LanguageTag(String)
];
impl AsRef<str> for LanguageTag {
Expand Down
27 changes: 27 additions & 0 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ new_type![
/// Set of authentication methods or procedures that are considered to be equivalent to each
/// other in a particular context.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
AuthenticationContextClass(String)
];
impl AsRef<str> for AuthenticationContextClass {
Expand All @@ -90,12 +91,14 @@ new_type![
///
/// Defining specific AMR identifiers is beyond the scope of the OpenID Connect Core spec.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
AuthenticationMethodReference(String)
];

new_type![
/// Access token hash.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
AccessTokenHash(String)
impl {
/// Initialize a new access token hash from an [`AccessToken`] and signature algorithm.
Expand All @@ -117,36 +120,42 @@ new_type![
new_type![
/// Country portion of address.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
AddressCountry(String)
];

new_type![
/// Locality portion of address.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
AddressLocality(String)
];

new_type![
/// Postal code portion of address.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
AddressPostalCode(String)
];

new_type![
/// Region portion of address.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
AddressRegion(String)
];

new_type![
/// Audience claim value.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
Audience(String)
];

new_type![
/// Authorization code hash.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
AuthorizationCodeHash(String)
impl {
/// Initialize a new authorization code hash from an [`AuthorizationCode`] and signature
Expand All @@ -169,6 +178,7 @@ new_type![
new_type![
/// OpenID Connect client name.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
ClientName(String)
];

Expand All @@ -185,6 +195,7 @@ new_url_type![
new_type![
/// Client contact e-mail address.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
ClientContactEmail(String)
];

Expand All @@ -203,79 +214,92 @@ new_type![
/// providing just year can result in varying month and day, so the implementers need to take
/// this factor into account to correctly process the dates.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
EndUserBirthday(String)
];

new_type![
/// End user's e-mail address.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
EndUserEmail(String)
];

new_type![
/// End user's family name.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
EndUserFamilyName(String)
];

new_type![
/// End user's given name.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
EndUserGivenName(String)
];

new_type![
/// End user's middle name.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
EndUserMiddleName(String)
];

new_type![
/// End user's name.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
EndUserName(String)
];

new_type![
/// End user's nickname.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
EndUserNickname(String)
];

new_type![
/// End user's phone number.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
EndUserPhoneNumber(String)
];

new_type![
/// URL of end user's profile picture.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
EndUserPictureUrl(String)
];

new_type![
/// URL of end user's profile page.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
EndUserProfileUrl(String)
];

new_type![
/// End user's time zone as a string from the
/// [time zone database](https://www.iana.org/time-zones).
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
EndUserTimezone(String)
];

new_type![
/// URL of end user's website.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
EndUserWebsiteUrl(String)
];

new_type![
/// End user's username.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
EndUserUsername(String)
];

Expand All @@ -286,6 +310,7 @@ new_type![
/// either as a carriage return/line feed pair (`"\r\n"`) or as a single line feed character
/// (`"\n"`).
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
FormattedAddress(String)
];

Expand Down Expand Up @@ -439,13 +464,15 @@ new_type![
/// separated by newlines. Newlines can be represented either as a carriage return/line feed
/// pair (`\r\n`) or as a single line feed character (`\n`).
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
StreetAddress(String)
];

new_type![
/// Locally unique and never reassigned identifier within the Issuer for the End-User, which is
/// intended to be consumed by the client application.
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
SubjectIdentifier(String)
];

Expand Down