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.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   */
61  public class AdvancedPermissionChecker extends BasePermissionChecker {
62  
63      public PermissionCheckerBag getUserBag(long userId, long groupId)
64          throws Exception {
65  
66          PermissionCheckerBag bag = PermissionCacheUtil.getBag(userId, groupId);
67  
68          if (bag != null) {
69              return bag;
70          }
71  
72          try {
73  
74              // If we are checking permissions on an object that belongs to a
75              // community, then it's only necessary to check the group that
76              // represents the community and not all the groups that the user
77              // belongs to. This is so because an object cannot belong to
78              // more than one community.
79  
80              List<Group> userGroups = new ArrayList<Group>();
81              //List<Group> userGroups = UserUtil.getGroups(userId);
82  
83              if (groupId > 0) {
84                  if (GroupLocalServiceUtil.hasUserGroup(userId, groupId)) {
85                      Group group = GroupLocalServiceUtil.getGroup(groupId);
86  
87                      userGroups.add(group);
88                  }
89              }
90  
91              List<Organization> userOrgs = getUserOrgs(userId);
92  
93              List<Group> userOrgGroups =
94                  GroupLocalServiceUtil.getOrganizationsGroups(userOrgs);
95  
96              List<UserGroup> userUserGroups =
97                  UserGroupLocalServiceUtil.getUserUserGroups(userId);
98  
99              List<Group> userUserGroupGroups =
100                 GroupLocalServiceUtil.getUserGroupsGroups(userUserGroups);
101 
102             List<Group> groups = new ArrayList<Group>(
103                 userGroups.size() + userOrgGroups.size() +
104                     userUserGroupGroups.size());
105 
106             groups.addAll(userGroups);
107             groups.addAll(userOrgGroups);
108             groups.addAll(userUserGroupGroups);
109 
110             List<Role> roles = new UniqueList<Role>();
111 
112             if ((PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 3) ||
113                 (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 4) ||
114                 (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 5) ||
115                 (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 6)) {
116 
117                 if (groups.size() > 0) {
118                     List<Role> userRelatedRoles=
119                         RoleLocalServiceUtil.getUserRelatedRoles(
120                             userId, groups);
121 
122                     roles.addAll(userRelatedRoles);
123                 }
124                 else {
125                     roles.addAll(RoleLocalServiceUtil.getUserRoles(userId));
126                 }
127 
128                 List<Role> userGroupRoles =
129                     RoleLocalServiceUtil.getUserGroupRoles(userId, groupId);
130 
131                 roles.addAll(userGroupRoles);
132 
133                 List<Role> userGroupGroupRoles =
134                     RoleLocalServiceUtil.getUserGroupGroupRoles(
135                         userId, groupId);
136 
137                 roles.addAll(userGroupGroupRoles);
138 
139                 if (!userGroups.isEmpty()) {
140                     Group group = userGroups.get(0);
141 
142                     addRequiredMemberRole(group, roles);
143                 }
144             }
145             else {
146                 roles = new ArrayList<Role>();
147             }
148 
149             bag = new PermissionCheckerBagImpl(
150                 userId, userGroups, userOrgs, userOrgGroups,
151                 userUserGroupGroups, groups, roles);
152 
153             return bag;
154         }
155         finally {
156             if (bag == null) {
157                 bag = new PermissionCheckerBagImpl(
158                     userId, new ArrayList<Group>(),
159                     new ArrayList<Organization>(), new ArrayList<Group>(),
160                     new ArrayList<Group>(), new ArrayList<Group>(),
161                     new ArrayList<Role>());
162             }
163 
164             PermissionCacheUtil.putBag(userId, groupId, bag);
165         }
166     }
167 
168     public boolean hasOwnerPermission(
169         long companyId, String name, String primKey, long ownerId,
170         String actionId) {
171 
172         if (ownerId != getUserId()) {
173             return false;
174         }
175 
176         if (ownerId == defaultUserId) {
177             if (actionId == ActionKeys.VIEW) {
178                 return true;
179             }
180             else {
181                 return false;
182             }
183         }
184 
185         try {
186             if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 6) {
187                 return ResourcePermissionLocalServiceUtil.hasResourcePermission(
188                     companyId, name, ResourceConstants.SCOPE_INDIVIDUAL,
189                     primKey, getOwnerRoleId(), actionId);
190             }
191             else {
192                 Resource resource = ResourceLocalServiceUtil.getResource(
193                     companyId, name, ResourceConstants.SCOPE_INDIVIDUAL,
194                     primKey);
195 
196                 List<Permission> permissions =
197                     PermissionLocalServiceUtil.getRolePermissions(
198                         getOwnerRoleId(), resource.getResourceId());
199 
200                 int pos = Collections.binarySearch(
201                     permissions, actionId, new PermissionActionIdComparator());
202 
203                 if (pos >= 0) {
204                     return true;
205                 }
206             }
207         }
208         catch (Exception e) {
209             if (_log.isDebugEnabled()) {
210                 _log.debug(e, e);
211             }
212         }
213 
214         return false;
215     }
216 
217     public boolean hasPermission(
218         long groupId, String name, String primKey, String actionId) {
219 
220         StopWatch stopWatch = null;
221 
222         if (_log.isDebugEnabled()) {
223             stopWatch = new StopWatch();
224 
225             stopWatch.start();
226         }
227 
228         Group group = null;
229 
230         // If the current group is a staging group, check the live group. If the
231         // current group is a scope group for a layout, check the original
232         // group.
233 
234         try {
235             if (groupId > 0) {
236                 group = GroupLocalServiceUtil.getGroup(groupId);
237 
238                 if (group.isStagingGroup()) {
239                     if (primKey.equals(String.valueOf(groupId))) {
240                         primKey = String.valueOf(group.getLiveGroupId());
241                     }
242 
243                     groupId = group.getLiveGroupId();
244                     group = group.getLiveGroup();
245                 }
246                 else if (group.isLayout()) {
247                     Layout layout = LayoutLocalServiceUtil.getLayout(
248                         group.getClassPK());
249 
250                     groupId = layout.getGroupId();
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         if (name.indexOf(StringPool.PERIOD) != -1) {
478 
479             // Check unsupported model actions
480 
481             List<String> actions = ResourceActionsUtil.
482                 getModelResourceGuestUnsupportedActions(name);
483 
484             if (actions.contains(actionId)) {
485                 return false;
486             }
487         }
488         else {
489 
490             // Check unsupported portlet actions
491 
492             List<String> actions = ResourceActionsUtil.
493                 getPortletResourceGuestUnsupportedActions(name);
494 
495             if (actions.contains(actionId)) {
496                 return false;
497             }
498         }
499 
500         long companyId = user.getCompanyId();
501 
502         List<Resource> resources = getResources(
503             companyId, groupId, name, primKey, actionId);
504 
505         Group guestGroup = GroupLocalServiceUtil.getGroup(
506             companyId, GroupConstants.GUEST);
507 
508         PermissionCheckerBag bag = PermissionCacheUtil.getBag(
509             defaultUserId, guestGroup.getGroupId());
510 
511         if (bag == null) {
512             try {
513                 List<Group> groups = new ArrayList<Group>();
514 
515                 groups.add(guestGroup);
516 
517                 List<Role> roles = RoleLocalServiceUtil.getUserRelatedRoles(
518                     defaultUserId, groups);
519 
520                 bag = new PermissionCheckerBagImpl(
521                     defaultUserId, new ArrayList<Group>(),
522                     new ArrayList<Organization>(), new ArrayList<Group>(),
523                     new ArrayList<Group>(), new ArrayList<Group>(), roles);
524             }
525             finally {
526                 if (bag == null) {
527                     bag = new PermissionCheckerBagImpl(
528                         defaultUserId, new ArrayList<Group>(),
529                         new ArrayList<Organization>(), new ArrayList<Group>(),
530                         new ArrayList<Group>(), new ArrayList<Group>(),
531                         new ArrayList<Role>());
532                 }
533 
534                 PermissionCacheUtil.putBag(
535                     defaultUserId, guestGroup.getGroupId(), bag);
536             }
537         }
538 
539         try {
540             return PermissionLocalServiceUtil.hasUserPermissions(
541                 defaultUserId, groupId, resources, actionId, bag);
542         }
543         catch (Exception e) {
544             _log.error(e, e);
545 
546             return false;
547         }
548     }
549 
550     protected boolean hasPermissionImpl(
551         long groupId, String name, String primKey, String actionId) {
552 
553         try {
554             if (!signedIn) {
555                 return hasGuestPermission(groupId, name, primKey, actionId);
556             }
557             else {
558                 boolean value = false;
559 
560                 if (checkGuest) {
561                     value = hasGuestPermission(
562                         groupId, name, primKey, actionId);
563                 }
564 
565                 if (!value) {
566                     value = hasUserPermission(
567                         groupId, name, primKey, actionId, true);
568                 }
569 
570                 return value;
571             }
572         }
573         catch (Exception e) {
574             _log.error(e, e);
575 
576             return false;
577         }
578     }
579 
580     protected boolean hasUserPermissionImpl(
581             long groupId, String name, String primKey, String actionId,
582             boolean checkAdmin)
583         throws Exception {
584 
585         StopWatch stopWatch = null;
586 
587         if (_log.isDebugEnabled()) {
588             stopWatch = new StopWatch();
589 
590             stopWatch.start();
591         }
592 
593         long companyId = user.getCompanyId();
594 
595         boolean hasLayoutManagerPermission = true;
596 
597         // Check if the layout manager has permission to do this action for the
598         // current portlet
599 
600         if ((Validator.isNotNull(name)) && (Validator.isNotNull(primKey)) &&
601             (primKey.indexOf(PortletConstants.LAYOUT_SEPARATOR) != -1)) {
602 
603             hasLayoutManagerPermission =
604                 PortletPermissionUtil.hasLayoutManagerPermission(
605                     name, actionId);
606         }
607 
608         if (checkAdmin &&
609             (isCompanyAdminImpl(companyId) ||
610                 (isCommunityAdminImpl(groupId) &&
611                     hasLayoutManagerPermission))) {
612 
613             return true;
614         }
615 
616         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 1);
617 
618         List<Resource> resources = getResources(
619             companyId, groupId, name, primKey, actionId);
620 
621         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 2);
622 
623         // Check if user has access to perform the action on the given
624         // resource scopes. The resources are scoped to check first for an
625         // individual class, then for the group that the class may belong
626         // to, and then for the company that the class belongs to.
627 
628         PermissionCheckerBag bag = getUserBag(user.getUserId(), groupId);
629 
630         boolean value = PermissionLocalServiceUtil.hasUserPermissions(
631             user.getUserId(), groupId, resources, actionId, bag);
632 
633         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 3);
634 
635         return value;
636     }
637 
638     protected boolean isCommunityAdminImpl(long groupId) throws Exception {
639         if (!signedIn) {
640             return false;
641         }
642 
643         if (isOmniadmin()) {
644             return true;
645         }
646 
647         if (groupId <= 0) {
648             return false;
649         }
650 
651         Group group = GroupLocalServiceUtil.getGroup(groupId);
652 
653         if (isCompanyAdmin(group.getCompanyId())) {
654             return true;
655         }
656 
657         PermissionCheckerBag bag = getUserBag(user.getUserId(), groupId);
658 
659         if (bag == null) {
660             _log.error("Bag should never be null");
661         }
662 
663         if (bag.isCommunityAdmin(this, group)) {
664             return true;
665         }
666         else {
667             return false;
668         }
669     }
670 
671     protected boolean isCommunityOwnerImpl(long groupId) throws Exception {
672         if (!signedIn) {
673             return false;
674         }
675 
676         if (isOmniadmin()) {
677             return true;
678         }
679 
680         if (groupId <= 0) {
681             return false;
682         }
683 
684         Group group = GroupLocalServiceUtil.getGroup(groupId);
685 
686         if (isCompanyAdmin(group.getCompanyId())) {
687             return true;
688         }
689 
690         PermissionCheckerBag bag = getUserBag(user.getUserId(), groupId);
691 
692         if (bag == null) {
693             _log.error("Bag should never be null");
694         }
695 
696         if (bag.isCommunityOwner(this, group)) {
697             return true;
698         }
699         else {
700             return false;
701         }
702     }
703 
704     protected boolean isCompanyAdminImpl() throws Exception {
705         return isCompanyAdminImpl(user.getCompanyId());
706     }
707 
708     protected boolean isCompanyAdminImpl(long companyId) throws Exception {
709         if (!signedIn) {
710             return false;
711         }
712 
713         if (isOmniadmin()) {
714             return true;
715         }
716 
717         Boolean value = companyAdmins.get(companyId);
718 
719         if (value == null) {
720             boolean hasAdminRole = RoleLocalServiceUtil.hasUserRole(
721                 user.getUserId(), companyId, RoleConstants.ADMINISTRATOR, true);
722 
723             value = Boolean.valueOf(hasAdminRole);
724 
725             companyAdmins.put(companyId, value);
726         }
727 
728         return value.booleanValue();
729     }
730 
731     protected void logHasUserPermission(
732         long groupId, String name, String primKey, String actionId,
733         StopWatch stopWatch, int block) {
734 
735         if (!_log.isDebugEnabled()) {
736             return;
737         }
738 
739         _log.debug(
740             "Checking user permission block " + block + " for " + groupId +
741                 " " + name + " " + primKey + " " + actionId + " takes " +
742                     stopWatch.getTime() + " ms");
743     }
744 
745     /**
746      * @deprecated
747      */
748     protected static final String RESULTS_SEPARATOR = "_RESULTS_SEPARATOR_";
749 
750     protected Map<Long, Boolean> companyAdmins = new HashMap<Long, Boolean>();
751 
752     private static Log _log = LogFactoryUtil.getLog(
753         AdvancedPermissionChecker.class);
754 
755 }