closer to OAuth2 vocabulary
This commit is contained in:
parent
94bea324e5
commit
70cf6f7d31
3 changed files with 79 additions and 64 deletions
62
README.md
62
README.md
|
@ -31,14 +31,13 @@ An `IdentityInfo` is defined as:
|
||||||
data by some authentication layer. Typically, an email, a phone number, etc...
|
data by some authentication layer. Typically, an email, a phone number, etc...
|
||||||
"
|
"
|
||||||
(st/merge
|
(st/merge
|
||||||
{:id s/Str
|
{:id s/Str}
|
||||||
:name s/Str}
|
;; could contain other meta datas (name, nickname, email, address, phone number, etc...)
|
||||||
;; could contain other meta datas (email, address, phone number, etc...)
|
|
||||||
{s/Keyword s/Any}))
|
{s/Keyword s/Any}))
|
||||||
|
|
||||||
(s/defschema Group
|
(s/defschema Org
|
||||||
"A Group can be understood as a Community of People, an Organization, a
|
"An Org can be understood as a Community of People, an Organization, a
|
||||||
Business, etc...
|
Business, etc... This also can be thought as a UNIX group.
|
||||||
|
|
||||||
Mainly this should provide a way to filter document for an organization.
|
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
|
A group could also have some meta informations. For example, a physical
|
||||||
address, an Identity Provider URL, etc.."
|
address, an Identity Provider URL, etc.."
|
||||||
(st/merge
|
(st/merge
|
||||||
{:id s/Str
|
{:id s/Str}
|
||||||
:name s/Str}
|
;; could contain other meta datas (name, Identity Provider URL, etc...)
|
||||||
;; could contain other meta datas (Identity Provider URL, etc...)
|
|
||||||
{s/Keyword s/Any}))
|
{s/Keyword s/Any}))
|
||||||
|
|
||||||
(def Role
|
(def Scope
|
||||||
"What are the roles of the user.
|
"The scope of an user.
|
||||||
|
|
||||||
|
The scope is a string without any space.
|
||||||
Mainly this should provide a way to filter route access.
|
Mainly this should provide a way to filter route access.
|
||||||
|
|
||||||
Typical values are: :admin :user :read-only etc... "
|
Typical values are:
|
||||||
s/Keyword)
|
|
||||||
|
- \"admin\"
|
||||||
|
- \"service\"
|
||||||
|
- \"service/subservice:read-only\"
|
||||||
|
|
||||||
|
etc..."
|
||||||
|
s/Str)
|
||||||
|
|
||||||
(s/defschema IdentityInfo
|
(s/defschema IdentityInfo
|
||||||
"An IdentityInfo provide the information to identify and determine the
|
"An IdentityInfo provide the information to identify and determine the
|
||||||
permissions relative to some request.
|
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
|
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 roles via
|
IdentityInfo. This enable the same user to provide different scopes via
|
||||||
different API-Key for example.
|
different API-Key for example.
|
||||||
|
|
||||||
An IdentityInfo while having some mandatory informations could also contains
|
An IdentityInfo while having some mandatory informations could also contains
|
||||||
some other informations generally for dealing with technical details and ease
|
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
|
(st/merge
|
||||||
{:user User
|
{:user User
|
||||||
:groups #{Group}
|
:org Org
|
||||||
:roles #{Role}}
|
:scopes #{Scope}}
|
||||||
{s/Keyword s/Any}))
|
{s/Keyword s/Any}))
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -100,16 +111,17 @@ Where here are some example of extractors:
|
||||||
|
|
||||||
(s/defn extract-identity-infos :- IdentityInfo
|
(s/defn extract-identity-infos :- IdentityInfo
|
||||||
[jwt-info]
|
[jwt-info]
|
||||||
{:id {:id (:sub jwt-info)
|
{:user {:id (:sub jwt-info)
|
||||||
:name (:sub jwt-info)}
|
:name (:sub jwt-info)
|
||||||
|
:email (:user_email jwt-info)}
|
||||||
:groups #{{:id (:org_guid jwt-info)
|
:groups #{{:id (:org_guid jwt-info)
|
||||||
:name (:org_name jwt-info)}}
|
:name (:org_name jwt-info)}}
|
||||||
:roles (if (= "true"
|
:scopes (if (= "true"
|
||||||
;; this test handle the case when :user_admin is a string
|
;; this test handle the case when :user_admin is a string
|
||||||
;; and when its a boolean
|
;; and when its a boolean
|
||||||
(str (:user_admin jwt-info)))
|
(str (:user_admin jwt-info)))
|
||||||
#{:admin :user}
|
#{"admin" "user"}
|
||||||
#{:user})
|
#{"user"})
|
||||||
:auth-type :jwt})
|
:auth-type :jwt})
|
||||||
|
|
||||||
(s/defn jwt-extractor :- (s/maybe IdentityInfo)
|
(s/defn jwt-extractor :- (s/maybe IdentityInfo)
|
||||||
|
|
|
@ -13,14 +13,6 @@
|
||||||
[compojure.api.meta :as meta]
|
[compojure.api.meta :as meta]
|
||||||
[schema.core :as s]))
|
[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
|
(s/defn wrap-auths-fn
|
||||||
"You should provide a list of [[AuthExtractor]]s your ring request should have
|
"You should provide a list of [[AuthExtractor]]s your ring request should have
|
||||||
a :auth key in them."
|
a :auth key in them."
|
||||||
|
@ -46,32 +38,32 @@
|
||||||
new-letks [id-infos (meta/src-coerce! schema :identity-info :string)]]
|
new-letks [id-infos (meta/src-coerce! schema :identity-info :string)]]
|
||||||
(update-in acc [:letks] into new-letks)))
|
(update-in acc [:letks] into new-letks)))
|
||||||
|
|
||||||
;; Add the :roles-filter
|
;; Add the :scopes-filter
|
||||||
;; to compojure api params
|
;; to compojure api params
|
||||||
;; it should contains a set of hash-maps
|
;; it should contains a set of hash-maps
|
||||||
;; example:
|
;; 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!
|
(defn check-scopes-filter!
|
||||||
[authorized-roles request-roles]
|
[authorized-scopes request-scopes]
|
||||||
(when-not (set? authorized-roles)
|
(when-not (set? authorized-scopes)
|
||||||
(throw (ex-info ":roles-filter argument in compojure-api must be a set!" {})))
|
(throw (ex-info ":scopes-filter argument in compojure-api must be a set!" {})))
|
||||||
(when-not (and (set? request-roles)
|
(when-not (and (set? request-scopes)
|
||||||
(set/intersection authorized-roles request-roles))
|
(set/intersection authorized-scopes request-scopes))
|
||||||
(ring.util.http-response/unauthorized!
|
(ring.util.http-response/unauthorized!
|
||||||
{:msg "You don't have the required credentials to access this route"})))
|
{:msg "You don't have the required credentials to access this route"})))
|
||||||
|
|
||||||
(defmethod compojure.api.meta/restructure-param
|
(defmethod compojure.api.meta/restructure-param
|
||||||
:roles-filter [_ authorized acc]
|
:scopes-filter [_ authorized acc]
|
||||||
(update-in
|
(update-in
|
||||||
acc
|
acc
|
||||||
[:lets]
|
[:lets]
|
||||||
into
|
into
|
||||||
['_ `(check-roles-filter!
|
['_ `(check-scopes-filter!
|
||||||
~authorized
|
~authorized
|
||||||
(:identity-info ~'+compojure-api-request+))]))
|
(:identity-info ~'+compojure-api-request+))]))
|
||||||
|
|
|
@ -11,14 +11,13 @@
|
||||||
data by some authentication layer. Typically, an email, a phone number, etc...
|
data by some authentication layer. Typically, an email, a phone number, etc...
|
||||||
"
|
"
|
||||||
(st/merge
|
(st/merge
|
||||||
{:id s/Str
|
{:id s/Str}
|
||||||
:name s/Str}
|
;; could contain other meta datas (name, nickname, email, address, phone number, etc...)
|
||||||
;; could contain other meta datas (email, address, phone number, etc...)
|
|
||||||
{s/Keyword s/Any}))
|
{s/Keyword s/Any}))
|
||||||
|
|
||||||
(s/defschema Group
|
(s/defschema Org
|
||||||
"A Group can be understood as a Community of People, an Organization, a
|
"An Org can be understood as a Community of People, an Organization, a
|
||||||
Business, etc...
|
Business, etc... This also can be thought as a UNIX group.
|
||||||
|
|
||||||
Mainly this should provide a way to filter document for an organization.
|
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
|
A group could also have some meta informations. For example, a physical
|
||||||
address, an Identity Provider URL, etc.."
|
address, an Identity Provider URL, etc.."
|
||||||
(st/merge
|
(st/merge
|
||||||
{:id s/Str
|
{:id s/Str}
|
||||||
:name s/Str}
|
;; could contain other meta datas (name, Identity Provider URL, etc...)
|
||||||
;; could contain other meta datas (Identity Provider URL, etc...)
|
|
||||||
{s/Keyword s/Any}))
|
{s/Keyword s/Any}))
|
||||||
|
|
||||||
(def Role
|
(def Scope
|
||||||
"What are the roles of the user.
|
"The scope of an user.
|
||||||
|
|
||||||
|
The scope is a string without any space.
|
||||||
Mainly this should provide a way to filter route access.
|
Mainly this should provide a way to filter route access.
|
||||||
|
|
||||||
Typical values are: :admin :user :read-only etc... "
|
Typical values are:
|
||||||
s/Keyword)
|
|
||||||
|
- \"admin\"
|
||||||
|
- \"service\"
|
||||||
|
- \"service/subservice:read-only\"
|
||||||
|
|
||||||
|
etc..."
|
||||||
|
s/Str)
|
||||||
|
|
||||||
(s/defschema IdentityInfo
|
(s/defschema IdentityInfo
|
||||||
"An IdentityInfo provide the information to identify and determine the
|
"An IdentityInfo provide the information to identify and determine the
|
||||||
permissions relative to some request.
|
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
|
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 roles via
|
IdentityInfo. This enable the same user to provide different scopes via
|
||||||
different API-Key for example.
|
different API-Key for example.
|
||||||
|
|
||||||
An IdentityInfo while having some mandatory informations could also contains
|
An IdentityInfo while having some mandatory informations could also contains
|
||||||
some other informations generally for dealing with technical details and ease
|
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
|
(st/merge
|
||||||
{:user User
|
{:user User
|
||||||
:groups #{Group}
|
:org Org
|
||||||
:roles #{Role}}
|
:scopes #{Scope}}
|
||||||
{s/Keyword s/Any}))
|
{s/Keyword s/Any}))
|
||||||
|
|
Loading…
Reference in a new issue