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