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