001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.service.permission;
016    
017    import com.liferay.exportimport.kernel.staging.permission.StagingPermissionUtil;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.model.Group;
020    import com.liferay.portal.kernel.model.Layout;
021    import com.liferay.portal.kernel.model.LayoutConstants;
022    import com.liferay.portal.kernel.model.LayoutType;
023    import com.liferay.portal.kernel.model.LayoutTypeController;
024    import com.liferay.portal.kernel.model.Organization;
025    import com.liferay.portal.kernel.model.ResourceConstants;
026    import com.liferay.portal.kernel.model.ResourcePermission;
027    import com.liferay.portal.kernel.model.User;
028    import com.liferay.portal.kernel.model.impl.VirtualLayout;
029    import com.liferay.portal.kernel.security.auth.PrincipalException;
030    import com.liferay.portal.kernel.security.permission.ActionKeys;
031    import com.liferay.portal.kernel.security.permission.BaseModelPermissionChecker;
032    import com.liferay.portal.kernel.security.permission.PermissionChecker;
033    import com.liferay.portal.kernel.service.GroupLocalServiceUtil;
034    import com.liferay.portal.kernel.service.LayoutLocalServiceUtil;
035    import com.liferay.portal.kernel.service.OrganizationLocalServiceUtil;
036    import com.liferay.portal.kernel.service.ResourceLocalServiceUtil;
037    import com.liferay.portal.kernel.service.ResourcePermissionLocalServiceUtil;
038    import com.liferay.portal.kernel.service.UserLocalServiceUtil;
039    import com.liferay.portal.kernel.service.permission.GroupPermissionUtil;
040    import com.liferay.portal.kernel.service.permission.LayoutPermission;
041    import com.liferay.portal.kernel.service.permission.LayoutPrototypePermissionUtil;
042    import com.liferay.portal.kernel.service.permission.LayoutSetPrototypePermissionUtil;
043    import com.liferay.portal.kernel.service.permission.OrganizationPermissionUtil;
044    import com.liferay.portal.kernel.service.permission.UserGroupPermissionUtil;
045    import com.liferay.portal.kernel.service.permission.UserPermissionUtil;
046    import com.liferay.portal.kernel.spring.osgi.OSGiBeanProperties;
047    import com.liferay.portal.util.PropsValues;
048    import com.liferay.sites.kernel.util.SitesUtil;
049    
050    import java.util.List;
051    
052    /**
053     * @author Charles May
054     * @author Brian Wing Shun Chan
055     * @author Raymond Augé
056     */
057    @OSGiBeanProperties(
058            property = {"model.class.name=com.liferay.portal.kernel.model.Layout"}
059    )
060    public class LayoutPermissionImpl
061            implements BaseModelPermissionChecker, LayoutPermission {
062    
063            @Override
064            public void check(
065                            PermissionChecker permissionChecker, Layout layout,
066                            boolean checkViewableGroup, String actionId)
067                    throws PortalException {
068    
069                    if (!contains(
070                                    permissionChecker, layout, checkViewableGroup, actionId)) {
071    
072                            throw new PrincipalException.MustHavePermission(
073                                    permissionChecker, Layout.class.getName(), layout.getLayoutId(),
074                                    actionId);
075                    }
076            }
077    
078            @Override
079            public void check(
080                            PermissionChecker permissionChecker, Layout layout, String actionId)
081                    throws PortalException {
082    
083                    if (!contains(permissionChecker, layout, actionId)) {
084                            throw new PrincipalException.MustHavePermission(
085                                    permissionChecker, Layout.class.getName(), layout.getLayoutId(),
086                                    actionId);
087                    }
088            }
089    
090            @Override
091            public void check(
092                            PermissionChecker permissionChecker, long groupId,
093                            boolean privateLayout, long layoutId, String actionId)
094                    throws PortalException {
095    
096                    if (!contains(
097                                    permissionChecker, groupId, privateLayout, layoutId,
098                                    actionId)) {
099    
100                            throw new PrincipalException.MustHavePermission(
101                                    permissionChecker, Layout.class.getName(), layoutId, actionId);
102                    }
103            }
104    
105            @Override
106            public void check(
107                            PermissionChecker permissionChecker, long plid, String actionId)
108                    throws PortalException {
109    
110                    Layout layout = LayoutLocalServiceUtil.getLayout(plid);
111    
112                    check(permissionChecker, layout, actionId);
113            }
114    
115            @Override
116            public void checkBaseModel(
117                            PermissionChecker permissionChecker, long groupId, long primaryKey,
118                            String actionId)
119                    throws PortalException {
120    
121                    check(permissionChecker, primaryKey, actionId);
122            }
123    
124            @Override
125            public boolean contains(
126                            PermissionChecker permissionChecker, Layout layout,
127                            boolean checkViewableGroup, String actionId)
128                    throws PortalException {
129    
130                    if (actionId.equals(ActionKeys.VIEW)) {
131                            LayoutType layoutType = layout.getLayoutType();
132    
133                            LayoutTypeController layoutTypeController =
134                                    layoutType.getLayoutTypeController();
135    
136                            if (!layoutTypeController.isCheckLayoutViewPermission()) {
137                                    return true;
138                            }
139                    }
140    
141                    if (layout.isTypeControlPanel()) {
142                            if (!permissionChecker.isSignedIn()) {
143                                    return false;
144                            }
145    
146                            return true;
147                    }
148    
149                    if (actionId.equals(ActionKeys.CUSTOMIZE) &&
150                            (layout instanceof VirtualLayout)) {
151    
152                            VirtualLayout virtualLayout = (VirtualLayout)layout;
153    
154                            layout = virtualLayout.getWrappedModel();
155                    }
156    
157                    if (isAttemptToModifyLockedLayout(layout, actionId)) {
158                            return false;
159                    }
160    
161                    Boolean hasPermission = StagingPermissionUtil.hasPermission(
162                            permissionChecker, layout.getGroup(), Layout.class.getName(),
163                            layout.getGroupId(), null, actionId);
164    
165                    if (hasPermission != null) {
166                            return hasPermission.booleanValue();
167                    }
168    
169                    return containsWithViewableGroup(
170                            permissionChecker, layout, checkViewableGroup, actionId);
171            }
172    
173            @Override
174            public boolean contains(
175                            PermissionChecker permissionChecker, Layout layout, String actionId)
176                    throws PortalException {
177    
178                    return contains(permissionChecker, layout, false, actionId);
179            }
180    
181            @Override
182            public boolean contains(
183                            PermissionChecker permissionChecker, long groupId,
184                            boolean privateLayout, long layoutId, String actionId)
185                    throws PortalException {
186    
187                    Layout layout = LayoutLocalServiceUtil.getLayout(
188                            groupId, privateLayout, layoutId);
189    
190                    return contains(permissionChecker, layout, actionId);
191            }
192    
193            @Override
194            public boolean contains(
195                            PermissionChecker permissionChecker, long plid, String actionId)
196                    throws PortalException {
197    
198                    Layout layout = LayoutLocalServiceUtil.getLayout(plid);
199    
200                    return contains(permissionChecker, layout, actionId);
201            }
202    
203            @Override
204            public boolean containsWithoutViewableGroup(
205                            PermissionChecker permissionChecker, Layout layout,
206                            boolean checkLayoutUpdateable, String actionId)
207                    throws PortalException {
208    
209                    if (layout.isTypeControlPanel()) {
210                            return false;
211                    }
212    
213                    if (checkLayoutUpdateable && !actionId.equals(ActionKeys.CUSTOMIZE) &&
214                            !actionId.equals(ActionKeys.VIEW) &&
215                            (layout instanceof VirtualLayout)) {
216    
217                            return false;
218                    }
219    
220                    if (actionId.equals(ActionKeys.CUSTOMIZE) &&
221                            (layout instanceof VirtualLayout)) {
222    
223                            VirtualLayout virtualLayout = (VirtualLayout)layout;
224    
225                            layout = virtualLayout.getWrappedModel();
226                    }
227    
228                    if (actionId.equals(ActionKeys.ADD_LAYOUT)) {
229                            if (!SitesUtil.isLayoutSortable(layout)) {
230                                    return false;
231                            }
232    
233                            LayoutType layoutType = layout.getLayoutType();
234    
235                            if (!layoutType.isParentable()) {
236                                    return false;
237                            }
238                    }
239    
240                    if (actionId.equals(ActionKeys.DELETE) &&
241                            !SitesUtil.isLayoutDeleteable(layout)) {
242    
243                            return false;
244                    }
245    
246                    Group group = layout.getGroup();
247    
248                    if (checkLayoutUpdateable && !group.isLayoutSetPrototype() &&
249                            isAttemptToModifyLockedLayout(layout, actionId)) {
250    
251                            return false;
252                    }
253    
254                    User user = permissionChecker.getUser();
255    
256                    if (!user.isDefaultUser() && !group.isUser()) {
257    
258                            // This is new way of doing an ownership check without having to
259                            // have a userId field on the model. When the instance model was
260                            // first created, we set the user's userId as the ownerId of the
261                            // individual scope ResourcePermission of the Owner Role. Therefore,
262                            // ownership can be determined by obtaining the Owner role
263                            // ResourcePermission for the current instance model and testing it
264                            // with the hasOwnerPermission call.
265    
266                            ResourcePermission resourcePermission =
267                                    ResourcePermissionLocalServiceUtil.getResourcePermission(
268                                            layout.getCompanyId(), Layout.class.getName(),
269                                            ResourceConstants.SCOPE_INDIVIDUAL,
270                                            String.valueOf(layout.getPlid()),
271                                            permissionChecker.getOwnerRoleId());
272    
273                            if (permissionChecker.hasOwnerPermission(
274                                            layout.getCompanyId(), Layout.class.getName(),
275                                            String.valueOf(layout.getPlid()),
276                                            resourcePermission.getOwnerId(), actionId)) {
277    
278                                    return true;
279                            }
280                    }
281    
282                    if (actionId.equals(ActionKeys.ADD_LAYOUT) &&
283                            GroupPermissionUtil.contains(
284                                    permissionChecker, group, ActionKeys.ADD_LAYOUT)) {
285    
286                            return true;
287                    }
288    
289                    if (GroupPermissionUtil.contains(
290                                    permissionChecker, group, ActionKeys.MANAGE_LAYOUTS)) {
291    
292                            return true;
293                    }
294    
295                    if (PropsValues.PERMISSIONS_VIEW_DYNAMIC_INHERITANCE &&
296                            !actionId.equals(ActionKeys.VIEW)) {
297    
298                            // Check upward recursively to see if any pages above grant the
299                            // action
300    
301                            long parentLayoutId = layout.getParentLayoutId();
302    
303                            while (parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
304                                    Layout parentLayout = LayoutLocalServiceUtil.getLayout(
305                                            layout.getGroupId(), layout.isPrivateLayout(),
306                                            parentLayoutId);
307    
308                                    if (contains(permissionChecker, parentLayout, actionId)) {
309                                            return true;
310                                    }
311    
312                                    parentLayoutId = parentLayout.getParentLayoutId();
313                            }
314                    }
315    
316                    int resourcePermissionsCount =
317                            ResourcePermissionLocalServiceUtil.getResourcePermissionsCount(
318                                    layout.getCompanyId(), Layout.class.getName(),
319                                    ResourceConstants.SCOPE_INDIVIDUAL,
320                                    String.valueOf(layout.getPlid()));
321    
322                    if (resourcePermissionsCount == 0) {
323                            boolean addGroupPermission = true;
324                            boolean addGuestPermission = true;
325    
326                            if (layout.isPrivateLayout()) {
327                                    addGuestPermission = false;
328    
329                                    if (group.isUser() || group.isUserGroup()) {
330                                            addGroupPermission = false;
331                                    }
332                            }
333    
334                            ResourceLocalServiceUtil.addResources(
335                                    layout.getCompanyId(), layout.getGroupId(), 0,
336                                    Layout.class.getName(), layout.getPlid(), false,
337                                    addGroupPermission, addGuestPermission);
338                    }
339    
340                    return permissionChecker.hasPermission(
341                            layout.getGroupId(), Layout.class.getName(), layout.getPlid(),
342                            actionId);
343            }
344    
345            @Override
346            public boolean containsWithoutViewableGroup(
347                            PermissionChecker permissionChecker, Layout layout, String actionId)
348                    throws PortalException {
349    
350                    return containsWithoutViewableGroup(
351                            permissionChecker, layout, true, actionId);
352            }
353    
354            protected boolean containsWithViewableGroup(
355                            PermissionChecker permissionChecker, Layout layout,
356                            boolean checkViewableGroup, String actionId)
357                    throws PortalException {
358    
359                    if (actionId.equals(ActionKeys.VIEW) && checkViewableGroup) {
360                            return isViewableGroup(
361                                    permissionChecker, layout, checkViewableGroup);
362                    }
363    
364                    return containsWithoutViewableGroup(
365                            permissionChecker, layout, actionId);
366            }
367    
368            protected boolean isAttemptToModifyLockedLayout(
369                    Layout layout, String actionId) {
370    
371                    if ((ActionKeys.CUSTOMIZE.equals(actionId) ||
372                             ActionKeys.UPDATE.equals(actionId)) &&
373                            !SitesUtil.isLayoutUpdateable(layout)) {
374    
375                            return true;
376                    }
377    
378                    return false;
379            }
380    
381            protected boolean isViewableGroup(
382                            PermissionChecker permissionChecker, Layout layout,
383                            boolean checkResourcePermission)
384                    throws PortalException {
385    
386                    Group group = GroupLocalServiceUtil.getGroup(layout.getGroupId());
387    
388                    // Inactive sites are not viewable
389    
390                    if (!group.isActive()) {
391                            return false;
392                    }
393                    else if (group.isStagingGroup()) {
394                            Group liveGroup = group.getLiveGroup();
395    
396                            if (!liveGroup.isActive()) {
397                                    return false;
398                            }
399                    }
400    
401                    // User private layouts are only viewable by the user and anyone who can
402                    // update the user. The user must also be active.
403    
404                    if (group.isUser()) {
405                            long groupUserId = group.getClassPK();
406    
407                            if (groupUserId == permissionChecker.getUserId()) {
408                                    return true;
409                            }
410    
411                            User groupUser = UserLocalServiceUtil.getUserById(groupUserId);
412    
413                            if (!groupUser.isActive()) {
414                                    return false;
415                            }
416    
417                            if (layout.isPrivateLayout()) {
418                                    if (GroupPermissionUtil.contains(
419                                                    permissionChecker, group, ActionKeys.MANAGE_LAYOUTS) ||
420                                            UserPermissionUtil.contains(
421                                                    permissionChecker, groupUserId,
422                                                    groupUser.getOrganizationIds(), ActionKeys.UPDATE)) {
423    
424                                            return true;
425                                    }
426    
427                                    return false;
428                            }
429                    }
430    
431                    // If the current group is staging, only users with editorial rights can
432                    // access it
433    
434                    if (group.isStagingGroup()) {
435                            if (GroupPermissionUtil.contains(
436                                            permissionChecker, group, ActionKeys.VIEW_STAGING)) {
437    
438                                    return true;
439                            }
440    
441                            return false;
442                    }
443    
444                    // Site layouts are only viewable by users who are members of the site
445                    // or by users who can update the site
446    
447                    if (group.isSite()) {
448                            if (GroupPermissionUtil.contains(
449                                            permissionChecker, group, ActionKeys.MANAGE_LAYOUTS) ||
450                                    GroupPermissionUtil.contains(
451                                            permissionChecker, group, ActionKeys.UPDATE)) {
452    
453                                    return true;
454                            }
455    
456                            if (layout.isPrivateLayout() &&
457                                    !permissionChecker.isGroupMember(group.getGroupId())) {
458    
459                                    return false;
460                            }
461                    }
462    
463                    // Organization site layouts are also viewable by users who belong to
464                    // the organization or by users who can update organization
465    
466                    if (group.isCompany()) {
467                            return false;
468                    }
469                    else if (group.isLayoutPrototype()) {
470                            if (LayoutPrototypePermissionUtil.contains(
471                                            permissionChecker, group.getClassPK(), ActionKeys.VIEW)) {
472    
473                                    return true;
474                            }
475    
476                            return false;
477                    }
478                    else if (group.isLayoutSetPrototype()) {
479                            if (LayoutSetPrototypePermissionUtil.contains(
480                                            permissionChecker, group.getClassPK(), ActionKeys.VIEW)) {
481    
482                                    return true;
483                            }
484    
485                            return false;
486                    }
487                    else if (group.isOrganization()) {
488                            long organizationId = group.getOrganizationId();
489    
490                            if (OrganizationLocalServiceUtil.hasUserOrganization(
491                                            permissionChecker.getUserId(), organizationId, false,
492                                            false)) {
493    
494                                    return true;
495                            }
496                            else if (OrganizationPermissionUtil.contains(
497                                                    permissionChecker, organizationId, ActionKeys.UPDATE)) {
498    
499                                    return true;
500                            }
501    
502                            if (!PropsValues.ORGANIZATIONS_MEMBERSHIP_STRICT) {
503                                    List<Organization> userOrgs =
504                                            OrganizationLocalServiceUtil.getUserOrganizations(
505                                                    permissionChecker.getUserId());
506    
507                                    for (Organization organization : userOrgs) {
508                                            for (Organization ancestorOrganization :
509                                                            organization.getAncestors()) {
510    
511                                                    if (organizationId ==
512                                                                    ancestorOrganization.getOrganizationId()) {
513    
514                                                            return true;
515                                                    }
516                                            }
517                                    }
518                            }
519                    }
520                    else if (group.isUserGroup()) {
521                            if (UserGroupPermissionUtil.contains(
522                                            permissionChecker, group.getClassPK(), ActionKeys.UPDATE)) {
523    
524                                    return true;
525                            }
526                    }
527    
528                    // Only check the actual Layout if all of the above failed
529    
530                    if (containsWithoutViewableGroup(
531                                    permissionChecker, layout, ActionKeys.VIEW)) {
532    
533                            return true;
534                    }
535    
536                    // As a last resort, check if any top level pages are viewable by the
537                    // user
538    
539                    List<Layout> layouts = LayoutLocalServiceUtil.getLayouts(
540                            layout.getGroupId(), layout.isPrivateLayout(),
541                            LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
542    
543                    for (Layout curLayout : layouts) {
544                            if (containsWithoutViewableGroup(
545                                            permissionChecker, curLayout, ActionKeys.VIEW) &&
546                                    !curLayout.isHidden()) {
547    
548                                    return true;
549                            }
550                    }
551    
552                    return false;
553            }
554    
555    }