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 = PortletMode.VIEW;
335
336 String portletId = portlet.getPortletId();
337 String ppid = request.getParameter("p_p_id");
338 String ppmode = request.getParameter("p_p_mode");
339
340 if (portletId.equals(ppid) && (ppmode != null)) {
341 portletMode = PortletModeFactory.getPortletMode(ppmode);
342 }
343
344 return PortletPermissionUtil.hasAccessPermission(
345 permissionChecker, themeDisplay.getScopeGroupId(), layout, portlet,
346 portletMode);
347 }
348
349 protected void isAccessAllowedToControlPanelPortlet(
350 HttpServletRequest request, Portlet portlet)
351 throws PortalException, SystemException {
352
353 PermissionChecker permissionChecker =
354 PermissionThreadLocal.getPermissionChecker();
355
356 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
357 WebKeys.THEME_DISPLAY);
358
359 if (PortletPermissionUtil.hasControlPanelAccessPermission(
360 permissionChecker, themeDisplay.getScopeGroupId(), portlet)) {
361
362 return;
363 }
364
365 if (isAccessGrantedByRuntimePortlet(request, portlet)) {
366 return;
367 }
368
369 if (isAccessGrantedByPortletAuthenticationToken(request, portlet)) {
370 return;
371 }
372
373 throw new PrincipalException();
374 }
375
376 protected boolean isAccessAllowedToLayoutPortlet(
377 HttpServletRequest request, Portlet portlet)
378 throws PortalException, SystemException {
379
380 if (isAccessGrantedByRuntimePortlet(request, portlet)) {
381 return true;
382 }
383
384 if (isAccessGrantedByPortletOnPage(request, portlet)) {
385 return true;
386 }
387
388 if (isLayoutConfigurationAllowed(request, portlet)) {
389 return true;
390 }
391
392 if (isAccessGrantedByPortletAuthenticationToken(request, portlet)) {
393 return true;
394 }
395
396 return false;
397 }
398
399 protected boolean isAccessGrantedByPortletAuthenticationToken(
400 HttpServletRequest request, Portlet portlet) {
401
402 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
403 WebKeys.THEME_DISPLAY);
404
405 String portletId = portlet.getPortletId();
406
407 if (!portlet.isAddDefaultResource()) {
408 return false;
409 }
410
411 if (!PropsValues.PORTLET_ADD_DEFAULT_RESOURCE_CHECK_ENABLED) {
412 return true;
413 }
414
415 String namespace = PortalUtil.getPortletNamespace(portletId);
416
417 String strutsAction = ParamUtil.getString(
418 request, namespace + "struts_action");
419
420 if (Validator.isNull(strutsAction)) {
421 strutsAction = ParamUtil.getString(request, "struts_action");
422 }
423
424 String requestPortletAuthenticationToken = ParamUtil.getString(
425 request, "p_p_auth");
426
427 if (Validator.isNull(requestPortletAuthenticationToken)) {
428 HttpServletRequest originalRequest =
429 PortalUtil.getOriginalServletRequest(request);
430
431 requestPortletAuthenticationToken = ParamUtil.getString(
432 originalRequest, "p_p_auth");
433 }
434
435 if (AuthTokenUtil.isValidPortletInvocationToken(
436 request, themeDisplay.getPlid(), portletId, strutsAction,
437 requestPortletAuthenticationToken)) {
438
439 return true;
440 }
441
442 return false;
443 }
444
445 protected boolean isAccessGrantedByPortletOnPage(
446 HttpServletRequest request, Portlet portlet)
447 throws PortalException, SystemException {
448
449 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
450 WebKeys.THEME_DISPLAY);
451
452 Layout layout = themeDisplay.getLayout();
453
454 String portletId = portlet.getPortletId();
455
456 if (layout.isTypePanel() &&
457 isPanelSelectedPortlet(themeDisplay, portletId)) {
458
459 return true;
460 }
461
462 LayoutTypePortlet layoutTypePortlet =
463 themeDisplay.getLayoutTypePortlet();
464
465 if ((layoutTypePortlet != null) &&
466 layoutTypePortlet.hasPortletId(portletId)) {
467
468 return true;
469 }
470
471 return false;
472 }
473
474 protected boolean isAccessGrantedByRuntimePortlet(
475 HttpServletRequest request, Portlet portlet) {
476
477 Boolean renderPortletResource = (Boolean)request.getAttribute(
478 WebKeys.RENDER_PORTLET_RESOURCE);
479
480 if (renderPortletResource != null) {
481 boolean runtimePortlet = renderPortletResource.booleanValue();
482
483 if (runtimePortlet) {
484 return true;
485 }
486 }
487
488 return false;
489 }
490
491 protected boolean isLayoutConfigurationAllowed(
492 HttpServletRequest request, Portlet portlet)
493 throws PortalException, SystemException {
494
495 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
496 WebKeys.THEME_DISPLAY);
497
498 if (!themeDisplay.isSignedIn()) {
499 return false;
500 }
501
502 String portletId = portlet.getPortletId();
503
504 if (!portletId.equals(PortletKeys.LAYOUTS_ADMIN)) {
505 return false;
506 }
507
508 PermissionChecker permissionChecker =
509 themeDisplay.getPermissionChecker();
510
511 Layout layout = themeDisplay.getLayout();
512
513 Group group = layout.getGroup();
514
515 if (group.isSite()) {
516 if (LayoutPermissionUtil.contains(
517 permissionChecker, layout, ActionKeys.CUSTOMIZE) ||
518 LayoutPermissionUtil.contains(
519 permissionChecker, layout, ActionKeys.UPDATE)) {
520
521 return true;
522 }
523 }
524
525 if (group.isCompany()) {
526 if (permissionChecker.isCompanyAdmin()) {
527 return true;
528 }
529 }
530 else if (group.isLayoutPrototype()) {
531 long layoutPrototypeId = group.getClassPK();
532
533 if (LayoutPrototypePermissionUtil.contains(
534 permissionChecker, layoutPrototypeId,
535 ActionKeys.UPDATE)) {
536
537 return true;
538 }
539 }
540 else if (group.isLayoutSetPrototype()) {
541 long layoutSetPrototypeId = group.getClassPK();
542
543 if (LayoutSetPrototypePermissionUtil.contains(
544 permissionChecker, layoutSetPrototypeId,
545 ActionKeys.UPDATE)) {
546
547 return true;
548 }
549 }
550 else if (group.isOrganization()) {
551 long organizationId = group.getOrganizationId();
552
553 if (OrganizationPermissionUtil.contains(
554 permissionChecker, organizationId, ActionKeys.UPDATE)) {
555
556 return true;
557 }
558 }
559 else if (group.isUserGroup()) {
560 long scopeGroupId = themeDisplay.getScopeGroupId();
561
562 if (GroupPermissionUtil.contains(
563 permissionChecker, scopeGroupId, ActionKeys.UPDATE)) {
564
565 return true;
566 }
567 }
568 else if (group.isUser()) {
569 return true;
570 }
571
572 return false;
573 }
574
575 protected boolean isPanelSelectedPortlet(
576 ThemeDisplay themeDisplay, String portletId) {
577
578 Layout layout = themeDisplay.getLayout();
579
580 String panelSelectedPortlets = layout.getTypeSettingsProperty(
581 "panelSelectedPortlets");
582
583 if (Validator.isNotNull(panelSelectedPortlets)) {
584 String[] panelSelectedPortletsArray = StringUtil.split(
585 panelSelectedPortlets);
586
587 return ArrayUtil.contains(panelSelectedPortletsArray, portletId);
588 }
589
590 return false;
591 }
592
593 protected boolean isValidPortletId(String portletId) {
594 for (int i = 0; i < portletId.length(); i++) {
595 char c = portletId.charAt(i);
596
597 if ((c >= CharPool.LOWER_CASE_A) && (c <= CharPool.LOWER_CASE_Z)) {
598 continue;
599 }
600
601 if ((c >= CharPool.UPPER_CASE_A) && (c <= CharPool.UPPER_CASE_Z)) {
602 continue;
603 }
604
605 if ((c >= CharPool.NUMBER_0) && (c <= CharPool.NUMBER_9)) {
606 continue;
607 }
608
609 if (c == CharPool.UNDERLINE) {
610 continue;
611 }
612
613 return false;
614 }
615
616 return true;
617 }
618
619 protected ActionResult processActionException(
620 HttpServletRequest request, HttpServletResponse response,
621 Portlet portlet, PrincipalException e) {
622
623 if (_log.isDebugEnabled()) {
624 _log.debug(e);
625 }
626
627 String url = getOriginalURL(request);
628
629 if (_log.isWarnEnabled()) {
630 _log.warn(
631 "Reject process action for " + url + " on " +
632 portlet.getPortletId());
633 }
634
635 return ActionResult.EMPTY_ACTION_RESULT;
636 }
637
638 protected void processRenderException(
639 HttpServletRequest request, HttpServletResponse response,
640 Portlet portlet)
641 throws PortletContainerException {
642
643 String portletContent = null;
644
645 if (portlet.isShowPortletAccessDenied()) {
646 portletContent = "/html/portal/portlet_access_denied.jsp";
647 }
648
649 try {
650 if (portletContent != null) {
651 RequestDispatcher requestDispatcher =
652 request.getRequestDispatcher(portletContent);
653
654 requestDispatcher.include(request, response);
655 }
656 }
657 catch (Exception ex) {
658 throw new PortletContainerException(ex);
659 }
660 }
661
662 protected void processServeResourceException(
663 HttpServletRequest request, HttpServletResponse response,
664 Portlet portlet, PrincipalException e) {
665
666 if (_log.isDebugEnabled()) {
667 _log.debug(e);
668 }
669
670 String url = getOriginalURL(request);
671
672 response.setHeader(
673 HttpHeaders.CACHE_CONTROL,
674 HttpHeaders.CACHE_CONTROL_NO_CACHE_VALUE);
675
676 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
677
678 if (_log.isWarnEnabled()) {
679 _log.warn(
680 "Reject serveResource for " + url + " on " +
681 portlet.getPortletId());
682 }
683 }
684
685 private static Log _log = LogFactoryUtil.getLog(
686 SecurityPortletContainerWrapper.class);
687
688 private PortletContainer _portletContainer;
689
690 }