1032 lines
32 KiB
Org Mode
1032 lines
32 KiB
Org Mode
:PROPERTIES:
|
|
:ID: 1208f09c-d37d-4e6b-9110-151f3c6b7d34
|
|
:END:
|
|
#+TITLE: Cisco FT SecureX Simplified Registration
|
|
#+Author: Yann Esposito
|
|
#+Date: [2021-12-07]
|
|
#+OPTIONS: prop:t
|
|
|
|
- tags :: [[id:299643a7-00e5-47fb-a987-3b9278e89da3][Auth]]
|
|
- ref :: https://github.com/advthreat/response/issues/821
|
|
- source :: https://github.com/advthreat/iroh/issues/6076
|
|
- dashboard :: https://github.com/advthreat/iroh/projects/32
|
|
|
|
* Table of Content :TOC_4:QUOTE:
|
|
#+BEGIN_QUOTE
|
|
- [[#functional-spec][Functional Spec]]
|
|
- [[#17-technical-plan][=17= Technical Plan]]
|
|
- [[#0-support-private-email-vs-public-emails][=0= Support private email vs public emails]]
|
|
- [[#canceled-support-allow-list-exceptions-for-some-cisco-user][CANCELED Support allow-list exceptions for some Cisco user.]]
|
|
- [[#1-support-search-admin-with-same-email-domain][=1= Support, search admin with same email domain]]
|
|
- [[#12-new-ui-sync][=12= New UI Sync]]
|
|
- [[#1-new-auth-apis][=1= New Auth APIs]]
|
|
- [[#tasks][Tasks]]
|
|
- [[#1-new-api-jwt-middleware][=1= New API JWT middleware]]
|
|
- [[#5-new-iroh-auth-api-endpoints][=5= New IROH-Auth API endpoints]]
|
|
- [[#4-orgaccessrequestservice][=4= ~OrgAccessRequestService~]]
|
|
- [[#1-optional-useridentityservice][=1= /OPTIONAL/ ~UserIdentityService~]]
|
|
- [[#4-new-iroh-auth-api][=4= New IROH-Auth API]]
|
|
- [[#whoami-endpoint][=whoami= Endpoint]]
|
|
- [[#create-new-account][Create New Account]]
|
|
- [[#list-matching-accounts---ref][List Matching Accounts - ref]]
|
|
- [[#list-pending-invites][List Pending Invites]]
|
|
- [[#request-org-access][Request Org Access]]
|
|
- [[#list-matching-orgs][List Matching Orgs]]
|
|
- [[#registration-view][Registration View]]
|
|
- [[#optional-hide-matching-org][/OPTIONAL/ Hide Matching Org]]
|
|
- [[#redirects-user][Redirects User]]
|
|
- [[#1-optional-sync-useridentity-on-all-successful-securex-login][=1= /OPTIONAL/ Sync UserIdentity on all successful SecureX login]]
|
|
- [[#3-email-notification-of-org-request-accesses][=3= Email Notification of Org Request Accesses]]
|
|
- [[#notes][Notes]]
|
|
- [[#2-org-requests-crud-api-for-admins-of-the-orgs][=2= Org Requests CRUD API for Admins of the Orgs]]
|
|
- [[#list][List]]
|
|
- [[#read][Read]]
|
|
- [[#patch-the-org-access][Patch the Org Access]]
|
|
- [[#notes-1][Notes]]
|
|
- [[#number-of-admins-per-org][Number of admins per org]]
|
|
#+END_QUOTE
|
|
|
|
* Functional Spec
|
|
|
|
Response issues:
|
|
- https://github.com/advthreat/response/issues/821
|
|
|
|
Figma: https://www.figma.com/file/Bz3m25kpWXpdct7AnhmNsW/SXSO-Registeration?node-id=759%3A5926
|
|
|
|
* =17= Technical Plan
|
|
/Estimate: 17 rcd/
|
|
|
|
- rcd :: rcd stands for release cycle for 1 dev
|
|
|
|
** DONE =0= Support private email vs public emails
|
|
|
|
*DONE*
|
|
+/Estimate: 1 rcd after the list is provided./+
|
|
|
|
The solution is to use a blacklist of domains where any user could create
|
|
multiple email accounts pseudo-anonymously.
|
|
|
|
Details: https://github.com/advthreat/response/issues/979
|
|
|
|
*** CANCELED Support allow-list exceptions for some Cisco user.
|
|
:LOGBOOK:
|
|
- State "CANCELED" from "HOLD" [2022-01-17 Mon 10:57] \\
|
|
This only concern new account creation. User with gmail account could still login.
|
|
:END:
|
|
|
|
/Estimate: 1 rcd after the list is provided./
|
|
|
|
Typically we should allow some users with an email like =some-user+XXX@gmail.com=
|
|
|
|
** =1= Support, search admin with same email domain
|
|
|
|
/Estimate: 1 rcd./
|
|
Note: *Work in progress*
|
|
|
|
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.
|
|
|
|
2. 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.
|
|
|
|
** =12= New UI Sync
|
|
|
|
/Estimate: 12 rcd/
|
|
|
|
We should find a way to hand the UI work to the UI team.
|
|
Right now, the page are all generated in IROH.
|
|
|
|
To reach that ideally we should sync the source code as a jar in IROH.
|
|
|
|
In order to give the UI the ability to make a front-end application, we
|
|
should create news APIS that support a new UserIdentity-level JWT
|
|
|
|
*** =1= New Auth APIs
|
|
/Estimate: 1 rcd/
|
|
|
|
ref :: https://github.com/advthreat/iroh/issues/6242
|
|
|
|
Continue to use the =/code= route of iroh-auth.
|
|
But instead of returning a Session Token, it will return a UserIdentity Token.
|
|
This is a JWT with the important data from the IdP:
|
|
|
|
- idp-id
|
|
- user-identity-id
|
|
- user-email
|
|
- etc…
|
|
|
|
When the user is redirected to an HTML generated page, we should add the
|
|
=code= in the anchor parameter of the route so the UI will be able to use
|
|
that code to retrieve a UserIdentity Token.
|
|
We should derive the current mechanism with code, but use the login code store.
|
|
|
|
**** Tasks
|
|
|
|
- Create a new function to generate these new JWT using the "token-infos"
|
|
|
|
*** =1= New API JWT middleware
|
|
/Estimate: 1 rcd/
|
|
- ref :: https://github.com/advthreat/iroh/issues/6266
|
|
|
|
We need to change the configuration of the check JWT middleware to support
|
|
UserIdentity Token instead. And use this configuration for this new API.
|
|
|
|
The =user-identity-jwt= should contain enough data to retrieve:
|
|
- =idp-mapping=
|
|
- =user-email=
|
|
- all other metas, as user-name, user-nick, etc…
|
|
|
|
*** =5= New IROH-Auth API endpoints
|
|
/Estimate: 5 rcd/
|
|
- ref :: https://github.com/advthreat/iroh/issues/6268
|
|
|
|
**** =4= ~OrgAccessRequestService~
|
|
|
|
/Estimate: 4 rcd/
|
|
|
|
- ref :: https://github.com/advthreat/iroh/issues/6272
|
|
|
|
This new service should be mostly a CRUD service on top of =TKStore= with the
|
|
following schema:
|
|
|
|
#+begin_src clojure
|
|
(s/defschema OrgAccessRequestStatus
|
|
(s/enum :pending :accepted :rejected))
|
|
|
|
(s/defschema OrgAccessRequest
|
|
(st/merge
|
|
{:id UUID
|
|
:secret s/Str ;; should be generated via `iroh-auth.lib.security/password`
|
|
:idp-mapping IdPMapping
|
|
:user-email s/Str
|
|
:org-id s/Str
|
|
:status OrgAccessRequestStatus
|
|
:created-at DateTime}
|
|
(st/optional-keys
|
|
{:user-name s/Str
|
|
:user-nick s/Str
|
|
:granted-role Role ;; the role granted if the request is accepted
|
|
:approver-id UserId
|
|
:approver-email UserEmail ;; email of the approver
|
|
:updated-at DateTime
|
|
})))
|
|
#+end_src
|
|
|
|
#+begin_src clojure
|
|
(defprotocol OrgAccessRequestService
|
|
"See iroh-auth.registration.org-access-request.schemas/ServiceFns for schemas."
|
|
:extend-via-metadata true
|
|
|
|
;; service function for the Admins logged in SecureX
|
|
;; User filtered CRUD+Search for REST API related methods
|
|
(search-org-access-requests-for-org
|
|
[this request-identity filter-map pagination-params]
|
|
"Search all OrgAccessRequest of the org of the user of the request-identity")
|
|
|
|
(get-org-access-request
|
|
[this request-identity org-access-request-id]
|
|
"Return the OrgAccessRequest for a user using the org-access-request-id")
|
|
|
|
(patch-org-access-request
|
|
[this request-identity org-access-request-id org-access-request-patch]
|
|
"Change the status of an OrgAccessRequest to grant/reject it.
|
|
Note user creation could be a side effect.")
|
|
|
|
;; For the New Registration Page (the user logged in via the IdP successfully)
|
|
(search-org-access-requests-for-user-identity
|
|
[this user-identity filter-map pagination-params]
|
|
"Search all OrgAccessRequest made by this user identity accross all orgs.
|
|
This should only be visible via the registration page on the new API accepting
|
|
user-identity JWT")
|
|
|
|
(create-org-access-request
|
|
[this user-identity org-id]
|
|
"Create a new OrgAccessRequest.")
|
|
|
|
(delete-org-access-request
|
|
[this user-identity org-access-request-id]
|
|
"Remove an org request access.")
|
|
|
|
;; Internal CRUD+Search
|
|
(raw-search-org-access-requests
|
|
[this filter-map pagination-params]
|
|
"Search all OrgAccessRequest grants")
|
|
|
|
(raw-get-org-access-request
|
|
[this org-access-request-id]
|
|
"Return the OrgAccessRequest grant")
|
|
|
|
(raw-patch-org-access-request
|
|
[this org-access-request-id org-access-request-patch]
|
|
"Update the status of an OrgAccessRequest.")
|
|
|
|
;; To be used in the `iroh-auth-web-service` directly without any password
|
|
(patch-org-access-request
|
|
[this org-access-request-id org-access-request-secret org-access-request-patch]
|
|
"Similar to patch-org-access-request but for non logged in users can be used by
|
|
providing both the OrgAccessRequest id and secret.
|
|
That way we could build a URL into emails sent to admins to create
|
|
the new user in the correct org."))
|
|
#+end_src
|
|
***** =1= search/get/patch
|
|
/Estimate: 1 rcd/
|
|
***** =1= Create
|
|
|
|
For the =create-org-access-request= an email should be send to the oldest
|
|
active admin of the matching org.
|
|
|
|
***** =3= PATCH
|
|
/Estimate: 3 rcd/
|
|
|
|
The org-access-request-patch should have the following schema:
|
|
|
|
#+begin_src clojure
|
|
{(s/optional-key :role) Role
|
|
:status (s/enum :accepted :rejected)}
|
|
#+end_src
|
|
|
|
If the role is not provided, the default value should be =user=.
|
|
If the old ~OrgAccessRequest~ is not ~:pending~ this should throw a 400.
|
|
If the status is set to =:accepted=:
|
|
|
|
1. create a new user for the org of the ~OrgAccessRequest~.
|
|
2. send an email to the user that requested the access
|
|
|
|
If the status is set to =:rejected=, then send an email to the user that
|
|
requested the access.
|
|
|
|
Note we should test that the user created that way could login correctly.
|
|
***** =1= Unauthenticated PATCH
|
|
/Estimate: 1 rcd/
|
|
|
|
Similar to the =PATCH= but should check the authenticity of the call by
|
|
checking both the ~OrgAccessRequest~ id and secret.
|
|
|
|
**** =1= /OPTIONAL/ ~UserIdentityService~
|
|
|
|
/Estimate: 1 rcd/
|
|
|
|
- ref :: https://github.com/advthreat/iroh/issues/6274
|
|
|
|
Create a new service dedicated to ~UserIdentities~.
|
|
|
|
#+begin_src clojure
|
|
(defprotocol UserIdentityService
|
|
"Service which handle UserIdentities (mostly CRUD operations). "
|
|
(create-user-identity [this user-params])
|
|
(get-user-identity [this user-id])
|
|
(update-user-identity [this user-params])
|
|
(update-login-date [this user-id])
|
|
(search-user-identities
|
|
[this filter-map pagination-params]
|
|
[this filter-map pagination-params stringmatch-query-params])
|
|
(delete-user-identity [this user-id]))
|
|
#+end_src
|
|
|
|
It should also contain a field containing a set of hidden org-ids that will
|
|
be the orgs not to display on the registration webpages.
|
|
|
|
#+begin_src clojure
|
|
(s/defschema UserIdentity
|
|
(ist/open-schema-any-keys
|
|
{:id s/Str
|
|
:email
|
|
:name
|
|
:nickname
|
|
:last-logged-in [,,,]
|
|
(s/optional-key :hidden-orgs) #{,,,}}))
|
|
#+end_src
|
|
|
|
*** =4= New IROH-Auth API
|
|
/Estimate: 4 rcd/
|
|
- ref :: https://github.com/advthreat/iroh/issues/6268
|
|
|
|
/Depends: IROH-Auth CRUD Service/
|
|
|
|
This new API should only work with UserIdentity JWT.
|
|
|
|
#+begin_src
|
|
GET /iroh/iroh-auth-ui/whoami ;; whoami at the User Identity level
|
|
POST /iroh/iroh-auth-ui/org-access/:org-id ;; request access to a matching org
|
|
POST /iroh/iroh-auth-ui/hide-org/:org-id ;; ability to hide an org-access
|
|
GET /iroh/iroh-auth-ui/matching-accounts ;; list all the matching accounts
|
|
GET /iroh/iroh-auth-ui/matching-orgs ;; list all the matching orgs
|
|
GET /iroh/iroh-auth-ui/pending-invites ;; list all the pending invites
|
|
GET /iroh/iroh-auth-ui/registration-view ;; helper to make a single http call
|
|
#+end_src
|
|
|
|
**** =whoami= Endpoint
|
|
|
|
- ref :: https://github.com/advthreat/iroh/issues/6266
|
|
|
|
Write an endpoint that would use the ~UserIdentity~ JWT and decode it.
|
|
Ideally should instead read the value in DB via the ~UserIdentityService~.
|
|
**** Create New Account
|
|
/Estimate: 2 rcd/
|
|
- ref :: https://github.com/advthreat/iroh/issues/6280
|
|
|
|
Create a new endpoint to create a new account (user + org):
|
|
|
|
#+begin_src http
|
|
GET /iroh/iroh-auth-ui/create-new-account
|
|
|
|
Accept: application/json
|
|
Content-Type: application/json
|
|
User-Agent: ob-http
|
|
Authorization: Bearer ${user-identity-jwt}
|
|
|
|
{"org-name":"Cisco",
|
|
"country":"US"}
|
|
#+end_src
|
|
|
|
The clojure code for the route should roughly look like:
|
|
|
|
#+begin_src clojure
|
|
(s/defschema NewAccount
|
|
(st/merge
|
|
{:org-name :- s/Str
|
|
:country :- (apply s/enum country-iso-codes)
|
|
(st/optional-keys
|
|
{:department :- s/Str
|
|
:street1 :- s/Str
|
|
:street2 :- s/Str
|
|
:postal-code :- s/Str
|
|
:city :- s/Str})}))
|
|
|
|
(POST "/create-new-account" []
|
|
:summary "Given a code and some org-settings create a new account (new org and new user)"
|
|
:description "This is an internal temporary route needed to select the user/org."
|
|
:body [{:keys [country
|
|
org-name
|
|
department
|
|
street1
|
|
street2
|
|
postal-code
|
|
city] :as new-account} NewAccount]
|
|
(let [address (iroh-core/assoc-some?
|
|
{:country-iso-code country}
|
|
:department department
|
|
:street1 street1
|
|
:street2 street2
|
|
:postal-code postal-code
|
|
:city city)
|
|
org-settings {:name org-name
|
|
:address address}]
|
|
(resp/found (create-new-account org-settings))))
|
|
#+end_src
|
|
|
|
|
|
As we now have a session, we should take care about a few details:
|
|
|
|
***** Important Security Remarks
|
|
|
|
****** Should we keep track of the =origin=?
|
|
|
|
When a user login there is always an =origin= parameter (by default it will
|
|
point to SecureX).
|
|
But a user can login and create an account and should ultimately be
|
|
redirected to the correct URL (product).
|
|
Currently, the user can be redirected to:
|
|
|
|
- SecureX
|
|
- CTR
|
|
- Orbital
|
|
|
|
We should put the =origin= in the JWT and we should take care that the origin
|
|
has been checked via the =allowed-login-origins=.
|
|
|
|
The question about should we return a 301 to the =create-new-account= is open.
|
|
But this is probably a good idea to let only the backend take care of the
|
|
security of the redirection.
|
|
Note this is a very important security concern otherwise an attack in the
|
|
redirection code might send the credentials to an attacker quite easily.
|
|
****** Should we prevent a user identity to create multiple accounts?
|
|
|
|
I don't think so.
|
|
Not in the first round at least.
|
|
It will probably be easy to add a =created-by= metas in the org, and prevent
|
|
duplicates (or put a maximal number of authorized enabled orgs)
|
|
**** List Matching Accounts - ref ::
|
|
https://github.com/advthreat/iroh/issues/6270 #+begin_src http GET
|
|
/iroh/iroh-auth-ui/matching-accounts
|
|
|
|
Accept: application/json
|
|
Content-Type: application/json
|
|
User-Agent: ob-http
|
|
Authorization: Bearer ${user-identity-jwt}
|
|
#+end_src
|
|
|
|
It should return a list of object with the following schema sorted by last
|
|
logged in time by the user:
|
|
|
|
#+begin_src clojure
|
|
{:user User
|
|
:org Org
|
|
:last-login-date DateTime
|
|
:relative-last-login s/Str
|
|
:org-created-at DateTime
|
|
:relative-org-created-at s/Str
|
|
:activated? s/Bool
|
|
:org-nb-users s/Int}
|
|
#+end_src
|
|
|
|
Mainly should return the data structure used in the current selection
|
|
account page using similar order and functionalities.
|
|
**** List Pending Invites
|
|
|
|
- ref :: https://github.com/advthreat/iroh/issues/6269
|
|
|
|
#+begin_src http
|
|
GET /iroh/iroh-auth-ui/pending-invites
|
|
#+end_src
|
|
|
|
Here is an example value:
|
|
|
|
#+begin_src clojure
|
|
[{:role "admin",
|
|
:org-id "org-1",
|
|
:expires-in-nb-days 7,
|
|
:status "pending",
|
|
:invitee-email "chuck@example.org",
|
|
:inviter-user-id "org-1-admin-1"}]
|
|
#+end_src
|
|
|
|
We already retrieve pending invite in the code. The work would be about
|
|
taking care of having a specialized method from either an existing or a new
|
|
TK service dedicated to this functionality.
|
|
|
|
Use this method to expose it via the API.
|
|
**** Request Org Access
|
|
|
|
- ref :: https://github.com/advthreat/iroh/issues/6271
|
|
|
|
We need to create another store with another Entity for access request to an Org.
|
|
|
|
#+begin_src clojure
|
|
(s/defschema OrgAccessRequest
|
|
(st/merge
|
|
{:id UUID
|
|
:secret s/Str ;; should be generated via `iroh-auth.lib.security/password`
|
|
:idp-mapping IdPMapping
|
|
:user-email s/Str
|
|
:org-id s/Str
|
|
:status OrgAccessRequestStatus
|
|
:created-at DateTime}
|
|
(st/optional-keys
|
|
{:user-name s/Str
|
|
:user-nick s/Str
|
|
:granted-role Role ;; the role granted if the request is accepted
|
|
: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.
|
|
|
|
|
|
#+begin_src
|
|
POST /iroh/iroh-auth-ui/org-access/:org-id ;; request access to a matching org
|
|
#+end_src
|
|
|
|
#+begin_src http
|
|
POST /iroh/iroh-auth-ui/org-access/:org-id
|
|
|
|
Accept: application/json
|
|
Content-Type: application/json
|
|
User-Agent: ob-http
|
|
Authorization: Bearer ${user-identity-jwt}
|
|
#+end_src
|
|
|
|
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 the Email Notification of Org Request Accesses section)
|
|
|
|
**** List Matching Orgs
|
|
|
|
- ref :: https://github.com/advthreat/iroh/issues/6273
|
|
|
|
#+begin_src http
|
|
GET /iroh/iroh-auth-ui/matching-orgs
|
|
#+end_src
|
|
|
|
Given a ~UserIdentity~ with some email.
|
|
Should return every Org whose at least one admin has an email with the same
|
|
domain address.
|
|
So if you login via ~chuck@cisco.com~ you should return all orgs for which
|
|
there is at least one admin with a ~cisco.com~ email address.
|
|
|
|
Should return a list of objects with the following schema (sort to be defined):
|
|
|
|
#+begin_src clojure
|
|
{:org Org
|
|
:org-nb-users s/Int
|
|
:org-request-access-status OrgRequestAccessStatus}
|
|
#+end_src
|
|
|
|
*Note*
|
|
|
|
This endpoint is not straightforward.
|
|
We should list all current matching org, and concurrently list all current
|
|
=OrgRequestAccess= made by this =UserIdentity=.
|
|
We should also list all orgs for which there is already a pending invite.
|
|
|
|
We shall finally return a list of orgs sorted by the number of users (from
|
|
max to min) with the current status and remove the org for which there is
|
|
still a non expired pending invite.
|
|
|
|
If there is more than 6 orgs, we should only return
|
|
the firsts 6 of them but make it clear in the pagination headers that there
|
|
are more than 6 matching org so the frontend could react accordingly.
|
|
Another option would be to return a 400 with an error message.
|
|
|
|
***** /OPTIONAL/ Hide some matching orgs manually
|
|
|
|
Optionally we might also retrieve the orgs marked as hidden for this =UserIdentity= in DB.
|
|
|
|
We should support query parameter to show all orgs, even the hidden ones so
|
|
a user should be able to unhide a previously hidden org.
|
|
|
|
|
|
**** Registration View
|
|
|
|
- ref :: https://github.com/advthreat/iroh/issues/6275
|
|
|
|
#+begin_src http
|
|
GET /iroh/iroh-auth-ui/registration-view
|
|
#+end_src
|
|
|
|
Should return the same result as the union of the calls to
|
|
=matching-accounts=, =matching-orgs= and =pending-invites=.
|
|
|
|
#+begin_src clojure
|
|
{:matching-accounts [,,,]
|
|
:matching-orgs [,,,]
|
|
:pending-invites [,,,]}
|
|
#+end_src
|
|
**** /OPTIONAL/ Hide Matching Org
|
|
|
|
- ref :: https://github.com/advthreat/iroh/issues/6276
|
|
|
|
#+begin_src http
|
|
POST /iroh/iroh-auth-ui/hide-org/:org-id
|
|
|
|
Accept: application/json
|
|
Content-Type: application/json
|
|
User-Agent: ob-http
|
|
Authorization: Bearer ${user-identity-jwt}
|
|
#+end_src
|
|
|
|
Should save in the ~UserIdentity~ store a new ~org-id~ to hide.
|
|
This impacts the call to ~matching-orgs~ such that orgs marked as hidden
|
|
should not be displayed when calling the ~matching-org~ route.
|
|
**** Redirects User
|
|
|
|
Create a new endpoint to redirect users using the value in the UserIdentity JWT.
|
|
See https://github.com/advthreat/iroh/issues/6280
|
|
|
|
#+begin_src http
|
|
GET /iroh/iroh-auth-ui/redirect
|
|
#+end_src
|
|
|
|
So this should be a route which should looks like this:
|
|
|
|
#+begin_src clojure
|
|
(GET "/redirect" []
|
|
:summary "Given a code and some org-settings create a new account (new org and new user)"
|
|
:description "This is an internal temporary route needed to select the user/org."
|
|
:identity [session-redirect]
|
|
(if (allowed-login-origin? session-redirect)
|
|
(resp/found session-redirect)
|
|
(err/bad-request :forbidden-redirect-url
|
|
(format "The redirect URL %s is not a valid redirect for login."
|
|
session-redirect)
|
|
{})))
|
|
#+end_src
|
|
|
|
*** =1= /OPTIONAL/ Sync UserIdentity on all successful SecureX login
|
|
/Estimate: 1 rcd/
|
|
|
|
- ref :: https://github.com/advthreat/iroh/issues/6367
|
|
|
|
From #6076 we have a new CRUD service that should keep track of `UserIdentity`.
|
|
Mainly this information could be used as providing more details than what is currently set int he user's `idp-mapping`. Typically we have access to the email of the UserIdentity, user name from the IdP, and probably a lot more details that will be useful.
|
|
|
|
So every time a successful login occurs we should update the UserIdentity object last logged in date (as we do for users) which will probably be quite useful.
|
|
|
|
** =3= Email Notification of Org Request Accesses
|
|
/Estimate: 3 rcd after email+html templates/
|
|
- ref :: https://github.com/advthreat/iroh/issues/6368
|
|
|
|
- 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)
|
|
*** Notes
|
|
|
|
Need to be able to trigger a new request to join after 7 days.
|
|
|
|
** =2= Org Requests CRUD API for Admins of the Orgs
|
|
/Estimate: 2 rcd after mail templates + text/
|
|
- ref :: https://github.com/advthreat/iroh/issues/6369
|
|
|
|
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
|
|
- ~PATCH /iroh/user-mgmt/org-requests/<id>~ Grant or 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.
|
|
|
|
*** Patch the Org Access
|
|
|
|
~PATCH /iroh/user-mgmt/org-requests/<id>~ Grant/Reject the access
|
|
|
|
The body should be a JSON Object with:
|
|
- an optional field =role= whose value could be either =admin= or =user= (default
|
|
to =user=)
|
|
- a mandatory =status= field whose value could be either =accepted= or =rejected=.
|
|
|
|
A few examples of valid values:
|
|
|
|
#+begin_src js
|
|
{"granted-role":"admin"
|
|
"status":"accepted"}
|
|
#+end_src
|
|
|
|
#+begin_src js
|
|
{"status":"accepted"}
|
|
#+end_src
|
|
|
|
#+begin_src js
|
|
{"status":"rejected"}
|
|
#+end_src
|
|
|
|
During the call we 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
|
|
|
|
2. Send an email to user confirming his access was granted.
|
|
|
|
*TODO* have an email template + text.
|
|
* Notes
|
|
|
|
Here is the list of the total number of orgs with >100 users in prod NAM:
|
|
|
|
#+begin_src
|
|
101 a9876101-3d6a-4a6b-b09a-175d554e446a
|
|
107 18fc4fd9-fb31-48bd-a828-a8a0783a1d2e
|
|
115 threatgrid:7
|
|
118 threatgrid:1
|
|
136 75016e07-5850-4054-a537-eea5d2897d17
|
|
144 b3c172f8-792a-4c0e-b572-b580e1a8c6b6
|
|
144 cb3958cf-992d-44f6-8803-de684b614f97
|
|
146 9755f0e4-57b9-4514-a8c6-93d66edf5f9b
|
|
146 ce6c4a4b-fd10-4a07-a23b-88e5f1580565
|
|
153 e1ee0f83-56d2-4dd8-8463-dc6bfd6afcb8
|
|
195 9ec78968-adff-40c2-b57c-7bc2ed2132cc
|
|
204 681c3549-1c52-4ca3-b88c-3de68438bb03
|
|
220 a94805d9-ad26-47f6-9fa4-647cbd89cb6c
|
|
239 7045f4c2-3a38-49ff-9bb5-01052219e8da
|
|
267 6fcb8a6f-c043-4842-a1a4-9bfff5f57f15
|
|
347 56e851ae-8146-4834-9257-d0068d5885ba
|
|
352 7df4fb52-3ded-4e75-9160-eaa07614192a
|
|
381 a1ff6ab0-6693-4c2d-a203-54db28d34e78
|
|
472 f81d494c-ec2d-4589-80b2-1941a3a9d875
|
|
473 399a1a44-f230-4997-8195-f111172a503e
|
|
560 f86053fc-f173-488f-9d55-825fc0117239
|
|
694 threatgrid:1182
|
|
#+end_src
|
|
|
|
So 22 orgs out of 29541 orgs.
|
|
|
|
Matching domain names:
|
|
|
|
#+begin_src
|
|
103 yahoo.com
|
|
115 anm.com
|
|
116 corebts.com
|
|
118 hotmail.com
|
|
124 ubc.ca
|
|
132 sfsnort.com
|
|
134 scitum.com.mx
|
|
147 purdue.edu
|
|
186 atp-us.com
|
|
201 sentinel.com
|
|
253 cognizant.com
|
|
337 port53tech.com
|
|
842 dcloud.cisco.com
|
|
1315 gmail.com
|
|
2036 unknown mail
|
|
14762 cisco.com
|
|
#+end_src
|
|
|
|
So 16 domain email with >100 users while there are 15542 different email domains in the DB in PROD NAM.
|
|
|
|
The number of matching orgs per email filtered by orgs with >6 matching orgs:
|
|
|
|
|
|
#+begin_src
|
|
7 businessinformationgroup.com
|
|
7 carouselindustries.com
|
|
7 censystems.com.mx
|
|
7 chickasawtel.com
|
|
7 choctawnation.com
|
|
7 deloitte.com
|
|
7 hammer.net
|
|
7 ikusi.com
|
|
7 its-networks.com
|
|
7 live.com
|
|
7 mac.com
|
|
7 mail.mil
|
|
7 mfec.co.th
|
|
7 ndc.com.br
|
|
7 orange.com
|
|
7 orben.com
|
|
7 redesmayab.com
|
|
7 securesoftcorp.com
|
|
7 spcinternacional.com
|
|
7 teledinamica.com.mx
|
|
7 tetradefense.com
|
|
7 us.logicalis.com
|
|
8 att.com
|
|
8 compucom.com
|
|
8 comstor.com
|
|
8 dsitech.com
|
|
8 gdt.com
|
|
8 getgds.com
|
|
8 ineteng.com
|
|
8 mitgs.com
|
|
8 outcomex.com.au
|
|
8 telcion.com
|
|
8 zebra.com
|
|
9 apple.com
|
|
9 aqueducttech.com
|
|
9 conscia.com
|
|
9 icloud.com
|
|
9 katalystng.com
|
|
9 protonmail.com
|
|
9 securview.com
|
|
9 softserveinc.com
|
|
9 techdata.com
|
|
9 telefonica.com
|
|
9 tfmx.com
|
|
9 veytec.com
|
|
10 aspiretransforms.com
|
|
10 comstor-la.com
|
|
10 me.com
|
|
10 trace3.com
|
|
10 uncommonx.com
|
|
11 3rtnetworks.com
|
|
11 axity.com
|
|
11 cognizant.com
|
|
11 compunet.biz
|
|
11 dimensiondata.com
|
|
11 hyetechnetworks.com
|
|
11 italtel.com
|
|
11 meraki.net
|
|
11 sonda.com
|
|
11 state.nm.us
|
|
11 tgs-mtc.com
|
|
11 voseda.com
|
|
11 wwt.com
|
|
12 5thcolumn.net
|
|
12 bvstv.com
|
|
12 ceriumnetworks.com
|
|
12 iconvergence.com
|
|
12 ignitessg.com
|
|
12 marconet.com
|
|
12 promenet.com
|
|
13 atsg.net
|
|
13 hbs.net
|
|
13 oneneck.com
|
|
14 atp-us.com
|
|
14 scitum.com.mx
|
|
14 teletex.com.br
|
|
15 un-mx.net
|
|
16 thinkgard.com
|
|
17 digitalhands.com
|
|
17 ingrammicro.com
|
|
18 arrayasolutions.com
|
|
18 ccd.com.co
|
|
19 la.logicalis.com
|
|
20 eplus.com
|
|
20 global.ntt
|
|
22 connext.com.mx
|
|
22 sourcefire.com
|
|
23 anm.com
|
|
23 presidio.com
|
|
26 cdw.com
|
|
26 nwnit.com
|
|
30 outlook.com
|
|
30 sentinel.com
|
|
33 insight.com
|
|
37 convergeone.com
|
|
46 port53tech.com
|
|
51 corebts.com
|
|
51 hotmail.com
|
|
59 yahoo.com
|
|
66 sfsnort.com
|
|
76 external.cisco.com
|
|
188 dcloud.cisco.com
|
|
199 unknown mail
|
|
577 gmail.com
|
|
4817 cisco.com
|
|
#+end_src
|
|
|
|
|
|
22 domains email will match 6 orgs
|
|
|
|
#+begin_src
|
|
6 2s.com.br
|
|
6 bynet.co.il
|
|
6 charter.ca
|
|
6 citynet.net
|
|
6 comcast.net
|
|
6 comsoltx.com
|
|
6 evcon-group.com
|
|
6 fxti.ca
|
|
6 gbm.net
|
|
6 hainc.com
|
|
6 ibm.com
|
|
6 iementor.com
|
|
6 infranetgroup.com
|
|
6 lannet.net
|
|
6 netconsulting.com.br
|
|
6 netsync.com
|
|
6 opendns.com
|
|
6 shi.com
|
|
6 softchoice.com
|
|
6 solucionesorion.com
|
|
6 synnapex.com
|
|
6 synnex.com
|
|
6 tcs.com
|
|
6 teltecsolutions.com.br
|
|
6 ubc.ca
|
|
6 yssy.com.br
|
|
#+end_src
|
|
|
|
- 22 domains email will match 6 orgs
|
|
- 42 domains email will match 5 orgs
|
|
- 90 domain emails will match 4 orgs.
|
|
- 339 domain emails will match 3 orgs.
|
|
- 1606 domain emails will match 2 orgs.
|
|
- 8591 domain emails will match a single org.
|
|
** Number of admins per org
|
|
|
|
#+begin_src
|
|
21 1850c06a-e8a5-44d4-a9a3-9410ab278454,evansville.in.gov
|
|
21 a684a119-0c88-458e-8291-a890998be3c6,cisco.com
|
|
21 a72a2650-ab6b-4c81-a2cf-dc15be3025f9,cisco.com
|
|
21 ac44b1c0-2f6a-4536-9d03-0b717c1c843c,dconc.gov
|
|
21 cb3770c1-64c5-4925-83f5-290fadc355b6,adexus.cl
|
|
21 d45dc5fd-c336-45a3-848f-b28bc22e122c,cisco.com
|
|
21 fe331828-8f82-4371-91e7-257c7745645c,arrayasolutions.com
|
|
22 2465d67c-bb5e-4ad1-8b0e-a67b7ce36569,network-data.com
|
|
22 3620d167-1aeb-4dca-b7f7-dc66acfe9c08,airnz.co.nz
|
|
22 67eea099-b310-47e9-8036-ae44bfe30e0b,cisco.com
|
|
22 713fc255-f061-4557-9fda-aec7f385dd9f,sentinel.com
|
|
22 7cf1057a-ed3c-4da7-a251-22e106691acd,atp-us.com
|
|
23 04b4d7b7-542c-47e4-8c45-2cde5dde09f8,uncp.edu
|
|
23 67bcaf0d-3eef-49ac-b15e-ef5da3c3472f,cisco.com
|
|
23 70d84b1c-a2f1-403b-bf90-af6ffdec4c84,sentinel.com
|
|
23 eb388261-c20e-48a9-9554-8816b63d182c,cisco.com
|
|
24 42ac91b9-d9df-48d8-a1d0-8c76988d0a9f,cisco.com
|
|
24 684df03f-e062-4696-8271-5ac1ce00ac94,cisco.com
|
|
24 71295ced-1fd3-44bd-926f-2f23712cf2a9,egyde.ca
|
|
24 90ab7d03-2507-4700-b07e-ddfcdc51e652,nm.org
|
|
25 086ab5fd-1b56-4abb-b652-c47a3d8eab0c,digitalhands.com
|
|
25 23058a37-2181-4dee-8057-57722a6efb0e,rsfh.com
|
|
25 328bc4ec-b74e-4db1-b7ef-4c391ed270c9,aspiretransforms.com
|
|
25 491257d7-6257-48e4-a103-1fd31b01daf5,cityoftulsa.org
|
|
25 5934ea5e-0c08-4d37-8d36-c4a1fe3dbb01,cisco.com
|
|
25 6f6027d8-3348-4f06-8e85-48bb1215c9d8,aqueducttech.com
|
|
25 81318155-45ca-49ff-9328-18ce53e97547,sentinel.com
|
|
25 ac782c34-66ad-4b26-a245-6943e6d7146a,illinois.gov
|
|
25 c3ffe79f-77d9-433c-b76b-dda8b776fb8c,telconet.ec
|
|
25 f81d494c-ec2d-4589-80b2-1941a3a9d875,cisco.com
|
|
26 39f7ec21-203f-4817-8737-bb889457495c,metlife.com
|
|
26 b8bf2598-2836-4156-ad5c-14bdedd3acf0,abm.com
|
|
26 cfef1746-df05-45a2-b421-bc2cdb68b233,cdk.com
|
|
26 threatgrid:1,cisco.com
|
|
26 threatgrid:9647,cisco.com
|
|
27 572df3d2-d561-46eb-95df-d85479f5f98f,wisc.edu
|
|
27 a2d41370-0db2-4605-8a1b-6bbf2041f0de,alvarezandmarsal.com
|
|
27 e2cd17b2-4fd7-439c-a414-62a3737abe96,cisco.com
|
|
28 2a8fecff-3c72-4177-97d6-39d6eb1338a6,choa.org
|
|
28 5643fbcc-453f-4ea6-a4bd-36414d10b64b,myoccu.org
|
|
28 8b78a2fd-1995-4ba7-a4fd-75cfefafb7a3,cisco.com
|
|
29 95e571e0-d496-46ae-a85f-fad859a1f97a,txdot.gov
|
|
29 b376744b-cf4a-4434-a43d-5d9304d01d03,altagas.ca
|
|
29 b71d47b8-3d53-44af-bbcc-5a7bbf5de4ec,cisco.com
|
|
30 1bb4024c-0d38-448e-9ec0-32fb17b3c881,ferc.gov
|
|
31 08f89d0d-d3a3-43cb-9605-dfe30109d71f,verint.com
|
|
31 2f878d5d-0212-4948-9dbd-18ae3afdced9,cisco.com
|
|
32 b230c988-2d9a-47bb-9404-6b7003d238ea,harley-davidson.com
|
|
33 36c4891e-fbf2-4e55-9e73-47320d5b8293,scitum.com.mx
|
|
33 77c16812-c601-4a7a-87f8-c60c0d354277,ahs.ca
|
|
33 97ac3ac5-604d-4284-8f84-a3c4d4db5f1f,sanfordhealth.org
|
|
33 cd2da7c0-db7e-4446-ab69-f8e6097e92d6,messa.org
|
|
34 1088e378-b2b3-4ab5-bc68-128885662140,ntrs.com
|
|
34 threatgrid:299019,cisco.com
|
|
36 e5745b0f-8ad7-4290-b008-16cb4c40b026,scitum.com.mx
|
|
36 f598e1b3-db04-42a7-ae17-31ffde6aa94f,cisco.com
|
|
37 1c9cb3e5-d876-4e4f-853f-f09ee5ea2f3c,cisco.com
|
|
37 b3c172f8-792a-4c0e-b572-b580e1a8c6b6,west.com
|
|
38 1d46f11e-17ab-4df6-8c8b-8dafd1dbde63,cisco.com
|
|
38 33ddd5e5-d8ea-40b8-9c46-2f25eefc983b,demandscience.com
|
|
38 8b8ae50d-0da7-4461-94e4-3d5a8d23a791,cisco.com
|
|
39 2c638d3a-57be-49fb-8896-c5a1c4cb402f,cisco.com
|
|
40 a127256e-d154-4535-9824-10f24e938ece,evopayments.com
|
|
40 db6fa2c3-3271-4ee6-8dae-47d21eb0f59c,cisco.com
|
|
41 4f5f7fb1-3e51-4808-99fb-02a9d3d12d15,dcloud.cisco.com
|
|
41 c55ed22f-4204-424d-9f7e-c71470b97c73,libertyutilities.com
|
|
42 1841d0d7-36df-45e7-8c94-43c7710b80cb,cisco.com
|
|
42 4ca63e42-4a71-4c85-9a28-06afac0c2273,cisco.com
|
|
44 ea3f7333-aede-44b2-b3d5-0a9e0e1b52a2,cisco.com
|
|
47 d76c035d-e896-438c-8d75-158be85fc958,cisco.com
|
|
50 473db1e7-cc1e-434f-b33f-642abf4b1d2d,cisco.com
|
|
51 77145ba3-ccb7-40ec-b91f-b869cdcf2c8b,cisco.com
|
|
55 threatgrid:1182,cisco.com
|
|
64 7045f4c2-3a38-49ff-9bb5-01052219e8da,cognizant.com
|
|
66 f47a89bf-5d2e-4392-b770-ad4821a82acf,cisco.com
|
|
68 18fc4fd9-fb31-48bd-a828-a8a0783a1d2e,cisco.com
|
|
88 6fcb8a6f-c043-4842-a1a4-9bfff5f57f15,cisco.com
|
|
91 a9876101-3d6a-4a6b-b09a-175d554e446a,shurtape.com
|
|
116 75016e07-5850-4054-a537-eea5d2897d17,cisco.com
|
|
142 ce6c4a4b-fd10-4a07-a23b-88e5f1580565,cisco.com
|
|
193 9ec78968-adff-40c2-b57c-7bc2ed2132cc,cisco.com
|
|
204 681c3549-1c52-4ca3-b88c-3de68438bb03,cisco.com
|
|
372 399a1a44-f230-4997-8195-f111172a503e,cisco.com
|
|
560 f86053fc-f173-488f-9d55-825fc0117239,cisco.com
|
|
#+end_src
|