@uniorganization/uni-lib 4.1.4 → 4.2.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/dist/modules/common/jwt.strategy.js +6 -2
- package/dist/modules/tenant/redis-tenant-state.store.js +10 -0
- package/dist/modules/tenant/tenant-authorization.service.js +77 -19
- package/dist/modules/tenant/tenant-authorization.types.d.ts +10 -0
- package/dist/modules/tenant/tenant.types.d.ts +9 -0
- package/package.json +1 -1
|
@@ -76,8 +76,9 @@ let JwtStrategy = class JwtStrategy extends (0, passport_1.PassportStrategy)(pas
|
|
|
76
76
|
const { identity, snapshot } = resolved;
|
|
77
77
|
const isMasterTenantAdmin = !impersonating &&
|
|
78
78
|
snapshot.clientId === tenant_1.NEWTECH_CLIENT_ID &&
|
|
79
|
-
snapshot.
|
|
80
|
-
role.
|
|
79
|
+
(snapshot.permissions.includes('master.users.read') ||
|
|
80
|
+
snapshot.roles.some((role) => role.moduleName.toLowerCase() === 'root' &&
|
|
81
|
+
role.roleName.toLowerCase() === 'sysadmin'));
|
|
81
82
|
return {
|
|
82
83
|
id: identity.id,
|
|
83
84
|
first_name: identity.firstName,
|
|
@@ -104,6 +105,9 @@ let JwtStrategy = class JwtStrategy extends (0, passport_1.PassportStrategy)(pas
|
|
|
104
105
|
: null,
|
|
105
106
|
roles: Array.from(new Set(snapshot.roles.map((role) => role.roleName))),
|
|
106
107
|
privileges: snapshot.privileges,
|
|
108
|
+
role: snapshot.accessRole,
|
|
109
|
+
permissions: snapshot.permissions,
|
|
110
|
+
authzVersion: snapshot.authzVersion,
|
|
107
111
|
isMasterTenantAdmin,
|
|
108
112
|
};
|
|
109
113
|
});
|
|
@@ -154,6 +154,16 @@ let RedisTenantStateStore = RedisTenantStateStore_1 = class RedisTenantStateStor
|
|
|
154
154
|
typeof role.moduleName === 'string') &&
|
|
155
155
|
Array.isArray(value.privileges) &&
|
|
156
156
|
value.privileges.every((privilege) => typeof privilege === 'string') &&
|
|
157
|
+
value.accessRole &&
|
|
158
|
+
Number.isInteger(value.accessRole.id) &&
|
|
159
|
+
value.accessRole.id >= 0 &&
|
|
160
|
+
typeof value.accessRole.code === 'string' &&
|
|
161
|
+
typeof value.accessRole.name === 'string' &&
|
|
162
|
+
['GLOBAL', 'CLIENT'].includes(value.accessRole.scope) &&
|
|
163
|
+
Array.isArray(value.permissions) &&
|
|
164
|
+
value.permissions.every((permission) => typeof permission === 'string') &&
|
|
165
|
+
Number.isInteger(value.authzVersion) &&
|
|
166
|
+
value.authzVersion > 0 &&
|
|
157
167
|
((_a = value.identity) === null || _a === void 0 ? void 0 : _a.id) === value.userId &&
|
|
158
168
|
value.identity.homeClientId === value.homeClientId &&
|
|
159
169
|
typeof value.cachedAt === 'string');
|
|
@@ -71,8 +71,9 @@ let TenantAuthorizationService = TenantAuthorizationService_1 = class TenantAuth
|
|
|
71
71
|
throw new common_1.UnauthorizedException();
|
|
72
72
|
}
|
|
73
73
|
const origin = yield this.resolve(userId, homeClientId, homeClientId);
|
|
74
|
-
const isNewtechMaster = origin.snapshot.
|
|
75
|
-
role.
|
|
74
|
+
const isNewtechMaster = origin.snapshot.permissions.includes('master.users.read') ||
|
|
75
|
+
origin.snapshot.roles.some((role) => role.moduleName.toLowerCase() === 'root' &&
|
|
76
|
+
role.roleName.toLowerCase() === 'sysadmin');
|
|
76
77
|
const targetClient = yield this.clientRepository.findOne({
|
|
77
78
|
where: { id: targetClientId, deletedAt: (0, typeorm_2.IsNull)() },
|
|
78
79
|
});
|
|
@@ -94,6 +95,15 @@ let TenantAuthorizationService = TenantAuthorizationService_1 = class TenantAuth
|
|
|
94
95
|
},
|
|
95
96
|
],
|
|
96
97
|
privileges: [],
|
|
98
|
+
accessRole: {
|
|
99
|
+
id: 0,
|
|
100
|
+
code: tenant_constants_1.TENANT_IMPERSONATOR_ROLE,
|
|
101
|
+
name: 'Tenant impersonator',
|
|
102
|
+
scope: 'GLOBAL',
|
|
103
|
+
clientId: null,
|
|
104
|
+
},
|
|
105
|
+
permissions: [],
|
|
106
|
+
authzVersion: 1,
|
|
97
107
|
identity: origin.identity,
|
|
98
108
|
cachedAt: new Date().toISOString(),
|
|
99
109
|
};
|
|
@@ -115,7 +125,7 @@ let TenantAuthorizationService = TenantAuthorizationService_1 = class TenantAuth
|
|
|
115
125
|
}
|
|
116
126
|
loadFromDatabase(userId, clientId, expectedHomeClientId) {
|
|
117
127
|
return __awaiter(this, void 0, void 0, function* () {
|
|
118
|
-
const [user, client, assignments] = yield Promise.all([
|
|
128
|
+
const [user, client, assignments, accessRows] = yield Promise.all([
|
|
119
129
|
this.userRepository.findOne({ where: { id: userId } }),
|
|
120
130
|
this.clientRepository.findOne({
|
|
121
131
|
where: { id: clientId, deletedAt: (0, typeorm_2.IsNull)() },
|
|
@@ -129,23 +139,64 @@ let TenantAuthorizationService = TenantAuthorizationService_1 = class TenantAuth
|
|
|
129
139
|
.where('assignment."USER_ID" = :userId', { userId })
|
|
130
140
|
.andWhere('assignment.client_id = :clientId', { clientId })
|
|
131
141
|
.getMany(),
|
|
142
|
+
this.userRoleRepository.manager.query(`SELECT
|
|
143
|
+
role.id,
|
|
144
|
+
role.code,
|
|
145
|
+
role.name,
|
|
146
|
+
role.scope,
|
|
147
|
+
role.client_id AS "roleClientId",
|
|
148
|
+
role.authz_version AS "authzVersion",
|
|
149
|
+
COALESCE(
|
|
150
|
+
jsonb_agg(permission.code ORDER BY permission.code)
|
|
151
|
+
FILTER (WHERE permission.id IS NOT NULL AND permission.is_active),
|
|
152
|
+
'[]'::jsonb
|
|
153
|
+
) AS permissions
|
|
154
|
+
FROM stm."USER_ACCESS_ROLES" membership
|
|
155
|
+
JOIN stm."ACCESS_ROLES" role
|
|
156
|
+
ON role.id = membership.role_id
|
|
157
|
+
AND role.is_active
|
|
158
|
+
LEFT JOIN stm."ACCESS_ROLE_PERMISSIONS" definition
|
|
159
|
+
ON definition.role_id = role.id
|
|
160
|
+
LEFT JOIN stm."ACCESS_PERMISSIONS" permission
|
|
161
|
+
ON permission.id = definition.permission_id
|
|
162
|
+
WHERE membership.user_id = $1
|
|
163
|
+
AND membership.client_id = $2
|
|
164
|
+
GROUP BY role.id`, [userId, clientId]),
|
|
132
165
|
]);
|
|
133
166
|
if (!user ||
|
|
134
167
|
!Number(user.is_active) ||
|
|
135
168
|
user.clientId !== expectedHomeClientId ||
|
|
136
169
|
!client ||
|
|
137
|
-
|
|
170
|
+
accessRows.length !== 1) {
|
|
138
171
|
throw new common_1.UnauthorizedException();
|
|
139
172
|
}
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
173
|
+
const accessRow = accessRows[0];
|
|
174
|
+
const accessRole = {
|
|
175
|
+
id: Number(accessRow.id),
|
|
176
|
+
code: accessRow.code,
|
|
177
|
+
name: accessRow.name,
|
|
178
|
+
scope: accessRow.scope,
|
|
179
|
+
clientId: accessRow.roleClientId == null ? null : Number(accessRow.roleClientId),
|
|
180
|
+
};
|
|
181
|
+
const usingLegacyCompatibility = accessRole.code.startsWith('migrated-');
|
|
182
|
+
const roles = usingLegacyCompatibility && assignments.length
|
|
183
|
+
? assignments.map((assignment) => {
|
|
184
|
+
var _a, _b, _c, _d, _e, _f;
|
|
185
|
+
return ({
|
|
186
|
+
roleId: Number(assignment.roleId || ((_a = assignment.role) === null || _a === void 0 ? void 0 : _a.id)),
|
|
187
|
+
roleName: (_b = assignment.role) === null || _b === void 0 ? void 0 : _b.roleName,
|
|
188
|
+
moduleId: Number((_d = (_c = assignment.role) === null || _c === void 0 ? void 0 : _c.module) === null || _d === void 0 ? void 0 : _d.id),
|
|
189
|
+
moduleName: (_f = (_e = assignment.role) === null || _e === void 0 ? void 0 : _e.module) === null || _f === void 0 ? void 0 : _f.moduleName,
|
|
190
|
+
});
|
|
191
|
+
})
|
|
192
|
+
: [
|
|
193
|
+
{
|
|
194
|
+
roleId: accessRole.id,
|
|
195
|
+
roleName: accessRole.name,
|
|
196
|
+
moduleId: accessRole.id,
|
|
197
|
+
moduleName: 'access-control',
|
|
198
|
+
},
|
|
199
|
+
];
|
|
149
200
|
if (roles.some((role) => !Number.isInteger(role.roleId) ||
|
|
150
201
|
role.roleId <= 0 ||
|
|
151
202
|
!role.roleName ||
|
|
@@ -154,12 +205,14 @@ let TenantAuthorizationService = TenantAuthorizationService_1 = class TenantAuth
|
|
|
154
205
|
!role.moduleName)) {
|
|
155
206
|
throw new common_1.UnauthorizedException();
|
|
156
207
|
}
|
|
157
|
-
const privileges =
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
208
|
+
const privileges = usingLegacyCompatibility
|
|
209
|
+
? Array.from(new Set(assignments.flatMap((assignment) => {
|
|
210
|
+
var _a;
|
|
211
|
+
return (((_a = assignment.role) === null || _a === void 0 ? void 0 : _a.privileges) || [])
|
|
212
|
+
.map((definition) => { var _a; return (_a = definition.privilege) === null || _a === void 0 ? void 0 : _a.privilege; })
|
|
213
|
+
.filter((privilege) => Boolean(privilege));
|
|
214
|
+
}))).sort()
|
|
215
|
+
: [];
|
|
163
216
|
const identity = {
|
|
164
217
|
id: user.id,
|
|
165
218
|
homeClientId: user.clientId,
|
|
@@ -183,6 +236,11 @@ let TenantAuthorizationService = TenantAuthorizationService_1 = class TenantAuth
|
|
|
183
236
|
clientAlias: client.alias,
|
|
184
237
|
roles,
|
|
185
238
|
privileges,
|
|
239
|
+
accessRole,
|
|
240
|
+
permissions: Array.isArray(accessRow.permissions)
|
|
241
|
+
? accessRow.permissions
|
|
242
|
+
: [],
|
|
243
|
+
authzVersion: Number(accessRow.authzVersion),
|
|
186
244
|
identity,
|
|
187
245
|
cachedAt: new Date().toISOString(),
|
|
188
246
|
};
|
|
@@ -12,9 +12,19 @@ export interface TenantAuthorizationSnapshot {
|
|
|
12
12
|
clientAlias: string;
|
|
13
13
|
roles: TenantRoleAuthorization[];
|
|
14
14
|
privileges: string[];
|
|
15
|
+
accessRole: TenantAccessRoleAuthorization;
|
|
16
|
+
permissions: string[];
|
|
17
|
+
authzVersion: number;
|
|
15
18
|
identity: TenantAuthorizationIdentity;
|
|
16
19
|
cachedAt: string;
|
|
17
20
|
}
|
|
21
|
+
export interface TenantAccessRoleAuthorization {
|
|
22
|
+
id: number;
|
|
23
|
+
code: string;
|
|
24
|
+
name: string;
|
|
25
|
+
scope: 'GLOBAL' | 'CLIENT';
|
|
26
|
+
clientId: number | null;
|
|
27
|
+
}
|
|
18
28
|
export interface TenantAuthorizationIdentity {
|
|
19
29
|
id: number;
|
|
20
30
|
homeClientId: number;
|
|
@@ -23,6 +23,15 @@ export interface AuthenticatedTenantUser {
|
|
|
23
23
|
impersonationReason: string | null;
|
|
24
24
|
roles: string[];
|
|
25
25
|
privileges: string[];
|
|
26
|
+
role: {
|
|
27
|
+
id: number;
|
|
28
|
+
code: string;
|
|
29
|
+
name: string;
|
|
30
|
+
scope: 'GLOBAL' | 'CLIENT';
|
|
31
|
+
clientId: number | null;
|
|
32
|
+
};
|
|
33
|
+
permissions: string[];
|
|
34
|
+
authzVersion: number;
|
|
26
35
|
isMasterTenantAdmin: boolean;
|
|
27
36
|
first_name?: string;
|
|
28
37
|
username?: string;
|