001
014
015 package com.liferay.portlet;
016
017 import com.liferay.portal.kernel.exception.PortalException;
018 import com.liferay.portal.kernel.exception.SystemException;
019 import com.liferay.portal.kernel.log.Log;
020 import com.liferay.portal.kernel.log.LogFactoryUtil;
021 import com.liferay.portal.kernel.portlet.ActionResult;
022 import com.liferay.portal.kernel.portlet.PortletContainer;
023 import com.liferay.portal.kernel.portlet.PortletContainerException;
024 import com.liferay.portal.kernel.portlet.PortletContainerUtil;
025 import com.liferay.portal.kernel.portlet.PortletModeFactory;
026 import com.liferay.portal.kernel.resiliency.spi.SPIUtil;
027 import com.liferay.portal.kernel.security.pacl.DoPrivileged;
028 import com.liferay.portal.kernel.servlet.HttpHeaders;
029 import com.liferay.portal.kernel.servlet.TempAttributesServletRequest;
030 import com.liferay.portal.kernel.struts.LastPath;
031 import com.liferay.portal.kernel.util.ArrayUtil;
032 import com.liferay.portal.kernel.util.CharPool;
033 import com.liferay.portal.kernel.util.GetterUtil;
034 import com.liferay.portal.kernel.util.ParamUtil;
035 import com.liferay.portal.kernel.util.StringUtil;
036 import com.liferay.portal.kernel.util.Validator;
037 import com.liferay.portal.model.Group;
038 import com.liferay.portal.model.Layout;
039 import com.liferay.portal.model.LayoutTypePortlet;
040 import com.liferay.portal.model.Portlet;
041 import com.liferay.portal.security.auth.AuthTokenUtil;
042 import com.liferay.portal.security.auth.PrincipalException;
043 import com.liferay.portal.security.permission.ActionKeys;
044 import com.liferay.portal.security.permission.PermissionChecker;
045 import com.liferay.portal.security.permission.PermissionThreadLocal;
046 import com.liferay.portal.service.permission.GroupPermissionUtil;
047 import com.liferay.portal.service.permission.LayoutPermissionUtil;
048 import com.liferay.portal.service.permission.LayoutPrototypePermissionUtil;
049 import com.liferay.portal.service.permission.LayoutSetPrototypePermissionUtil;
050 import com.liferay.portal.service.permission.OrganizationPermissionUtil;
051 import com.liferay.portal.service.permission.PortletPermissionUtil;
052 import com.liferay.portal.theme.ThemeDisplay;
053 import com.liferay.portal.util.PortalUtil;
054 import com.liferay.portal.util.PortletKeys;
055 import com.liferay.portal.util.PropsValues;
056 import com.liferay.portal.util.WebKeys;
057
058 import java.util.List;
059 import java.util.Map;
060
061 import javax.portlet.Event;
062 import javax.portlet.PortletMode;
063
064 import javax.servlet.RequestDispatcher;
065 import javax.servlet.http.HttpServletRequest;
066 import javax.servlet.http.HttpServletResponse;
067
068
072 @DoPrivileged
073 public class SecurityPortletContainerWrapper implements PortletContainer {
074
075 public static PortletContainer createSecurityPortletContainerWrapper(
076 PortletContainer portletContainer) {
077
078 if (!SPIUtil.isSPI()) {
079 portletContainer = new SecurityPortletContainerWrapper(
080 portletContainer);
081 }
082
083 return portletContainer;
084 }
085
086 public SecurityPortletContainerWrapper(PortletContainer portletContainer) {
087 _portletContainer = portletContainer;
088 }
089
090 @Override
091 public void preparePortlet(HttpServletRequest request, Portlet portlet)
092 throws PortletContainerException {
093
094 _portletContainer.preparePortlet(request, portlet);
095 }
096
097 @Override
098 public ActionResult processAction(
099 HttpServletRequest request, HttpServletResponse response,
100 Portlet portlet)
101 throws PortletContainerException {
102
103 try {
104 HttpServletRequest ownerLayoutRequest =
105 getOwnerLayoutRequestWrapper(request, portlet);
106
107 checkAction(ownerLayoutRequest, portlet);
108
109 return _portletContainer.processAction(request, response, portlet);
110 }
111 catch (PrincipalException pe) {
112 return processActionException(request, response, portlet, pe);
113 }
114 catch (PortletContainerException pce) {
115 throw pce;
116 }
117 catch (Exception e) {
118 throw new PortletContainerException(e);
119 }
120 }
121
122 @Override
123 public List<Event> processEvent(
124 HttpServletRequest request, HttpServletResponse response,
125 Portlet portlet, Layout layout, Event event)
126 throws PortletContainerException {
127
128 return _portletContainer.processEvent(
129 request, response, portlet, layout, event);
130 }
131
132 @Override
133 public void render(
134 HttpServletRequest request, HttpServletResponse response,
135 Portlet portlet)
136 throws PortletContainerException {
137
138 try {
139 checkRender(request, portlet);
140
141 _portletContainer.render(request, response, portlet);
142 }
143 catch (PrincipalException e) {
144 processRenderException(request, response, portlet);
145 }
146 catch (PortletContainerException e) {
147 throw e;
148 }
149 catch (Exception e) {
150 throw new PortletContainerException(e);
151 }
152 }
153
154 @Override
155 public void serveResource(
156 HttpServletRequest request, HttpServletResponse response,
157 Portlet portlet)
158 throws PortletContainerException {
159
160 try {
161 HttpServletRequest ownerLayoutRequest =
162 getOwnerLayoutRequestWrapper(request, portlet);
163
164 checkResource(ownerLayoutRequest, portlet);
165
166 _portletContainer.serveResource(request, response, portlet);
167 }
168 catch (PrincipalException pe) {
169 processServeResourceException(request, response, portlet, pe);
170 }
171 catch (PortletContainerException pce) {
172 throw pce;
173 }
174 catch (Exception e) {
175 throw new PortletContainerException(e);
176 }
177 }
178
179 protected void check(HttpServletRequest request, Portlet portlet)
180 throws Exception {
181
182 if (portlet == null) {
183 return;
184 }
185
186 if (!isValidPortletId(portlet.getPortletId())) {
187 if (_log.isWarnEnabled()) {
188 _log.warn("Invalid portlet id " + portlet.getPortletId());
189 }
190
191 throw new PrincipalException();
192 }
193
194 if (portlet.isUndeployedPortlet()) {
195 return;
196 }
197
198 Layout layout = (Layout)request.getAttribute(WebKeys.LAYOUT);
199
200 if (layout.isTypeControlPanel()) {
201 isAccessAllowedToControlPanelPortlet(request, portlet);
202
203 return;
204 }
205
206 if (isAccessAllowedToLayoutPortlet(request, portlet)) {
207 PortalUtil.addPortletDefaultResource(request, portlet);
208
209 if (hasAccessPermission(request, portlet)) {
210 return;
211 }
212 }
213
214 throw new PrincipalException();
215 }
216
217 protected void checkAction(HttpServletRequest request, Portlet portlet)
218 throws Exception {
219
220 checkCSRFProtection(request, portlet);
221
222 check(request, portlet);
223 }
224
225 protected void checkCSRFProtection(
226 HttpServletRequest request, Portlet portlet)
227 throws PortalException {
228
229 Map<String, String> initParams = portlet.getInitParams();
230
231 boolean checkAuthToken = GetterUtil.getBoolean(
232 initParams.get("check-auth-token"), true);
233
234 if (checkAuthToken) {
235 AuthTokenUtil.checkCSRFToken(
236 request, SecurityPortletContainerWrapper.class.getName());
237 }
238 }
239
240 protected void checkRender(HttpServletRequest request, Portlet portlet)
241 throws Exception {
242
243 check(request, portlet);
244 }
245
246 protected void checkResource(HttpServletRequest request, Portlet portlet)
247 throws Exception {
248
249 check(request, portlet);
250 }
251
252 protected String getOriginalURL(HttpServletRequest request) {
253 LastPath lastPath = (LastPath)request.getAttribute(WebKeys.LAST_PATH);
254
255 if (lastPath == null) {
256 return String.valueOf(request.getRequestURI());
257 }
258
259 String portalURL = PortalUtil.getPortalURL(request);
260
261 return portalURL.concat(
262 lastPath.getContextPath()).concat(lastPath.getPath());
263 }
264
265 protected HttpServletRequest getOwnerLayoutRequestWrapper(
266 HttpServletRequest request, Portlet portlet)
267 throws Exception {
268
269 if (!PropsValues.PORTLET_EVENT_DISTRIBUTION_LAYOUT_SET ||
270 PropsValues.PORTLET_CROSS_LAYOUT_INVOCATION_MODE.equals("render")) {
271
272 return request;
273 }
274
275 Layout ownerLayout = null;
276 LayoutTypePortlet ownerLayoutTypePortlet = null;
277
278 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
279 WebKeys.THEME_DISPLAY);
280
281 Layout requestLayout = (Layout)request.getAttribute(WebKeys.LAYOUT);
282
283 List<LayoutTypePortlet> layoutTypePortlets =
284 PortletContainerUtil.getLayoutTypePortlets(requestLayout);
285
286 for (LayoutTypePortlet layoutTypePortlet : layoutTypePortlets) {
287 if (layoutTypePortlet.hasPortletId(portlet.getPortletId())) {
288 ownerLayoutTypePortlet = layoutTypePortlet;
289
290 ownerLayout = layoutTypePortlet.getLayout();
291
292 break;
293 }
294 }
295
296 if (ownerLayout == null) {
297 return request;
298 }
299
300 Layout currentLayout = themeDisplay.getLayout();
301
302 if (currentLayout.equals(ownerLayout)) {
303 return request;
304 }
305
306 ThemeDisplay themeDisplayClone = (ThemeDisplay)themeDisplay.clone();
307
308 themeDisplayClone.setLayout(ownerLayout);
309 themeDisplayClone.setLayoutTypePortlet(ownerLayoutTypePortlet);
310
311 TempAttributesServletRequest tempAttributesServletRequest =
312 new TempAttributesServletRequest(request);
313
314 tempAttributesServletRequest.setTempAttribute(
315 WebKeys.LAYOUT, ownerLayout);
316 tempAttributesServletRequest.setTempAttribute(
317 WebKeys.THEME_DISPLAY, themeDisplayClone);
318
319 return tempAttributesServletRequest;
320 }
321
322 protected boolean hasAccessPermission(
323 HttpServletRequest request, Portlet portlet)
324 throws PortalException, SystemException {
325
326 PermissionChecker permissionChecker =
327 PermissionThreadLocal.getPermissionChecker();
328
329 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
330 WebKeys.THEME_DISPLAY);
331
332 Layout layout = (Layout)request.getAttribute(WebKeys.LAYOUT);
333
334 PortletMode portletMode = PortletModeFactory.getPortletMode(
335 ParamUtil.getString(request, "p_p_mode"));
336
337 return PortletPermissionUtil.hasAccessPermission(
338 permissionChecker, themeDisplay.getScopeGroupId(), layout, portlet,
339 portletMode);
340 }
341
342 protected void isAccessAllowedToControlPanelPortlet(
343 HttpServletRequest request, Portlet portlet)
344 throws PortalException, SystemException {
345
346 PermissionChecker permissionChecker =
347 PermissionThreadLocal.getPermissionChecker();
348
349 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
350 WebKeys.THEME_DISPLAY);
351
352 if (PortletPermissionUtil.hasControlPanelAccessPermission(
353 permissionChecker, themeDisplay.getScopeGroupId(), portlet)) {
354
355 return;
356 }
357
358 if (isAccessGrantedByRuntimePortlet(request, portlet)) {
359 return;
360 }
361
362 if (isAccessGrantedByPortletAuthenticationToken(request, portlet)) {
363 return;
364 }
365
366 throw new PrincipalException();
367 }
368
369 protected boolean isAccessAllowedToLayoutPortlet(
370 HttpServletRequest request, Portlet portlet)
371 throws PortalException, SystemException {
372
373 if (isAccessGrantedByRuntimePortlet(request, portlet)) {
374 return true;
375 }
376
377 if (isAccessGrantedByPortletOnPage(request, portlet)) {
378 return true;
379 }
380
381 if (isLayoutConfigurationAllowed(request, portlet)) {
382 return true;
383 }
384
385 if (isAccessGrantedByPortletAuthenticationToken(request, portlet)) {
386 return true;
387 }
388
389 return false;
390 }
391
392 protected boolean isAccessGrantedByPortletAuthenticationToken(
393 HttpServletRequest request, Portlet portlet) {
394
395 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
396 WebKeys.THEME_DISPLAY);
397
398 String portletId = portlet.getPortletId();
399
400 if (!portlet.isAddDefaultResource()) {
401 return false;
402 }
403
404 if (!PropsValues.PORTLET_ADD_DEFAULT_RESOURCE_CHECK_ENABLED) {
405 return true;
406 }
407
408 String namespace = PortalUtil.getPortletNamespace(portletId);
409
410 String strutsAction = ParamUtil.getString(
411 request, namespace + "struts_action");
412
413 if (Validator.isNull(strutsAction)) {
414 strutsAction = ParamUtil.getString(request, "struts_action");
415 }
416
417 String requestPortletAuthenticationToken = ParamUtil.getString(
418 request, "p_p_auth");
419
420 if (Validator.isNull(requestPortletAuthenticationToken)) {
421 HttpServletRequest originalRequest =
422 PortalUtil.getOriginalServletRequest(request);
423
424 requestPortletAuthenticationToken = ParamUtil.getString(
425 originalRequest, "p_p_auth");
426 }
427
428 if (AuthTokenUtil.isValidPortletInvocationToken(
429 request, themeDisplay.getPlid(), portletId, strutsAction,
430 requestPortletAuthenticationToken)) {
431
432 return true;
433 }
434
435 return false;
436 }
437
438 protected boolean isAccessGrantedByPortletOnPage(
439 HttpServletRequest request, Portlet portlet)
440 throws PortalException, SystemException {
441
442 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
443 WebKeys.THEME_DISPLAY);
444
445 Layout layout = themeDisplay.getLayout();
446
447 String portletId = portlet.getPortletId();
448
449 if (layout.isTypePanel() &&
450 isPanelSelectedPortlet(themeDisplay, portletId)) {
451
452 return true;
453 }
454
455 LayoutTypePortlet layoutTypePortlet =
456 themeDisplay.getLayoutTypePortlet();
457
458 if ((layoutTypePortlet != null) &&
459 layoutTypePortlet.hasPortletId(portletId)) {
460
461 return true;
462 }
463
464 return false;
465 }
466
467 protected boolean isAccessGrantedByRuntimePortlet(
468 HttpServletRequest request, Portlet portlet) {
469
470 Boolean renderPortletResource = (Boolean)request.getAttribute(
471 WebKeys.RENDER_PORTLET_RESOURCE);
472
473 if (renderPortletResource != null) {
474 boolean runtimePortlet = renderPortletResource.booleanValue();
475
476 if (runtimePortlet) {
477 return true;
478 }
479 }
480
481 return false;
482 }
483
484 protected boolean isLayoutConfigurationAllowed(
485 HttpServletRequest request, Portlet portlet)
486 throws PortalException, SystemException {
487
488 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
489 WebKeys.THEME_DISPLAY);
490
491 if (!themeDisplay.isSignedIn()) {
492 return false;
493 }
494
495 String portletId = portlet.getPortletId();
496
497 if (!portletId.equals(PortletKeys.LAYOUTS_ADMIN)) {
498 return false;
499 }
500
501 PermissionChecker permissionChecker =
502 themeDisplay.getPermissionChecker();
503
504 Layout layout = themeDisplay.getLayout();
505
506 Group group = layout.getGroup();
507
508 if (group.isSite()) {
509 if (LayoutPermissionUtil.contains(
510 permissionChecker, layout, ActionKeys.CUSTOMIZE) ||
511 LayoutPermissionUtil.contains(
512 permissionChecker, layout, ActionKeys.UPDATE)) {
513
514 return true;
515 }
516 }
517
518 if (group.isCompany()) {
519 if (permissionChecker.isCompanyAdmin()) {
520 return true;
521 }
522 }
523 else if (group.isLayoutPrototype()) {
524 long layoutPrototypeId = group.getClassPK();
525
526 if (LayoutPrototypePermissionUtil.contains(
527 permissionChecker, layoutPrototypeId,
528 ActionKeys.UPDATE)) {
529
530 return true;
531 }
532 }
533 else if (group.isLayoutSetPrototype()) {
534 long layoutSetPrototypeId = group.getClassPK();
535
536 if (LayoutSetPrototypePermissionUtil.contains(
537 permissionChecker, layoutSetPrototypeId,
538 ActionKeys.UPDATE)) {
539
540 return true;
541 }
542 }
543 else if (group.isOrganization()) {
544 long organizationId = group.getOrganizationId();
545
546 if (OrganizationPermissionUtil.contains(
547 permissionChecker, organizationId, ActionKeys.UPDATE)) {
548
549 return true;
550 }
551 }
552 else if (group.isUserGroup()) {
553 long scopeGroupId = themeDisplay.getScopeGroupId();
554
555 if (GroupPermissionUtil.contains(
556 permissionChecker, scopeGroupId, ActionKeys.UPDATE)) {
557
558 return true;
559 }
560 }
561 else if (group.isUser()) {
562 return true;
563 }
564
565 return false;
566 }
567
568 protected boolean isPanelSelectedPortlet(
569 ThemeDisplay themeDisplay, String portletId) {
570
571 Layout layout = themeDisplay.getLayout();
572
573 String panelSelectedPortlets = layout.getTypeSettingsProperty(
574 "panelSelectedPortlets");
575
576 if (Validator.isNotNull(panelSelectedPortlets)) {
577 String[] panelSelectedPortletsArray = StringUtil.split(
578 panelSelectedPortlets);
579
580 return ArrayUtil.contains(panelSelectedPortletsArray, portletId);
581 }
582
583 return false;
584 }
585
586 protected boolean isValidPortletId(String portletId) {
587 for (int i = 0; i < portletId.length(); i++) {
588 char c = portletId.charAt(i);
589
590 if ((c >= CharPool.LOWER_CASE_A) && (c <= CharPool.LOWER_CASE_Z)) {
591 continue;
592 }
593
594 if ((c >= CharPool.UPPER_CASE_A) && (c <= CharPool.UPPER_CASE_Z)) {
595 continue;
596 }
597
598 if ((c >= CharPool.NUMBER_0) && (c <= CharPool.NUMBER_9)) {
599 continue;
600 }
601
602 if (c == CharPool.UNDERLINE) {
603 continue;
604 }
605
606 return false;
607 }
608
609 return true;
610 }
611
612 protected ActionResult processActionException(
613 HttpServletRequest request, HttpServletResponse response,
614 Portlet portlet, PrincipalException e) {
615
616 if (_log.isDebugEnabled()) {
617 _log.debug(e);
618 }
619
620 String url = getOriginalURL(request);
621
622 if (_log.isWarnEnabled()) {
623 _log.warn(
624 "Reject process action for " + url + " on " +
625 portlet.getPortletId());
626 }
627
628 return ActionResult.EMPTY_ACTION_RESULT;
629 }
630
631 protected void processRenderException(
632 HttpServletRequest request, HttpServletResponse response,
633 Portlet portlet)
634 throws PortletContainerException {
635
636 String portletContent = null;
637
638 if (portlet.isShowPortletAccessDenied()) {
639 portletContent = "/html/portal/portlet_access_denied.jsp";
640 }
641
642 try {
643 if (portletContent != null) {
644 RequestDispatcher requestDispatcher =
645 request.getRequestDispatcher(portletContent);
646
647 requestDispatcher.include(request, response);
648 }
649 }
650 catch (Exception ex) {
651 throw new PortletContainerException(ex);
652 }
653 }
654
655 protected void processServeResourceException(
656 HttpServletRequest request, HttpServletResponse response,
657 Portlet portlet, PrincipalException e) {
658
659 if (_log.isDebugEnabled()) {
660 _log.debug(e);
661 }
662
663 String url = getOriginalURL(request);
664
665 response.setHeader(
666 HttpHeaders.CACHE_CONTROL,
667 HttpHeaders.CACHE_CONTROL_NO_CACHE_VALUE);
668
669 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
670
671 if (_log.isWarnEnabled()) {
672 _log.warn(
673 "Reject serveResource for " + url + " on " +
674 portlet.getPortletId());
675 }
676 }
677
678 private static Log _log = LogFactoryUtil.getLog(
679 SecurityPortletContainerWrapper.class);
680
681 private PortletContainer _portletContainer;
682
683 }