Skip to content
This repository has been archived by the owner on Mar 8, 2021. It is now read-only.

Commit

Permalink
Allow :roles to be a function, which will be executed with no args an…
Browse files Browse the repository at this point in the history
…d assumed to return a collection of roles each time user authorizations are checked.

This allows, e.g., promoting a user to a new role without forcing a logout+login.

Closes #21.
  • Loading branch information
lynaghk committed Mar 25, 2013
1 parent 2bb8807 commit 683bacc
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 3 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ to the application, but two entries are priviliged:
form or HTTP Basic authentication, an oAuth token, etc.; this value form or HTTP Basic authentication, an oAuth token, etc.; this value
_must_ be unique across all users within the application _must_ be unique across all users within the application
* `:roles`, an optional collection of values enumerating the roles for * `:roles`, an optional collection of values enumerating the roles for
which the user is authorized. which the user is authorized, or a function returning the same.


_If a map of credentials is found to be invalid, the credential function must _If a map of credentials is found to be invalid, the credential function must
return nil._ return nil._
Expand Down
9 changes: 7 additions & 2 deletions src/cemerick/friend.clj
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -248,9 +248,14 @@ Equivalent to (complement current-authentication)."}
"Returns the first value in the :roles of the current authentication "Returns the first value in the :roles of the current authentication
in the given identity map that isa? one of the required roles. in the given identity map that isa? one of the required roles.
Returns nil otherwise, indicating that the identity is not authorized Returns nil otherwise, indicating that the identity is not authorized
for the set of required roles." for the set of required roles. If :roles is a fn, it will be executed
with no args and assumed to return a collection of roles."
[roles identity] [roles identity]
(let [granted-roles (-> identity current-authentication :roles)] (let [granted-roles (-> identity current-authentication :roles)
granted-roles (if (fn? granted-roles)
(granted-roles)
granted-roles)]

(first (for [granted granted-roles (first (for [granted granted-roles
required roles required roles
:when (isa? granted required)] :when (isa? granted required)]
Expand Down
5 changes: 5 additions & 0 deletions test/test_friend/functional.clj
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@
(check-user-role-access) (check-user-role-access)
(is (= {:roles ["test-friend.mock-app/admin"]} (:body (http/get (url "/echo-roles") {:as :json})))))) (is (= {:roles ["test-friend.mock-app/admin"]} (:body (http/get (url "/echo-roles") {:as :json}))))))


(deftest admin-login-fn-role
(binding [clj-http.core/*cookie-store* (clj-http.cookies/cookie-store)]
(http/post (url "/login") {:form-params {:username "root-fn-role" :password "admin_password"}})
(check-user-role-access)))

(deftest logout-only-on-correct-uri (deftest logout-only-on-correct-uri
;; logout middleware was previously being applied eagerly ;; logout middleware was previously being applied eagerly
(binding [clj-http.core/*cookie-store* (clj-http.cookies/cookie-store)] (binding [clj-http.core/*cookie-store* (clj-http.cookies/cookie-store)]
Expand Down
4 changes: 4 additions & 0 deletions test/test_friend/mock_app.clj
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@
(def users {"root" {:username "root" (def users {"root" {:username "root"
:password (creds/hash-bcrypt "admin_password") :password (creds/hash-bcrypt "admin_password")
:roles #{::admin}} :roles #{::admin}}

"root-fn-role" {:username "root-fn-role"
:password (creds/hash-bcrypt "admin_password")
:roles (constantly #{::admin})}
"jane" {:username "jane" "jane" {:username "jane"
:password (creds/hash-bcrypt "user_password") :password (creds/hash-bcrypt "user_password")
:roles #{::user}}}) :roles #{::user}}})
Expand Down

0 comments on commit 683bacc

Please sign in to comment.