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