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,144 @@
|
|
|
1
|
+
import { PLUGIN_ID, SERVICES, ERROR_MESSAGES } from '../constants.js';
|
|
2
|
+
|
|
3
|
+
const auditController = ({ strapi }) => ({
|
|
4
|
+
/**
|
|
5
|
+
* Find audit logs with filters
|
|
6
|
+
*/
|
|
7
|
+
async find(ctx) {
|
|
8
|
+
const user = ctx.state.user;
|
|
9
|
+
const { realmName, action, limit = 50, offset = 0 } = ctx.query;
|
|
10
|
+
|
|
11
|
+
if (!user) {
|
|
12
|
+
return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const permissionService = strapi.plugin(PLUGIN_ID).service(SERVICES.PERMISSION);
|
|
17
|
+
|
|
18
|
+
// Non-super admins can only see logs for their accessible realms
|
|
19
|
+
if (!permissionService.isSuperAdmin(user)) {
|
|
20
|
+
const accessibleRealms = await permissionService.getAccessibleRealms(user);
|
|
21
|
+
const accessibleRealmNames = accessibleRealms.map((r) => r.name);
|
|
22
|
+
|
|
23
|
+
// If filtering by realm, verify access
|
|
24
|
+
if (realmName && !accessibleRealmNames.includes(realmName)) {
|
|
25
|
+
return ctx.forbidden(ERROR_MESSAGES.REALM_ACCESS_DENIED);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// If no realm filter, only return logs for accessible realms
|
|
29
|
+
const auditLogService = strapi.plugin(PLUGIN_ID).service(SERVICES.AUDIT_LOG);
|
|
30
|
+
|
|
31
|
+
if (!realmName) {
|
|
32
|
+
// Fetch logs for all accessible realms
|
|
33
|
+
const allLogs = [];
|
|
34
|
+
for (const rn of accessibleRealmNames) {
|
|
35
|
+
const { entries } = await auditLogService.find({
|
|
36
|
+
realmName: rn,
|
|
37
|
+
action,
|
|
38
|
+
limit: parseInt(limit, 10),
|
|
39
|
+
offset: parseInt(offset, 10),
|
|
40
|
+
});
|
|
41
|
+
allLogs.push(...entries);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Sort by createdAt desc and apply limit
|
|
45
|
+
allLogs.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
|
|
46
|
+
ctx.body = { data: allLogs.slice(0, parseInt(limit, 10)) };
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const auditLogService = strapi.plugin(PLUGIN_ID).service(SERVICES.AUDIT_LOG);
|
|
52
|
+
const result = await auditLogService.find({
|
|
53
|
+
realmName,
|
|
54
|
+
action,
|
|
55
|
+
limit: parseInt(limit, 10),
|
|
56
|
+
offset: parseInt(offset, 10),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
ctx.body = { data: result.entries, meta: { total: result.total } };
|
|
60
|
+
} catch (err) {
|
|
61
|
+
strapi.log.error(`[${PLUGIN_ID}] audit.find error:`, err);
|
|
62
|
+
ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Find audit logs by realm
|
|
68
|
+
*/
|
|
69
|
+
async findByRealm(ctx) {
|
|
70
|
+
const user = ctx.state.user;
|
|
71
|
+
const { realmId } = ctx.params;
|
|
72
|
+
const { limit = 50, offset = 0 } = ctx.query;
|
|
73
|
+
|
|
74
|
+
if (!user) {
|
|
75
|
+
return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const permissionService = strapi.plugin(PLUGIN_ID).service(SERVICES.PERMISSION);
|
|
80
|
+
const realmService = strapi.plugin(PLUGIN_ID).service(SERVICES.REALM);
|
|
81
|
+
|
|
82
|
+
const canAccess = await permissionService.canAccessRealm(user, realmId, 'canRead');
|
|
83
|
+
|
|
84
|
+
if (!canAccess) {
|
|
85
|
+
return ctx.forbidden(ERROR_MESSAGES.REALM_ACCESS_DENIED);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const realm = await realmService.findOne(realmId);
|
|
89
|
+
const auditLogService = strapi.plugin(PLUGIN_ID).service(SERVICES.AUDIT_LOG);
|
|
90
|
+
const result = await auditLogService.findByRealm(realm.name, {
|
|
91
|
+
limit: parseInt(limit, 10),
|
|
92
|
+
offset: parseInt(offset, 10),
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
ctx.body = { data: result.entries, meta: { total: result.total } };
|
|
96
|
+
} catch (err) {
|
|
97
|
+
strapi.log.error(`[${PLUGIN_ID}] audit.findByRealm error:`, err);
|
|
98
|
+
ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Find audit logs by Keycloak user
|
|
104
|
+
*/
|
|
105
|
+
async findByUser(ctx) {
|
|
106
|
+
const user = ctx.state.user;
|
|
107
|
+
const { keycloakUserId } = ctx.params;
|
|
108
|
+
const { limit = 50, offset = 0 } = ctx.query;
|
|
109
|
+
|
|
110
|
+
if (!user) {
|
|
111
|
+
return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const auditLogService = strapi.plugin(PLUGIN_ID).service(SERVICES.AUDIT_LOG);
|
|
116
|
+
const result = await auditLogService.findByKeycloakUser(keycloakUserId, {
|
|
117
|
+
limit: parseInt(limit, 10),
|
|
118
|
+
offset: parseInt(offset, 10),
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Filter by accessible realms for non-super admins
|
|
122
|
+
const permissionService = strapi.plugin(PLUGIN_ID).service(SERVICES.PERMISSION);
|
|
123
|
+
|
|
124
|
+
if (!permissionService.isSuperAdmin(user)) {
|
|
125
|
+
const accessibleRealms = await permissionService.getAccessibleRealms(user);
|
|
126
|
+
const accessibleRealmNames = accessibleRealms.map((r) => r.name);
|
|
127
|
+
|
|
128
|
+
const filteredEntries = result.entries.filter((e) =>
|
|
129
|
+
accessibleRealmNames.includes(e.realmName)
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
ctx.body = { data: filteredEntries, meta: { total: filteredEntries.length } };
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
ctx.body = { data: result.entries, meta: { total: result.total } };
|
|
137
|
+
} catch (err) {
|
|
138
|
+
strapi.log.error(`[${PLUGIN_ID}] audit.findByUser error:`, err);
|
|
139
|
+
ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
export default auditController;
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { PLUGIN_ID, SERVICES, ERROR_MESSAGES } from '../constants.js';
|
|
2
|
+
|
|
3
|
+
const realmController = ({ strapi }) => ({
|
|
4
|
+
/**
|
|
5
|
+
* Get all realms (filtered by user access)
|
|
6
|
+
*/
|
|
7
|
+
async find(ctx) {
|
|
8
|
+
const user = ctx.state.user;
|
|
9
|
+
|
|
10
|
+
if (!user) {
|
|
11
|
+
return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const permissionService = strapi.plugin(PLUGIN_ID).service(SERVICES.PERMISSION);
|
|
16
|
+
const realms = await permissionService.getAccessibleRealms(user);
|
|
17
|
+
ctx.body = { data: realms };
|
|
18
|
+
} catch (err) {
|
|
19
|
+
strapi.log.error(`[${PLUGIN_ID}] realm.find error:`, err);
|
|
20
|
+
ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Get a single realm by ID
|
|
26
|
+
*/
|
|
27
|
+
async findOne(ctx) {
|
|
28
|
+
const user = ctx.state.user;
|
|
29
|
+
const { id } = ctx.params;
|
|
30
|
+
|
|
31
|
+
if (!user) {
|
|
32
|
+
return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const permissionService = strapi.plugin(PLUGIN_ID).service(SERVICES.PERMISSION);
|
|
37
|
+
const realmService = strapi.plugin(PLUGIN_ID).service(SERVICES.REALM);
|
|
38
|
+
|
|
39
|
+
const canAccess = await permissionService.canAccessRealm(user, id, 'canRead');
|
|
40
|
+
|
|
41
|
+
if (!canAccess) {
|
|
42
|
+
return ctx.forbidden(ERROR_MESSAGES.REALM_ACCESS_DENIED);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const realm = await realmService.findOne(id);
|
|
46
|
+
const permissions = await permissionService.getRealmPermissions(user, id);
|
|
47
|
+
|
|
48
|
+
ctx.body = { data: { ...realm, permissions } };
|
|
49
|
+
} catch (err) {
|
|
50
|
+
strapi.log.error(`[${PLUGIN_ID}] realm.findOne error:`, err);
|
|
51
|
+
ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Create a new realm (super admin only)
|
|
57
|
+
*/
|
|
58
|
+
async create(ctx) {
|
|
59
|
+
const user = ctx.state.user;
|
|
60
|
+
const { data } = ctx.request.body;
|
|
61
|
+
|
|
62
|
+
if (!user) {
|
|
63
|
+
return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const permissionService = strapi.plugin(PLUGIN_ID).service(SERVICES.PERMISSION);
|
|
68
|
+
|
|
69
|
+
if (!permissionService.isSuperAdmin(user)) {
|
|
70
|
+
return ctx.forbidden('Only super admins can create realm configurations.');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const realmService = strapi.plugin(PLUGIN_ID).service(SERVICES.REALM);
|
|
74
|
+
const realm = await realmService.create(data);
|
|
75
|
+
|
|
76
|
+
ctx.body = { data: realm };
|
|
77
|
+
} catch (err) {
|
|
78
|
+
strapi.log.error(`[${PLUGIN_ID}] realm.create error:`, err);
|
|
79
|
+
ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Update a realm (super admin only)
|
|
85
|
+
*/
|
|
86
|
+
async update(ctx) {
|
|
87
|
+
const user = ctx.state.user;
|
|
88
|
+
const { id } = ctx.params;
|
|
89
|
+
const { data } = ctx.request.body;
|
|
90
|
+
|
|
91
|
+
if (!user) {
|
|
92
|
+
return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
const permissionService = strapi.plugin(PLUGIN_ID).service(SERVICES.PERMISSION);
|
|
97
|
+
|
|
98
|
+
if (!permissionService.isSuperAdmin(user)) {
|
|
99
|
+
return ctx.forbidden('Only super admins can update realm configurations.');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const realmService = strapi.plugin(PLUGIN_ID).service(SERVICES.REALM);
|
|
103
|
+
const realm = await realmService.update(id, data);
|
|
104
|
+
|
|
105
|
+
ctx.body = { data: realm };
|
|
106
|
+
} catch (err) {
|
|
107
|
+
strapi.log.error(`[${PLUGIN_ID}] realm.update error:`, err);
|
|
108
|
+
ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Delete a realm (super admin only)
|
|
114
|
+
*/
|
|
115
|
+
async delete(ctx) {
|
|
116
|
+
const user = ctx.state.user;
|
|
117
|
+
const { id } = ctx.params;
|
|
118
|
+
|
|
119
|
+
if (!user) {
|
|
120
|
+
return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
const permissionService = strapi.plugin(PLUGIN_ID).service(SERVICES.PERMISSION);
|
|
125
|
+
|
|
126
|
+
if (!permissionService.isSuperAdmin(user)) {
|
|
127
|
+
return ctx.forbidden('Only super admins can delete realm configurations.');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const realmService = strapi.plugin(PLUGIN_ID).service(SERVICES.REALM);
|
|
131
|
+
await realmService.delete(id);
|
|
132
|
+
|
|
133
|
+
ctx.body = { data: { success: true } };
|
|
134
|
+
} catch (err) {
|
|
135
|
+
strapi.log.error(`[${PLUGIN_ID}] realm.delete error:`, err);
|
|
136
|
+
ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Test realm connection
|
|
142
|
+
*/
|
|
143
|
+
async testConnection(ctx) {
|
|
144
|
+
const user = ctx.state.user;
|
|
145
|
+
const { id } = ctx.params;
|
|
146
|
+
|
|
147
|
+
if (!user) {
|
|
148
|
+
return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const permissionService = strapi.plugin(PLUGIN_ID).service(SERVICES.PERMISSION);
|
|
153
|
+
const realmService = strapi.plugin(PLUGIN_ID).service(SERVICES.REALM);
|
|
154
|
+
|
|
155
|
+
const canAccess = await permissionService.canAccessRealm(user, id, 'canRead');
|
|
156
|
+
|
|
157
|
+
if (!canAccess) {
|
|
158
|
+
return ctx.forbidden(ERROR_MESSAGES.REALM_ACCESS_DENIED);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const result = await realmService.testConnection(id);
|
|
162
|
+
ctx.body = { data: result };
|
|
163
|
+
} catch (err) {
|
|
164
|
+
strapi.log.error(`[${PLUGIN_ID}] realm.testConnection error:`, err);
|
|
165
|
+
ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Test connection before saving (with raw config)
|
|
171
|
+
*/
|
|
172
|
+
async testConnectionRaw(ctx) {
|
|
173
|
+
const user = ctx.state.user;
|
|
174
|
+
const { data } = ctx.request.body;
|
|
175
|
+
|
|
176
|
+
if (!user) {
|
|
177
|
+
return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
const permissionService = strapi.plugin(PLUGIN_ID).service(SERVICES.PERMISSION);
|
|
182
|
+
|
|
183
|
+
if (!permissionService.isSuperAdmin(user)) {
|
|
184
|
+
return ctx.forbidden('Only super admins can test realm configurations.');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const realmService = strapi.plugin(PLUGIN_ID).service(SERVICES.REALM);
|
|
188
|
+
const result = await realmService.testConnectionRaw(data);
|
|
189
|
+
|
|
190
|
+
ctx.body = { data: result };
|
|
191
|
+
} catch (err) {
|
|
192
|
+
strapi.log.error(`[${PLUGIN_ID}] realm.testConnectionRaw error:`, err);
|
|
193
|
+
ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Get admins assigned to a realm
|
|
199
|
+
*/
|
|
200
|
+
async getAdmins(ctx) {
|
|
201
|
+
const user = ctx.state.user;
|
|
202
|
+
const { id } = ctx.params;
|
|
203
|
+
|
|
204
|
+
if (!user) {
|
|
205
|
+
return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
const permissionService = strapi.plugin(PLUGIN_ID).service(SERVICES.PERMISSION);
|
|
210
|
+
|
|
211
|
+
if (!permissionService.isSuperAdmin(user)) {
|
|
212
|
+
return ctx.forbidden('Only super admins can view realm admin assignments.');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const admins = await permissionService.getRealmAdmins(id);
|
|
216
|
+
ctx.body = { data: admins };
|
|
217
|
+
} catch (err) {
|
|
218
|
+
strapi.log.error(`[${PLUGIN_ID}] realm.getAdmins error:`, err);
|
|
219
|
+
ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Assign an admin to a realm
|
|
225
|
+
*/
|
|
226
|
+
async addAdmin(ctx) {
|
|
227
|
+
const user = ctx.state.user;
|
|
228
|
+
const { id } = ctx.params;
|
|
229
|
+
const { data } = ctx.request.body;
|
|
230
|
+
|
|
231
|
+
if (!user) {
|
|
232
|
+
return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
try {
|
|
236
|
+
const permissionService = strapi.plugin(PLUGIN_ID).service(SERVICES.PERMISSION);
|
|
237
|
+
|
|
238
|
+
if (!permissionService.isSuperAdmin(user)) {
|
|
239
|
+
return ctx.forbidden('Only super admins can assign realm admins.');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const { strapiUserId, strapiUserEmail, permissions } = data;
|
|
243
|
+
|
|
244
|
+
if (!strapiUserId) {
|
|
245
|
+
return ctx.badRequest('strapiUserId is required.');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const assignment = await permissionService.assignUserToRealm(
|
|
249
|
+
strapiUserId,
|
|
250
|
+
strapiUserEmail,
|
|
251
|
+
id,
|
|
252
|
+
permissions
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
ctx.body = { data: assignment };
|
|
256
|
+
} catch (err) {
|
|
257
|
+
strapi.log.error(`[${PLUGIN_ID}] realm.addAdmin error:`, err);
|
|
258
|
+
ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Update admin permissions for a realm
|
|
264
|
+
*/
|
|
265
|
+
async updateAdmin(ctx) {
|
|
266
|
+
const user = ctx.state.user;
|
|
267
|
+
const { id, adminId } = ctx.params;
|
|
268
|
+
const { data } = ctx.request.body;
|
|
269
|
+
|
|
270
|
+
if (!user) {
|
|
271
|
+
return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
try {
|
|
275
|
+
const permissionService = strapi.plugin(PLUGIN_ID).service(SERVICES.PERMISSION);
|
|
276
|
+
|
|
277
|
+
if (!permissionService.isSuperAdmin(user)) {
|
|
278
|
+
return ctx.forbidden('Only super admins can update realm admin assignments.');
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const { permissions } = data;
|
|
282
|
+
|
|
283
|
+
const assignment = await permissionService.assignUserToRealm(
|
|
284
|
+
parseInt(adminId, 10),
|
|
285
|
+
null,
|
|
286
|
+
id,
|
|
287
|
+
permissions
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
ctx.body = { data: assignment };
|
|
291
|
+
} catch (err) {
|
|
292
|
+
strapi.log.error(`[${PLUGIN_ID}] realm.updateAdmin error:`, err);
|
|
293
|
+
ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Remove an admin from a realm
|
|
299
|
+
*/
|
|
300
|
+
async removeAdmin(ctx) {
|
|
301
|
+
const user = ctx.state.user;
|
|
302
|
+
const { id, adminId } = ctx.params;
|
|
303
|
+
|
|
304
|
+
if (!user) {
|
|
305
|
+
return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
try {
|
|
309
|
+
const permissionService = strapi.plugin(PLUGIN_ID).service(SERVICES.PERMISSION);
|
|
310
|
+
|
|
311
|
+
if (!permissionService.isSuperAdmin(user)) {
|
|
312
|
+
return ctx.forbidden('Only super admins can remove realm admins.');
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
await permissionService.removeUserFromRealm(parseInt(adminId, 10), id);
|
|
316
|
+
ctx.body = { data: { success: true } };
|
|
317
|
+
} catch (err) {
|
|
318
|
+
strapi.log.error(`[${PLUGIN_ID}] realm.removeAdmin error:`, err);
|
|
319
|
+
ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
export default realmController;
|