Global authentication/authorization in Rocket based on a header

Viewed 300

I know I can use a Request guard. However, if I have a REST API with hundreds of handlers, not only it would be annoying to have to add an extra function param to all of them, but it kinda scares me that it could be easy to miss adding such a param here or there and therefore create a security hole. That's why I'd like to know if there is a way to do such a validation globally.

The documentation on Fairings mentions they can be used for global security policies:

As a general rule of thumb, only globally applicable actions should be implemented via fairings. For instance, you should not use a fairing to implement authentication or authorization (preferring to use a request guard instead) unless the authentication or authorization applies to the entire application. On the other hand, you should use a fairing to record timing and/or usage statistics or to implement global security policies.

But at the same time the docs on the on_request() callback say this:

A request callback can modify the request at will and Data::peek() into the incoming data. It may not, however, abort or respond directly to the request; these issues are better handled via request guards or via response callbacks.

So how am I supposed to return an error to the user in the case of an invalid token for example?

1 Answers

OK, I think I found a way...

First we create a "dummy" handler like this:

#[put("/errHnd", format = "json")]
fn err_handler() -> ApiResult {
    // Here simply return an error
}

Then we attach a fairing like this:

rocket::custom(cfg)
    .attach(AdHoc::on_request("OnReq", |req, _| {
        // Here we validate the token and if it's not OK,
        // forward the request to our "dummy" handler:
        let u = Origin::parse("/errHnd").unwrap();
        req.set_uri(u);
        req.set_method(Method::Put);
    }))
    .mount("/", routes![err_handler, ...
    

I'm not sure that's the best way to do it, but I tested it and it seems to work. I'm open to other suggestions.

P.S. It may also be worth mentioning that if we wanted to have an exception, so as to skip the validation in the fairing, say, based on the URL, we could simply add something like this in it:

if req.uri().path() == "/let-me-in-please" {
    return;
}
Related