mirror of
https://git.asonix.dog/asonix/http-signature-normalization.git
synced 2024-11-24 18:31:01 +00:00
Try async trait, web block on client signing
This commit is contained in:
parent
dbd852156b
commit
20cad6bea8
5 changed files with 100 additions and 34 deletions
|
@ -27,6 +27,7 @@ required-features = ["sha-2"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-web = "3.0.0-alpha.1"
|
actix-web = "3.0.0-alpha.1"
|
||||||
actix-http = "2.0.0-alpha.2"
|
actix-http = "2.0.0-alpha.2"
|
||||||
|
async-trait = "0.1.27"
|
||||||
base64 = { version = "0.11", optional = true }
|
base64 = { version = "0.11", optional = true }
|
||||||
bytes = "0.5.4"
|
bytes = "0.5.4"
|
||||||
chrono = "0.4.6"
|
chrono = "0.4.6"
|
||||||
|
|
|
@ -7,6 +7,7 @@ use actix_http::encoding::Decoder;
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
client::{ClientRequest, ClientResponse, SendRequestError},
|
client::{ClientRequest, ClientResponse, SendRequestError},
|
||||||
dev::Payload,
|
dev::Payload,
|
||||||
|
error::BlockingError,
|
||||||
http::header::{InvalidHeaderValue, ToStrError},
|
http::header::{InvalidHeaderValue, ToStrError},
|
||||||
};
|
};
|
||||||
use std::{fmt::Display, future::Future};
|
use std::{fmt::Display, future::Future};
|
||||||
|
@ -43,9 +44,10 @@ pub trait DigestVerify {
|
||||||
/// It generates HTTP Signatures after the Digest header has been added, in order to have
|
/// It generates HTTP Signatures after the Digest header has been added, in order to have
|
||||||
/// verification that the body has not been tampered with, or that the request can't be replayed by
|
/// verification that the body has not been tampered with, or that the request can't be replayed by
|
||||||
/// a malicious entity
|
/// a malicious entity
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
pub trait SignExt: Sign {
|
pub trait SignExt: Sign {
|
||||||
/// Set the Digest and Authorization headers on the request
|
/// Set the Digest and Authorization headers on the request
|
||||||
fn authorization_signature_with_digest<F, E, K, D, V>(
|
async fn authorization_signature_with_digest<F, E, K, D, V>(
|
||||||
self,
|
self,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
key_id: K,
|
key_id: K,
|
||||||
|
@ -54,15 +56,20 @@ pub trait SignExt: Sign {
|
||||||
f: F,
|
f: F,
|
||||||
) -> Result<DigestClient<V>, E>
|
) -> Result<DigestClient<V>, E>
|
||||||
where
|
where
|
||||||
F: FnOnce(&str) -> Result<String, E>,
|
F: FnOnce(&str) -> Result<String, E> + Send + 'static,
|
||||||
E: From<ToStrError> + From<InvalidHeaderValue>,
|
E: From<BlockingError<E>>
|
||||||
|
+ From<ToStrError>
|
||||||
|
+ From<InvalidHeaderValue>
|
||||||
|
+ std::fmt::Debug
|
||||||
|
+ Send
|
||||||
|
+ 'static,
|
||||||
K: Display,
|
K: Display,
|
||||||
D: DigestCreate,
|
D: DigestCreate,
|
||||||
V: AsRef<[u8]>,
|
V: AsRef<[u8]>,
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
|
||||||
/// Set the Digest and Signature headers on the request
|
/// Set the Digest and Signature headers on the request
|
||||||
fn signature_with_digest<F, E, K, D, V>(
|
async fn signature_with_digest<F, E, K, D, V>(
|
||||||
self,
|
self,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
key_id: K,
|
key_id: K,
|
||||||
|
@ -71,8 +78,13 @@ pub trait SignExt: Sign {
|
||||||
f: F,
|
f: F,
|
||||||
) -> Result<DigestClient<V>, E>
|
) -> Result<DigestClient<V>, E>
|
||||||
where
|
where
|
||||||
F: FnOnce(&str) -> Result<String, E>,
|
F: FnOnce(&str) -> Result<String, E> + Send + 'static,
|
||||||
E: From<ToStrError> + From<InvalidHeaderValue>,
|
E: From<BlockingError<E>>
|
||||||
|
+ From<ToStrError>
|
||||||
|
+ From<InvalidHeaderValue>
|
||||||
|
+ std::fmt::Debug
|
||||||
|
+ Send
|
||||||
|
+ 'static,
|
||||||
K: Display,
|
K: Display,
|
||||||
D: DigestCreate,
|
D: DigestCreate,
|
||||||
V: AsRef<[u8]>,
|
V: AsRef<[u8]>,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
client::ClientRequest,
|
client::ClientRequest,
|
||||||
|
error::BlockingError,
|
||||||
http::header::{InvalidHeaderValue, ToStrError},
|
http::header::{InvalidHeaderValue, ToStrError},
|
||||||
};
|
};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
@ -9,8 +10,9 @@ use crate::{
|
||||||
Config, Sign,
|
Config, Sign,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
impl SignExt for ClientRequest {
|
impl SignExt for ClientRequest {
|
||||||
fn authorization_signature_with_digest<F, E, K, D, V>(
|
async fn authorization_signature_with_digest<F, E, K, D, V>(
|
||||||
self,
|
self,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
key_id: K,
|
key_id: K,
|
||||||
|
@ -19,8 +21,13 @@ impl SignExt for ClientRequest {
|
||||||
f: F,
|
f: F,
|
||||||
) -> Result<DigestClient<V>, E>
|
) -> Result<DigestClient<V>, E>
|
||||||
where
|
where
|
||||||
F: FnOnce(&str) -> Result<String, E>,
|
F: FnOnce(&str) -> Result<String, E> + Send + 'static,
|
||||||
E: From<ToStrError> + From<InvalidHeaderValue>,
|
E: From<BlockingError<E>>
|
||||||
|
+ From<ToStrError>
|
||||||
|
+ From<InvalidHeaderValue>
|
||||||
|
+ std::fmt::Debug
|
||||||
|
+ Send
|
||||||
|
+ 'static,
|
||||||
K: Display,
|
K: Display,
|
||||||
D: DigestCreate,
|
D: DigestCreate,
|
||||||
V: AsRef<[u8]>,
|
V: AsRef<[u8]>,
|
||||||
|
@ -30,10 +37,11 @@ impl SignExt for ClientRequest {
|
||||||
|
|
||||||
self.set_header("Digest", format!("{}={}", D::NAME, digest))
|
self.set_header("Digest", format!("{}={}", D::NAME, digest))
|
||||||
.authorization_signature(config, key_id, f)
|
.authorization_signature(config, key_id, f)
|
||||||
|
.await
|
||||||
.map(|c| DigestClient::new(c, v))
|
.map(|c| DigestClient::new(c, v))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature_with_digest<F, E, K, D, V>(
|
async fn signature_with_digest<F, E, K, D, V>(
|
||||||
self,
|
self,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
key_id: K,
|
key_id: K,
|
||||||
|
@ -42,8 +50,13 @@ impl SignExt for ClientRequest {
|
||||||
f: F,
|
f: F,
|
||||||
) -> Result<DigestClient<V>, E>
|
) -> Result<DigestClient<V>, E>
|
||||||
where
|
where
|
||||||
F: FnOnce(&str) -> Result<String, E>,
|
F: FnOnce(&str) -> Result<String, E> + Send + 'static,
|
||||||
E: From<ToStrError> + From<InvalidHeaderValue>,
|
E: From<BlockingError<E>>
|
||||||
|
+ From<ToStrError>
|
||||||
|
+ From<InvalidHeaderValue>
|
||||||
|
+ std::fmt::Debug
|
||||||
|
+ Send
|
||||||
|
+ 'static,
|
||||||
K: Display,
|
K: Display,
|
||||||
D: DigestCreate,
|
D: DigestCreate,
|
||||||
V: AsRef<[u8]>,
|
V: AsRef<[u8]>,
|
||||||
|
@ -53,6 +66,7 @@ impl SignExt for ClientRequest {
|
||||||
|
|
||||||
self.set_header("Digest", format!("{}={}", D::NAME, digest))
|
self.set_header("Digest", format!("{}={}", D::NAME, digest))
|
||||||
.signature(config, key_id, f)
|
.signature(config, key_id, f)
|
||||||
|
.await
|
||||||
.map(|c| DigestClient::new(c, v))
|
.map(|c| DigestClient::new(c, v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,10 +146,13 @@
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use actix_web::http::{
|
use actix_web::{
|
||||||
header::{HeaderMap, InvalidHeaderValue, ToStrError},
|
error::BlockingError,
|
||||||
uri::PathAndQuery,
|
http::{
|
||||||
Method,
|
header::{HeaderMap, InvalidHeaderValue, ToStrError},
|
||||||
|
uri::PathAndQuery,
|
||||||
|
Method,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use chrono::Duration;
|
use chrono::Duration;
|
||||||
use std::{collections::BTreeMap, fmt::Display, future::Future};
|
use std::{collections::BTreeMap, fmt::Display, future::Future};
|
||||||
|
@ -213,20 +216,36 @@ pub trait SignatureVerify {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait implemented by the Actix Web ClientRequest type to add an HTTP signature to the request
|
/// A trait implemented by the Actix Web ClientRequest type to add an HTTP signature to the request
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
pub trait Sign {
|
pub trait Sign {
|
||||||
/// Add an Authorization Signature to the request
|
/// Add an Authorization Signature to the request
|
||||||
fn authorization_signature<F, E, K>(self, config: &Config, key_id: K, f: F) -> Result<Self, E>
|
async fn authorization_signature<F, E, K>(
|
||||||
|
self,
|
||||||
|
config: &Config,
|
||||||
|
key_id: K,
|
||||||
|
f: F,
|
||||||
|
) -> Result<Self, E>
|
||||||
where
|
where
|
||||||
F: FnOnce(&str) -> Result<String, E>,
|
F: FnOnce(&str) -> Result<String, E> + Send + 'static,
|
||||||
E: From<ToStrError> + From<InvalidHeaderValue>,
|
E: From<BlockingError<E>>
|
||||||
|
+ From<ToStrError>
|
||||||
|
+ From<InvalidHeaderValue>
|
||||||
|
+ std::fmt::Debug
|
||||||
|
+ Send
|
||||||
|
+ 'static,
|
||||||
K: Display,
|
K: Display,
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
|
||||||
/// Add a Signature to the request
|
/// Add a Signature to the request
|
||||||
fn signature<F, E, K>(self, config: &Config, key_id: K, f: F) -> Result<Self, E>
|
async fn signature<F, E, K>(self, config: &Config, key_id: K, f: F) -> Result<Self, E>
|
||||||
where
|
where
|
||||||
F: FnOnce(&str) -> Result<String, E>,
|
F: FnOnce(&str) -> Result<String, E> + Send + 'static,
|
||||||
E: From<ToStrError> + From<InvalidHeaderValue>,
|
E: From<BlockingError<E>>
|
||||||
|
+ From<ToStrError>
|
||||||
|
+ From<InvalidHeaderValue>
|
||||||
|
+ std::fmt::Debug
|
||||||
|
+ Send
|
||||||
|
+ 'static,
|
||||||
K: Display,
|
K: Display,
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,44 +1,64 @@
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
client::ClientRequest,
|
client::ClientRequest,
|
||||||
|
error::BlockingError,
|
||||||
http::header::{InvalidHeaderValue, ToStrError},
|
http::header::{InvalidHeaderValue, ToStrError},
|
||||||
|
web,
|
||||||
};
|
};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
use crate::{create::Signed, Config, Sign};
|
use crate::{create::Signed, Config, Sign};
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Sign for ClientRequest {
|
impl Sign for ClientRequest {
|
||||||
fn authorization_signature<F, E, K>(
|
async fn authorization_signature<F, E, K>(
|
||||||
mut self,
|
mut self,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
key_id: K,
|
key_id: K,
|
||||||
f: F,
|
f: F,
|
||||||
) -> Result<Self, E>
|
) -> Result<Self, E>
|
||||||
where
|
where
|
||||||
F: FnOnce(&str) -> Result<String, E>,
|
F: FnOnce(&str) -> Result<String, E> + Send + 'static,
|
||||||
E: From<ToStrError> + From<InvalidHeaderValue>,
|
E: From<BlockingError<E>>
|
||||||
|
+ From<ToStrError>
|
||||||
|
+ From<InvalidHeaderValue>
|
||||||
|
+ std::fmt::Debug
|
||||||
|
+ Send
|
||||||
|
+ 'static,
|
||||||
K: Display,
|
K: Display,
|
||||||
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let signed = prepare(&self, config, key_id, f)?;
|
let signed = prepare(&self, config, key_id, f).await?;
|
||||||
signed.authorization_header(self.headers_mut())?;
|
signed.authorization_header(self.headers_mut())?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature<F, E, K>(mut self, config: &Config, key_id: K, f: F) -> Result<Self, E>
|
async fn signature<F, E, K>(mut self, config: &Config, key_id: K, f: F) -> Result<Self, E>
|
||||||
where
|
where
|
||||||
F: FnOnce(&str) -> Result<String, E>,
|
F: FnOnce(&str) -> Result<String, E> + Send + 'static,
|
||||||
E: From<ToStrError> + From<InvalidHeaderValue>,
|
E: From<BlockingError<E>>
|
||||||
|
+ From<ToStrError>
|
||||||
|
+ From<InvalidHeaderValue>
|
||||||
|
+ std::fmt::Debug
|
||||||
|
+ Send
|
||||||
|
+ 'static,
|
||||||
K: Display,
|
K: Display,
|
||||||
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let signed = prepare(&self, config, key_id, f)?;
|
let signed = prepare(&self, config, key_id, f).await?;
|
||||||
signed.signature_header(self.headers_mut())?;
|
signed.signature_header(self.headers_mut())?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare<F, E, K>(request: &ClientRequest, config: &Config, key_id: K, f: F) -> Result<Signed, E>
|
async fn prepare<F, E, K>(
|
||||||
|
request: &ClientRequest,
|
||||||
|
config: &Config,
|
||||||
|
key_id: K,
|
||||||
|
f: F,
|
||||||
|
) -> Result<Signed, E>
|
||||||
where
|
where
|
||||||
F: FnOnce(&str) -> Result<String, E>,
|
F: FnOnce(&str) -> Result<String, E> + Send + 'static,
|
||||||
E: From<ToStrError>,
|
E: From<BlockingError<E>> + From<ToStrError> + std::fmt::Debug + Send + 'static,
|
||||||
K: Display,
|
K: Display,
|
||||||
{
|
{
|
||||||
let unsigned = config.begin_sign(
|
let unsigned = config.begin_sign(
|
||||||
|
@ -49,7 +69,7 @@ where
|
||||||
|
|
||||||
let key_id = key_id.to_string();
|
let key_id = key_id.to_string();
|
||||||
|
|
||||||
let signed = unsigned.sign(key_id, f)?;
|
let signed = web::block(move || unsigned.sign(key_id, f)).await?;
|
||||||
|
|
||||||
Ok(signed)
|
Ok(signed)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue