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