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