1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
13   */
14  
15  package com.liferay.portal.security.permission;
16  
17  import com.liferay.portal.NoSuchResourceException;
18  import com.liferay.portal.kernel.log.Log;
19  import com.liferay.portal.kernel.log.LogFactoryUtil;
20  import com.liferay.portal.kernel.util.StringPool;
21  import com.liferay.portal.kernel.util.Validator;
22  import com.liferay.portal.model.Group;
23  import com.liferay.portal.model.GroupConstants;
24  import com.liferay.portal.model.Layout;
25  import com.liferay.portal.model.Organization;
26  import com.liferay.portal.model.Permission;
27  import com.liferay.portal.model.PortletConstants;
28  import com.liferay.portal.model.Resource;
29  import com.liferay.portal.model.ResourceConstants;
30  import com.liferay.portal.model.Role;
31  import com.liferay.portal.model.RoleConstants;
32  import com.liferay.portal.model.UserGroup;
33  import com.liferay.portal.security.permission.comparator.PermissionActionIdComparator;
34  import com.liferay.portal.service.GroupLocalServiceUtil;
35  import com.liferay.portal.service.LayoutLocalServiceUtil;
36  import com.liferay.portal.service.OrganizationLocalServiceUtil;
37  import com.liferay.portal.service.PermissionLocalServiceUtil;
38  import com.liferay.portal.service.ResourceLocalServiceUtil;
39  import com.liferay.portal.service.ResourcePermissionLocalServiceUtil;
40  import com.liferay.portal.service.RoleLocalServiceUtil;
41  import com.liferay.portal.service.UserGroupLocalServiceUtil;
42  import com.liferay.portal.service.permission.PortletPermissionUtil;
43  import com.liferay.portal.util.PropsValues;
44  import com.liferay.util.UniqueList;
45  
46  import java.util.ArrayList;
47  import java.util.Collections;
48  import java.util.HashMap;
49  import java.util.List;
50  import java.util.Map;
51  
52  import org.apache.commons.lang.time.StopWatch;
53  
54  /**
55   * <a href="AdvancedPermissionChecker.java.html"><b><i>View Source</i></b></a>
56   *
57   * @author Charles May
58   * @author Brian Wing Shun Chan
59   * @author Raymond Augé
60   * @author Wesley Gong
61   */
62  public class AdvancedPermissionChecker extends BasePermissionChecker {
63  
64      public PermissionCheckerBag getUserBag(long userId, long groupId)
65          throws Exception {
66  
67          PermissionCheckerBag bag = PermissionCacheUtil.getBag(userId, groupId);
68  
69          if (bag != null) {
70              return bag;
71          }
72  
73          try {
74  
75              Group group = null;
76  
77              if (groupId > 0) {
78                  group = GroupLocalServiceUtil.getGroup(groupId);
79              }
80  
81              List<Group> userGroups = GroupLocalServiceUtil.getUserGroups(
82                  userId, true);
83  
84              List<Organization> userOrgs = getUserOrgs(userId);
85  
86              List<Group> userOrgGroups =
87                  GroupLocalServiceUtil.getOrganizationsGroups(userOrgs);
88  
89              List<UserGroup> userUserGroups =
90                  UserGroupLocalServiceUtil.getUserUserGroups(userId);
91  
92              List<Group> userUserGroupGroups =
93                  GroupLocalServiceUtil.getUserGroupsGroups(userUserGroups);
94  
95              List<Group> groups = new ArrayList<Group>(
96                  userGroups.size() + userOrgGroups.size() +
97                      userUserGroupGroups.size());
98  
99              groups.addAll(userGroups);
100             groups.addAll(userOrgGroups);
101             groups.addAll(userUserGroupGroups);
102 
103             List<Role> roles = new UniqueList<Role>();
104 
105             if ((PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 3) ||
106                 (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 4) ||
107                 (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 5) ||
108                 (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 6)) {
109 
110                 if (groups.size() > 0) {
111                     List<Role> userRelatedRoles=
112                         RoleLocalServiceUtil.getUserRelatedRoles(
113                             userId, groups);
114 
115                     roles.addAll(userRelatedRoles);
116                 }
117                 else {
118                     roles.addAll(RoleLocalServiceUtil.getUserRoles(userId));
119                 }
120 
121                 List<Role> userGroupRoles =
122                     RoleLocalServiceUtil.getUserGroupRoles(userId, groupId);
123 
124                 roles.addAll(userGroupRoles);
125 
126                 List<Role> userGroupGroupRoles =
127                     RoleLocalServiceUtil.getUserGroupGroupRoles(
128                         userId, groupId);
129 
130                 roles.addAll(userGroupGroupRoles);
131 
132                 if ((group != null) &&
133                     ((group.isCommunity() && userGroups.contains(group)) ||
134                      (group.isOrganization() &&
135                         userOrgGroups.contains(group)))) {
136 
137                     addRequiredMemberRole(group, roles);
138                 }
139             }
140             else {
141                 roles = new ArrayList<Role>();
142             }
143 
144             bag = new PermissionCheckerBagImpl(
145                 userId, userGroups, userOrgs, userOrgGroups,
146                 userUserGroupGroups, groups, roles);
147 
148             return bag;
149         }
150         finally {
151             if (bag == null) {
152                 bag = new PermissionCheckerBagImpl(
153                     userId, new ArrayList<Group>(),
154                     new ArrayList<Organization>(), new ArrayList<Group>(),
155                     new ArrayList<Group>(), new ArrayList<Group>(),
156                     new ArrayList<Role>());
157             }
158 
159             PermissionCacheUtil.putBag(userId, groupId, bag);
160         }
161     }
162 
163     public boolean hasOwnerPermission(
164         long companyId, String name, String primKey, long ownerId,
165         String actionId) {
166 
167         if (ownerId != getUserId()) {
168             return false;
169         }
170 
171         if (ownerId == defaultUserId) {
172             if (actionId.equals(ActionKeys.VIEW)) {
173                 return true;
174             }
175             else {
176                 return false;
177             }
178         }
179 
180         try {
181             if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 6) {
182                 return ResourcePermissionLocalServiceUtil.hasResourcePermission(
183                     companyId, name, ResourceConstants.SCOPE_INDIVIDUAL,
184                     primKey, getOwnerRoleId(), actionId);
185             }
186             else {
187                 ResourceActionsUtil.checkAction(name, actionId);
188 
189                 Resource resource = ResourceLocalServiceUtil.getResource(
190                     companyId, name, ResourceConstants.SCOPE_INDIVIDUAL,
191                     primKey);
192 
193                 List<Permission> permissions =
194                     PermissionLocalServiceUtil.getRolePermissions(
195                         getOwnerRoleId(), resource.getResourceId());
196 
197                 int pos = Collections.binarySearch(
198                     permissions, actionId, new PermissionActionIdComparator());
199 
200                 if (pos >= 0) {
201                     return true;
202                 }
203             }
204         }
205         catch (Exception e) {
206             if (_log.isDebugEnabled()) {
207                 _log.debug(e, e);
208             }
209         }
210 
211         return false;
212     }
213 
214     public boolean hasPermission(
215         long groupId, String name, String primKey, String actionId) {
216 
217         StopWatch stopWatch = null;
218 
219         if (_log.isDebugEnabled()) {
220             stopWatch = new StopWatch();
221 
222             stopWatch.start();
223         }
224 
225         Group group = null;
226 
227         // If the current group is a staging group, check the live group. If the
228         // current group is a scope group for a layout, check the original
229         // group.
230 
231         try {
232             if (groupId > 0) {
233                 group = GroupLocalServiceUtil.getGroup(groupId);
234 
235                 if (group.isLayout()) {
236                     Layout layout = LayoutLocalServiceUtil.getLayout(
237                         group.getClassPK());
238 
239                     groupId = layout.getGroupId();
240 
241                     group = GroupLocalServiceUtil.getGroup(groupId);
242                 }
243 
244                 if (group.isStagingGroup()) {
245                     if (primKey.equals(String.valueOf(groupId))) {
246                         primKey = String.valueOf(group.getLiveGroupId());
247                     }
248 
249                     groupId = group.getLiveGroupId();
250                     group = group.getLiveGroup();
251                 }
252             }
253         }
254         catch (Exception e) {
255             _log.error(e, e);
256         }
257 
258         Boolean value = PermissionCacheUtil.getPermission(
259             user.getUserId(), groupId, name, primKey, actionId);
260 
261         if (value == null) {
262             try {
263                 value = Boolean.valueOf(
264                     hasPermissionImpl(groupId, name, primKey, actionId));
265 
266                 if (_log.isDebugEnabled()) {
267                     _log.debug(
268                         "Checking permission for " + groupId + " " + name +
269                             " " + primKey + " " + actionId + " takes " +
270                                 stopWatch.getTime() + " ms");
271                 }
272             }
273             finally {
274                 if (value == null) {
275                     value = Boolean.FALSE;
276                 }
277 
278                 PermissionCacheUtil.putPermission(
279                     user.getUserId(), groupId, name, primKey, actionId, value);
280             }
281         }
282 
283         return value.booleanValue();
284     }
285 
286     public boolean hasUserPermission(
287         long groupId, String name, String primKey, String actionId,
288         boolean checkAdmin) {
289 
290         try {
291             return hasUserPermissionImpl(
292                 groupId, name, primKey, actionId, checkAdmin);
293         }
294         catch (Exception e) {
295             _log.error(e, e);
296 
297             return false;
298         }
299     }
300 
301     public boolean isCommunityAdmin(long groupId) {
302         try {
303             return isCommunityAdminImpl(groupId);
304         }
305         catch (Exception e) {
306             _log.error(e, e);
307 
308             return false;
309         }
310     }
311 
312     public boolean isCommunityOwner(long groupId) {
313         try {
314             return isCommunityOwnerImpl(groupId);
315         }
316         catch (Exception e) {
317             _log.error(e, e);
318 
319             return false;
320         }
321     }
322 
323     public boolean isCompanyAdmin() {
324         try {
325             return isCompanyAdminImpl();
326         }
327         catch (Exception e) {
328             _log.error(e, e);
329 
330             return false;
331         }
332     }
333 
334     public boolean isCompanyAdmin(long companyId) {
335         try {
336             return isCompanyAdminImpl(companyId);
337         }
338         catch (Exception e) {
339             _log.error(e, e);
340 
341             return false;
342         }
343     }
344 
345     protected void addRequiredMemberRole(Group group, List<Role> roles)
346         throws Exception {
347 
348         if (group.isCommunity()) {
349             Role communityMemberRole = RoleLocalServiceUtil.getRole(
350                 group.getCompanyId(), RoleConstants.COMMUNITY_MEMBER);
351 
352             roles.add(communityMemberRole);
353         }
354         else if (group.isOrganization()) {
355             Role organizationMemberRole = RoleLocalServiceUtil.getRole(
356                 group.getCompanyId(), RoleConstants.ORGANIZATION_MEMBER);
357 
358             roles.add(organizationMemberRole);
359         }
360     }
361 
362     protected List<Resource> getResources(
363             long companyId, long groupId, String name, String primKey,
364             String actionId)
365         throws Exception {
366 
367         // Individual
368 
369         List<Resource> resources = new ArrayList<Resource>(4);
370 
371         try {
372             Resource resource = ResourceLocalServiceUtil.getResource(
373                 companyId, name, ResourceConstants.SCOPE_INDIVIDUAL, primKey);
374 
375             resources.add(resource);
376         }
377         catch (NoSuchResourceException nsre) {
378             if (_log.isWarnEnabled()) {
379                 _log.warn(
380                     "Resource " + companyId + " " + name + " " +
381                         ResourceConstants.SCOPE_INDIVIDUAL + " " + primKey +
382                             " does not exist");
383             }
384         }
385 
386         // Group
387 
388         try {
389             if (groupId > 0) {
390                 Resource resource = ResourceLocalServiceUtil.getResource(
391                     companyId, name, ResourceConstants.SCOPE_GROUP,
392                     String.valueOf(groupId));
393 
394                 resources.add(resource);
395             }
396         }
397         catch (NoSuchResourceException nsre) {
398             if (_log.isWarnEnabled()) {
399                 _log.warn(
400                     "Resource " + companyId + " " + name + " " +
401                         ResourceConstants.SCOPE_GROUP + " " + groupId +
402                             " does not exist");
403             }
404         }
405 
406         // Group template
407 
408         try {
409             if (signedIn && (groupId > 0)) {
410                 Resource resource = ResourceLocalServiceUtil.getResource(
411                     companyId, name, ResourceConstants.SCOPE_GROUP_TEMPLATE,
412                     String.valueOf(GroupConstants.DEFAULT_PARENT_GROUP_ID));
413 
414                 resources.add(resource);
415             }
416         }
417         catch (NoSuchResourceException nsre) {
418             if (_log.isWarnEnabled()) {
419                 _log.warn(
420                     "Resource " + companyId + " " + name + " " +
421                         ResourceConstants.SCOPE_GROUP_TEMPLATE + " " +
422                             GroupConstants.DEFAULT_PARENT_GROUP_ID +
423                                 " does not exist");
424             }
425         }
426 
427         // Company
428 
429         try {
430             Resource resource = ResourceLocalServiceUtil.getResource(
431                 companyId, name, ResourceConstants.SCOPE_COMPANY,
432                 String.valueOf(companyId));
433 
434             resources.add(resource);
435         }
436         catch (NoSuchResourceException nsre) {
437             if (_log.isWarnEnabled()) {
438                 _log.warn(
439                     "Resource " + companyId + " " + name + " " +
440                         ResourceConstants.SCOPE_COMPANY + " " + companyId +
441                             " does not exist");
442             }
443         }
444 
445         return resources;
446     }
447 
448     protected List<Organization> getUserOrgs(long userId) throws Exception {
449         List<Organization> userOrgs =
450             OrganizationLocalServiceUtil.getUserOrganizations(userId, true);
451 
452         if (userOrgs.size() == 0) {
453             return userOrgs;
454         }
455 
456         List<Organization> organizations = new UniqueList<Organization>();
457 
458         for (Organization organization : userOrgs) {
459             if (!organizations.contains(organization)) {
460                 organizations.add(organization);
461 
462                 List<Organization> ancestorOrganizations =
463                     OrganizationLocalServiceUtil.getParentOrganizations(
464                         organization.getOrganizationId());
465 
466                 organizations.addAll(ancestorOrganizations);
467             }
468         }
469 
470         return organizations;
471     }
472 
473     protected boolean hasGuestPermission(
474             long groupId, String name, String primKey, String actionId)
475         throws Exception {
476 
477         ResourceActionsUtil.checkAction(name, actionId);
478 
479         if (name.indexOf(StringPool.PERIOD) != -1) {
480 
481             // Check unsupported model actions
482 
483             List<String> actions = ResourceActionsUtil.
484                 getModelResourceGuestUnsupportedActions(name);
485 
486             if (actions.contains(actionId)) {
487                 return false;
488             }
489         }
490         else {
491 
492             // Check unsupported portlet actions
493 
494             List<String> actions = ResourceActionsUtil.
495                 getPortletResourceGuestUnsupportedActions(name);
496 
497             if (actions.contains(actionId)) {
498                 return false;
499             }
500         }
501 
502         long companyId = user.getCompanyId();
503 
504         List<Resource> resources = getResources(
505             companyId, groupId, name, primKey, actionId);
506 
507         Group guestGroup = GroupLocalServiceUtil.getGroup(
508             companyId, GroupConstants.GUEST);
509 
510         PermissionCheckerBag bag = PermissionCacheUtil.getBag(
511             defaultUserId, guestGroup.getGroupId());
512 
513         if (bag == null) {
514             try {
515                 List<Group> groups = new ArrayList<Group>();
516 
517                 groups.add(guestGroup);
518 
519                 List<Role> roles = RoleLocalServiceUtil.getUserRelatedRoles(
520                     defaultUserId, groups);
521 
522                 bag = new PermissionCheckerBagImpl(
523                     defaultUserId, new ArrayList<Group>(),
524                     new ArrayList<Organization>(), new ArrayList<Group>(),
525                     new ArrayList<Group>(), new ArrayList<Group>(), roles);
526             }
527             finally {
528                 if (bag == null) {
529                     bag = new PermissionCheckerBagImpl(
530                         defaultUserId, new ArrayList<Group>(),
531                         new ArrayList<Organization>(), new ArrayList<Group>(),
532                         new ArrayList<Group>(), new ArrayList<Group>(),
533                         new ArrayList<Role>());
534                 }
535 
536                 PermissionCacheUtil.putBag(
537                     defaultUserId, guestGroup.getGroupId(), bag);
538             }
539         }
540 
541         try {
542             return PermissionLocalServiceUtil.hasUserPermissions(
543                 defaultUserId, groupId, resources, actionId, bag);
544         }
545         catch (Exception e) {
546             _log.error(e, e);
547 
548             return false;
549         }
550     }
551 
552     protected boolean hasPermissionImpl(
553         long groupId, String name, String primKey, String actionId) {
554 
555         try {
556             if (!signedIn) {
557                 return hasGuestPermission(groupId, name, primKey, actionId);
558             }
559             else {
560                 boolean value = false;
561 
562                 if (checkGuest) {
563                     value = hasGuestPermission(
564                         groupId, name, primKey, actionId);
565                 }
566 
567                 if (!value) {
568                     value = hasUserPermission(
569                         groupId, name, primKey, actionId, true);
570                 }
571 
572                 return value;
573             }
574         }
575         catch (Exception e) {
576             _log.error(e, e);
577 
578             return false;
579         }
580     }
581 
582     protected boolean hasUserPermissionImpl(
583             long groupId, String name, String primKey, String actionId,
584             boolean checkAdmin)
585         throws Exception {
586 
587         StopWatch stopWatch = null;
588 
589         if (_log.isDebugEnabled()) {
590             stopWatch = new StopWatch();
591 
592             stopWatch.start();
593         }
594 
595         long companyId = user.getCompanyId();
596 
597         boolean hasLayoutManagerPermission = true;
598 
599         // Check if the layout manager has permission to do this action for the
600         // current portlet
601 
602         if ((Validator.isNotNull(name)) && (Validator.isNotNull(primKey)) &&
603             (primKey.indexOf(PortletConstants.LAYOUT_SEPARATOR) != -1)) {
604 
605             hasLayoutManagerPermission =
606                 PortletPermissionUtil.hasLayoutManagerPermission(
607                     name, actionId);
608         }
609 
610         if (checkAdmin &&
611             (isCompanyAdminImpl(companyId) ||
612                 (isCommunityAdminImpl(groupId) &&
613                     hasLayoutManagerPermission))) {
614 
615             return true;
616         }
617 
618         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 1);
619 
620         List<Resource> resources = getResources(
621             companyId, groupId, name, primKey, actionId);
622 
623         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 2);
624 
625         // Check if user has access to perform the action on the given
626         // resource scopes. The resources are scoped to check first for an
627         // individual class, then for the group that the class may belong
628         // to, and then for the company that the class belongs to.
629 
630         PermissionCheckerBag bag = getUserBag(user.getUserId(), groupId);
631 
632         boolean value = PermissionLocalServiceUtil.hasUserPermissions(
633             user.getUserId(), groupId, resources, actionId, bag);
634 
635         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 3);
636 
637         return value;
638     }
639 
640     protected boolean isCommunityAdminImpl(long groupId) throws Exception {
641         if (!signedIn) {
642             return false;
643         }
644 
645         if (isOmniadmin()) {
646             return true;
647         }
648 
649         if (groupId <= 0) {
650             return false;
651         }
652 
653         Group group = GroupLocalServiceUtil.getGroup(groupId);
654 
655         if (isCompanyAdmin(group.getCompanyId())) {
656             return true;
657         }
658 
659         PermissionCheckerBag bag = getUserBag(user.getUserId(), groupId);
660 
661         if (bag == null) {
662             _log.error("Bag should never be null");
663         }
664 
665         if (bag.isCommunityAdmin(this, group)) {
666             return true;
667         }
668         else {
669             return false;
670         }
671     }
672 
673     protected boolean isCommunityOwnerImpl(long groupId) throws Exception {
674         if (!signedIn) {
675             return false;
676         }
677 
678         if (isOmniadmin()) {
679             return true;
680         }
681 
682         if (groupId <= 0) {
683             return false;
684         }
685 
686         Group group = GroupLocalServiceUtil.getGroup(groupId);
687 
688         if (isCompanyAdmin(group.getCompanyId())) {
689             return true;
690         }
691 
692         PermissionCheckerBag bag = getUserBag(user.getUserId(), groupId);
693 
694         if (bag == null) {
695             _log.error("Bag should never be null");
696         }
697 
698         if (bag.isCommunityOwner(this, group)) {
699             return true;
700         }
701         else {
702             return false;
703         }
704     }
705 
706     protected boolean isCompanyAdminImpl() throws Exception {
707         return isCompanyAdminImpl(user.getCompanyId());
708     }
709 
710     protected boolean isCompanyAdminImpl(long companyId) throws Exception {
711         if (!signedIn) {
712             return false;
713         }
714 
715         if (isOmniadmin()) {
716             return true;
717         }
718 
719         Boolean value = companyAdmins.get(companyId);
720 
721         if (value == null) {
722             boolean hasAdminRole = RoleLocalServiceUtil.hasUserRole(
723                 user.getUserId(), companyId, RoleConstants.ADMINISTRATOR, true);
724 
725             value = Boolean.valueOf(hasAdminRole);
726 
727             companyAdmins.put(companyId, value);
728         }
729 
730         return value.booleanValue();
731     }
732 
733     protected void logHasUserPermission(
734         long groupId, String name, String primKey, String actionId,
735         StopWatch stopWatch, int block) {
736 
737         if (!_log.isDebugEnabled()) {
738             return;
739         }
740 
741         _log.debug(
742             "Checking user permission block " + block + " for " + groupId +
743                 " " + name + " " + primKey + " " + actionId + " takes " +
744                     stopWatch.getTime() + " ms");
745     }
746 
747     /**
748      * @deprecated
749      */
750     protected static final String RESULTS_SEPARATOR = "_RESULTS_SEPARATOR_";
751 
752     protected Map<Long, Boolean> companyAdmins = new HashMap<Long, Boolean>();
753 
754     private static Log _log = LogFactoryUtil.getLog(
755         AdvancedPermissionChecker.class);
756 
757 }