From 1357713752a3c5b874a8c9e5d78b56e242a588d3 Mon Sep 17 00:00:00 2001 From: Riley Trautman Date: Sat, 23 Dec 2017 16:59:53 -0600 Subject: [PATCH] Add documentation for 0.1.1 release --- ACKNOWLEDGEMENTS | 1 + Cargo.toml | 2 +- src/create.rs | 147 +++++++++++++++++++++++++++++++++----- src/error.rs | 62 ++++++++++++++-- src/lib.rs | 153 +++++++++++++++++++++++++++++++++++----- src/use_hyper_client.rs | 13 +++- src/use_hyper_server.rs | 6 ++ src/use_reqwest.rs | 13 +++- src/use_rocket.rs | 7 ++ src/verify.rs | 64 ++++++++++++++++- 10 files changed, 421 insertions(+), 47 deletions(-) diff --git a/ACKNOWLEDGEMENTS b/ACKNOWLEDGEMENTS index 80308ead..e0d24d12 100644 --- a/ACKNOWLEDGEMENTS +++ b/ACKNOWLEDGEMENTS @@ -72,6 +72,7 @@ relay | 0.1.0 | MIT OR Apache-2.0 reqwest | 0.8.2 | Apache-2.0, MIT ring | 0.11.0 | Specified in license file rocket | 0.3.5 | Apache-2.0, MIT +rocket_codegen | 0.3.5 | Apache-2.0, MIT safemem | 0.2.0 | MIT OR Apache-2.0 schannel | 0.1.9 | MIT scoped-tls | 0.1.0 | Apache-2.0, MIT diff --git a/Cargo.toml b/Cargo.toml index 9d1e09bb..3d7104ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "http-signatures" description = "An implementation of the HTTP Signatures RFC" -version = "0.1.0" +version = "0.1.1" license = "GPL-3.0" authors = ["Riley Trautman "] repository = "https://github.com/asonix/http-signatures" diff --git a/src/create.rs b/src/create.rs index 72229d1c..0a546e5b 100644 --- a/src/create.rs +++ b/src/create.rs @@ -13,6 +13,8 @@ // You should have received a copy of the GNU General Public License // along with HTTP Signatures If not, see . +//! This module defines types and traits for creating HTTP Signatures. + use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; use std::sync::Arc; @@ -23,12 +25,16 @@ use base64::encode; use untrusted::Input; use super::{SignatureAlgorithm, ShaSize}; -use error::Error; +use error::{Error, CreationError}; +/// `AsHttpSignature` defines a trait for getting an Authorization Header string from any type that +/// implements it. It provides two methods: as_http_signature, which implementors must define, and +/// authorization_header, which uses as_http_signature to create the header string. pub trait AsHttpSignature where T: Read, { + /// Gets an `HttpSignature` struct from an immutably borrowed Self fn as_http_signature( &self, key_id: String, @@ -36,20 +42,20 @@ where algorithm: SignatureAlgorithm, ) -> Result, Error>; + /// Generates the Authorization Header from an immutably borrowed Self fn authorization_header( &self, key_id: String, key: T, algorithm: SignatureAlgorithm, ) -> Result { - let signing_string: SigningString = self.as_http_signature(key_id, key, algorithm)? - .into(); - let signature: Signature = signing_string.try_into()?; - - Ok(signature.authorization()) + Ok(self.as_http_signature(key_id, key, algorithm)? + .authorization_header()?) } } +/// `WithHttpSignature` defines a trait for adding an Authorization header to another library's +/// request or response object. pub trait WithHttpSignature: AsHttpSignature where T: Read, @@ -62,22 +68,58 @@ where ) -> Result<&mut Self, Error>; } -pub struct HttpSignature { +/// The `HttpSignature` struct, this is the entry point for creating an Authorization header. It +/// contains all the values required for generation. +pub struct HttpSignature +where + T: Read, +{ + /// The keyId field in the Authorization header key_id: String, + /// The key (implementing `Read`) used to sign the request key: T, + /// The algorithm used to sign the request algorithm: SignatureAlgorithm, + /// The headers that will be included in the signature headers: HashMap>, } -impl HttpSignature { +impl HttpSignature +where + T: Read, +{ + /// Create a new HttpSignature from its components. + /// + /// This method will Error if `headers` is empty. + /// + /// ### Example + /// ```rust + /// # use std::fs::File; + /// # use std::collections::HashMap; + /// # use http_signatures::Error; + /// use http_signatures::{HttpSignature, SignatureAlgorithm, ShaSize, REQUEST_TARGET}; + /// + /// # fn run() -> Result<(), Error> { + /// let key_id = "test/assets/public.der".into(); + /// let priv_key = File::open("test/assets/private.der")?; + /// + /// let alg = SignatureAlgorithm::RSA(ShaSize::FiveTwelve); + /// + /// let mut headers = HashMap::new(); + /// headers.insert(REQUEST_TARGET.into(), vec!["get /".into()]); + /// + /// let http_sig = HttpSignature::new(key_id, priv_key, alg, headers)?; + /// # Ok(()) + /// # } + /// ``` pub fn new( key_id: String, key: T, algorithm: SignatureAlgorithm, headers: HashMap>, - ) -> Result { + ) -> Result { if headers.is_empty() { - return Err(Error::NoHeaders); + return Err(CreationError::NoHeaders); } Ok(HttpSignature { @@ -99,17 +141,76 @@ impl HttpSignature { pub fn headers(&self) -> &HashMap> { &self.headers } + + /// Generate the Authorization Header from the `HttpSignature` + /// + /// This method errors if signing the signing-string fails. + /// + /// ### Example + /// ```rust + /// # use std::fs::File; + /// # use std::collections::HashMap; + /// # use http_signatures::{Error, SignatureAlgorithm, ShaSize, REQUEST_TARGET}; + /// use http_signatures::HttpSignature; + /// # fn run() -> Result<(), Error> { + /// # let key_id = "test/assets/public.der".into(); + /// # let priv_key = File::open("test/assets/private.der")?; + /// # let alg = SignatureAlgorithm::RSA(ShaSize::FiveTwelve); + /// # let mut headers = HashMap::new(); + /// # headers.insert(REQUEST_TARGET.into(), vec!["get /".into()]); + /// # let http_signature = HttpSignature::new(key_id, priv_key, alg, headers)?; + /// + /// let auth_header = http_signature.authorization_header()?; + /// # Ok(()) + /// # } + /// ``` + pub fn authorization_header(self) -> Result { + let signing_string: SigningString = self.into(); + let signature: Signature = signing_string.try_into()?; + + Ok(signature.authorization()) + } } +/// A default implementation of `AsHttpSignature` for `HttpSignature`. +/// +/// This only works if type `T` is `Clone` in addition to `Read`, which is normally required. This +/// implementation doesn't serve much of a purpose. +impl AsHttpSignature for HttpSignature +where + T: Read + Clone, +{ + fn as_http_signature(&self, _: String, _: T, _: SignatureAlgorithm) -> Result { + Ok(HttpSignature { + key_id: self.key_id.clone(), + key: self.key.clone(), + algorithm: self.algorithm.clone(), + headers: self.headers.clone(), + }) + } +} + +/// The `SigningString` struct uses what was given in the `HttpSignature` struct, but also has a +/// plaintext field called `signing_string` which holds the string used to sign the request. +/// +/// Since `From>` was implemented for `SigningString`, the transition is as +/// simple as calling `http_signature.into()`. +/// +/// This struct does not have public fields, and does not have a constructor since it should only +/// be used as an intermediate point from `HttpSignature` to the signed string. pub struct SigningString { key_id: String, key: T, headers: Vec, algorithm: SignatureAlgorithm, + // The plaintext string used to sign the request signing_string: String, } -impl From> for SigningString { +impl From> for SigningString +where + T: Read, +{ fn from(http_signature: HttpSignature) -> Self { let (header_keys, signing_vec): (Vec<_>, Vec<_>) = http_signature .headers @@ -132,6 +233,11 @@ impl From> for SigningString { } } +/// `Signature` is the result of using the `key: T` of `SigningString` to sign the +/// `signing_string`. +/// +/// To get the Authorization Header String from the Signature, the `authorization` method is +/// provided. pub struct Signature { sig: String, key_id: String, @@ -140,6 +246,7 @@ pub struct Signature { } impl Signature { + /// Get the Authorization Header String. pub fn authorization(self) -> String { let alg: &str = self.algorithm.into(); @@ -151,7 +258,7 @@ impl Signature { ) } - fn rsa(mut key: T, size: &ShaSize, signing_string: &[u8]) -> Result + fn rsa(mut key: T, size: &ShaSize, signing_string: &[u8]) -> Result where T: Read, { @@ -161,14 +268,14 @@ impl Signature { let key_pair = signature::RSAKeyPair::from_der(private_key_der).map_err( |_| { - Error::BadPrivateKey + CreationError::BadPrivateKey }, )?; let key_pair = Arc::new(key_pair); - let mut signing_state = signature::RSASigningState::new(key_pair).map_err( - |_| Error::Unknown, - )?; + let mut signing_state = signature::RSASigningState::new(key_pair).map_err(|_| { + CreationError::SigningError + })?; let rng = rand::SystemRandom::new(); let mut signature = vec![0; signing_state.key_pair().public_modulus_len()]; @@ -183,12 +290,12 @@ impl Signature { signing_string, signature.as_mut_slice(), ) - .map_err(|_| Error::SigningError)?; + .map_err(|_| CreationError::SigningError)?; Ok(encode(signature.as_slice())) } - fn hmac(mut key: T, size: &ShaSize, signing_string: &[u8]) -> Result + fn hmac(mut key: T, size: &ShaSize, signing_string: &[u8]) -> Result where T: Read, { @@ -212,8 +319,10 @@ impl TryFrom> for Signature where T: Read, { - type Error = Error; + type Error = CreationError; + /// Attempt to sign the signing_string. If signing fails, a `Signature` will not be created and + /// an `Error` will be returned. fn try_from(signing_string: SigningString) -> Result { Ok(match signing_string.algorithm { SignatureAlgorithm::RSA(size) => { diff --git a/src/error.rs b/src/error.rs index 12fddf5c..a8c9f0a9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -13,14 +13,20 @@ // You should have received a copy of the GNU General Public License // along with HTTP Signatures If not, see . +//! This module defines the Error types for http_signatures. + use std::io::Error as IoError; +/// The root Error #[derive(Debug)] pub enum Error { + /// Problems opening files and such IO(IoError), - NoHeaders, - SigningError, - BadPrivateKey, + /// Problems verifying a request + Verification(VerificationError), + /// Problems creating a signature + Creation(CreationError), + /// Unknown error occurred Unknown, } @@ -30,22 +36,70 @@ impl From for Error { } } +impl From for Error { + fn from(e: VerificationError) -> Self { + Error::Verification(e) + } +} + +impl From for Error { + fn from(e: DecodeError) -> Self { + VerificationError::Decode(e).into() + } +} + +impl From for Error { + fn from(e: CreationError) -> Self { + Error::Creation(e) + } +} + +/// When creating a signature doesn't work +#[derive(Debug)] +pub enum CreationError { + /// Problems reading keys + IO(IoError), + /// Headers must be provided to sign a request + NoHeaders, + /// An error occurred when signing the request + SigningError, + /// An error occurred when interacting with an RSA key + BadPrivateKey, +} + +impl From for CreationError { + fn from(e: IoError) -> Self { + CreationError::IO(e) + } +} + +/// When decoding a signature doesn't work #[derive(Debug)] pub enum DecodeError { + /// A required key is missing MissingKey(&'static str), + /// The signature algorithm is not supported InvalidAlgorithm(String), + /// The key was not properly encoded to base64 NotBase64, - Unknown, } +/// When a request cannot be verified #[derive(Debug)] pub enum VerificationError { + /// Issues decoding a signature Decode(DecodeError), + /// Headers present in the `headers` field are missing from the request MissingHeaders(String), + /// When the `get_key` method from the `GetKey` type fails GetKey, + /// Problems reading the required keys ReadKey, + /// Problems verifying the signature BadSignature, + /// When the Authorization header is missing HeaderNotPresent, + /// When we're not sure what went wrong Unknown, } diff --git a/src/lib.rs b/src/lib.rs index 4699b746..5aa5d737 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,8 +13,112 @@ // You should have received a copy of the GNU General Public License // along with HTTP Signatures If not, see . +//! HTTP Signatures, an implementation of [the http signatures specification](https://tools.ietf.org/html/draft-cavage-http-signatures-09) +//! +//! The base crate provides types for creating and verifying signatures, and the features +//! `use_hyper`, `use_reqwest`, and `use_rocket` provide implementations of required traits for +//! easily using HTTP Signatures with web applications. +//! +//! # Creating an HTTP Signature +//! +//! To get a string that would be the contents of an HTTP Request's Authorization header, a few +//! steps must be taken. The method, path, and query must be known, furthermore, there must be at +//! least one item in the headers hashmap, if there is not, the HTTP Signature creation will fail. +//! +//! ```rust +//! use http_signatures::{HttpSignature, SignatureAlgorithm, ShaSize}; +//! use http_signatures::REQUEST_TARGET; +//! # use http_signatures::Error; +//! # use std::fs::File; +//! # use std::collections::HashMap; +//! # fn run() -> Result<(), Error> { +//! # let priv_key = File::open("test/assets/private.der")?; +//! +//! let method = "GET"; +//! let path = "/test"; +//! let query = "key=value"; +//! +//! let mut headers: HashMap> = HashMap::new(); +//! headers.insert("Accept".into(), vec!["application/json".into()]); +//! headers.insert( +//! REQUEST_TARGET.into(), +//! vec![format!("{} {}?{}", method.to_lowercase(), path, query)], +//! ); +//! +//! let algorithm = SignatureAlgorithm::RSA(ShaSize::FiveTwelve); +//! let key_id = "1".into(); +//! +//! let auth_header = HttpSignature::new(key_id, priv_key, algorithm, headers)? +//! .authorization_header()?; +//! +//! println!("Authorization: {}", auth_header); +//! # Ok(()) +//! # } +//! ``` +//! +//! # Verifying an HTTP Signature +//! +//! To verify a header, one must implement a type called `GetKey`. This type is imporant because it +//! contains the information required to convert a key id, represented as &str, into a Key. This +//! can be done by accessing some external state, or by storing the required state in the struct +//! that implements GetKey. +//! +//! ```rust +//! # use http_signatures::{HttpSignature, SignatureAlgorithm, ShaSize}; +//! # use http_signatures::REQUEST_TARGET; +//! # use http_signatures::Error; +//! use http_signatures::{GetKey, AuthorizationHeader}; +//! # use std::fs::File; +//! # use std::collections::HashMap; +//! # fn some_auth_header() -> Result { +//! # let priv_key = File::open("test/assets/private.der")?; +//! # let method = "GET"; +//! # let path = "/test"; +//! # let query = "key=value"; +//! # let mut headers: HashMap> = HashMap::new(); +//! # headers.insert("Accept".into(), vec!["application/json".into()]); +//! # headers.insert( +//! # REQUEST_TARGET.into(), +//! # vec![format!("{} {}?{}", method.to_lowercase(), path, query)], +//! # ); +//! # let algorithm = SignatureAlgorithm::RSA(ShaSize::FiveTwelve); +//! # let key_id = "1".into(); +//! # let auth_header = HttpSignature::new(key_id, priv_key, algorithm, headers)? +//! # .authorization_header()?; +//! # Ok(auth_header) +//! # } +//! +//! struct MyKeyGetter; +//! +//! impl GetKey for MyKeyGetter { +//! type Key = File; +//! type Error = Error; +//! +//! fn get_key(self, _key_id: &str) -> Result { +//! File::open("test/assets/public.der").map_err(Error::from) +//! } +//! } +//! # fn run() -> Result<(), Error> { +//! # let auth_header = some_auth_header()?; +//! +//! let mut headers = Vec::new(); +//! headers.push(("Accept".into(), "application/json".into())); +//! +//! let method = "GET"; +//! let path = "/test"; +//! let query = "key=value"; +//! +//! let key_getter = MyKeyGetter; +//! +//! let auth_header = AuthorizationHeader::new(&auth_header)?; +//! auth_header +//! .verify(&headers, method, path, Some(query), key_getter)?; +//! +//! # Ok(()) +//! # } +//! ``` + #![feature(try_from)] -#![feature(underscore_lifetimes)] #[cfg(feature = "use_hyper")] extern crate hyper; @@ -41,25 +145,41 @@ mod create; mod verify; mod error; -pub use create::{AsHttpSignature, WithHttpSignature, HttpSignature, SigningString}; +use error::DecodeError; + +pub use create::{AsHttpSignature, WithHttpSignature, HttpSignature}; pub use verify::{AuthorizationHeader, VerifyAuthorizationHeader, GetKey}; -pub use error::{Error, DecodeError, VerificationError}; +pub use error::Error; -const REQUEST_TARGET: &'static str = "(request-target)"; +pub const REQUEST_TARGET: &'static str = "(request-target)"; -#[derive(Debug)] +/// Variations of the Sha hashing function. +/// +/// This stuct is used to tell the RSA and HMAC signature functions how big the sha hash should be. +/// It currently offers three variations. +#[derive(Debug, Clone)] pub enum ShaSize { + /// SHA256 TwoFiftySix, + /// SHA384 ThreeEightyFour, + /// SHA512 FiveTwelve, } -#[derive(Debug)] +/// Which algorithm should be used to create an HTTP header. +/// +/// This library uses Ring 0.11.0 for creating and verifying hashes, so this determines whether the +/// library will use Ring's RSA Signatures or Rings's HMAC signatures. +#[derive(Debug, Clone)] pub enum SignatureAlgorithm { + /// RSA RSA(ShaSize), + /// HMAC HMAC(ShaSize), } +/// Convert an &str into a SignatureAlgorithm impl<'a> TryFrom<&'a str> for SignatureAlgorithm { type Error = DecodeError; @@ -76,6 +196,7 @@ impl<'a> TryFrom<&'a str> for SignatureAlgorithm { } } +/// Convert a SignatureAlgorithm into an &str impl From for &'static str { fn from(alg: SignatureAlgorithm) -> Self { match alg { @@ -102,7 +223,6 @@ mod tests { use ring::{digest, hmac, rand}; use std::collections::HashMap; - use std::convert::TryInto; use std::io::Cursor; use std::fs::File; @@ -110,11 +230,9 @@ mod tests { use super::ShaSize; use super::REQUEST_TARGET; use create::HttpSignature; - use create::SigningString; use verify::GetKey; use verify::AuthorizationHeader; use error::VerificationError; - use create::Signature; struct HmacKeyGetter { key: Vec, @@ -201,13 +319,11 @@ mod tests { let algorithm = SignatureAlgorithm::HMAC(sha_size); let key_id = "1".into(); - let http_sig = HttpSignature::new(key_id, Cursor::new(key_vec), algorithm, headers_one) + let auth_header = HttpSignature::new(key_id, Cursor::new(key_vec), algorithm, headers_one) + .unwrap() + .authorization_header() .unwrap(); - let signing_string: SigningString<_> = http_sig.into(); - let signature: Signature = signing_string.try_into().unwrap(); - - let auth_header = signature.authorization(); let auth_header = AuthorizationHeader::new(&auth_header).unwrap(); auth_header @@ -238,12 +354,11 @@ mod tests { let algorithm = SignatureAlgorithm::RSA(sha_size); let key_id = "1".into(); - let http_sig = HttpSignature::new(key_id, priv_key, algorithm, headers_one).unwrap(); - - let signing_string: SigningString<_> = http_sig.into(); - let signature: Signature = signing_string.try_into().unwrap(); + let auth_header = HttpSignature::new(key_id, priv_key, algorithm, headers_one) + .unwrap() + .authorization_header() + .unwrap(); - let auth_header = signature.authorization(); let auth_header = AuthorizationHeader::new(&auth_header).unwrap(); auth_header diff --git a/src/use_hyper_client.rs b/src/use_hyper_client.rs index e2ce82a4..be9654e6 100644 --- a/src/use_hyper_client.rs +++ b/src/use_hyper_client.rs @@ -22,6 +22,10 @@ use create::{AsHttpSignature, WithHttpSignature, HttpSignature}; use hyper::Request as HyperRequest; +/// An implementation of `AsHttpSignature` for `hyper::Request`. +/// +/// This trait is not often used directly, but is required by the `WithHttpSignature` trait defined +/// below. impl AsHttpSignature for HyperRequest where T: Read, @@ -61,10 +65,17 @@ where acc }); - HttpSignature::new(key_id, key, algorithm, headers) + HttpSignature::new(key_id, key, algorithm, headers).map_err(Error::from) } } +/// An implementation of `WithHttpSignature` for `hyper::Request` +/// +/// This automatically adds an Authorization header to a given `hyper::Request` struct containing +/// an HTTP Signature. +/// +/// See [https://github.com/asonix/http-signatures/blob/master/examples/hyper_client.rs](this +/// example) for usage information. impl WithHttpSignature for HyperRequest where T: Read, diff --git a/src/use_hyper_server.rs b/src/use_hyper_server.rs index 9ffefc34..82c7eb79 100644 --- a/src/use_hyper_server.rs +++ b/src/use_hyper_server.rs @@ -19,6 +19,12 @@ use hyper::server::Request; use verify::{AuthorizationHeader, VerifyAuthorizationHeader, GetKey}; use error::VerificationError; +/// Implements `VerifyAuthorizationHeader` for `hyper::server::Request`. +/// +/// This allows easy verification of incomming requests in Hyper. +/// +/// See [https://github.com/asonix/http-signatures/blob/master/examples/hyper_server.rs](this +/// example) for usage information. impl VerifyAuthorizationHeader for Request { fn verify_authorization_header( &self, diff --git a/src/use_reqwest.rs b/src/use_reqwest.rs index 7c1326a8..6904cbed 100644 --- a/src/use_reqwest.rs +++ b/src/use_reqwest.rs @@ -22,6 +22,10 @@ use create::{AsHttpSignature, WithHttpSignature, HttpSignature}; use reqwest::Request as ReqwestRequest; +/// An implementation of `AsHttpSignature` for `reqwest::Request`. +/// +/// This trait is not often used directly, but is required by the `WithHttpSignature` trait defined +/// below. impl AsHttpSignature for ReqwestRequest where T: Read, @@ -61,10 +65,17 @@ where acc }); - HttpSignature::new(key_id, key, algorithm, headers) + HttpSignature::new(key_id, key, algorithm, headers).map_err(Error::from) } } +/// An implementation of `WithHttpSignature` for `reqwest::Request` +/// +/// This automatically adds an Authorization header to a given `reqwest::Request` struct containing +/// an HTTP Signature. +/// +/// See [https://github.com/asonix/http-signatures/blob/master/examples/reqwest.rs](this +/// example) for usage information. impl WithHttpSignature for ReqwestRequest where T: Read, diff --git a/src/use_rocket.rs b/src/use_rocket.rs index 43e9342b..05466eb2 100644 --- a/src/use_rocket.rs +++ b/src/use_rocket.rs @@ -18,6 +18,13 @@ use rocket::Request; use verify::{AuthorizationHeader, VerifyAuthorizationHeader, GetKey}; use error::VerificationError; +/// Implements `VerifyAuthorizationHeader` for `rocket::Request`. +/// +/// This allows easy verification of incomming requests in Rocket, and can be used with Request +/// guards. +/// +/// See [https://github.com/asonix/http-signatures/blob/master/examples/rocket.rs](this +/// example) for usage information. impl<'r> VerifyAuthorizationHeader for Request<'r> { fn verify_authorization_header( &self, diff --git a/src/verify.rs b/src/verify.rs index 20b06e52..9cc01ec0 100644 --- a/src/verify.rs +++ b/src/verify.rs @@ -31,6 +31,50 @@ const ALGORITHM: &'static str = "algorithm"; const DATE: &'static str = "date"; const SIGNATURE: &'static str = "signature"; +/// The GetKey trait is used during HTTP Signature verification to access the required decryption +/// key based on a given key_id. +/// +/// The `key_id` is provided in the Authorization header of the request as `KeyId`. +/// +/// ### Example +/// ```rust +/// # use std::io::Cursor; +/// # use std::collections::HashMap; +/// use http_signatures::GetKey; +/// +/// struct MyKeyGetter { +/// keys: HashMap>, +/// } +/// +/// impl MyKeyGetter { +/// pub fn new() -> Self { +/// MyKeyGetter { +/// keys: HashMap::new(), +/// } +/// } +/// +/// pub fn add_key(&mut self, key_id: String, key: Vec) { +/// self.keys.insert(key_id, key); +/// } +/// } +/// +/// impl GetKey for MyKeyGetter { +/// type Key = Cursor>; +/// type Error = (); +/// +/// fn get_key(self, key_id: &str) -> Result { +/// self.keys.get(key_id).map(|key| Cursor::new(key.clone())).ok_or(()) +/// } +/// } +/// +/// # fn run() -> Result<(), ()> { +/// let mut key_getter = MyKeyGetter::new(); +/// key_getter.add_key("key-1".into(), vec![1, 2, 3, 4, 5]); +/// +/// key_getter.get_key("key-1")?; +/// # Ok(()) +/// # } +/// ``` pub trait GetKey { type Key: Read; type Error; @@ -38,6 +82,13 @@ pub trait GetKey { fn get_key(self, key_id: &str) -> Result; } +/// The `VerifyAuthorizationHeader` trait is meant to be implemented for the request types from +/// http libraries (such as Hyper and Rocket). This trait makes verifying requests much easier, +/// since the `verify_authorization_header()` method can be called directly on a Request type. +/// +/// For examples, see the +/// [hyper server](https://github.com/asonix/http-signatures/blob/master/examples/hyper_server.rs) +/// and [rocket](https://github.com/asonix/http-signatures/blob/master/examples/rocket.rs) files. pub trait VerifyAuthorizationHeader { fn verify_authorization_header( &self, @@ -45,6 +96,13 @@ pub trait VerifyAuthorizationHeader { ) -> Result<(), VerificationError>; } +/// The `AuthorizationHeader` struct is the direct reasult of reading in the Authorization header +/// from a given request. +/// +/// It contains the keys to the request's headers in the correct order for recreating the signing +/// string, the algorithm used to create the signature, and the signature itself. +/// +/// It also contains the key_id, which will be handled by a type implementing `GetKey`. pub struct AuthorizationHeader<'a> { key_id: &'a str, header_keys: Vec<&'a str>, @@ -53,10 +111,12 @@ pub struct AuthorizationHeader<'a> { } impl<'a> AuthorizationHeader<'a> { + /// Try to create an `AuthorizationHeader` from a given String. pub fn new(s: &'a str) -> Result { s.try_into() } + /// Try to verify the current `AuthorizationHeader`. pub fn verify( self, headers: &[(&str, &str)], @@ -68,7 +128,7 @@ impl<'a> AuthorizationHeader<'a> { where G: GetKey, { - let vah: CheckAuthorizationHeader = CheckAuthorizationHeader { + let vah = CheckAuthorizationHeader { auth_header: self, headers: headers, method: method, @@ -133,7 +193,7 @@ impl<'a> TryFrom<&'a str> for AuthorizationHeader<'a> { } } -pub struct CheckAuthorizationHeader<'a> { +struct CheckAuthorizationHeader<'a> { auth_header: AuthorizationHeader<'a>, headers: &'a [(&'a str, &'a str)], method: &'a str,