001
014
015 package com.liferay.portal.security.permission;
016
017 import com.liferay.portal.kernel.exception.PortalException;
018 import com.liferay.portal.kernel.log.Log;
019 import com.liferay.portal.kernel.log.LogFactoryUtil;
020 import com.liferay.portal.kernel.model.Group;
021 import com.liferay.portal.kernel.model.GroupConstants;
022 import com.liferay.portal.kernel.model.ResourceConstants;
023 import com.liferay.portal.kernel.security.pacl.DoPrivileged;
024 import com.liferay.portal.kernel.security.permission.ActionKeys;
025 import com.liferay.portal.kernel.security.permission.InlineSQLHelper;
026 import com.liferay.portal.kernel.security.permission.PermissionChecker;
027 import com.liferay.portal.kernel.security.permission.PermissionThreadLocal;
028 import com.liferay.portal.kernel.service.GroupLocalServiceUtil;
029 import com.liferay.portal.kernel.service.ResourceBlockLocalServiceUtil;
030 import com.liferay.portal.kernel.service.ResourcePermissionLocalServiceUtil;
031 import com.liferay.portal.kernel.service.ResourceTypePermissionLocalServiceUtil;
032 import com.liferay.portal.kernel.util.ArrayUtil;
033 import com.liferay.portal.kernel.util.CharPool;
034 import com.liferay.portal.kernel.util.StringBundler;
035 import com.liferay.portal.kernel.util.StringPool;
036 import com.liferay.portal.kernel.util.StringUtil;
037 import com.liferay.portal.kernel.util.Validator;
038 import com.liferay.portal.util.PropsValues;
039 import com.liferay.util.dao.orm.CustomSQLUtil;
040
041 import java.util.HashSet;
042 import java.util.Set;
043
044
048 @DoPrivileged
049 public class InlineSQLHelperImpl implements InlineSQLHelper {
050
051 public static final String FILTER_BY_RESOURCE_BLOCK_ID =
052 InlineSQLHelper.class.getName() + ".filterByResourceBlockId";
053
054 public static final String FILTER_BY_RESOURCE_BLOCK_ID_OWNER =
055 InlineSQLHelper.class.getName() + ".filterByResourceBlockIdOwner";
056
057 public static final String FIND_BY_RESOURCE_BLOCK_ID =
058 InlineSQLHelper.class.getName() + ".findByResourceBlockId";
059
060 public static final String JOIN_RESOURCE_PERMISSION =
061 InlineSQLHelper.class.getName() + ".joinResourcePermission";
062
063 @Override
064 public boolean isEnabled() {
065 return isEnabled(0, 0);
066 }
067
068 @Override
069 public boolean isEnabled(long groupId) {
070 return isEnabled(0, groupId);
071 }
072
073 @Override
074 public boolean isEnabled(long companyId, long groupId) {
075 if (!PropsValues.PERMISSIONS_INLINE_SQL_CHECK_ENABLED) {
076 return false;
077 }
078
079 PermissionChecker permissionChecker =
080 PermissionThreadLocal.getPermissionChecker();
081
082 if (permissionChecker == null) {
083 throw new IllegalStateException("Permission checker is null");
084 }
085
086 if (groupId > 0) {
087 if (permissionChecker.isGroupAdmin(groupId) ||
088 permissionChecker.isGroupOwner(groupId)) {
089
090 return false;
091 }
092 }
093 else if (companyId > 0) {
094 if (permissionChecker.isCompanyAdmin(companyId)) {
095 return false;
096 }
097 }
098 else {
099 if (permissionChecker.isOmniadmin()) {
100 return false;
101 }
102 }
103
104 return true;
105 }
106
107 @Override
108 public boolean isEnabled(long[] groupIds) {
109 if (!PropsValues.PERMISSIONS_INLINE_SQL_CHECK_ENABLED) {
110 return false;
111 }
112
113 for (long groupId : groupIds) {
114 if (isEnabled(groupId)) {
115 return true;
116 }
117 }
118
119 return false;
120 }
121
122 @Override
123 public String replacePermissionCheck(
124 String sql, String className, String classPKField) {
125
126 return replacePermissionCheck(
127 sql, className, classPKField, null, new long[] {0}, null);
128 }
129
130 @Override
131 public String replacePermissionCheck(
132 String sql, String className, String classPKField, long groupId) {
133
134 return replacePermissionCheck(
135 sql, className, classPKField, null, new long[] {groupId}, null);
136 }
137
138 @Override
139 public String replacePermissionCheck(
140 String sql, String className, String classPKField, long groupId,
141 String bridgeJoin) {
142
143 return replacePermissionCheck(
144 sql, className, classPKField, null, new long[] {groupId},
145 bridgeJoin);
146 }
147
148 @Override
149 public String replacePermissionCheck(
150 String sql, String className, String classPKField, long[] groupIds) {
151
152 return replacePermissionCheck(
153 sql, className, classPKField, null, groupIds, null);
154 }
155
156 @Override
157 public String replacePermissionCheck(
158 String sql, String className, String classPKField, long[] groupIds,
159 String bridgeJoin) {
160
161 return replacePermissionCheck(
162 sql, className, classPKField, null, groupIds, bridgeJoin);
163 }
164
165 @Override
166 public String replacePermissionCheck(
167 String sql, String className, String classPKField, String userIdField) {
168
169 return replacePermissionCheck(
170 sql, className, classPKField, userIdField, new long[] {0}, null);
171 }
172
173 @Override
174 public String replacePermissionCheck(
175 String sql, String className, String classPKField, String userIdField,
176 long groupId) {
177
178 return replacePermissionCheck(
179 sql, className, classPKField, userIdField, new long[] {groupId},
180 null);
181 }
182
183 @Override
184 public String replacePermissionCheck(
185 String sql, String className, String classPKField, String userIdField,
186 long groupId, String bridgeJoin) {
187
188 return replacePermissionCheck(
189 sql, className, classPKField, userIdField, new long[] {groupId},
190 bridgeJoin);
191 }
192
193 @Override
194 public String replacePermissionCheck(
195 String sql, String className, String classPKField, String userIdField,
196 long[] groupIds) {
197
198 return replacePermissionCheck(
199 sql, className, classPKField, userIdField, groupIds, null);
200 }
201
202 @Override
203 public String replacePermissionCheck(
204 String sql, String className, String classPKField, String userIdField,
205 long[] groupIds, String bridgeJoin) {
206
207 String groupIdField = classPKField.substring(
208 0, classPKField.lastIndexOf(CharPool.PERIOD));
209
210 return replacePermissionCheck(
211 sql, className, classPKField, userIdField,
212 groupIdField.concat(".groupId"), groupIds, bridgeJoin);
213 }
214
215 @Override
216 public String replacePermissionCheck(
217 String sql, String className, String classPKField, String userIdField,
218 String bridgeJoin) {
219
220 return replacePermissionCheck(
221 sql, className, classPKField, userIdField, 0, bridgeJoin);
222 }
223
224 @Override
225 public String replacePermissionCheck(
226 String sql, String className, String classPKField, String userIdField,
227 String groupIdField, long[] groupIds, String bridgeJoin) {
228
229 if (!isEnabled(groupIds)) {
230 return sql;
231 }
232
233 if (Validator.isNull(className)) {
234 throw new IllegalArgumentException("className is null");
235 }
236
237 if (Validator.isNull(sql)) {
238 return sql;
239 }
240
241 if (ResourceBlockLocalServiceUtil.isSupported(className)) {
242 return replacePermissionCheckBlocks(
243 sql, className, classPKField, userIdField, groupIds,
244 bridgeJoin);
245 }
246 else {
247 return replacePermissionCheckJoin(
248 sql, className, classPKField, userIdField, groupIdField,
249 groupIds, bridgeJoin);
250 }
251 }
252
253 protected Set<Long> getOwnerResourceBlockIds(
254 long companyId, long[] groupIds, String className) {
255
256 Set<Long> resourceBlockIds = new HashSet<>();
257
258 PermissionChecker permissionChecker =
259 PermissionThreadLocal.getPermissionChecker();
260
261 for (long groupId : groupIds) {
262 resourceBlockIds.addAll(
263 permissionChecker.getOwnerResourceBlockIds(
264 companyId, groupId, className, ActionKeys.VIEW));
265 }
266
267 return resourceBlockIds;
268 }
269
270 protected String getOwnerResourceBlockIdsSQL(
271 PermissionChecker permissionChecker, long checkGroupId,
272 String className, Set<Long> ownerResourceBlockIds) {
273
274 if (ownerResourceBlockIds.size() <
275 PropsValues.
276 PERMISSIONS_INLINE_SQL_RESOURCE_BLOCK_QUERY_THRESHOLD) {
277
278 return StringUtil.merge(ownerResourceBlockIds);
279 }
280
281 return StringUtil.replace(
282 CustomSQLUtil.get(FIND_BY_RESOURCE_BLOCK_ID),
283 new String[] {
284 "[$COMPANY_ID$]", "[$GROUP_ID$]", "[$RESOURCE_BLOCK_NAME$]",
285 "[$ROLE_ID$]"
286 },
287 new String[] {
288 String.valueOf(permissionChecker.getCompanyId()),
289 String.valueOf(checkGroupId), className,
290 StringUtil.valueOf(permissionChecker.getOwnerRoleId())
291 });
292 }
293
294 protected Set<Long> getResourceBlockIds(
295 long companyId, long[] groupIds, String className) {
296
297 Set<Long> resourceBlockIds = new HashSet<>();
298
299 PermissionChecker permissionChecker =
300 PermissionThreadLocal.getPermissionChecker();
301
302 for (long groupId : groupIds) {
303 resourceBlockIds.addAll(
304 permissionChecker.getResourceBlockIds(
305 companyId, groupId, permissionChecker.getUserId(),
306 className, ActionKeys.VIEW));
307 }
308
309 return resourceBlockIds;
310 }
311
312 protected long[] getRoleIds(long groupId) {
313 long[] roleIds = PermissionChecker.DEFAULT_ROLE_IDS;
314
315 PermissionChecker permissionChecker =
316 PermissionThreadLocal.getPermissionChecker();
317
318 if (permissionChecker != null) {
319 roleIds = permissionChecker.getRoleIds(
320 permissionChecker.getUserId(), groupId);
321 }
322
323 return roleIds;
324 }
325
326 protected long[] getRoleIds(long[] groupIds) {
327 Set<Long> roleIds = new HashSet<>();
328
329 for (long groupId : groupIds) {
330 for (long roleId : getRoleIds(groupId)) {
331 roleIds.add(roleId);
332 }
333 }
334
335 return ArrayUtil.toLongArray(roleIds);
336 }
337
338 protected String getRoleIdsOrOwnerIdSQL(
339 PermissionChecker permissionChecker, long[] groupIds,
340 String userIdField) {
341
342 StringBundler sb = new StringBundler();
343
344 sb.append(StringPool.OPEN_PARENTHESIS);
345
346 sb.append("ResourcePermission.roleId IN (");
347
348 long[] roleIds = getRoleIds(groupIds);
349
350 if (roleIds.length == 0) {
351 roleIds = _NO_ROLE_IDS;
352 }
353
354 sb.append(StringUtil.merge(roleIds));
355
356 sb.append(StringPool.CLOSE_PARENTHESIS);
357
358 if (permissionChecker.isSignedIn()) {
359 sb.append(" OR ");
360
361 long userId = permissionChecker.getUserId();
362
363 if (Validator.isNotNull(userIdField)) {
364 sb.append(StringPool.OPEN_PARENTHESIS);
365 sb.append(userIdField);
366 sb.append(" = ");
367 sb.append(userId);
368 sb.append(StringPool.CLOSE_PARENTHESIS);
369 }
370 else {
371 sb.append("(ResourcePermission.ownerId = ");
372 sb.append(userId);
373 sb.append(StringPool.CLOSE_PARENTHESIS);
374 }
375 }
376
377 sb.append(StringPool.CLOSE_PARENTHESIS);
378
379 return sb.toString();
380 }
381
382 protected long getUserId() {
383 long userId = 0;
384
385 PermissionChecker permissionChecker =
386 PermissionThreadLocal.getPermissionChecker();
387
388 if (permissionChecker != null) {
389 userId = permissionChecker.getUserId();
390 }
391
392 return userId;
393 }
394
395 protected String getUserResourceBlockIdsSQL(
396 PermissionChecker permissionChecker, long checkGroupId, long[] roleIds,
397 String className, Set<Long> userResourceBlockIds) {
398
399 if (userResourceBlockIds.size() <
400 PropsValues.
401 PERMISSIONS_INLINE_SQL_RESOURCE_BLOCK_QUERY_THRESHOLD) {
402
403 return StringUtil.merge(userResourceBlockIds);
404 }
405
406 return StringUtil.replace(
407 CustomSQLUtil.get(FIND_BY_RESOURCE_BLOCK_ID),
408 new String[] {
409 "[$COMPANY_ID$]", "[$GROUP_ID$]", "[$RESOURCE_BLOCK_NAME$]",
410 "[$ROLE_ID$]"
411 },
412 new String[] {
413 String.valueOf(permissionChecker.getCompanyId()),
414 String.valueOf(checkGroupId), className,
415 StringUtil.merge(roleIds)
416 });
417 }
418
419 protected String replacePermissionCheckBlocks(
420 String sql, String className, String classPKField, String userIdField,
421 long[] groupIds, String bridgeJoin) {
422
423 PermissionChecker permissionChecker =
424 PermissionThreadLocal.getPermissionChecker();
425
426 long checkGroupId = 0;
427
428 if (groupIds.length == 1) {
429 checkGroupId = groupIds[0];
430 }
431
432 long[] roleIds = permissionChecker.getRoleIds(
433 getUserId(), checkGroupId);
434
435 try {
436 for (long roleId : roleIds) {
437 if (ResourceTypePermissionLocalServiceUtil.
438 hasCompanyScopePermission(
439 permissionChecker.getCompanyId(), className, roleId,
440 ActionKeys.VIEW)) {
441
442 return sql;
443 }
444 }
445 }
446 catch (Exception e) {
447 }
448
449 Set<Long> userResourceBlockIds = getResourceBlockIds(
450 permissionChecker.getCompanyId(), groupIds, className);
451
452 String permissionWhere = StringPool.BLANK;
453
454 if (Validator.isNotNull(bridgeJoin)) {
455 permissionWhere = bridgeJoin;
456 }
457
458 Set<Long> ownerResourceBlockIds = getOwnerResourceBlockIds(
459 permissionChecker.getCompanyId(), groupIds, className);
460
461
462
463
464 ownerResourceBlockIds.removeAll(userResourceBlockIds);
465
466
467
468
469 if (ownerResourceBlockIds.isEmpty()) {
470 ownerResourceBlockIds.add(_NO_RESOURCE_BLOCKS_ID);
471 }
472
473 if (userResourceBlockIds.isEmpty()) {
474 userResourceBlockIds.add(_NO_RESOURCE_BLOCKS_ID);
475 }
476
477 if (Validator.isNotNull(userIdField)) {
478 permissionWhere = permissionWhere.concat(
479 CustomSQLUtil.get(FILTER_BY_RESOURCE_BLOCK_ID_OWNER));
480
481 permissionWhere = StringUtil.replace(
482 permissionWhere,
483 new String[] {
484 "[$OWNER_RESOURCE_BLOCK_ID$]", "[$USER_ID$]",
485 "[$USER_ID_FIELD$]", "[$USER_RESOURCE_BLOCK_ID$]"
486 },
487 new String[] {
488 getOwnerResourceBlockIdsSQL(
489 permissionChecker, checkGroupId, className,
490 ownerResourceBlockIds),
491 String.valueOf(permissionChecker.getUserId()), userIdField,
492 getUserResourceBlockIdsSQL(
493 permissionChecker, checkGroupId, roleIds, className,
494 userResourceBlockIds)
495 });
496 }
497 else {
498 permissionWhere = permissionWhere.concat(
499 CustomSQLUtil.get(FILTER_BY_RESOURCE_BLOCK_ID));
500
501 permissionWhere = StringUtil.replace(
502 permissionWhere, "[$USER_RESOURCE_BLOCK_ID$]",
503 getUserResourceBlockIdsSQL(
504 permissionChecker, checkGroupId, roleIds, className,
505 userResourceBlockIds));
506 }
507
508 int pos = sql.indexOf(_WHERE_CLAUSE);
509
510 if (pos != -1) {
511 StringBundler sb = new StringBundler(4);
512
513 sb.append(sql.substring(0, pos));
514 sb.append(permissionWhere);
515 sb.append(" AND ");
516 sb.append(sql.substring(pos + 7));
517
518 return sb.toString();
519 }
520
521 pos = sql.indexOf(_GROUP_BY_CLAUSE);
522
523 if (pos != -1) {
524 return sql.substring(0, pos + 1).concat(permissionWhere).concat(
525 sql.substring(pos + 1));
526 }
527
528 pos = sql.indexOf(_ORDER_BY_CLAUSE);
529
530 if (pos != -1) {
531 return sql.substring(0, pos + 1).concat(permissionWhere).concat(
532 sql.substring(pos + 1));
533 }
534
535 return sql.concat(StringPool.SPACE).concat(permissionWhere);
536 }
537
538 protected String replacePermissionCheckJoin(
539 String sql, String className, String classPKField, String userIdField,
540 String groupIdField, long[] groupIds, String bridgeJoin) {
541
542 if (Validator.isNull(classPKField)) {
543 throw new IllegalArgumentException("classPKField is null");
544 }
545
546 PermissionChecker permissionChecker =
547 PermissionThreadLocal.getPermissionChecker();
548
549 long companyId = 0;
550
551 if (groupIds.length == 1) {
552 long groupId = groupIds[0];
553
554 Group group = GroupLocalServiceUtil.fetchGroup(groupId);
555
556 if (group != null) {
557 companyId = group.getCompanyId();
558
559 long[] roleIds = getRoleIds(groupId);
560
561 try {
562 if (ResourcePermissionLocalServiceUtil.
563 hasResourcePermission(
564 companyId, className,
565 ResourceConstants.SCOPE_GROUP,
566 String.valueOf(groupId), roleIds,
567 ActionKeys.VIEW)) {
568
569 return sql;
570 }
571
572 if (ResourcePermissionLocalServiceUtil.
573 hasResourcePermission(
574 companyId, className,
575 ResourceConstants.SCOPE_GROUP_TEMPLATE,
576 String.valueOf(
577 GroupConstants.DEFAULT_PARENT_GROUP_ID),
578 roleIds, ActionKeys.VIEW)) {
579
580 return sql;
581 }
582
583 if (ResourcePermissionLocalServiceUtil.
584 hasResourcePermission(
585 companyId, className,
586 ResourceConstants.SCOPE_COMPANY,
587 String.valueOf(companyId), roleIds,
588 ActionKeys.VIEW)) {
589
590 return sql;
591 }
592 }
593 catch (PortalException pe) {
594 if (_log.isDebugEnabled()) {
595 _log.debug(
596 "Unable to get resource permissions for " +
597 className + " with group " + groupId,
598 pe);
599 }
600 }
601 }
602 }
603 else {
604 for (long groupId : groupIds) {
605 Group group = GroupLocalServiceUtil.fetchGroup(groupId);
606
607 if (group == null) {
608 continue;
609 }
610
611 if (companyId == 0) {
612 companyId = group.getCompanyId();
613
614 continue;
615 }
616
617 if (group.getCompanyId() != companyId) {
618 throw new IllegalArgumentException(
619 "Permission queries across multiple portal instances " +
620 "are not supported");
621 }
622 }
623 }
624
625 if (companyId == 0) {
626 companyId = permissionChecker.getCompanyId();
627 }
628
629 String permissionJoin = StringPool.BLANK;
630
631 if (Validator.isNotNull(bridgeJoin)) {
632 permissionJoin = bridgeJoin;
633 }
634
635 permissionJoin += CustomSQLUtil.get(JOIN_RESOURCE_PERMISSION);
636
637 StringBundler sb = new StringBundler(8);
638
639 sb.append("((ResourcePermission.primKeyId = ");
640 sb.append(classPKField);
641
642 if (Validator.isNotNull(groupIdField) && (groupIds.length > 0)) {
643 sb.append(") AND (");
644
645 sb.append(groupIdField);
646
647 if (groupIds.length > 1) {
648 sb.append(" IN (");
649 sb.append(StringUtil.merge(groupIds));
650 sb.append(StringPool.CLOSE_PARENTHESIS);
651 }
652 else {
653 sb.append(" = ");
654 sb.append(groupIds[0]);
655 }
656 }
657
658 sb.append("))");
659
660 String roleIdsOrOwnerIdSQL = getRoleIdsOrOwnerIdSQL(
661 permissionChecker, groupIds, userIdField);
662
663 int scope = ResourceConstants.SCOPE_INDIVIDUAL;
664
665 permissionJoin = StringUtil.replace(
666 permissionJoin,
667 new String[] {
668 "[$CLASS_NAME$]", "[$COMPANY_ID$]", "[$PRIM_KEYS$]",
669 "[$RESOURCE_SCOPE_INDIVIDUAL$]", "[$ROLE_IDS_OR_OWNER_ID$]"
670 },
671 new String[] {
672 className, String.valueOf(companyId), sb.toString(),
673 String.valueOf(scope), roleIdsOrOwnerIdSQL
674 });
675
676 int pos = sql.indexOf(_WHERE_CLAUSE);
677
678 if (pos != -1) {
679 return sql.substring(0, pos + 1).concat(permissionJoin).concat(
680 sql.substring(pos + 1));
681 }
682
683 pos = sql.indexOf(_GROUP_BY_CLAUSE);
684
685 if (pos != -1) {
686 return sql.substring(0, pos + 1).concat(permissionJoin).concat(
687 sql.substring(pos + 1));
688 }
689
690 pos = sql.indexOf(_ORDER_BY_CLAUSE);
691
692 if (pos != -1) {
693 return sql.substring(0, pos + 1).concat(permissionJoin).concat(
694 sql.substring(pos + 1));
695 }
696
697 return sql.concat(StringPool.SPACE).concat(permissionJoin);
698 }
699
700 private static final String _GROUP_BY_CLAUSE = " GROUP BY ";
701
702 private static final long _NO_RESOURCE_BLOCKS_ID = -1;
703
704 private static final long[] _NO_ROLE_IDS = {0};
705
706 private static final String _ORDER_BY_CLAUSE = " ORDER BY ";
707
708 private static final String _WHERE_CLAUSE = " WHERE ";
709
710 private static final Log _log = LogFactoryUtil.getLog(
711 InlineSQLHelperImpl.class);
712
713 }