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