In this article
There are two kinds of suspension supported in the security pipeline:
- User suspension – Part of the authentication step of the pipeline, user suspension denies requests if the user associated with the authenticated identity is marked suspended.
- Entity suspension – Part of the data authorization step of the pipeline, entity suspension denies requests if a specified EntityId or any of its ancestors (the related references) is found to be suspended and the requested operation is not marked as allowed for suspension as per the suspension rules.
The IUser interface has three properties: Suspended, SuspensionReason and SuspensionDate. You update suspension state of the user using IUserService.SetSuspensionStatus method. If suspending, the method also expires all active sessions so that the suspension is immediately enforced.
Whether you login user using IAuthSessionProvider or IUserService, both methods support a
letSuspended parameter that determines whether a suspended user is allowed to login. Even Load methods of IUserService support similar parameter to deny access during reload for an existing session (to help in enforcing suspension immediately).
We recommend you to use ISecuritySettings.LetSuspendedAuthenticate as an argument to any such functions to control suspension behavior from single source.
The authentication step of the pipeline makes call to an overload of IUserService.Load, which takes a
letSuspended parameter. You can disable user suspension check either for all requests using the LetSuspendedAuthenticate setting or for specific requests by marking them with RequestFeature.AllowSuspendedUser (use
AllowSuspendedUserAttribute in ASP.NET or ServiceStack to indicate the same).
The SuspensionReason property is for both informational and action purposes and you should store a constant value rather than a message as the reason. For example, in ISCP, if a known investor client, who hasn’t yet registered as a user on this new cloud platform, tries to register, we create the user as suspended with reason value as ‘ReconciliationRequired’ and then require the client to verify that he’s really the same investor who registered with IRA Services through other means (paper or pdf form). One way to automatically verify is to send a link on the email specified during original registration, if the user clicks the link, we can confirm he’s the same investor, and suspension is removed automatically.
Certain kinds of businesses (E.G. financial ones) often require a capability to suspend other business entities like financial accounts while the associated users are still active. An important trait of such a suspension is that it’ll likely allow read-only or view access to the account, but the user can’t perform any transactions on it.
If the suspension is due to some routine policy requirement, wherein the user is required to furnish some documents like KYC related, operations related to update those documents or information on the account would also be permitted.
Entity suspension could be of multiple types each of which represents a state of account or reason of suspension. Closed, inactive, pending KYC, potentially breached, fraud suspected are a few of the popular examples.
Why is entity suspension part of data authorization?
As we’ve already seen that entity suspension is not mere locking the user out of complete access to the data, which can be handled with permit-based checks, rather, it’s limiting what the user can do on that data until the suspension is in place. If the user has view access to the data, we need to allow relevant get operations requesting suspended entityIds.
Additionally, the limitation may likely extend to related entities, such as in case of a financial accounts, it would be extended to related investments etc. which may mean that the user can view investments but cannot change them in any way until the parent account is suspended.
You may have different rules – depending on your business needs – to allow a different set of operations on different types of entities during the suspension of a particular type of entity. It’s evident that These rules expect a sort of entity hierarchy for enforcement, and the related references feature of data authorization is exactly loading that hierarchy.
Moreover, upon reflection we can conclude that suspension is essentially a type of data authorization check, as it is also determining whether or not the user is permitted to perform the specified operation on the specified data; the suspension is an access control mechanism that revokes user’s otherwise legitimate privileges on the related data as long as it’s in effect.
Entity suspension workflow
The EntityIdAuthorizer has IsSuspended method which executes the entity suspension logic. After permit checks are succeeded, this method is invoked with the same EntityId members collection that has just gone through permit authorization.
At a high-level, the logic works as follows:
- a call to ISuspensionService.GetSuspendedIds is made to obtain a collection of suspended EntityIds related to the EntityId members (and their related references).
- For each suspended EntityId received, a call is made to ISuspensionService.IsAllowed to determine if the requested operation is still allowed for it, based on exclusion rules.
- If there’s still a suspended EntityId left, the same is reported as a failure with error code as OpResult.Suspended, error message as EntitiesSuspended and errors collection containing one item per suspended EntityId. The item is populated as follows: ErrorCode is with Reason and ErrorDetail is with SuspendedEntityDetail error message (having EntityType, EntityId and Reason as values).
Following the principle of zero-trust security, ASPSecurityKit disallows every request related to the suspended EntityId by default. You can define exclusion rules to explicitly allow certain requests. These rules are defined and managed within your application code. The Premium source packages provide you ready-to-use data models and Manager for suspension rule management.
An exclusion rule has following inputs which help in determining whether the rule is applicable on the specified suspended EntityId and the requested operation:
EntityTypePattern– A Case-insensitive regular expression pattern that attempts to match the given suspended entity instance by its type.
SuspensionTypePattern– A Case-insensitive regular expression pattern that attempts to match the given suspended entity instance by the reason of suspension.
VerbPattern– A Case-insensitive regular expression pattern that attempts to match the requested operation by request’s verb.
OperationPattern– A Case-insensitive regular expression pattern that attempts to match the requested operation by its name.
PossessesAnyOfThePermissions– A vertical bar (|) delimited list of permissionCodes that attempts to match the current identity on the basis of whether it possesses any of the specified permissions. Keep it empty to ignore this condition during the match.
Some sample rules you can define (assuming a financial account as the suspended entity):
- A rule to allow all get* operations on the suspended account to have read-only access.
[json sample rule]
- A rule to allow UploadDocument operation to investors on the suspended account so the account holder can upload KYC docs.
[json sample rule]
- A rule to allow all kinds of operations on the suspended account if the user possesses an admin permission.
[json sample rule]