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