184 lines
5 KiB
Rust
184 lines
5 KiB
Rust
use actix_web::{
|
|
body::Body,
|
|
dev::{Service, ServiceRequest, ServiceResponse, Transform},
|
|
HttpResponse, ResponseError,
|
|
};
|
|
use failure::Fail;
|
|
use futures::{
|
|
future::{err, ok, Either, FutureResult, IntoFuture},
|
|
Future, Poll,
|
|
};
|
|
use std::{cell::RefCell, rc::Rc};
|
|
|
|
use crate::{Config, SignatureVerify};
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct VerifySignature<T>(T, Config, HeaderKind, bool);
|
|
#[derive(Clone, Debug)]
|
|
pub struct VerifyMiddleware<T, S>(Rc<RefCell<S>>, Config, HeaderKind, bool, T);
|
|
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
|
pub enum HeaderKind {
|
|
Authorization,
|
|
Signature,
|
|
}
|
|
#[derive(Clone, Debug, Fail)]
|
|
#[fail(display = "Failed to verify http signature")]
|
|
pub struct VerifyError;
|
|
|
|
impl<T> VerifySignature<T>
|
|
where
|
|
T: SignatureVerify,
|
|
{
|
|
pub fn new(verify_signature: T, config: Config) -> Self {
|
|
VerifySignature(verify_signature, config, HeaderKind::Signature, true)
|
|
}
|
|
|
|
pub fn authorization(self) -> Self {
|
|
VerifySignature(self.0, self.1, HeaderKind::Authorization, self.3)
|
|
}
|
|
|
|
pub fn optional(self) -> Self {
|
|
VerifySignature(self.0, self.1, self.2, false)
|
|
}
|
|
}
|
|
|
|
impl<T, S> VerifyMiddleware<T, S>
|
|
where
|
|
T: SignatureVerify + 'static,
|
|
T::Future: 'static,
|
|
S: Service<
|
|
Request = ServiceRequest,
|
|
Response = ServiceResponse<Body>,
|
|
Error = actix_web::Error,
|
|
> + 'static,
|
|
S::Error: 'static,
|
|
{
|
|
fn handle(
|
|
&mut self,
|
|
req: ServiceRequest,
|
|
) -> Box<dyn Future<Item = ServiceResponse<Body>, Error = actix_web::Error>> {
|
|
let res = self.1.begin_verify(
|
|
req.method(),
|
|
req.uri().path_and_query(),
|
|
req.headers().clone(),
|
|
);
|
|
|
|
let unverified = match res {
|
|
Ok(unverified) => unverified,
|
|
Err(_) => return Box::new(err(VerifyError.into())),
|
|
};
|
|
|
|
let algorithm = unverified.algorithm().map(|a| a.clone());
|
|
let key_id = unverified.key_id().to_owned();
|
|
|
|
let verified = unverified.verify(|signature, signing_string| {
|
|
self.4
|
|
.signature_verify(algorithm, &key_id, signature, signing_string)
|
|
});
|
|
|
|
let service = self.0.clone();
|
|
|
|
Box::new(
|
|
verified
|
|
.into_future()
|
|
.from_err::<actix_web::Error>()
|
|
.and_then(move |verified| {
|
|
if verified {
|
|
Either::A(service.borrow_mut().call(req))
|
|
} else {
|
|
Either::B(err(VerifyError.into()))
|
|
}
|
|
}),
|
|
)
|
|
}
|
|
}
|
|
|
|
impl HeaderKind {
|
|
pub fn is_authorization(&self) -> bool {
|
|
HeaderKind::Authorization == *self
|
|
}
|
|
|
|
pub fn is_signature(&self) -> bool {
|
|
HeaderKind::Signature == *self
|
|
}
|
|
}
|
|
|
|
impl<T, S> Transform<S> for VerifySignature<T>
|
|
where
|
|
T: SignatureVerify + Clone + 'static,
|
|
S: Service<
|
|
Request = ServiceRequest,
|
|
Response = ServiceResponse<Body>,
|
|
Error = actix_web::Error,
|
|
> + 'static,
|
|
S::Error: 'static,
|
|
{
|
|
type Request = ServiceRequest;
|
|
type Response = ServiceResponse<Body>;
|
|
type Error = actix_web::Error;
|
|
type Transform = VerifyMiddleware<T, S>;
|
|
type InitError = ();
|
|
type Future = FutureResult<Self::Transform, Self::InitError>;
|
|
|
|
fn new_transform(&self, service: S) -> Self::Future {
|
|
ok(VerifyMiddleware(
|
|
Rc::new(RefCell::new(service)),
|
|
self.1.clone(),
|
|
self.2,
|
|
self.3,
|
|
self.0.clone(),
|
|
))
|
|
}
|
|
}
|
|
|
|
impl<T, S> Service for VerifyMiddleware<T, S>
|
|
where
|
|
T: SignatureVerify + Clone + 'static,
|
|
S: Service<
|
|
Request = ServiceRequest,
|
|
Response = ServiceResponse<Body>,
|
|
Error = actix_web::Error,
|
|
> + 'static,
|
|
S::Error: 'static,
|
|
{
|
|
type Request = ServiceRequest;
|
|
type Response = ServiceResponse<Body>;
|
|
type Error = actix_web::Error;
|
|
type Future = Box<dyn Future<Item = Self::Response, Error = Self::Error>>;
|
|
|
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
|
self.0.borrow_mut().poll_ready()
|
|
}
|
|
|
|
fn call(&mut self, req: ServiceRequest) -> Self::Future {
|
|
let authorization = req.headers().get("Authorization").is_some();
|
|
let signature = req.headers().get("Signature").is_some();
|
|
|
|
if authorization || signature {
|
|
if self.2.is_authorization() && authorization {
|
|
return self.handle(req);
|
|
}
|
|
|
|
if self.2.is_signature() && signature {
|
|
return self.handle(req);
|
|
}
|
|
|
|
Box::new(err(VerifyError.into()))
|
|
} else if self.3 {
|
|
Box::new(self.0.borrow_mut().call(req))
|
|
} else {
|
|
Box::new(err(VerifyError.into()))
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ResponseError for VerifyError {
|
|
fn error_response(&self) -> HttpResponse {
|
|
HttpResponse::BadRequest().finish()
|
|
}
|
|
|
|
fn render_response(&self) -> HttpResponse {
|
|
self.error_response()
|
|
}
|
|
}
|