Gert,

There is no declarative way to satisfy that requirement at the moment.  
Fine-grained authorization often falls out to imperative checks, though there 
are mostly-declarative approaches in other libraries/frameworks that I have yet 
to grok enough to have a feel for what Friend should do in this area.  (As an 
aside, I think something like trammel will prove to be very useful for 
fine-grained authorization.)

There is a function `cemerick.friend/throw-unauthorized` that will raise an 
unauthorized exception that the top level `authenticate` middleware will catch, 
and either redirect to your :login-uri if the user isn't logged in, or pass 
along to the :unauthorized-handler you provide if the user is logged in (the 
default simply returns an HTTP 401 with a plain text message).

So, assuming the user's :id is in the authentication map your credential fn is 
returning, you can do something like:

(POST "/user/:id" [id & params :as req]
  (let [identity (friend/identity req)]
    (if-not (or (friend/authorized? #{"admin"} identity)
                (and (friend/authorized? #{"user"} identity)
                     (= id (:id (friend/current-authentication identity)))))
      (friend/throw-unauthorized identity)
      ;; actual implementation of POST /user/:id...
      )))

Of course, you can factor the above out into a function to apply generally to 
any route/function that has similar authorization requirements (and maybe 
applied as a hook, depending on personal taste).

Does that help?

FWIW, there's no reason for solutions to problems like these to come 
exclusively from Friend itself.  I'd love to have contributions addressing 
general-interest requirements (of which fine-grained, declarative authorization 
is an example), but especially for more esoteric security requirements, I hope 
I've made it possible for enterprising and informed hackers to independently 
build extensions and addons.

Cheers,

- Chas

--
http://cemerick.com
[Clojure Programming from O'Reilly](http://www.clojurebook.com)

On Apr 18, 2012, at 7:38 PM, Gert Verhoog wrote:

> That looks promising, good work!
> 
> I read through the docs and browsed the sources, and (admittedly without 
> trying to code an example myself) it's not immediately obvious to me how 
> Friend would handle the following use case:
> 
> Given:
> - three users: alice, bob, and admin. Alice and Bob have a "user" role, and 
> admin is "admin"
> - "edit user account" routes, such as
>  (GET  "/user/:id/edit" [id] (show-edit-form))
>  (POST "/user/:id"      [id & params] (update-user))
> 
> How would I use Friend to ensure that these resources can only be accessed if:
> - you have the "admin" role, OR
> - you are a user AND your id matches the id in the url?
> 
> 
> cheers,
> gert
> 
> 
> 
> 
> On 12/04/2012, at 2:34 AM, Chas Emerick wrote:
> 
>> For your consideration, a new library:
>> 
>> I’m hoping this can eventually be a warden/spring-security/everyauth 
>> /omniauth for Clojure; that is, a common abstraction for authentication and 
>> authorization mechanisms.  Clojure has been around long enough that adding 
>> pedestrian things like form and HTTP Basic and $AUTH_METHOD_HERE to a Ring 
>> application should be easy.  Right now, it’s not: either you’re pasting 
>> together a bunch of different libraries that don’t necessarily compose well 
>> together, or you get drawn into shaving the authentication and authorization 
>> yaks for the fifth time in your life so you can sleep well at night.
>> 
>> Hopefully Friend will make this a solved problem, or at least push things in 
>> that direction.
>> 
>> Read more here: http://wp.me/p10OJi-d6
>> 
>> Cheers,
>> 
>> - Chas
>> 
>> --
>> http://cemerick.com
>> [Clojure Programming from O'Reilly](http://www.clojurebook.com)
>> 
>> -- 
>> You received this message because you are subscribed to the Google
>> Groups "Clojure" group.
>> To post to this group, send email to clojure@googlegroups.com
>> Note that posts from new members are moderated - please be patient with your 
>> first post.
>> To unsubscribe from this group, send email to
>> clojure+unsubscr...@googlegroups.com
>> For more options, visit this group at
>> http://groups.google.com/group/clojure?hl=en
> 
> -- 
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with your 
> first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to