diff --git a/README.md b/README.md index 947b9af..998b566 100644 --- a/README.md +++ b/README.md @@ -31,14 +31,13 @@ An `IdentityInfo` is defined as: data by some authentication layer. Typically, an email, a phone number, etc... " (st/merge - {:id s/Str - :name s/Str} - ;; could contain other meta datas (email, address, phone number, etc...) + {:id s/Str} + ;; could contain other meta datas (name, nickname, email, address, phone number, etc...) {s/Keyword s/Any})) -(s/defschema Group - "A Group can be understood as a Community of People, an Organization, a - Business, etc... +(s/defschema Org + "An Org can be understood as a Community of People, an Organization, a + Business, etc... This also can be thought as a UNIX group. Mainly this should provide a way to filter document for an organization. @@ -47,36 +46,48 @@ An `IdentityInfo` is defined as: A group could also have some meta informations. For example, a physical address, an Identity Provider URL, etc.." (st/merge - {:id s/Str - :name s/Str} - ;; could contain other meta datas (Identity Provider URL, etc...) + {:id s/Str} + ;; could contain other meta datas (name, Identity Provider URL, etc...) {s/Keyword s/Any})) -(def Role - "What are the roles of the user. +(def Scope + "The scope of an user. + The scope is a string without any space. Mainly this should provide a way to filter route access. - Typical values are: :admin :user :read-only etc... " - s/Keyword) + Typical values are: + + - \"admin\" + - \"service\" + - \"service/subservice:read-only\" + + etc..." + s/Str) (s/defschema IdentityInfo "An IdentityInfo provide the information to identify and determine the permissions relative to some request. - It provide an user, a set of groups and a set of roles. + It provide an user, a main org and a set of scopes. - It is important to note that roles aren't associated to an user but to an - IdentityInfo. This enable the same user to provide different roles via + It is important to note that scopes aren't associated to an user but to an + IdentityInfo. This enable the same user to provide different scopes via different API-Key for example. An IdentityInfo while having some mandatory informations could also contains some other informations generally for dealing with technical details and ease - the debugging." + the debugging. + + But they could also be used to extend the actual spec. + For example, we could imagine that we might want to associate a set of orgs + to an identity. + + But that's out of the scope of this specific spec." (st/merge - {:user User - :groups #{Group} - :roles #{Role}} + {:user User + :org Org + :scopes #{Scope}} {s/Keyword s/Any})) ``` @@ -100,16 +111,17 @@ Where here are some example of extractors: (s/defn extract-identity-infos :- IdentityInfo [jwt-info] - {:id {:id (:sub jwt-info) - :name (:sub jwt-info)} + {:user {:id (:sub jwt-info) + :name (:sub jwt-info) + :email (:user_email jwt-info)} :groups #{{:id (:org_guid jwt-info) :name (:org_name jwt-info)}} - :roles (if (= "true" + :scopes (if (= "true" ;; this test handle the case when :user_admin is a string ;; and when its a boolean (str (:user_admin jwt-info))) - #{:admin :user} - #{:user}) + #{"admin" "user"} + #{"user"}) :auth-type :jwt}) (s/defn jwt-extractor :- (s/maybe IdentityInfo) diff --git a/src/ring_homogeneous_auth_middleware/core.clj b/src/ring_homogeneous_auth_middleware/core.clj index ba5cecc..fb84ba0 100644 --- a/src/ring_homogeneous_auth_middleware/core.clj +++ b/src/ring_homogeneous_auth_middleware/core.clj @@ -13,14 +13,6 @@ [compojure.api.meta :as meta] [schema.core :as s])) -(s/defn get-identity-info :- (s/maybe IdentityInfo) - "Given a ring request and and a couple auth-key auth-info->identity-info. - We return the identity-info if possible" - [request - [auth-key auth-infos->identity-info]] - (when-let [auth-infos (get request auth-key)] - (auth-infos->identity-info auth-infos))) - (s/defn wrap-auths-fn "You should provide a list of [[AuthExtractor]]s your ring request should have a :auth key in them." @@ -46,32 +38,32 @@ new-letks [id-infos (meta/src-coerce! schema :identity-info :string)]] (update-in acc [:letks] into new-letks))) -;; Add the :roles-filter +;; Add the :scopes-filter ;; to compojure api params ;; it should contains a set of hash-maps ;; example: ;; ;; ~~~ -;; (POST "/foo" [] :roles-filter #{:admin}) +;; (POST "/foo" [] :scopes-filter #{:admin}) ;; ~~~ ;; -;; Will be accepted only for requests having a role in the authorized set. +;; Will be accepted only for requests having a scope in the authorized set. -(defn check-roles-filter! - [authorized-roles request-roles] - (when-not (set? authorized-roles) - (throw (ex-info ":roles-filter argument in compojure-api must be a set!" {}))) - (when-not (and (set? request-roles) - (set/intersection authorized-roles request-roles)) +(defn check-scopes-filter! + [authorized-scopes request-scopes] + (when-not (set? authorized-scopes) + (throw (ex-info ":scopes-filter argument in compojure-api must be a set!" {}))) + (when-not (and (set? request-scopes) + (set/intersection authorized-scopes request-scopes)) (ring.util.http-response/unauthorized! {:msg "You don't have the required credentials to access this route"}))) (defmethod compojure.api.meta/restructure-param - :roles-filter [_ authorized acc] + :scopes-filter [_ authorized acc] (update-in acc [:lets] into - ['_ `(check-roles-filter! + ['_ `(check-scopes-filter! ~authorized (:identity-info ~'+compojure-api-request+))])) diff --git a/src/ring_homogeneous_auth_middleware/schemas.clj b/src/ring_homogeneous_auth_middleware/schemas.clj index 75e23d6..4db70a8 100644 --- a/src/ring_homogeneous_auth_middleware/schemas.clj +++ b/src/ring_homogeneous_auth_middleware/schemas.clj @@ -11,14 +11,13 @@ data by some authentication layer. Typically, an email, a phone number, etc... " (st/merge - {:id s/Str - :name s/Str} - ;; could contain other meta datas (email, address, phone number, etc...) + {:id s/Str} + ;; could contain other meta datas (name, nickname, email, address, phone number, etc...) {s/Keyword s/Any})) -(s/defschema Group - "A Group can be understood as a Community of People, an Organization, a - Business, etc... +(s/defschema Org + "An Org can be understood as a Community of People, an Organization, a + Business, etc... This also can be thought as a UNIX group. Mainly this should provide a way to filter document for an organization. @@ -27,34 +26,46 @@ A group could also have some meta informations. For example, a physical address, an Identity Provider URL, etc.." (st/merge - {:id s/Str - :name s/Str} - ;; could contain other meta datas (Identity Provider URL, etc...) + {:id s/Str} + ;; could contain other meta datas (name, Identity Provider URL, etc...) {s/Keyword s/Any})) -(def Role - "What are the roles of the user. +(def Scope + "The scope of an user. + The scope is a string without any space. Mainly this should provide a way to filter route access. - Typical values are: :admin :user :read-only etc... " - s/Keyword) + Typical values are: + + - \"admin\" + - \"service\" + - \"service/subservice:read-only\" + + etc..." + s/Str) (s/defschema IdentityInfo "An IdentityInfo provide the information to identify and determine the permissions relative to some request. - It provide an user, a set of groups and a set of roles. + It provide an user, a main org and a set of scopes. - It is important to note that roles aren't associated to an user but to an - IdentityInfo. This enable the same user to provide different roles via + It is important to note that scopes aren't associated to an user but to an + IdentityInfo. This enable the same user to provide different scopes via different API-Key for example. An IdentityInfo while having some mandatory informations could also contains some other informations generally for dealing with technical details and ease - the debugging." + the debugging. + + But they could also be used to extend the actual spec. + For example, we could imagine that we might want to associate a set of orgs + to an identity. + + But that's out of the scope of this specific spec." (st/merge - {:user User - :groups #{Group} - :roles #{Role}} + {:user User + :org Org + :scopes #{Scope}} {s/Keyword s/Any}))