209 lines
6 KiB
Org Mode
209 lines
6 KiB
Org Mode
# Created 2021-12-07 Tue 16:36
|
|
#+title: Cisco FT SecureX Simplified Registration
|
|
#+date: [2021-12-07 Tue]
|
|
#+author: Yann Esposito
|
|
- tags :: [[id:299643a7-00e5-47fb-a987-3b9278e89da3][Auth]]
|
|
- source :: https://github.com/advthreat/response/issues/821
|
|
- dashboard :: https://github.com/advthreat/iroh/projects/32
|
|
|
|
* Technical Plan
|
|
** Support private email vs public emails
|
|
|
|
The solution is to use a blacklist of domains where any user could create
|
|
multiple email accounts pseudo-anonymously.
|
|
|
|
** Support, search admin with same email domain
|
|
|
|
We should be able given an email from a user, to find all the orgs for
|
|
which at least one of its admin has a matching domain name.
|
|
|
|
1. Most efficient: add an invisible field =email-domain= to all users. This
|
|
should be lower-case, and we will need a migration.
|
|
Doing this we could have a faster match than using string related queries.
|
|
|
|
Problems, users can login in the same user, with the same public email with
|
|
different emails.
|
|
This should be rare.
|
|
|
|
1. Search via text match.
|
|
|
|
|
|
The algorithm should look a bit like:
|
|
|
|
#+begin_src clojure
|
|
|
|
;; only when this is an unknown user
|
|
;; so a single approval will prevent the user to see this page.
|
|
(let [user-email ,,,
|
|
domain (string/replace user-email #".*@" "")
|
|
users (matching-admins domain) ;; returns a potentially big list of admin users
|
|
indexed-orgs (group-by :org-id users)]
|
|
(vals indexed-orgs))
|
|
#+end_src
|
|
|
|
|
|
Once this list of orgs is found.
|
|
We should also check the list of pending or rejected OrgAccessRequest for this user in
|
|
order to prevent the user to request access multiple time.
|
|
|
|
** Support Org request to admins
|
|
|
|
We need to create another Entity for access request to an Org.
|
|
|
|
#+begin_src clojure
|
|
(s/defschema OrgAccessRequest
|
|
(st/merge
|
|
{:id UUID
|
|
:idp-mapping IdPMapping
|
|
:user-email s/Str
|
|
:org-id s/Str
|
|
:status (s/enum :pending :accepted :rejected)
|
|
:created-at DateTime}
|
|
(st/optional-keys
|
|
{:user-name s/Str
|
|
:user-nick s/Str
|
|
:approver-id UserId
|
|
:approver-email UserEmail ;; email of the approver
|
|
:updated-at DateTime
|
|
})))
|
|
#+end_src
|
|
|
|
When a user request access to an organization.
|
|
We should create this object in DB.
|
|
|
|
** Support the mechanism to create a new Org Access Request
|
|
|
|
After the UserIdentity is known and after retrieving the matching orgs, and
|
|
matching org access requests for this UserIdentity.
|
|
|
|
We should allow the user to create new OrgAccessRequest.
|
|
The way to do this is to create a new POST endpoint.
|
|
As the user will not have any JWT at this point.
|
|
We might probably build a "UserIdentity JWT" and trust it.
|
|
So the webpage could make request on behalf of a UserIdentity and not a User.
|
|
|
|
There should be an endpoint:
|
|
|
|
#+begin_src http
|
|
POST
|
|
/iroh/iroh-auth/request-org-access
|
|
|
|
Accept: application/json
|
|
Content-Type: application/json
|
|
User-Agent: ob-http
|
|
Authorization: Bearer ${user-jwt}
|
|
|
|
{"org-id":"the-id-of-the-org-the-user-request-access-to"}
|
|
#+end_src
|
|
|
|
After this call the =user-jwt= should contain enough data to retrieve:
|
|
- =idp-mapping=
|
|
- =user-email=
|
|
- all other metas, as user-name, user-nick, etc…
|
|
|
|
With this, and if every check matches:
|
|
|
|
1. There is a known active admin of this org with an email with the same domain name
|
|
2. The org is active
|
|
|
|
We should:
|
|
|
|
1. create a new =OrgAccessRequest= object in DB.
|
|
2. Send emails (see next section)
|
|
|
|
** Email Notification of Org Request Accesses
|
|
|
|
1. List all the admins of the requested org.
|
|
2.a. If there is fewer admins than a number that could be configured in the
|
|
node configuration. Then we send an email to all admins.
|
|
2.b. If there are more admins than this specific number, then we randomly
|
|
chose this maximal number of admins and send them an email notification.
|
|
|
|
*TODO* Have an email template (both HTML and Text)
|
|
|
|
** Org Requests CRUD API for Admins of the Orgs
|
|
|
|
There should be a CRUD API restricted to the ~admin/user-mgmt/org-requests~ scope:
|
|
|
|
- ~GET /iroh/user-mgmt/org-requests~ list pending org access requests
|
|
- ~GET /iroh/user-mgmt/org-requests/<id>~ read a single org access request
|
|
- ~POST /iroh/user-mgmt/org-requests/<id>/accept~ Grant the access
|
|
- ~POST /iroh/user-mgmt/org-requests/<id>/reject~ Reject the access
|
|
|
|
*** List
|
|
|
|
~GET /iroh/user-mgmt/org-requests~
|
|
|
|
If no parameter is provided, only list pending =OrgAccessRequests= of the org
|
|
of the caller.
|
|
Otherwise we could pass the query-parameter =status= with the following
|
|
value(s):
|
|
|
|
- =pending=
|
|
- =accepted=
|
|
- =rejected=
|
|
|
|
Note we should probably support duplicate statuses.
|
|
Ex:
|
|
|
|
~GET /iroh/user-mgmt/org-requests?status=accepted&status=pending~
|
|
|
|
*** Read
|
|
|
|
~GET /iroh/user-mgmt/org-requests/org-request-id~
|
|
|
|
Should returns a 404 if not found or the single Org Access Request object.
|
|
|
|
*** Accept the Org Access
|
|
|
|
~POST /iroh/user-mgmt/org-requests/<id>/accept~ Grant the access
|
|
|
|
The body should contain the role (either =admin= or =user=) with the following schema:
|
|
|
|
#+begin_src js
|
|
{"role":"admin"}
|
|
#+end_src
|
|
|
|
During the call, should:
|
|
|
|
1. Create a new user with:
|
|
|
|
#+begin_src clojure
|
|
{:user-id (gen-uuid)
|
|
:org-id (:org-id org-access-request)
|
|
:user-email (:user-email org-access-request)
|
|
:idp-mappings [(:idp-mapping org-access-request)]
|
|
:user-name (:user-name org-access-request)
|
|
:user-nick (:user-nick org-access-request)
|
|
:role (get-in request [:body :role])
|
|
:enabled? true
|
|
}
|
|
#+end_src
|
|
|
|
1. Send an email to user confirming his access was granted.
|
|
|
|
*TODO* have an email template + text.
|
|
|
|
*** Reject the Org Access
|
|
|
|
~POST /iroh/user-mgmt/org-requests/<id>/reject~ Reject the access
|
|
|
|
This call should update the =OrgAccessRequest= object by patching with:
|
|
|
|
#+begin_src clojure
|
|
{:udpated-at (now)
|
|
:approver-id (get-in req [:identity :user :id])
|
|
:approver-email (get-in req [:identity :user :email])
|
|
:status :rejected}
|
|
#+end_src
|
|
|
|
Then send an email to user confirming his access was denied.
|
|
|
|
*TODO* have an email template + text.
|
|
** UI Revamp.
|
|
|
|
All the page shown during login are hosted in IROH.
|
|
So we should revamp all pages and we should probably, take great attention
|
|
to every shown webpage.
|
|
|
|
*TODO* have UI templates for every page of the workflow.
|