strapi-plugin-keycloak-realm-users 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +485 -0
- package/__tests__/constants.test.mjs +207 -0
- package/__tests__/mocks/strapi.mjs +182 -0
- package/__tests__/services/audit-log.test.mjs +283 -0
- package/__tests__/services/keycloak-client.test.mjs +651 -0
- package/__tests__/services/permission.test.mjs +374 -0
- package/__tests__/services/realm.test.mjs +415 -0
- package/__tests__/services/user.test.mjs +487 -0
- package/__tests__/utils/errors.test.mjs +109 -0
- package/admin/src/components/Initializer.jsx +14 -0
- package/admin/src/components/RealmBadge.jsx +17 -0
- package/admin/src/constants.js +14 -0
- package/admin/src/hooks/useAuditLogs.js +142 -0
- package/admin/src/hooks/useKeycloakRoles.js +182 -0
- package/admin/src/hooks/useKeycloakUsers.js +477 -0
- package/admin/src/hooks/useRealmAdmins.js +249 -0
- package/admin/src/hooks/useRealms.js +269 -0
- package/admin/src/index.js +46 -0
- package/admin/src/pages/App.jsx +21 -0
- package/admin/src/pages/AuditPage/index.jsx +213 -0
- package/admin/src/pages/RealmsPage/RealmEditPage.jsx +791 -0
- package/admin/src/pages/RealmsPage/RealmListPage.jsx +231 -0
- package/admin/src/pages/RealmsPage/index.jsx +7 -0
- package/admin/src/pages/UsersPage/UserEditPage.jsx +313 -0
- package/admin/src/pages/UsersPage/UserListPage.jsx +437 -0
- package/admin/src/pages/UsersPage/index.jsx +7 -0
- package/admin/src/pluginId.js +2 -0
- package/admin/src/translations/en.json +77 -0
- package/admin/src/translations/fr.json +77 -0
- package/babel.config.cjs +17 -0
- package/coverage/clover.xml +422 -0
- package/coverage/coverage-final.json +8 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +146 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov-report/src/bootstrap.js.html +346 -0
- package/coverage/lcov-report/src/config/index.html +116 -0
- package/coverage/lcov-report/src/config/index.js.html +106 -0
- package/coverage/lcov-report/src/constants.js.html +850 -0
- package/coverage/lcov-report/src/content-types/audit-log/index.html +116 -0
- package/coverage/lcov-report/src/content-types/audit-log/index.js.html +94 -0
- package/coverage/lcov-report/src/content-types/index.html +116 -0
- package/coverage/lcov-report/src/content-types/index.js.html +112 -0
- package/coverage/lcov-report/src/content-types/realm-admin/index.html +116 -0
- package/coverage/lcov-report/src/content-types/realm-admin/index.js.html +94 -0
- package/coverage/lcov-report/src/content-types/realm-config/index.html +116 -0
- package/coverage/lcov-report/src/content-types/realm-config/index.js.html +94 -0
- package/coverage/lcov-report/src/controllers/audit.js.html +517 -0
- package/coverage/lcov-report/src/controllers/index.html +161 -0
- package/coverage/lcov-report/src/controllers/index.js.html +112 -0
- package/coverage/lcov-report/src/controllers/realm.js.html +1057 -0
- package/coverage/lcov-report/src/controllers/user.js.html +1324 -0
- package/coverage/lcov-report/src/destroy.js.html +100 -0
- package/coverage/lcov-report/src/index.html +116 -0
- package/coverage/lcov-report/src/policies/can-access-realm.js.html +163 -0
- package/coverage/lcov-report/src/policies/index.html +146 -0
- package/coverage/lcov-report/src/policies/index.js.html +106 -0
- package/coverage/lcov-report/src/policies/is-authenticated.js.html +100 -0
- package/coverage/lcov-report/src/register.js.html +106 -0
- package/coverage/lcov-report/src/routes/admin.js.html +844 -0
- package/coverage/lcov-report/src/routes/index.html +131 -0
- package/coverage/lcov-report/src/routes/index.js.html +109 -0
- package/coverage/lcov-report/src/services/audit-log.js.html +673 -0
- package/coverage/lcov-report/src/services/index.html +176 -0
- package/coverage/lcov-report/src/services/index.js.html +124 -0
- package/coverage/lcov-report/src/services/keycloak-client.js.html +2359 -0
- package/coverage/lcov-report/src/services/permission.js.html +955 -0
- package/coverage/lcov-report/src/services/realm.js.html +1207 -0
- package/coverage/lcov-report/src/services/user.js.html +1924 -0
- package/coverage/lcov-report/src/utils/errors.js.html +274 -0
- package/coverage/lcov-report/src/utils/index.html +116 -0
- package/coverage/lcov-report/src/utils/index.js.html +103 -0
- package/coverage/lcov.info +804 -0
- package/dist/_chunks/App-BaKrvCeS.mjs +1975 -0
- package/dist/_chunks/App-DO6syS77.js +1975 -0
- package/dist/_chunks/en-Li-XBDe9.mjs +72 -0
- package/dist/_chunks/en-aCyfgNfr.js +72 -0
- package/dist/_chunks/fr-Cj33Q8jI.js +72 -0
- package/dist/_chunks/fr-vLrXph-Z.mjs +72 -0
- package/dist/_chunks/index-DwDO4-0C.js +69 -0
- package/dist/_chunks/index-jTVd7LdQ.mjs +70 -0
- package/dist/admin/index.js +3 -0
- package/dist/admin/index.mjs +4 -0
- package/dist/server/index.js +3003 -0
- package/dist/server/index.mjs +3004 -0
- package/jest.config.cjs +50 -0
- package/package.json +55 -0
- package/server/src/bootstrap.js +87 -0
- package/server/src/config/index.js +7 -0
- package/server/src/constants.js +255 -0
- package/server/src/content-types/audit-log/index.js +3 -0
- package/server/src/content-types/audit-log/schema.json +61 -0
- package/server/src/content-types/index.js +9 -0
- package/server/src/content-types/realm-admin/index.js +3 -0
- package/server/src/content-types/realm-admin/schema.json +45 -0
- package/server/src/content-types/realm-config/index.js +3 -0
- package/server/src/content-types/realm-config/schema.json +56 -0
- package/server/src/controllers/audit.js +144 -0
- package/server/src/controllers/index.js +9 -0
- package/server/src/controllers/realm.js +324 -0
- package/server/src/controllers/user.js +413 -0
- package/server/src/destroy.js +5 -0
- package/server/src/index.js +21 -0
- package/server/src/policies/can-access-realm.js +26 -0
- package/server/src/policies/index.js +7 -0
- package/server/src/policies/is-authenticated.js +5 -0
- package/server/src/register.js +7 -0
- package/server/src/routes/admin.js +253 -0
- package/server/src/routes/index.js +8 -0
- package/server/src/services/audit-log.js +196 -0
- package/server/src/services/index.js +13 -0
- package/server/src/services/keycloak-client.js +758 -0
- package/server/src/services/permission.js +290 -0
- package/server/src/services/realm.js +374 -0
- package/server/src/services/user.js +613 -0
- package/server/src/utils/errors.js +63 -0
- package/server/src/utils/index.js +6 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
export default [
|
|
2
|
+
// ==================== REALM MANAGEMENT ====================
|
|
3
|
+
|
|
4
|
+
// Get all realms (filtered by user access)
|
|
5
|
+
{
|
|
6
|
+
method: 'GET',
|
|
7
|
+
path: '/realms',
|
|
8
|
+
handler: 'realm.find',
|
|
9
|
+
config: { policies: [] },
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
// Test connection with raw config (before saving)
|
|
13
|
+
{
|
|
14
|
+
method: 'POST',
|
|
15
|
+
path: '/realms/test-connection',
|
|
16
|
+
handler: 'realm.testConnectionRaw',
|
|
17
|
+
config: { policies: [] },
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
// Get a single realm
|
|
21
|
+
{
|
|
22
|
+
method: 'GET',
|
|
23
|
+
path: '/realms/:id',
|
|
24
|
+
handler: 'realm.findOne',
|
|
25
|
+
config: { policies: [] },
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
// Create a new realm
|
|
29
|
+
{
|
|
30
|
+
method: 'POST',
|
|
31
|
+
path: '/realms',
|
|
32
|
+
handler: 'realm.create',
|
|
33
|
+
config: { policies: [] },
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
// Update a realm
|
|
37
|
+
{
|
|
38
|
+
method: 'PUT',
|
|
39
|
+
path: '/realms/:id',
|
|
40
|
+
handler: 'realm.update',
|
|
41
|
+
config: { policies: [] },
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
// Delete a realm
|
|
45
|
+
{
|
|
46
|
+
method: 'DELETE',
|
|
47
|
+
path: '/realms/:id',
|
|
48
|
+
handler: 'realm.delete',
|
|
49
|
+
config: { policies: [] },
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
// Test realm connection
|
|
53
|
+
{
|
|
54
|
+
method: 'POST',
|
|
55
|
+
path: '/realms/:id/test',
|
|
56
|
+
handler: 'realm.testConnection',
|
|
57
|
+
config: { policies: [] },
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
// ==================== REALM ADMIN ASSIGNMENTS ====================
|
|
61
|
+
|
|
62
|
+
// Get admins for a realm
|
|
63
|
+
{
|
|
64
|
+
method: 'GET',
|
|
65
|
+
path: '/realms/:id/admins',
|
|
66
|
+
handler: 'realm.getAdmins',
|
|
67
|
+
config: { policies: [] },
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
// Add admin to a realm
|
|
71
|
+
{
|
|
72
|
+
method: 'POST',
|
|
73
|
+
path: '/realms/:id/admins',
|
|
74
|
+
handler: 'realm.addAdmin',
|
|
75
|
+
config: { policies: [] },
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
// Update admin permissions
|
|
79
|
+
{
|
|
80
|
+
method: 'PUT',
|
|
81
|
+
path: '/realms/:id/admins/:adminId',
|
|
82
|
+
handler: 'realm.updateAdmin',
|
|
83
|
+
config: { policies: [] },
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
// Remove admin from realm
|
|
87
|
+
{
|
|
88
|
+
method: 'DELETE',
|
|
89
|
+
path: '/realms/:id/admins/:adminId',
|
|
90
|
+
handler: 'realm.removeAdmin',
|
|
91
|
+
config: { policies: [] },
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
// ==================== KEYCLOAK USERS ====================
|
|
95
|
+
|
|
96
|
+
// List users in a realm
|
|
97
|
+
{
|
|
98
|
+
method: 'GET',
|
|
99
|
+
path: '/realms/:realmId/users',
|
|
100
|
+
handler: 'user.find',
|
|
101
|
+
config: { policies: [] },
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
// Export users
|
|
105
|
+
{
|
|
106
|
+
method: 'GET',
|
|
107
|
+
path: '/realms/:realmId/users/export',
|
|
108
|
+
handler: 'user.exportUsers',
|
|
109
|
+
config: { policies: [] },
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
// Bulk import users
|
|
113
|
+
{
|
|
114
|
+
method: 'POST',
|
|
115
|
+
path: '/realms/:realmId/users/import',
|
|
116
|
+
handler: 'user.bulkImport',
|
|
117
|
+
config: { policies: [] },
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
// Get a single user
|
|
121
|
+
{
|
|
122
|
+
method: 'GET',
|
|
123
|
+
path: '/realms/:realmId/users/:id',
|
|
124
|
+
handler: 'user.findOne',
|
|
125
|
+
config: { policies: [] },
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
// Create a user
|
|
129
|
+
{
|
|
130
|
+
method: 'POST',
|
|
131
|
+
path: '/realms/:realmId/users',
|
|
132
|
+
handler: 'user.create',
|
|
133
|
+
config: { policies: [] },
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
// Update a user
|
|
137
|
+
{
|
|
138
|
+
method: 'PUT',
|
|
139
|
+
path: '/realms/:realmId/users/:id',
|
|
140
|
+
handler: 'user.update',
|
|
141
|
+
config: { policies: [] },
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
// Delete a user
|
|
145
|
+
{
|
|
146
|
+
method: 'DELETE',
|
|
147
|
+
path: '/realms/:realmId/users/:id',
|
|
148
|
+
handler: 'user.delete',
|
|
149
|
+
config: { policies: [] },
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
// ==================== USER ACTIONS ====================
|
|
153
|
+
|
|
154
|
+
// Reset password
|
|
155
|
+
{
|
|
156
|
+
method: 'POST',
|
|
157
|
+
path: '/realms/:realmId/users/:id/reset-password',
|
|
158
|
+
handler: 'user.resetPassword',
|
|
159
|
+
config: { policies: [] },
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
// Enable user
|
|
163
|
+
{
|
|
164
|
+
method: 'POST',
|
|
165
|
+
path: '/realms/:realmId/users/:id/enable',
|
|
166
|
+
handler: 'user.enable',
|
|
167
|
+
config: { policies: [] },
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
// Disable user
|
|
171
|
+
{
|
|
172
|
+
method: 'POST',
|
|
173
|
+
path: '/realms/:realmId/users/:id/disable',
|
|
174
|
+
handler: 'user.disable',
|
|
175
|
+
config: { policies: [] },
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
// Send verification email
|
|
179
|
+
{
|
|
180
|
+
method: 'POST',
|
|
181
|
+
path: '/realms/:realmId/users/:id/send-verify-email',
|
|
182
|
+
handler: 'user.sendVerifyEmail',
|
|
183
|
+
config: { policies: [] },
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
// Send password reset email
|
|
187
|
+
{
|
|
188
|
+
method: 'POST',
|
|
189
|
+
path: '/realms/:realmId/users/:id/send-reset-password-email',
|
|
190
|
+
handler: 'user.sendResetPasswordEmail',
|
|
191
|
+
config: { policies: [] },
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
// ==================== ROLES ====================
|
|
195
|
+
|
|
196
|
+
// Get realm roles
|
|
197
|
+
{
|
|
198
|
+
method: 'GET',
|
|
199
|
+
path: '/realms/:realmId/roles',
|
|
200
|
+
handler: 'user.getRoles',
|
|
201
|
+
config: { policies: [] },
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
// Get user's roles
|
|
205
|
+
{
|
|
206
|
+
method: 'GET',
|
|
207
|
+
path: '/realms/:realmId/users/:id/roles',
|
|
208
|
+
handler: 'user.getUserRoles',
|
|
209
|
+
config: { policies: [] },
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
// Assign roles to user
|
|
213
|
+
{
|
|
214
|
+
method: 'POST',
|
|
215
|
+
path: '/realms/:realmId/users/:id/roles',
|
|
216
|
+
handler: 'user.assignRoles',
|
|
217
|
+
config: { policies: [] },
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
// Remove roles from user
|
|
221
|
+
{
|
|
222
|
+
method: 'DELETE',
|
|
223
|
+
path: '/realms/:realmId/users/:id/roles',
|
|
224
|
+
handler: 'user.removeRoles',
|
|
225
|
+
config: { policies: [] },
|
|
226
|
+
},
|
|
227
|
+
|
|
228
|
+
// ==================== AUDIT LOGS ====================
|
|
229
|
+
|
|
230
|
+
// Get all audit logs
|
|
231
|
+
{
|
|
232
|
+
method: 'GET',
|
|
233
|
+
path: '/audit-logs',
|
|
234
|
+
handler: 'audit.find',
|
|
235
|
+
config: { policies: [] },
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
// Get audit logs by realm
|
|
239
|
+
{
|
|
240
|
+
method: 'GET',
|
|
241
|
+
path: '/audit-logs/realm/:realmId',
|
|
242
|
+
handler: 'audit.findByRealm',
|
|
243
|
+
config: { policies: [] },
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
// Get audit logs by Keycloak user
|
|
247
|
+
{
|
|
248
|
+
method: 'GET',
|
|
249
|
+
path: '/audit-logs/user/:keycloakUserId',
|
|
250
|
+
handler: 'audit.findByUser',
|
|
251
|
+
config: { policies: [] },
|
|
252
|
+
},
|
|
253
|
+
];
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Audit logging service for tracking user management actions.
|
|
3
|
+
* Records all significant operations for compliance and debugging purposes.
|
|
4
|
+
*
|
|
5
|
+
* @module services/audit-log
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
PLUGIN_ID,
|
|
10
|
+
CONTENT_TYPES,
|
|
11
|
+
PAGINATION,
|
|
12
|
+
UNKNOWN_USER_EMAIL,
|
|
13
|
+
} from '../constants.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {Object} AuditLogEntry
|
|
17
|
+
* @property {string} documentId - Entry document ID
|
|
18
|
+
* @property {string} realmName - Realm slug identifier
|
|
19
|
+
* @property {string} realmDisplayName - Realm display name
|
|
20
|
+
* @property {string} action - Action type (from AUDIT_ACTIONS constant)
|
|
21
|
+
* @property {string|null} keycloakUserId - Target Keycloak user ID
|
|
22
|
+
* @property {string|null} keycloakUsername - Target Keycloak username
|
|
23
|
+
* @property {Object|null} details - Action-specific metadata
|
|
24
|
+
* @property {number|null} performedById - Strapi admin user ID
|
|
25
|
+
* @property {string} performedByEmail - Strapi admin email
|
|
26
|
+
* @property {Date} createdAt - Entry creation timestamp
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @typedef {Object} AuditLogParams
|
|
31
|
+
* @property {string} realmName - Realm slug identifier
|
|
32
|
+
* @property {string} [realmDisplayName] - Realm display name (defaults to realmName)
|
|
33
|
+
* @property {string} action - Action type from AUDIT_ACTIONS
|
|
34
|
+
* @property {string} [keycloakUserId] - Target Keycloak user ID
|
|
35
|
+
* @property {string} [keycloakUsername] - Target Keycloak username
|
|
36
|
+
* @property {Object} [details] - Action-specific metadata
|
|
37
|
+
* @property {Object} [user] - Strapi user who performed the action
|
|
38
|
+
* @property {number} [user.id] - User ID
|
|
39
|
+
* @property {string} [user.email] - User email
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @typedef {Object} AuditLogQueryParams
|
|
44
|
+
* @property {string} [realmName] - Filter by realm
|
|
45
|
+
* @property {string} [action] - Filter by action type
|
|
46
|
+
* @property {string} [keycloakUserId] - Filter by Keycloak user
|
|
47
|
+
* @property {number} [limit=50] - Maximum entries to return
|
|
48
|
+
* @property {number} [offset=0] - Starting offset for pagination
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @typedef {Object} AuditLogQueryResult
|
|
53
|
+
* @property {AuditLogEntry[]} entries - Log entries
|
|
54
|
+
* @property {number} total - Total matching entries
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Creates the audit log service.
|
|
59
|
+
*
|
|
60
|
+
* @param {Object} params - Service parameters
|
|
61
|
+
* @param {Object} params.strapi - Strapi instance
|
|
62
|
+
* @returns {Object} Audit log service methods
|
|
63
|
+
*/
|
|
64
|
+
const auditLogService = ({ strapi }) => ({
|
|
65
|
+
/**
|
|
66
|
+
* Creates an audit log entry.
|
|
67
|
+
* This method is designed to be non-blocking and fail-safe - audit logging
|
|
68
|
+
* errors are caught and logged but do not interrupt the main operation.
|
|
69
|
+
*
|
|
70
|
+
* @param {AuditLogParams} params - Log entry parameters
|
|
71
|
+
* @returns {Promise<AuditLogEntry|undefined>} Created entry or undefined on error
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* await auditLogService.log({
|
|
75
|
+
* realmName: 'production',
|
|
76
|
+
* realmDisplayName: 'Production Users',
|
|
77
|
+
* action: AUDIT_ACTIONS.CREATE_USER,
|
|
78
|
+
* keycloakUserId: 'user-123',
|
|
79
|
+
* keycloakUsername: 'john.doe',
|
|
80
|
+
* details: { email: 'john@example.com' },
|
|
81
|
+
* user: ctx.state.user
|
|
82
|
+
* });
|
|
83
|
+
*/
|
|
84
|
+
async log({ realmName, realmDisplayName, action, keycloakUserId, keycloakUsername, details, user }) {
|
|
85
|
+
try {
|
|
86
|
+
return await strapi.documents(CONTENT_TYPES.AUDIT_LOG).create({
|
|
87
|
+
data: {
|
|
88
|
+
realmName,
|
|
89
|
+
realmDisplayName: realmDisplayName || realmName,
|
|
90
|
+
action,
|
|
91
|
+
keycloakUserId: keycloakUserId || null,
|
|
92
|
+
keycloakUsername: keycloakUsername || null,
|
|
93
|
+
details: details || null,
|
|
94
|
+
performedById: user?.id || null,
|
|
95
|
+
performedByEmail: user?.email || UNKNOWN_USER_EMAIL,
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
} catch (err) {
|
|
99
|
+
// Log error but don't throw - audit logging should not break main operations
|
|
100
|
+
strapi.log.error(`[${PLUGIN_ID}] Failed to create audit log entry:`, err);
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Queries audit log entries with optional filters.
|
|
106
|
+
*
|
|
107
|
+
* @param {AuditLogQueryParams} [params={}] - Query parameters
|
|
108
|
+
* @returns {Promise<AuditLogQueryResult>} Paginated log entries with total count
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* // Get all entries for a realm
|
|
112
|
+
* const { entries, total } = await auditLogService.find({
|
|
113
|
+
* realmName: 'production',
|
|
114
|
+
* limit: 25,
|
|
115
|
+
* offset: 0
|
|
116
|
+
* });
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* // Get all password reset actions
|
|
120
|
+
* const { entries } = await auditLogService.find({
|
|
121
|
+
* action: AUDIT_ACTIONS.RESET_PASSWORD
|
|
122
|
+
* });
|
|
123
|
+
*/
|
|
124
|
+
async find({
|
|
125
|
+
realmName,
|
|
126
|
+
action,
|
|
127
|
+
keycloakUserId,
|
|
128
|
+
limit = PAGINATION.AUDIT_LOG_LIMIT,
|
|
129
|
+
offset = 0
|
|
130
|
+
} = {}) {
|
|
131
|
+
// Build filters object
|
|
132
|
+
const filters = {};
|
|
133
|
+
|
|
134
|
+
if (realmName) {
|
|
135
|
+
filters.realmName = realmName;
|
|
136
|
+
}
|
|
137
|
+
if (action) {
|
|
138
|
+
filters.action = action;
|
|
139
|
+
}
|
|
140
|
+
if (keycloakUserId) {
|
|
141
|
+
filters.keycloakUserId = keycloakUserId;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Execute queries in parallel
|
|
145
|
+
const [entries, count] = await Promise.all([
|
|
146
|
+
strapi.documents(CONTENT_TYPES.AUDIT_LOG).findMany({
|
|
147
|
+
filters,
|
|
148
|
+
sort: { createdAt: 'desc' },
|
|
149
|
+
limit,
|
|
150
|
+
offset,
|
|
151
|
+
}),
|
|
152
|
+
strapi.documents(CONTENT_TYPES.AUDIT_LOG).count({ filters }),
|
|
153
|
+
]);
|
|
154
|
+
|
|
155
|
+
return { entries, total: count };
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Retrieves audit logs for a specific realm.
|
|
160
|
+
* Convenience method that wraps find() with realm filter.
|
|
161
|
+
*
|
|
162
|
+
* @param {string} realmName - Realm slug identifier
|
|
163
|
+
* @param {Object} [options={}] - Query options
|
|
164
|
+
* @param {number} [options.limit=50] - Maximum entries
|
|
165
|
+
* @param {number} [options.offset=0] - Starting offset
|
|
166
|
+
* @returns {Promise<AuditLogQueryResult>} Paginated log entries
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* const { entries, total } = await auditLogService.findByRealm('production', {
|
|
170
|
+
* limit: 100
|
|
171
|
+
* });
|
|
172
|
+
*/
|
|
173
|
+
async findByRealm(realmName, { limit = PAGINATION.AUDIT_LOG_LIMIT, offset = 0 } = {}) {
|
|
174
|
+
return this.find({ realmName, limit, offset });
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Retrieves audit logs for a specific Keycloak user.
|
|
179
|
+
* Useful for viewing all actions performed on a single user.
|
|
180
|
+
*
|
|
181
|
+
* @param {string} keycloakUserId - Keycloak user ID
|
|
182
|
+
* @param {Object} [options={}] - Query options
|
|
183
|
+
* @param {number} [options.limit=50] - Maximum entries
|
|
184
|
+
* @param {number} [options.offset=0] - Starting offset
|
|
185
|
+
* @returns {Promise<AuditLogQueryResult>} Paginated log entries
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* const { entries } = await auditLogService.findByKeycloakUser('user-123');
|
|
189
|
+
* // Shows: created, updated, password reset, role changes, etc.
|
|
190
|
+
*/
|
|
191
|
+
async findByKeycloakUser(keycloakUserId, { limit = PAGINATION.AUDIT_LOG_LIMIT, offset = 0 } = {}) {
|
|
192
|
+
return this.find({ keycloakUserId, limit, offset });
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
export default auditLogService;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import keycloakClient from './keycloak-client.js';
|
|
2
|
+
import auditLog from './audit-log.js';
|
|
3
|
+
import permission from './permission.js';
|
|
4
|
+
import realm from './realm.js';
|
|
5
|
+
import user from './user.js';
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
'keycloak-client': keycloakClient,
|
|
9
|
+
'audit-log': auditLog,
|
|
10
|
+
permission,
|
|
11
|
+
realm,
|
|
12
|
+
user,
|
|
13
|
+
};
|