- 24 May 2023
-
DarkLight
-
PDF
User Account References
- Updated on 24 May 2023
-
DarkLight
-
PDF
User accounts are uniquely identified in IAP by a database ID, or a username and provenance pair where the provenance is the name of the AAA adapter from which the user account originated. This guide lays out best practices for user account representation and discusses:
- Reference accounts in database documents.
- Return data in APIs for documents with referenced accounts.
- Query documents with referenced accounts.
- Sort documents with referenced accounts.
Best Practices
Account References in Database Documents
References to user accounts should be made via database ID. In MongoDB, accounts are keyed with ObjectId
, and the reference should use that type as well. This allows the application to make use of $lookup
in the MongoDB aggregation pipeline for purposes of sorting and filtering by account fields, but also for more efficient querying when account data should be retrieved.
Accounts in the UI
Users should not choose user accounts from a list of account IDs. User lists and references should be displayed in the UI using the username and provenance fields. Username only is no longer sufficient, as the user may need to distinguish between similarly named accounts in different systems.
Account References in APIs
Based on how existing APIs and documents are structured, user account IDs and username/provenance pairs should be accepted and returned by APIs. In the cases where account IDs are exposed, they should appear as strings in JSON, and the APIs should then assume the burden of validating IDs, converting them to ObjectId
where appropriate, and testing for equality using the appropriate methods.
Query, Filter and Sort Account Documents
Example Account Document
With the MongoDB aggregation pipeline as a framework, let's presume the following account document exists.
{
"_id" : ObjectId("5aebd2fae2c5b5614927362b"),
"provenance" : "Local AAA",
"username" : "admin@pronghorn",
"firstname" : "admin",
"memberOf" : [ ... ],
"assignedRoles" : [ ... ],
"lastLogin" : ISODate("2018-05-30T16:29:39.944Z"),
...,
}
Query Documents with Referenced Accounts
Denormalization of user account data, e.g., keeping a copy of the username alongside the account ID, creates a maintenance issue in cases where the account data has changed, but your copy has not. This is not a good practice and is discouraged. Instead, load the account data at query time in order to include it in the API response.
Example Workflow
{
"_id": "b6517ac9-a8fc-4621-902b-174458005c90",
"name": "Example Workflow",
"tasks": { ... },
"transitions": { ... },
"created": "5/18/2018, 9:32:50 AM",
"created_by" : {
"id": ObjectId("5aebd2fae2c5b5614927362b")
},
"last_updated" : "5/18/2018, 9:33:31 AM",
"last_updated_by" : {
"id": ObjectId("5aebd2fae2c5b5614927362b")
},
"groups" : [
ObjectId("5aebd2ffe2c5b5614927362d")
]
}
Reference Account in Document
In this example, the document references the user that created it and includes the user account's human-readable components in the API response.
[
{
"id": "b6517ac9-a8fc-4621-902b-174458005c90",
"name": "Example Workflow",
"created": "5/18/2018, 9:32:50 AM",
"created_by": { "id": "5aebd2fae2c5b5614927362b", "username": "admin@pronghorn", "provenance": "Local AAA" },
"last_updated": "5/18/2018, 9:33:31 AM",
"last_updated_by": { "id": "5aebd2fae2c5b5614927362b", "username": "admin@pronghorn", "provenance": "Local AAA" }
}
]
Query Document
This query produces the desired data set in a single request to MongoDB.
const workflowListWithInlineAccountsPipeline = [
{
$lookup: {
from: 'accounts',
localField: 'created_by.id',
foreignField: '_id',
as: 'created_by_accounts'
}
},
{
$lookup: {
from: 'accounts',
localField: 'last_updated_by.id',
foreignField: '_id',
as: 'last_updated_by_accounts'
}
},
{
$project: {
name: 1,
created: 1,
created_by_account: { $arrayElemAt: ['$created_by_accounts', 0] },
last_updated: 1,
last_updated_by_account: { $arrayElemAt: ['$created_by_accounts', 0] }
}
}
];
const workflowList = await workflowsCollection.aggregate(workflowListWithInlineAccountsPipeline).toArray();
Filter and Sort Documents by Referenced Account Fields
In addition to inline referenced document data, you can perform sorting and filtering.
const filteredAndSortedByCreatorPipeline = [
{ $match: { name: /^Exa/ } },
...workflowListWithInlineAccountsPipeline,
{ $sort: { 'created_by_account.username': 1 } },
];
const workflowList = await workflowsCollection.aggregate(filteredAndSortedByCreatorPipeline).toArray();