khrt / Raisin

Raisin - a REST API micro framework for Perl 🐫 🐪
61 stars 30 forks source link

Checking an OAuth2 bearer token #64

Open vipera opened 5 years ago

vipera commented 5 years ago

Hey,

I'm looking into using Raisin for implementing a nice API into a legacy system, using OAuth2 bearer tokens. I couldn't find any Raisin-based solution that does something similar, aside from Rack middleware that I include and then manually check the environment at the top of every handler (ugly!).

I'd like to make a proof of concept where I intercept a HTTP request, call a custom handler to check that a bearer token exists and is valid, and then proceed if that is the case.

I'm trying to do this as a plugin. However, I've hit a few walls, most notably that I can register a plugin but I can't actually get any information about the route handler I'm calling it before and I can't register a hook to intercept calls.

Working from a high-level concept of how I'd like it to work inspired by Wine Bouncer:

plugin 'OAuth2';
oauth2_setup(
  validate_bearer_token => sub {
    my ($token, $scopes) = @_;
    # ...
  }
);

summary 'Get user';
oauth2 'users:read', 'admin';
params(
  required('userid', type => Int, desc => 'User ID'),
);
get sub {

};

I'd like to mark up this route with users:read and admin as a list of required token scopes (any one will do). I tried hacking this into the $SETTINGS used by the Swagger plugin, but looks like the ones that aren't known are not actually propagated or stored anywhere.

Next up, I'd like to hook into the request chain, and have my handler fire at before_validation, for instance. However, hooks don't have any context about the route or request, and neither can they stop processing. Bummer! I was thinking to do something like:

before_validation sub {
  my ($self, $route, $request, $response) = @_;
  if ($route->metadata_or_whatever->{oauth2}) {
    # more checks here ...
    return (403, 'Not permitted to access this resource');
  }
};

from the plugin code iself, and just call into the user bearer validator (seen above) to check the token.

Is the idea behind hooks/plugins to be able to accommodate something like this or am I looking at the wrong feature?

khrt commented 5 years ago

Hey Marin,

Is the idea behind hooks/plugins to be able to accommodate something like this or am I looking at the wrong feature?

Plug-in (and hooks) isn't able to solve your problem. I actually see it as a plug-in which allows your to do oauth2 'users:read', 'admin';

and a middleware where you can do return 403, 'Forbidden';.

But there is indeed a problem that currently you're not able to put your own data to $SETTINGS.