duct

kelveden 2020-02-04T16:24:13.009300Z

Is there a way of annotating ataraxy routes in such a way as to make those annotations available to duct middleware? (As it'd only make sense doing this after ataraxy has routed, the middleware would have to be assigned individual routes too rather than :duct.handler/root.) Specifically, I'm trying to think of a way to create a generic bit of authorization middleware: the middleware will compare the permissions required for the route against those assigned to the user (available on the incoming request map) and (un)authorize as appropriate. So, I want to annotate each route in the duct config with the permissions required to access it - but in such a way as the authorization middleware can see them. The closest I can think of is if each permission were itself a piece of authorization middleware - that way each route could get assigned a middleware based on the permission required. But config would very quickly get cluttered up with middleware definitions as the API grew.

2020-02-04T16:28:58.009400Z

You can use metadata to assign middleware to a particular route, and this could be used to determine authorisation. For example:

{"/admin"
 ^{:roles #{"admin" "mods"}}
 {"/foo" [:foo]
  "/bar" [:bar]}}

2020-02-04T16:30:53.009700Z

So typically I’d have an single outer authentication middleware that determines the user ID and roles, and adds them to the request map, and then a bunch of inner authorisation middleware that checks to see if the user has a particular role, and forbids them from the resource if they don’t.

kelveden 2020-02-04T16:35:42.009900Z

An outer authentication middleware is exactly what I've got actually - it's the inner middleware I'm struggling with. How is that metadata you've added exposed to the inner middleware?

2020-02-04T16:36:20.010100Z

It’s passed as an argument to the :roles middleware.

kelveden 2020-02-04T16:36:49.010300Z

Ah... Thanks. I'll give that a go.

2020-02-04T16:37:31.010500Z

So:

{:routes     {"/foo" ^{:roles #{:admin}} [:foo]}
    :handlers   {:foo foo}
    :middleware {:roles wrap-roles}}

2020-02-04T16:38:03.010700Z

That calls the middleware (wrap-roles foo #{:admin})

2020-02-04T16:38:35.010900Z

See: https://github.com/weavejester/ataraxy#handlers

kelveden 2020-02-04T16:41:48.011300Z

:thumbsup:

kelveden 2020-02-04T16:49:43.011500Z

Yeah that does the trick. The key thing I was missing was that I could pass that metadata as a second argument to the middleware. Thanks!