1   /**
2    * Copyright (c) 2000-2007 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions 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.security.permission.PermissionChecker;
27  import com.liferay.portal.kernel.security.permission.PermissionCheckerBag;
28  import com.liferay.portal.kernel.util.GetterUtil;
29  import com.liferay.portal.kernel.util.StringPool;
30  import com.liferay.portal.model.Group;
31  import com.liferay.portal.model.Organization;
32  import com.liferay.portal.model.Resource;
33  import com.liferay.portal.model.User;
34  import com.liferay.portal.model.impl.GroupImpl;
35  import com.liferay.portal.model.impl.ResourceImpl;
36  import com.liferay.portal.service.GroupServiceUtil;
37  import com.liferay.portal.service.OrganizationLocalServiceUtil;
38  import com.liferay.portal.service.OrganizationServiceUtil;
39  import com.liferay.portal.service.PermissionServiceUtil;
40  import com.liferay.portal.service.ResourceServiceUtil;
41  import com.liferay.portal.service.RoleServiceUtil;
42  import com.liferay.portal.service.UserGroupServiceUtil;
43  import com.liferay.portal.service.UserServiceUtil;
44  import com.liferay.portal.util.PropsUtil;
45  import com.liferay.portlet.admin.util.OmniadminUtil;
46  import com.liferay.util.CollectionFactory;
47  
48  import java.io.Serializable;
49  
50  import java.util.ArrayList;
51  import java.util.Iterator;
52  import java.util.List;
53  import java.util.Map;
54  
55  import javax.portlet.PortletRequest;
56  
57  import org.apache.commons.lang.time.StopWatch;
58  import org.apache.commons.logging.Log;
59  import org.apache.commons.logging.LogFactory;
60  
61  /**
62   * <a href="PermissionCheckerImpl.java.html"><b><i>View Source</i></b></a>
63   *
64   * @author Charles May
65   * @author Brian Wing Shun Chan
66   *
67   */
68  public class PermissionCheckerImpl implements PermissionChecker, Serializable {
69  
70      public static final int USER_CHECK_ALGORITHM = GetterUtil.getInteger(
71          PropsUtil.get(PropsUtil.PERMISSIONS_USER_CHECK_ALGORITHM));
72  
73      public PermissionCheckerImpl() {
74      }
75  
76      public void init(User user, boolean checkGuest) {
77          this.user = user;
78  
79          if (user.isDefaultUser()) {
80              this.defaultUserId = user.getUserId();
81              this.signedIn = false;
82          }
83          else {
84              try {
85                  this.defaultUserId = UserServiceUtil.getDefaultUserId(
86                      user.getCompanyId());
87              }
88              catch (Exception e) {
89                  _log.error(e, e);
90              }
91  
92              this.signedIn = true;
93          }
94  
95          this.checkGuest = checkGuest;
96      }
97  
98      public void recycle() {
99          user = null;
100         defaultUserId = 0;
101         signedIn = false;
102         checkGuest = false;
103         bags.clear();
104         omniadmin = null;
105         resetValues();
106     }
107 
108     public void setValues(PortletRequest req) {
109 
110         // This method is called in com.liferay.portlet.StrutsPortlet to allow
111         // developers to hook in additiona parameters from the portlet request.
112         // Don't overwrite this method unless you're using Liferay in a 2 tier
113         // environment and don't expect to make remote calls. Remote calls to
114         // service beans will not have any values set from the portlet request.
115 
116     }
117 
118     public void resetValues() {
119     }
120 
121     public User getUser() {
122         return user;
123     }
124 
125     public void setUser(User user) {
126         this.user = user;
127     }
128 
129     public long getUserId() {
130         return user.getUserId();
131     }
132 
133     public boolean isSignedIn() {
134         return signedIn;
135     }
136 
137     public void setSignedIn(boolean signedIn) {
138         this.signedIn = signedIn;
139     }
140 
141     public boolean isCheckGuest() {
142         return checkGuest;
143     }
144 
145     public void setCheckGuest(boolean checkGuest) {
146         this.checkGuest = checkGuest;
147     }
148 
149     public boolean hasPermission(
150         long groupId, String name, long primKey, String actionId) {
151 
152         return hasPermission(groupId, name, String.valueOf(primKey), actionId);
153     }
154 
155     public boolean hasPermission(
156         long groupId, String name, String primKey, String actionId) {
157 
158         StopWatch stopWatch = null;
159 
160         if (_log.isDebugEnabled()) {
161             stopWatch = new StopWatch();
162 
163             stopWatch.start();
164         }
165 
166         PermissionCheckerBag bag = getBag(groupId);
167 
168         if (signedIn && (bag == null)) {
169             try {
170 
171                 Group group = null;
172 
173                 // If the current group is staging, the live group should be
174                 // checked for permissions instead
175 
176                 if (groupId > 0) {
177                     group = GroupServiceUtil.getGroup(groupId);
178 
179                     if (group.isStagingGroup()) {
180                         groupId = group.getLiveGroupId();
181                         group = group.getLiveGroup();
182                     }
183                 }
184 
185                 // If we are checking permissions an object that belongs to a
186                 // community, then it's only necessary to check the group that
187                 // represents the community and not all the groups that the user
188                 // belongs to. This is so because an object cannot belong to
189                 // more than one community.
190 
191                 List userGroups = new ArrayList();
192                 //List userGroups = UserUtil.getGroups(userId);
193 
194                 if (groupId > 0) {
195                     if (GroupServiceUtil.hasUserGroup(
196                             user.getUserId(), groupId)) {
197 
198                         userGroups.add(group);
199                     }
200                 }
201 
202                 List userOrgs = getUserOrgs(user.getUserId());
203 
204                 List userOrgGroups =
205                     GroupServiceUtil.getOrganizationsGroups(userOrgs);
206 
207                 List userUserGroups =
208                     UserGroupServiceUtil.getUserUserGroups(user.getUserId());
209 
210                 List userUserGroupGroups =
211                     GroupServiceUtil.getUserGroupsGroups(userUserGroups);
212 
213                 List groups = new ArrayList(
214                     userGroups.size() + userOrgGroups.size() +
215                         userUserGroupGroups.size());
216 
217                 groups.addAll(userGroups);
218                 groups.addAll(userOrgGroups);
219                 groups.addAll(userUserGroupGroups);
220 
221                 List roles = null;
222 
223                 if ((USER_CHECK_ALGORITHM == 3) ||
224                     (USER_CHECK_ALGORITHM == 4)) {
225 
226                     roles = RoleServiceUtil.getUserRelatedRoles(
227                         user.getUserId(), groups);
228 
229                     List userGroupRoles = RoleServiceUtil.getUserGroupRoles(
230                         user.getUserId(), groupId);
231 
232                     roles.addAll(userGroupRoles);
233                 }
234                 else {
235                     roles = new ArrayList();
236                 }
237 
238                 if (_log.isDebugEnabled()) {
239                     _log.debug(
240                         "Creating bag for " + groupId + " " + name + " " +
241                             primKey + " " + actionId + " takes " +
242                                 stopWatch.getTime() + " ms");
243                 }
244 
245                 bag = new PermissionCheckerBagImpl(
246                     user.getUserId(), userGroups, userOrgs, userOrgGroups,
247                     userUserGroupGroups, groups, roles);
248 
249                 putBag(groupId, bag);
250             }
251             catch (Exception e) {
252                 _log.error(e, e);
253             }
254         }
255 
256         if (user == null) {
257             return false;
258         }
259 
260         Boolean value = PermissionCacheUtil.hasPermission(
261             user.getUserId(), groupId, name, primKey, actionId);
262 
263         if (value == null) {
264             value = Boolean.valueOf(
265                 hasPermissionImpl(groupId, name, primKey, actionId));
266 
267             PermissionCacheUtil.putPermission(
268                 user.getUserId(), groupId, name, primKey, actionId, value);
269 
270             if (_log.isDebugEnabled()) {
271                 _log.debug(
272                     "Checking permission for " + groupId + " " + name + " " +
273                         primKey + " " + actionId + " takes " +
274                             stopWatch.getTime() + " ms");
275             }
276         }
277 
278         return value.booleanValue();
279     }
280 
281     public boolean hasUserPermission(
282             long groupId, String name, String primKey, String actionId,
283             boolean checkAdmin)
284         throws Exception {
285 
286         StopWatch stopWatch = null;
287 
288         if (_log.isDebugEnabled()) {
289             stopWatch = new StopWatch();
290 
291             stopWatch.start();
292         }
293 
294         long companyId = user.getCompanyId();
295 
296         if (checkAdmin && isAdmin(companyId, groupId, name)) {
297             return true;
298         }
299 
300         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 1);
301 
302         long[] resourceIds = getResourceIds(
303             companyId, groupId, name, primKey, actionId);
304 
305         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 2);
306 
307         // Check if user has access to perform the action on the given
308         // resource scopes. The resources are scoped to check first for an
309         // individual class, then for the group that the class may belong
310         // to, and then for the company that the class belongs to.
311 
312         PermissionCheckerBag bag = getBag(groupId);
313 
314         boolean value = PermissionServiceUtil.hasUserPermissions(
315             user.getUserId(), groupId, actionId, resourceIds, bag);
316 
317         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 3);
318 
319         return value;
320     }
321 
322     public boolean isOmniadmin() {
323         if (omniadmin == null) {
324             omniadmin = Boolean.valueOf(OmniadminUtil.isOmniadmin(getUserId()));
325         }
326 
327         return omniadmin.booleanValue();
328     }
329 
330     protected PermissionCheckerBag getBag(long groupId) {
331         return (PermissionCheckerBag)bags.get(new Long(groupId));
332     }
333 
334     protected long[] getResourceIds(
335             long companyId, long groupId, String name, String primKey,
336             String actionId)
337         throws Exception {
338 
339         // Individual
340 
341         long[] resourceIds = new long[4];
342 
343         try {
344             Resource resource = ResourceServiceUtil.getResource(
345                 companyId, name, ResourceImpl.SCOPE_INDIVIDUAL, primKey);
346 
347             resourceIds[0] = resource.getResourceId();
348         }
349         catch (NoSuchResourceException nsre) {
350             if (_log.isWarnEnabled()) {
351                 _log.warn(
352                     "Resource " + companyId + " " + name + " " +
353                         ResourceImpl.SCOPE_INDIVIDUAL + " " + primKey +
354                             " does not exist");
355             }
356         }
357 
358         // Group
359 
360         try {
361             if (groupId > 0) {
362                 Resource resource = ResourceServiceUtil.getResource(
363                     companyId, name, ResourceImpl.SCOPE_GROUP,
364                     String.valueOf(groupId));
365 
366                 resourceIds[1] = resource.getResourceId();
367             }
368         }
369         catch (NoSuchResourceException nsre) {
370             if (_log.isWarnEnabled()) {
371                 _log.warn(
372                     "Resource " + companyId + " " + name + " " +
373                         ResourceImpl.SCOPE_GROUP + " " + groupId +
374                             " does not exist");
375             }
376         }
377 
378         // Group template
379 
380         try {
381             if (groupId > 0) {
382                 Resource resource = ResourceServiceUtil.getResource(
383                     companyId, name, ResourceImpl.SCOPE_GROUP_TEMPLATE,
384                     String.valueOf(GroupImpl.DEFAULT_PARENT_GROUP_ID));
385 
386                 resourceIds[2] = resource.getResourceId();
387             }
388         }
389         catch (NoSuchResourceException nsre) {
390             if (_log.isWarnEnabled()) {
391                 _log.warn(
392                     "Resource " + companyId + " " + name + " " +
393                         ResourceImpl.SCOPE_GROUP_TEMPLATE + " " +
394                             GroupImpl.DEFAULT_PARENT_GROUP_ID +
395                                 " does not exist");
396             }
397         }
398 
399         // Company
400 
401         try {
402             Resource resource = ResourceServiceUtil.getResource(
403                 companyId, name, ResourceImpl.SCOPE_COMPANY,
404                 String.valueOf(companyId));
405 
406             resourceIds[3] = resource.getResourceId();
407         }
408         catch (NoSuchResourceException nsre) {
409             if (_log.isWarnEnabled()) {
410                 _log.warn(
411                     "Resource " + companyId + " " + name + " " +
412                         ResourceImpl.SCOPE_COMPANY + " " + companyId +
413                             " does not exist");
414             }
415         }
416 
417         return resourceIds;
418     }
419 
420     protected List getUserOrgs(long userId) throws Exception {
421         List userOrgs = OrganizationServiceUtil.getUserOrganizations(userId);
422 
423         if (userOrgs.size() == 0) {
424             return userOrgs;
425         }
426 
427         // Recursive calculation of organization ancestors with inheritable flag
428         // actived
429 
430         List organizations = new ArrayList();
431 
432         Iterator itr = userOrgs.iterator();
433 
434         while (itr.hasNext()){
435             Organization organization = (Organization)itr.next();
436 
437             if (!organization.isLocation()) {
438                 List recursableAncestorOrgs = OrganizationLocalServiceUtil.
439                     getRecursableAncestorOrganizations(
440                         organization.getOrganizationId());
441 
442                 organizations.addAll(recursableAncestorOrgs);
443             }
444             else {
445                 organizations.add(organization);
446             }
447         }
448 
449         return organizations;
450     }
451 
452     protected boolean hasPermissionImpl(
453         long groupId, String name, String primKey, String actionId) {
454 
455         try {
456             if (!signedIn) {
457                 return hasGuestPermission(name, primKey, actionId);
458             }
459             else {
460                 boolean value = false;
461 
462                 if (checkGuest) {
463                     value = hasGuestPermission(name, primKey, actionId);
464                 }
465 
466                 if (!value) {
467                     value = hasUserPermission(
468                         groupId, name, primKey, actionId, true);
469                 }
470 
471                 return value;
472             }
473         }
474         catch (Exception e) {
475             _log.error(e, e);
476 
477             return false;
478         }
479     }
480 
481     protected boolean hasGuestPermission(
482             String name, String primKey, String actionId)
483         throws Exception {
484 
485         if (name.indexOf(StringPool.PERIOD) != -1) {
486 
487             // Check unsupported model actions
488 
489             List actions = ResourceActionsUtil.
490                 getModelResourceGuestUnsupportedActions(name);
491 
492             if (actions.contains(actionId)) {
493                 return false;
494             }
495         }
496         else {
497 
498             // Check unsupported portlet actions
499 
500             List actions = ResourceActionsUtil.
501                 getPortletResourceGuestUnsupportedActions(name);
502 
503             if (actions.contains(actionId)) {
504                 return false;
505             }
506         }
507 
508         long companyId = user.getCompanyId();
509 
510         long[] resourceIds = getResourceIds(
511             companyId, 0, name, primKey, actionId);
512 
513         PermissionCheckerBag bag = getBag(GUEST_GROUP_BAG_ID);
514 
515         if (bag == null) {
516             Group guestGroup = GroupServiceUtil.getGroup(
517                 companyId, GroupImpl.GUEST);
518 
519             List roles = RoleServiceUtil.getGroupRoles(guestGroup.getGroupId());
520 
521             bag = new PermissionCheckerBagImpl(
522                 defaultUserId, new ArrayList(), new ArrayList(),
523                 new ArrayList(), new ArrayList(), new ArrayList(), roles);
524 
525             putBag(GUEST_GROUP_BAG_ID, bag);
526         }
527 
528         try {
529             return PermissionServiceUtil.hasUserPermissions(
530                 defaultUserId, 0, actionId, resourceIds, bag);
531         }
532         catch (Exception e) {
533             return false;
534         }
535     }
536 
537     protected boolean isAdmin(long companyId, long groupId, String name)
538         throws Exception {
539 
540         PermissionCheckerBag bag = getBag(groupId);
541 
542         if (bag == null) {
543             _log.error("Bag should never be null");
544         }
545 
546         if (bag.isCompanyAdmin(companyId)) {
547             return true;
548         }
549 
550         if (bag.isCommunityAdmin(this, companyId, groupId, name)) {
551             return true;
552         }
553 
554         // You can further modify this method to check if the user has the Admin
555         // permission to a portlet that the checked resource belongs to. This
556         // would then allow you to set up Admins scoped for a specific portlet.
557 
558         return false;
559     }
560 
561     protected void logHasUserPermission(
562         long groupId, String name, String primKey, String actionId,
563         StopWatch stopWatch, int block) {
564 
565         if (!_log.isDebugEnabled()) {
566             return;
567         }
568 
569         _log.debug(
570             "Checking user permission block " + block + " for " + groupId +
571                 " " + name + " " + primKey + " " + actionId + " takes " +
572                     stopWatch.getTime() + " ms");
573     }
574 
575     protected void putBag(long groupId, PermissionCheckerBag bag) {
576         bags.put(new Long(groupId), bag);
577     }
578 
579     protected static final int GUEST_GROUP_BAG_ID = -101;
580 
581     protected static final String RESULTS_SEPARATOR = "_RESULTS_SEPARATOR_";
582 
583     protected User user;
584     protected long defaultUserId;
585     protected boolean signedIn;
586     protected boolean checkGuest;
587     protected Map bags = CollectionFactory.getHashMap();
588     protected Boolean omniadmin;
589 
590     private static Log _log = LogFactory.getLog(PermissionCheckerImpl.class);
591 
592 }