deft/notes/cisco_ft_securex_registration.org
2022-04-12 14:36:34 +02:00

40 KiB

Cisco FT SecureX Simplified Registration

tags
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
design
https://www.figma.com/file/Bz3m25kpWXpdct7AnhmNsW/SXSO-Registeration?node-id=757%3A4369

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.

  • State "CANCELED" from "HOLD" [2022-01-17 Mon 10:57]
    This only concern new account creation. User with gmail account could still login.

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.

  1. Search via text match.

The algorithm should look a bit like:

;; 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))

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:

(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
     })))
(defprotocol OrgAccessRequestService
  "See iroh-auth.registration.org-access-request.schemas/ServiceFns for schemas."
  ;; Internal CRUD+Search almost only use iroh-crud
  (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.")

  ;; service function for the Admins logged in SecureX
  ;; User filtered CRUD+Search for REST API related methods
  ;; The first argument is a RequestIdentity (:identity request) generated from a normal JWT
  ;; via the ring-jwt-middleware.
  (search-org-access-requests
    [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)
  ;; The first argument is a UserIdentity (:identity request) it will not contain
  ;; any data related to any org
  (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. Should potentially send emails along the way")

  (renew-org-access-request
    [this user-identity org-id]
    "Renew an OrgAccessRequest. Mainly should send the email again and change the updated-at date."))
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:

{(s/optional-key :role) Role
 :status (s/enum :accepted :rejected)}

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

If possible (if we do not have any dependency cycle issue), it would be nice to put this new route under /iroh/iroh-auth (so IROHAuthWebService) because this web service already supports access to non-logged-in users.

So have a new GET endpoint; ideally:

POST /iroh/iroh-auth/org-access-request-approval?code=ENCRYPTED_DATA&role=ROLE

Where ENCRYPTED_DATA should contain the following:

  • org-access-request-id
  • org-access-request-secret
  • action ; either accepted or rejected
  • approver-id ; user-id of the approver

and

  • role; optional and only if accepted, if none provided, default to user

The separation of the role query parameter is important in order to give a chance for the UI to change the associated role before user creation. But once the user is created with a specified role it should be impossible to change its role from an unauthenticated route.

If someone hit this endpoint, then you should:

  1. Decrypt the code and retrieve the data.
  2. Check the org-access-request id and secret matches a pending org access request. If not, return the corresponding error message.
  3. check that approver-id is a user-id of an admin of the org of the org-access-request.
  4. If everything is fine, perform a patch that could potentially create a new user.

In order to make this work, you should probably have some work to do in the email creation. Instead of letting the URL be built inside the template, you should instead provide a data structure with 3 links:

  • accept-as-user-url
  • accept-as-admin-url
  • reject-url

And pass that to the template that will be able to be used with:

<li><a href="{{accept-as-user-url}}">Grant access as User</a></li>
<li><a href="{{accept-as-admin-url}}">Grant access as Admin</a></li>
<li><a href="{{reject-url}}">Reject</a></li>
title Unauthenticated Account creation

User -> SXSO: login
SXSO -> Registration UI:
User -> Registration UI: create OrgRequestAccess (admin receive email)
Admin -> Mail: click on accept link
User -> Mail: receive
UI

From the backend, we need a path where a page will be displayed. We should create links in the email that will look like this:

<IROH_URL>/<path-to-approval-page>?code=ENCRYPTED_DATA&role=ROLE

That UI page should parse the URL and get both the code and the role. The role query parameter should be optional. By default, it should be user.

If anyone ends up on this page, there should be a POST to the org-access-request-approval endpoint mentioned.

Once the call is made, there is no mechanism to change the attributed role.

1 OPTIONAL UserIdentityService

Estimate: 1 rcd

ref
https://github.com/advthreat/iroh/issues/6274

Create a new service dedicated to UserIdentities.

(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]))

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.

(s/defschema UserIdentity
  (ist/open-schema-any-keys
   {:id s/Str
    :email
    :name
    :nickname
    :last-logged-in [,,,]
    (s/optional-key :hidden-orgs) #{,,,}}))

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.

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
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):

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"}

The clojure code for the route should roughly look like:

(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))))

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)

CANCELED List Matching Accounts
ref
https://github.com/advthreat/iroh/issues/6270
/iroh/iroh-auth-ui/matching-accounts

Accept: application/json
Content-Type: application/json
User-Agent: ob-http
Authorization: Bearer ${user-identity-jwt}

It should return a list of object with the following schema sorted by last logged in time by the user:

{: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}

Mainly should return the data structure used in the current selection account page using similar order and functionalities.

DONE List Pending Invites
ref
https://github.com/advthreat/iroh/issues/6269
GET  /iroh/iroh-auth-ui/pending-invites

Here is an example value:

[{: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"}]

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.

(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
     })))

When a user request access to an organization. We should create this object in DB.

POST  /iroh/iroh-auth-ui/org-access/:org-id ;; request access to a matching org
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}

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)
Renew Org Access Request

There is an existing renew-org-access-request method from the OrgAcessRequestService that should be exposed. Probably under the route /renew-org-access-request.

In order to help the UI the return schema of the matching orgs should also have a new optional boolean field can-renew?. So, only for :

  1. matching org
  2. with a pending org-access-request
  3. such that this org access request could be renewed (the logic in the code say after 7 days from the last updated-at time)

You should dynamically add this field and set it to true.

List Matching Orgs
ref
https://github.com/advthreat/iroh/issues/6273
GET  /iroh/iroh-auth-ui/matching-orgs

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):

{:org Org
 :org-nb-users s/Int
 :org-request-access-status OrgRequestAccessStatus}

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.

CANCELED 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
GET  /iroh/iroh-auth-ui/registration-view

Should return the same result as the union of the calls to matching-accounts, matching-orgs and pending-invites.

{:matching-accounts [,,,]
 :matching-orgs [,,,]
 :pending-invites [,,,]}
CANCELED OPTIONAL Hide Matching Org
  • State "CANCELED" from [2022-03-21 Mon 10:53]
ref
https://github.com/advthreat/iroh/issues/6276
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}

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.

DONE Redirects User

Create a new endpoint to redirect users using the value in the UserIdentity JWT. See https://github.com/advthreat/iroh/issues/6280

GET /iroh/iroh-auth-ui/redirect

So this should be a route which should looks like this:

(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)
                     {})))

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:

{"granted-role":"admin"
 "status":"accepted"}
{"status":"accepted"}
{"status":"rejected"}

During the call we should:

  1. Create a new user with:
{: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
 }
  1. Send an email to user confirming his access was granted.

TODO have an email template + text.

3 OPTIONAL Email Templating Service & Interface

We should create new endpoints for the UI team to be able to upload new Email templates. We currently have a mail-templates mechanism only for invites. We should have a similar system for all the email sent in our IROH-Auth system.

With the Org Access Request Service, we will now have 3 new different kinds of emails:

  • the email sent to the admins of an org when a user request access to some org
  • the email sent to the user when an admin accept the org request
  • the email sent to the user when an admin reject the org request

In order to achieve this; you should:

  1. create a new MailTemplateService which contains two parts:

    1. a simple layer on top of iroh-crud but for MailTemplate (look at the code for the

    correct schema) BUT any update on any template should be kept in some history so we could undo any change and we should keep track of the author of the changes.

    1. expose an helper function to send emails with the following API: (send-templated-email [template-id template-params])
  2. create a new endpoint in iroh-admin so user with the correct privileges could update the templates. Use the scope iroh-master/dev-ui for the routes.
  3. In the OrgAccessRequestService use this MailTemplateService to send the email to the users. This refacto should potentially be used for the Invite mechanism, but as it appear to work fine today we might decide not to touch it.

Dev details

Here are some dev details that could probably be copy/pasted as-is:

(s/defschema MailTemplate
  (st/optional-keys
   {:subject s/Str
    :subtitle s/Str
    :text s/Str ;; could contain HTML
    :mail-source s/Str}))

(defprotocol EMailTemplatingService
  ;; CRUD operations
  (create-email-template [this email-template-id new-email-template])
  (get-email-template [this email-template-id])
  (delete-email-template [this email-template-id])
  (update-email-template [this email-template-id email-template])
  (patch-email-template [this email-template-id email-template-patch])
  ;; History
  (search-email-template-history
    [this email-template-id filter-map text-match pagination-params]
    "given an email-template-id, return the list of matched template-id saved in history.")
  (revert-email-template [this email-template-id email-template-history-id]
    "given a template-id and and corresponding email-template-history-id
     perform an update to revert the change to this old template")
  (undo-email-template [this email-template-id]
    "revert-email-template on the previous one.
     Beware reverting/undoing is also saved in history.")

  ;; SendEmails
  (send-templated-email [this email-template-id template-params]
    "send an email using some template id and template-params
     are object that will be used by the mustache templating system to fill the template."))

(defservice email-templating-service
  EmailTemplatingService
  [EMailService]
  ,,,)

SECURITY NOTES: If the DB is empty, there should always be a "default template by template-id" in the code.

As we are giving some power out of the backend regarding some security concerns. We should only provide the mandatory fields to the template params and take care of removing the other ones. Typically, the org-access-request secret should be dissoc'd and the admin user-id should be provided unencrypted for the correct emails, etc…

Notes

Number of user with a matching domain email by domain

csvtool namedcol "user-email" users.csv |sed 's/[^@]*@//'|sort|uniq -c|sort -n
|tail
    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

The maximal number of user by email domain which are not Cisco 337 users. And >= 134 only for 10 on >15k domains.

Number of orgs with more than 100 users

Here is the list of the total number of orgs with >100 users in prod NAM:

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

So 22 orgs out of 29541 orgs.

Number of orgs by email domain name

Matching domain names:

  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

Number of matching orgs per email domain name

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:

      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

22 domains email will match 6 orgs

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
  • 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

On 20816 activated orgs:

  • 20365 (97.8%) have less than 10 admins.
  • 451 (2.2%) have more than 10 admins
  • 167 (0.8%) have more than 15 admins
  • 89 (0.4%) have more than 20 admins
     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