//! Types for verifying requests with Actix Web use actix_web::{ dev::{Body, Payload, Service, ServiceRequest, ServiceResponse, Transform}, FromRequest, HttpMessage, HttpRequest, 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(Copy, Clone, Debug)] /// A marker type that can be used to guard routes when the signature middleware is set to /// 'optional' pub struct SignatureVerified; #[derive(Clone, Debug)] /// The Verify signature middleware /// /// ```rust,ignore /// let middleware = VerifySignature::new(MyVerifier::new(), Config::default()) /// .authorization() /// .optional(); /// /// HttpServer::new(move || { /// App::new() /// .wrap(middleware.clone()) /// .route("/protected", web::post().to(|_: SignatureVerified| "Verified Authorization Header")) /// .route("/unprotected", web::post().to(|| "No verification required")) /// }) /// ``` pub struct VerifySignature(T, Config, HeaderKind, bool); #[derive(Clone, Debug)] #[doc(hidden)] pub struct VerifyMiddleware(Rc>, Config, HeaderKind, bool, T); #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] enum HeaderKind { Authorization, Signature, } #[derive(Clone, Debug, Fail)] #[fail(display = "Failed to verify http signature")] #[doc(hidden)] pub struct VerifyError; impl VerifySignature where T: SignatureVerify, { /// Create a new middleware for verifying HTTP Signatures. A type implementing /// [`SignatureVerify`] is required, as well as a Config /// /// By default, this middleware expects to verify Signature headers, and requires the presence /// of the header pub fn new(verify_signature: T, config: Config) -> Self { VerifySignature(verify_signature, config, HeaderKind::Signature, true) } /// Verify Authorization headers instead of Signature headers pub fn authorization(self) -> Self { VerifySignature(self.0, self.1, HeaderKind::Authorization, self.3) } /// Mark the presence of a Signature or Authorization header as optional /// /// If a header is present, it will be verified, but if there is not one present, the request /// is passed through. This can be used to set a global middleware, and then guard each route /// handler with the [`SignatureVerified`] type. pub fn optional(self) -> Self { VerifySignature(self.0, self.1, self.2, false) } } impl VerifyMiddleware where T: SignatureVerify + 'static, T::Future: 'static, S: Service< Request = ServiceRequest, Response = ServiceResponse, Error = actix_web::Error, > + 'static, S::Error: 'static, { fn handle( &mut self, req: ServiceRequest, ) -> Box, 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::() .and_then(move |verified| { if verified { req.extensions_mut().insert(SignatureVerified); 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 FromRequest for SignatureVerified { type Error = VerifyError; type Future = Result; type Config = (); fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future { req.extensions() .get::() .map(|s| *s) .ok_or(VerifyError) } } impl Transform for VerifySignature where T: SignatureVerify + Clone + 'static, S: Service< Request = ServiceRequest, Response = ServiceResponse, Error = actix_web::Error, > + 'static, S::Error: 'static, { type Request = ServiceRequest; type Response = ServiceResponse; type Error = actix_web::Error; type Transform = VerifyMiddleware; type InitError = (); type Future = FutureResult; 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 Service for VerifyMiddleware where T: SignatureVerify + Clone + 'static, S: Service< Request = ServiceRequest, Response = ServiceResponse, Error = actix_web::Error, > + 'static, S::Error: 'static, { type Request = ServiceRequest; type Response = ServiceResponse; type Error = actix_web::Error; type Future = Box>; 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() } }