
(Updated October 2024 for the Q4 QRC release update)
The need to manage dormant users becomes increasingly important with the introduction of enforcement for named-user license entitlement. Over-provisioning of named-user licenses is problematic and discussed extensively in my blog.
Dormant users should no longer consume a license. They must be deleted or deactivated to free up limited licenses for others and ensure continued service.
However, there are issues facing any administrator:
Thanks to an update in the Q4 2024 Quarterly Release Update, the SCIM API can now be used to change users' status and deactivate them programmatically. The active user property was previously read-only, which meant manual intervention was the only option. Go to the Menu-Security-Users screen, select one or multiple users, and press the ‘activate’ or ‘deactivate’ button.
(The Q4 release is expected 15-17 November 2024)
Now the API is available this blog post describes the enhancements made to the sample API scripts that support the above requirements.
With this new API feature, it is now possible to:
I have updated my SAP Analytics Cloud SCIM API Samples with 4 new scripts and updated 5 ‘scenarios’ that provide a set of preconfigured configuration files (data files) that drive these samples. This means all the thinking has been done for you; you just need to make a few minor changes to suit your needs.
My sample script (Postman Collection) ‘1665-All_U-Uc-Uu-Oarrieei-Fj-Es-AdminToolKit’ remains unchanged as it already identified users who were active or deactivated. However, 4 new samples have been added, two of which can use a team created by the ‘1665 AdminToolKit’ to deactivate users. The 4 new samples added are:
The samples 1xxx, use version 1 of the SCIM API, and the samples 2xxx, use version 2.
The samples x402 update a user's active status one at a time, while samples x452 update a whole team of users. The data file that drives the x402 (user basis) looks like this:
file_userid,file_active
MATTHEW1,false
MATTHEW2,true
A data file that drives the x452 (team basis) looks like this:
file_team,file_active
Team1,false
Team2,true
Version 2 has a few advantages over version 1, as it supports the PATCH method, which saves having to read the user definition before saving back an update. A PATCH method request means we can make a request to update a single property and fully respect all existing properties without the need to read them first.
Sample script 2452 not only uses the PATCH but also a BULK request. The BULK is likely to be more stable for the client as there are fewer requests overall by a factor of 30. Thus, it's expected that script 2452 provides the greatest overall stability for whole team updates compared to script 1452 which has the same function but uses version 1. For example, a team of 30 users would require just 1 BULK request, compared to 60 requests (made by 30 pairs of GET/PUT requests) with version 1. Whilst the number of requests is considerably fewer, the overall throughput is expected to be comparable and not obviously greater. The performance is likely similar because the requests are still carried out in series and one by one inside SAP Analytics Cloud.
The remainder of this post provides the details of how this works.
Five sample scenarios are provided. A scenario is a straightforward concept comprising only sets of pre-configured sample data files, these files ‘drive’ the scripts. Each scenario addresses a single use case by combining different sample scripts (Postman collections) in a particular order.
It means most of the thinking has been done for you. All you need to do is tweak the data files for your needs, such as the team names, etc.
Each of the 5 scenarios basically follows the same pattern:
The 5 updated scenarios are:
Scenario | Description/use-case |
Deactivates users who were
Deletes users who were
| |
Same as D12, but users have no private folder content. | |
Same as D13, but users did not create public folder content. | |
Same as D14, but users are not managers. | |
Same as D15, but users have a named-user license. |
The basis of each scenario is to first deactivate dormant users, then leave them deactivated and, after more time has passed and a subsequent ‘run’ of the scripts, finally delete them. This gap between a user being deactivated and then deleted safeguards the deletion of users by ensuring all users are first deactivated before being deleted. Of course, you may not even wish to delete the users once they have been deactivated, but having the logic prebuilt might save some effort for those who do. Equally, you may wish to just delete the users without first deactivating them. In either case, you can easily make edits to the sample data files for your needs.
It’s not as easy as you first think, as there are many complications and use cases to support. For example, a dormant user would not be:
But it gets more complicated than that. For example:
They may have private content. When the user is deleted via the API, any content in their private folder is moved to the System Owner’s private folder. Even though it isn’t best practice to share private content directly with others, if this has been done, the system owner could start to own a lot of private content unexpectedly when the user is deleted.
A deactivated user doesn’t lose their content; it stays where it is, but any schedules they set up will be paused.
They may have created content now stored in public folders. By default, such content grants special access rights to the creator, known as owner rights. Whilst ownership can be transferred to others, this is only possible via the user interface and not via any API. It means when the user is deleted, the ownership is lost. Content without an owner isn’t necessarily a problem if others have been given rights; however, some artefacts, like models, require an owner to perform specific tasks on them. Overall, it could present unexpected and unnecessary surprises for others later. Ownership can be restored by recreating the user with the same user ID as the previously deleted user.
A deactivated user doesn’t lose their ownership, but there can be implications, especially for models, which could prevent import jobs from running.
The user could be a manager. Users who are managers can’t be deleted, and you may not wish to delete them anyway!
A deactivated manager means they can no longer grant request roles to others.
The user could be consuming a Business Intelligence concurrent session license. These users only consume a license at the time of login; they don’t consume a license when they have no active session. This means deleting a concurrent session-based user for license compliance may be unnecessary.
Equally, there’s no need to deactivate a concurrent-session-based user from a license perspective. (for more details about concurrent sessions, please visit my blog).
Some users just should never be either deactivated or deleted, and these might include:
Thankfully, all the hard work is done for you, and the above issues are either fully addressed or mitigated.
The solution is primarily captured in the sample script (Postman Collection) ‘1665-All_U-Uc-Uu-Oarrieei-Fj-Es-AdminToolKit’, which does nothing more than identify dormant users and adds them to a team. The team can then be further processed:
Depending upon your use case, other sample scripts may need to be run, for example, to remove certain users who are ‘special’ users (and members of specific teams) or you’d like to delete the users outright in an automated manner.
The sample script (Postman Collection) ‘1665-All_U-Uc-Uu-Oarrieei-Fj-Es-AdminToolKit’ reads a data file to determine a dormant user. This data file is easily editable and enables customisation to your needs. Once the dormant users are identified, they are added to a team, and any previously identified users who are no longer dormant are removed.
The data file can become quite complex, but do not fear! I’ve provided many samples for you to re-use; you only need to pick the most suitable example and make minor edits to things like the ‘number of days since last logon’.
As an example, here is the ‘Dormant users A’ data file, and you can see the data file, which is easily editable to change the values to your needs:
[
{
"file_team": "AdminToolKit_D12_Dormant_Users_A_deactivate",
"file_team_displayname": "Users to be deactivated. These users were created over 3 months ago, have not logged in within the last 30 days, are currently activated, and have 2 or fewer logins within the last 90 days. Updated TIMESTAMP",
"file_users_action": "replace",
"file_JSON_users_to_exclude": [{"value":"SAP_SUPPORTXXXXXXXXX"}],
"file_multiple_action_users_operator_is_AND": true,
"file_action_users_active": true,
"file_action_users_created_more_than_days_ago": true,
"file_users_created_more_than_days": 90,
"file_action_users_with_most_recent_login_at_least_days_ago": true,
"file_users_with_with_most_recent_login_at_least_days": 30,
"file_action_users_with_fewer_logins_than": true,
"file_users_with_fewer_logins_than": 2,
"file_action_users_with_fewer_logins_within_last_days": true,
"file_users_with_logins_within_last_days": 90
},
{
"file_team": "AdminToolKit_D12_Dormant_Users_A_delete",
"file_team_displayname": "Users to be deleted. These users were created over 6 months ago, have not logged in within the last 60 days, are currently deactivated, and have 2 or fewer logins within the last 120 days. Updated TIMESTAMP",
"file_users_action": "replace",
"file_JSON_users_to_exclude": [{"value":"SAP_SUPPORTXXXXXXXXX"}],
"file_multiple_action_users_operator_is_AND": true,
"file_action_users_not_active": true,
"file_action_users_created_more_than_days_ago": true,
"file_users_created_more_than_days": 182,
"file_action_users_with_most_recent_login_at_least_days_ago": true,
"file_users_with_with_most_recent_login_at_least_days": 60,
"file_action_users_with_fewer_logins_than": true,
"file_users_with_fewer_logins_than": 2,
"file_action_users_with_fewer_logins_within_last_days": true,
"file_users_with_logins_within_last_days": 120
}
]
My user guide provides the entire specification, but to understand what’s possible, let’s look at the most complex sample, ‘Dormant users E’ and what it means.
Deactivate users:
and delete users:
The image above shows when users were created and their historic login activity. This table explains the logic determining if the user is dormant or not:
User 1 | User-created over 3 months ago,without any logins since creation. | The user is deactivated. |
User 2 | User-created under 3 months,without any logins since creation. | No changes made |
User 3 | User-created over 3 months ago andhas 2 or fewer logins within the last 90 days.The user has no login within the last 30 days. | The user is deactivated. |
User 4 | User-created over 3 months ago, buthas 3 logins within the last 90 days anda login within the last 30 days. | No changes made |
User 5 | User-created over 3 months ago andhas 2 or fewer logins within the last 90 days, butthere was a login within the last 30 days. | No changes made |
User 6 | User-created over 3 months ago, buthas 4 logins within the last 90 days, althoughno login within the last 30 days. | No changes made |
User 7 | User-created over 6 months ago,without any logins since creation and is already deactivated. | The user is deleted |
User 8 | User-created under 6 months,without any logins since creation and is already deactivated. | No changes made |
User 9 | User-created over 6 months ago andhas 2 or fewer logins within the last 120 days.The user has no login within the last 60 days and is already deactivated. | The user is deleted |
User 10 | User-created over 6 months ago, buthas 3 logins within the last 120 days anda login within the last 60 days. | The user is deactivated. |
User 11 | User-created over 6 months ago andhas 2 or fewer logins within the last 120 days, butthere was a login within the last 60 days. | The user is deactivated. |
User 12 | User-created over 6 months ago,has 2 logins within the last 120 days, althoughno login within the last 60 days. The user is already deactivated. | No changes made |
This scenario partly resolves a problem when users have private content:
When the user is deleted via the API, any content in their private folder is moved to the System Owner’s private folder. Even though it isn’t best practice to share private content directly with others, if this has been done, the system owner could start to own a lot of private content unexpectedly when the user is deleted.
Users that have the following content types in their private folder are excluded:
This issue is only partly resolved because of many other types of content that aren’t identified. However, it’s likely that given these types of content are the most popular, it’s unlikely that a user with different content types would not have one of these identifiable types.
This scenario partly resolves a problem when users create content stored in public folders:
By default, any content created is granted special access rights to the creator, known as owner rights. Whilst ownership can be transferred to others, this is only possible via the user interface and not via any API. It means when the user is deleted, the ownership is lost. Content without an owner isn’t necessarily a problem if others have been given rights; however, some artefacts, like models, require an owner to perform specific tasks on them. Overall, it could present unexpected and unnecessary surprises for others later. Ownership can be restored by recreating the user with the same user ID as the previously deleted user.
This issue is only partly resolved because there is no check to see if the user owns the content. Ownership rights may have changed since creation. The check is if the user created the content, not if they are still the owner or have any particular rights to the content. However, any users that created public folder content will be excluded and thus help reduce future surprises with a lack of access to any content. It is more unlikely that such users would be owners of other content, which could be problematic if deleted.
Users who are managers can’t be deleted. Any attempts to delete the manager will fail, which could be unexpected or require some exception to manage. Excluding managers resolves this problem and would mean that the sample script that deletes users should not fail for this reason. Managers are thus excluded from being identified as dormant.
Deactivated users don’t consume a license and deleting them could be unnecessary. If your organisation grants permission to keep users registered but deactivated, consider adjusting the sample data files so that users are not deleted.
Users with a Business Intelligence concurrent-session-based license only consume a licence while having an active session in SAP Analytics Cloud. It means you can have as many registered users as you please that are configured this way and remain compliant; there is no limit to the number of Business Intelligence concurrent-session-based users in SAP Analytics Cloud. For more details about managing licenses, please visit my blog.
In this scenario, users with the ‘concurrent-session’ setting are excluded from being identified as dormant; however, there is a limitation. The ‘concurrent-session’ setting is only a ‘request’ for a concurrent-session license, and it does not mean the user will consume a concurrent-session license. The user could consume a named-user license because they were assigned a Planning Role (or an Analytics Hub Role). For more details on this, please visit the blog just mentioned. It means users could incorrectly be removed from the ‘dormant list’ of users because their setting is ‘requesting’ a concurrent-session license when they are consuming a named-user license. In turn, this means these users may not get deleted when you might want them to.
You can exclude individually named users using the settings ‘file_JSON_users_to_exclude’ even if they are dormant; they will not be added to the team. Such users could be SAP Support users or System Owner. Add multiple by separating them with a comma (,), for example [{"value":"SAP_SUPPORT12345"},{"value":"MATTHEW"}]
Once you have run the sample script (Postman Collection) ‘1665-All_U-Uc-Uu-Oarrieei-Fj-Es-AdminToolKit’, you may need to remove some users from being considered dormant because they are users of a given team.
You’ll need to run another sample script, ‘1653-T-Uc-Utr-Oarrkie-Fcj-Es-Teams on Teams’ with another data file. It could be a more favourable option to exclude users from being deleted than listing individual users earlier by file_JSON_users_to_exclude. It will remove users in teams called ‘TeamA’ and ‘TeamB’ from your team of so far identified dormant users.
The data file will need to contain something like:
[{
"file_source_team": "TeamA",
"file_target_team": "AdminToolKit_D16_Dormant_Users_E_deactivate",
"file_users_action": "remove",
"file_roles_action": "keep"
},
{
"file_source_team": "TeamB",
"file_target_team": "AdminToolKit_D16_Dormant_Users_E_deactivate",
"file_users_action": "remove",
"file_roles_action": "keep"
},
{
"file_source_team": "TeamA",
"file_target_team": "AdminToolKit_D16_Dormant_Users_E_delete",
"file_users_action": "remove",
"file_roles_action": "keep"
},
{
"file_source_team": "TeamB",
"file_target_team": "AdminToolKit_D16_Dormant_Users_E_delete",
"file_users_action": "remove",
"file_roles_action": "keep"
}]
Adjust the team names accordingly and add or remove other teams for your needs.
The teams TeamA and TeamB are not updated; they are read-only.
The data files needed to deactivate and delete users as well as the teams used to aid this process, are preconfigured for you. These preconfigured data files form a ‘scenario’.
Download the user guide found in my blog post and follow the step-by-step instructions.
Suppose you’ve already made use of my SCIM API samples. In that case, you will probably need to create a new OAuth client, as this updated 1665-AdminToolKit uses the ‘Activities’ and ‘Stories’ access to obtain login activity and read the repository content to determine personal and public folder usage. Without access, it can’t function.
Comment here if you found this blog and sample helpful, especially if it saved you time and effort.
The 1665-AdminToolKit, which inspects login events in the activities log, enables other use cases beyond dormant users. For example, the preconfigured data file provided describes their use case:
x665 sample - 20 - AdminToolKit_Users_Created_Over_A_Year_Ago.json
x665 sample - 21 - AdminToolKit_Users_Created_Recently.json
x665 sample - 22 - AdminToolKit_Users_With_A_Recent_Login.json
x665 sample - 23 - AdminToolKit_Users_Without_A_Recent_Login.json
x665 sample - 24 - AdminToolKit_Users_With_Few_Logins_Since_Oldest_Log_Entry.json
x665 sample - 25 - AdminToolKit_Users_With_Few_Logins_This_Last_Month.json
x665 sample - 26 - AdminToolKit_Users_Without_A_Recent_Login_And_Fewer_Than_3_Logins_Last_3_Months.json
x665 sample - 27 - AdminToolKit_Users_With_100_Or_More_Logins_Since_Oldest_Log_Entry.json
x665 sample - 28 - AdminToolKit_Users_With_100_Or_More_Logins_Within_Last_3_Months.json
x665 sample - 29 - AdminToolKit_Users_With_Private_Folder_Content.json
x665 sample - 30 - AdminToolKit_Users_Without_Private_Folder_Content.json
x665 sample - 31 - AdminToolKit_Users_That_Created_Public_Folder_Content.json
x665 sample - 32 - AdminToolKit_Users_That_Did_Not_Create_Public_Folder_Content.json
It means you can identify very productive users quickly and may go some way to help manage your user base more efficiently.
There is no need to download the Postman app, connect to any Postman website or web service or register with Postman. The open-source option doesn’t require any internet connectivity to operate.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
18 | |
16 | |
11 | |
7 | |
7 | |
7 | |
6 | |
5 | |
5 | |
5 |