httprustiron

How to enable Basic Authorization in Iron?


I would like enable Basic Authorization in Iron http server. I wrote code but is not working correctly. How enable Basic Authorization in Iron Http server? I am asking for an example.

let mut router = Router::new();
router.get("/json", get_json, "json");

fn get_json(_: &mut Request) -> IronResult<Response> {
    let mut headers = Headers::new();
    headers.set(
       Authorization(
           Basic {
               username: "root".to_owned(),
               password: Some("test".to_owned())
           }
       )
    );
    let payload = "{ \"json\" : \"test\" }".to_string();
    let mut resp = Response::with((status::Ok, payload));
    resp.headers = headers;
    Ok(resp)
}

match Iron::new(router).http(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 3000)) {
     Ok(_) => println!("Listening on {}", 3000),
     Err(e) => println!("Error: {}", e),
};

Solution

  • I'm solved this problem.

    extern crate iron;
    
    use std::error::Error;
    use std::fmt;
    
    use iron::prelude::*;
    use iron::{headers, middleware, status, AfterMiddleware, BeforeMiddleware};
    use iron::typemap::TypeMap;
    
    #[derive(Debug)]
    struct AuthError;
    
    impl fmt::Display for AuthError {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            fmt::Display::fmt("authentication error", f)
        }
    }
    
    impl Error for AuthError {
        fn description(&self) -> &str {
            "authentication error"
        }
    }
    
    pub trait CheckAuth {
        fn authorize(&self, user: &str, pass: &str) -> bool;
    
        #[allow(unused_variables)]
        fn wrong_credentials_error(&self, user: &str, pass: &str) -> &'static str {
            "Wrong username or password."
        }
    
        fn no_password_error(&self) -> &'static str {
            "No password found."
        }
    }
    
    pub struct Authentication {
        username: String,
        password: String
    }
    
    impl CheckAuth for Authentication {
        fn authorize(&self, user: &str, pass: &str) -> bool {
            user == self.username && pass == self.password
        }
    }
    
    impl CheckAuth for Fn(&str, &str) -> bool {
        fn authorize(&self, user: &str, pass: &str) -> bool {
            self(user, pass)
        }
    }
    
    impl BeforeMiddleware for Authentication {
           fn before(&self, req: &mut Request) -> IronResult<()> {
            match req.headers.get::<headers::Authorization<headers::Basic>>() {
                Some(&headers::Authorization(headers::Basic { ref username, password: Some(ref password) })) => {
                    if self.authorize(username, password) {
                        Ok(())
                    } else {
                        Err(IronError {
                            error: Box::new(AuthError),
                            response: Response::with((status::Unauthorized, self.wrong_credentials_error(username, password)))
                        })
                    }
                }
                Some(&headers::Authorization(headers::Basic { username: _, password: None })) => {
                    Err(IronError {
                        error: Box::new(AuthError),
                        response: Response::with((status::Unauthorized, self.no_password_error()))
                    })
                }
                None => {
                    let mut hs = headers::Headers::new();
                    hs.set_raw("WWW-Authenticate", vec![b"Basic realm=\"main\"".to_vec()]);
                    Err(IronError {
                        error: Box::new(AuthError),
                        response: Response {
                            status: Some(status::Unauthorized),
                            headers: hs,
                            extensions: TypeMap::new(),
                            body: None
                        }
                    })
                }
            }
        }
    }
    
    fn get_json(_: &mut Request) -> IronResult<Response> {
        let payload = "{ \"json\" : \"test\" }".to_string();
        let mut resp = Response::with((status::Ok, payload));
        Ok(resp)
    }
    
    fn main()
    {
        let mut chain = Chain::new(get_json);
        chain.link_before(Authentication{username : "test".to_string(), password : "test".to_string()});
        Iron::new(chain).http("localhost:3000");
    }
    

    Link : Github repo