-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added a new example to log the user login activities to an asset. This can help tenant admins to get insights on the user logins
- Loading branch information
Showing
8 changed files
with
84 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
"user_id";"STRING";"1";"50" | ||
"user_login";"BOOLEAN";"1";"" |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
# User Activity Tracker | ||
|
||
This flow monitors and tracks user login activities by collecting last login timestamps for all users. The flow automatically runs daily and stores the login data in a dedicated asset for historical analysis and tracking of user engagement patterns. Additional analysis for the login behaviour are then possible based on this data source. | ||
|
||
![image](./doc/UserActivityTracker.png) | ||
|
||
## Prerequisites | ||
- Access to Visual Flow Creator | ||
- Permissions to create assets and aspects in Asset Manager | ||
|
||
## Setup & Configuration | ||
|
||
1. Create the required asset structure in Asset Manager: | ||
- Create a new **Aspect** named "UserInsights" (or any custom name) with exaclty these parameters: | ||
| Variable Name | Data Type | | ||
|--------------|-----------| | ||
| user_login | BOOLEAN | | ||
| user_id | STRING | | ||
- Create an **Asset Type** that includes this aspect | ||
- Create an **Asset** from this asset type | ||
- Note down the **Asset ID** for configuration of the flow later | ||
(you can find this ID for example in the URL of your browser) | ||
|
||
2. Import the flow in Visual Flow Creator using the [Flow Tempalte](template.json) | ||
|
||
3. Configure the flow by: | ||
- Locate the "CONFIG" function node | ||
- Update the `assetId` variable with your created asset's ID | ||
- Update the `aspectName` variable if you used a custom aspect name | ||
|
||
4. Save the flow | ||
|
||
|
||
### Additional Setup Information | ||
|
||
Below are the visual references for the required setup in Asset Manager. | ||
1. Create the Aspect "UserInsights": | ||
![Aspect Creation](./doc/AM-Setup_Aspect.png) | ||
*Creating the `UserInsights` Aspect with required variables* | ||
|
||
2. Create the Asset Type: | ||
![Asset Type Creation](./doc/AM-Setup_AssetType.png) | ||
*Creating an `UserActivity` Asset Type that includes the `UserInsights` Aspect* | ||
|
||
3. Create the Asset: | ||
![Asset Creation](./doc/AM-Setup_Asset.png) | ||
*Final asset based on the `UserActivity` Asset Type with `UserInsights` Aspect which will received the data from the flow* | ||
|
||
:cloud: :heavy_check_mark: You're ready to track user login behavior! | ||
|
||
## How does this flow work | ||
|
||
1. The flow triggers automatically every 24 hours at 02:00 UTC | ||
2. It fetches the data from the User Management API to retrieve all user information | ||
3. For each user, it processes: | ||
- Last login timestamp | ||
- Identifies users who haven't logged in for over 365 days | ||
- Identifies users who have never logged in | ||
4. The processed login data is written to the configured asset with timestamps showing the login time of the user | ||
5. Inactive users (>365 days) and never-logged-in users are reported to the VFC console to enable further follow-up | ||
|
||
> Note: | ||
> The flow uses pagination to handle large user lists and includes error handling for robust operation. This might lead to an increased use of compute hours and flow duration. | ||
## Result | ||
|
||
The flow generates: | ||
- Historical login data for each user stored in the asset | ||
- Console notifications for: | ||
- Users who haven't logged in for over 365 days | ||
- Users who have never logged in | ||
- Time-series data showing login patterns over time | ||
|
||
![User Tracker Results in Monitor](./doc/UserActivityTracker_results.png) | ||
|
||
|
||
## See also | ||
- [Visual Flow Creator Documentation](https://documentation.mindsphere.io/MindSphere/apps/visual-flow-creator/introduction.html) | ||
- [Identity Management API Documentation](https://documentation.mindsphere.io/MindSphere/apis/core-identitymanagement/api-identitymanagement-overview.html) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
[{"id":"3a1c72de.97e6fe","type":"tab","allowCycles":false,"label":"User Activity Tracker","disabled":false,"info":"author: christoph.doehl@siemens.com\n\n\ndescription:\n"},{"id":"95274343.d3a4b","type":"group","z":"3a1c72de.97e6fe","name":"User Activity Tracker ","style":{"label":true},"nodes":["4b9358dd.f20278","f9e40926.54cb78","5ecf13d3.8a4b7c","8eb647fe.e3f408","d64b471c.5ff018"],"x":75,"y":21,"w":1015,"h":524},{"id":"d64b471c.5ff018","type":"group","z":"3a1c72de.97e6fe","g":"95274343.d3a4b","name":"do not change me","style":{"label":true},"nodes":["c58799e7.633558","cd7735e2.5bff18","61f08245.d75eac","9289c15b.da14c","eb3e427b.6496"],"x":635,"y":320,"w":430,"h":200},{"id":"4b9358dd.f20278","type":"comment","z":"3a1c72de.97e6fe","g":"95274343.d3a4b","name":"User Activity Tracker","info":"+ runs every 24h and gets when users logged in last time\n+ get current user list and write when user logged in last time\n\nAdditions:\n+ logins older than 365 days are reported to the console\n+ users who never logged in are reported to console\n\nLimits:\n* does only work for the last 365 days of login\n","sticky":1,"x":340,"y":160,"wires":[],"_type":"node"},{"id":"8eb647fe.e3f408","type":"comment","z":"3a1c72de.97e6fe","g":"95274343.d3a4b","name":"adjust and config your flow here ⬆️⬆️⬆️","info":"DO ONLY setup here, no other changes are needed","sticky":1,"x":360,"y":420,"wires":[]},{"id":"c58799e7.633558","type":"debug","z":"3a1c72de.97e6fe","g":"d64b471c.5ff018","name":"Debug","active":true,"xaxis":"","complete":"true","x":970,"y":440,"wires":[]},{"id":"f9e40926.54cb78","type":"function","z":"3a1c72de.97e6fe","g":"95274343.d3a4b","name":"CONFIG","func":"// ******************** CONFIGURATION ********************\n//\n// EDITABLE VALUES:\nvar assetId = \"fe290291bf044151a5d5d0abebbf211f\"; // Enter your asset ID\nvar aspectName = \"UserInsights\"; // Enter your aspect name\n//\n//\n// DO NOT MODIFY BELOW THIS LINE\n// **************************************************************\nmsg.userTracking_config = \n\n{\n \"assetId\": assetId,\n \"aspectName\": aspectName\n}\n\n// First request\nmsg.url = '/api/identitymanagement/v3/Users?count=250&page=1';\n\nreturn msg;","outputs":1,"language":"javascript","noerr":0,"x":440,"y":360,"wires":[["61f08245.d75eac"]],"_type":"node"},{"id":"cd7735e2.5bff18","type":"function","z":"3a1c72de.97e6fe","g":"d64b471c.5ff018","name":"Check and Process","func":"// Store or append users\ncontext.users = context.users || [];\ncontext.users = context.users.concat(msg.payload.resources);\n\nconst currentPage = parseInt(msg.url.match(/page=(\\d+)/)[1]);\nconst neededPages = Math.ceil(msg.payload.totalResults / msg.payload.itemsPerPage)\n\n// Check if we need more requests\nif (currentPage <= neededPages) {\n // Need next page\n console.log(\"current page processed:\" + currentPage + \"/\" + neededPages)\n msg.url = `/api/identitymanagement/v3/Users?count=250&page=${currentPage + 1}`;\n console.log(\"requesting now: \" + msg.url);\n return [msg, null];\n} else {\n // Process all users\n let results = [];\n const oneYearAgo = new Date();\n oneYearAgo.setDate(oneYearAgo.getDate() - 365); // Get date 365 days ago\n\n for (const user of context.users) { \n if (user.hasOwnProperty('previousLogonTime')) {\n const lastLogon = new Date(user.lastLogonTime);\n \n if (lastLogon > oneYearAgo) {\n results.push({\n user_id: user.userName,\n user_login: \"TRUE\",\n _time: lastLogon.toISOString()\n });\n } else {\n console.log(\"User login is older than 365 days: \" + user.userName + \"(\" + lastLogon.toISOString() + \")\");\n }\n } else {\n console.log(\"user never logged in: \" + user.userName); \n }\n }\n \n // Clear context\n context.users = [];\n \n // Prepare output message\n msg.payload = results;\n msg.topic = msg.userTracking_config.assetId + \"/\" + msg.userTracking_config.aspectName;\n \n return [null, msg];\n}\n\n// if (user.hasOwnProperty('previousLogonTime')){\n// //user has logged in\n// data = [{\n// 'user_id': email,\n// 'user_login': \"TRUE\"}\n// ]\n \n// //var date = new Date(user.previousLogonTime);\n// //console.log(\"previousLogonTime = \" + Date(user.previousLogonTime)); \n \n// msg.payload = data[aspect]\n// msg._time = new Date(user.lastLogonTime).toISOString() //.toISOString() //new Date();\n \n// node.send(msg)\n \n// }\n// else{\n// //user never logged in\n// console.log(\"user never logged in: \" + email); \n// }\n","outputs":2,"language":"javascript","noerr":0,"x":750,"y":460,"wires":[["61f08245.d75eac"],["c58799e7.633558","9289c15b.da14c"]],"_type":"node"},{"id":"61f08245.d75eac","type":"http request","z":"3a1c72de.97e6fe","g":"d64b471c.5ff018","name":"Fetch Users","method":"GET","ret":"obj","url":"","timeout":"","mindspherePath":"","useMindsphereAuth":true,"isAdmin":true,"secretHeaders":"","x":730,"y":360,"wires":[["cd7735e2.5bff18","eb3e427b.6496"]]},{"id":"5ecf13d3.8a4b7c","type":"inject","z":"3a1c72de.97e6fe","g":"95274343.d3a4b","name":"run every 24h","topic":"","payload":"","payloadType":"str","repeat":"","repeatEnd":"0","endTime":"0","crontab":"00 02 * * *","offset":"NaN","once":false,"properties":"","timezone":"utc","showNextExecution":false,"powerMode":true,"x":200,"y":360,"wires":[["f9e40926.54cb78"]],"_type":"node"},{"id":"9289c15b.da14c","type":"write timeseries","z":"3a1c72de.97e6fe","g":"d64b471c.5ff018","name":"","topic":"","topicData":"","topicLabel":"","assetName":"","aspectName":"","useMerging":false,"x":980,"y":480,"wires":[]},{"id":"eb3e427b.6496","type":"debug","z":"3a1c72de.97e6fe","g":"d64b471c.5ff018","name":"","active":true,"console":"false","xaxis":"_time","complete":"false","x":950,"y":360,"wires":[]}] |