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