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 (portlet.isUndeployedPortlet()) {
187 return;
188 }
189
190 if (!isValidPortletId(portlet.getPortletId())) {
191 _log.warn("Invalid portlet id " + portlet.getPortletId());
192
193 throw new PrincipalException();
194 }
195
196 Layout layout = (Layout)request.getAttribute(WebKeys.LAYOUT);
197
198 if (layout.isTypeControlPanel()) {
199 isAccessAllowedToControlPanelPortlet(request, portlet);
200
201 return;
202 }
203
204 if (isAccessAllowedToLayoutPortlet(request, portlet)) {
205 PortalUtil.addPortletDefaultResource(request, portlet);
206
207 if (hasAccessPermission(request, portlet)) {
208 return;
209 }
210 }
211
212 throw new PrincipalException();
213 }
214
215 protected void checkAction(HttpServletRequest request, Portlet portlet)
216 throws Exception {
217
218 checkCSRFProtection(request, portlet);
219
220 check(request, portlet);
221 }
222
223 protected void checkCSRFProtection(
224 HttpServletRequest request, Portlet portlet)
225 throws PortalException {
226
227 if (!PropsValues.AUTH_TOKEN_CHECK_ENABLED) {
228 return;
229 }
230
231 Map<String, String> initParams = portlet.getInitParams();
232
233 boolean checkAuthToken = GetterUtil.getBoolean(
234 initParams.get("check-auth-token"), true);
235
236 if (checkAuthToken) {
237 AuthTokenUtil.check(request);
238 }
239 }
240
241 protected void checkRender(HttpServletRequest request, Portlet portlet)
242 throws Exception {
243
244 check(request, portlet);
245 }
246
247 protected void checkResource(HttpServletRequest request, Portlet portlet)
248 throws Exception {
249
250 check(request, portlet);
251 }
252
253 protected String getOriginalURL(HttpServletRequest request) {
254 LastPath lastPath = (LastPath)request.getAttribute(WebKeys.LAST_PATH);
255
256 if (lastPath == null) {
257 return String.valueOf(request.getRequestURI());
258 }
259
260 String portalURL = PortalUtil.getPortalURL(request);
261
262 return portalURL.concat(
263 lastPath.getContextPath()).concat(lastPath.getPath());
264 }
265
266 protected HttpServletRequest getOwnerLayoutRequestWrapper(
267 HttpServletRequest request, Portlet portlet)
268 throws Exception {
269
270 if (!PropsValues.PORTLET_EVENT_DISTRIBUTION_LAYOUT_SET ||
271 PropsValues.PORTLET_CROSS_LAYOUT_INVOCATION_MODE.equals("render")) {
272
273 return request;
274 }
275
276 Layout ownerLayout = null;
277 LayoutTypePortlet ownerLayoutTypePortlet = null;
278
279 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
280 WebKeys.THEME_DISPLAY);
281
282 Layout requestLayout = (Layout)request.getAttribute(WebKeys.LAYOUT);
283
284 List<LayoutTypePortlet> layoutTypePortlets =
285 PortletContainerUtil.getLayoutTypePortlets(requestLayout);
286
287 for (LayoutTypePortlet layoutTypePortlet : layoutTypePortlets) {
288 if (layoutTypePortlet.hasPortletId(portlet.getPortletId())) {
289 ownerLayoutTypePortlet = layoutTypePortlet;
290
291 ownerLayout = layoutTypePortlet.getLayout();
292
293 break;
294 }
295 }
296
297 if (ownerLayout == null) {
298 return request;
299 }
300
301 Layout currentLayout = themeDisplay.getLayout();
302
303 if (currentLayout.equals(ownerLayout)) {
304 return request;
305 }
306
307 ThemeDisplay themeDisplayClone = (ThemeDisplay)themeDisplay.clone();
308
309 themeDisplayClone.setLayout(ownerLayout);
310 themeDisplayClone.setLayoutTypePortlet(ownerLayoutTypePortlet);
311
312 TempAttributesServletRequest tempAttributesServletRequest =
313 new TempAttributesServletRequest(request);
314
315 tempAttributesServletRequest.setTempAttribute(
316 WebKeys.LAYOUT, ownerLayout);
317 tempAttributesServletRequest.setTempAttribute(
318 WebKeys.THEME_DISPLAY, themeDisplayClone);
319
320 return tempAttributesServletRequest;
321 }
322
323 protected boolean hasAccessPermission(
324 HttpServletRequest request, Portlet portlet)
325 throws PortalException, SystemException {
326
327 PermissionChecker permissionChecker =
328 PermissionThreadLocal.getPermissionChecker();
329
330 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
331 WebKeys.THEME_DISPLAY);
332
333 Layout layout = (Layout)request.getAttribute(WebKeys.LAYOUT);
334
335 PortletMode portletMode = PortletModeFactory.getPortletMode(
336 ParamUtil.getString(request, "p_p_mode"));
337
338 return PortletPermissionUtil.hasAccessPermission(
339 permissionChecker, themeDisplay.getScopeGroupId(), layout, portlet,
340 portletMode);
341 }
342
343 protected void isAccessAllowedToControlPanelPortlet(
344 HttpServletRequest request, Portlet portlet)
345 throws PortalException, SystemException {
346
347 PermissionChecker permissionChecker =
348 PermissionThreadLocal.getPermissionChecker();
349
350 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
351 WebKeys.THEME_DISPLAY);
352
353 if (PortletPermissionUtil.hasControlPanelAccessPermission(
354 permissionChecker, themeDisplay.getScopeGroupId(), portlet)) {
355
356 return;
357 }
358
359 if (isAccessGrantedByRuntimePortlet(request, portlet)) {
360 return;
361 }
362
363 if (isAccessGrantedByPortletAuthenticationToken(request, portlet)) {
364 return;
365 }
366
367 throw new PrincipalException();
368 }
369
370 protected boolean isAccessAllowedToLayoutPortlet(
371 HttpServletRequest request, Portlet portlet)
372 throws PortalException, SystemException {
373
374 if (isAccessGrantedByRuntimePortlet(request, portlet)) {
375 return true;
376 }
377
378 if (isAccessGrantedByPortletOnPage(request, portlet)) {
379 return true;
380 }
381
382 if (isLayoutConfigurationAllowed(request, portlet)) {
383 return true;
384 }
385
386 if (isAccessGrantedByPortletAuthenticationToken(request, portlet)) {
387 return true;
388 }
389
390 return false;
391 }
392
393 protected boolean isAccessGrantedByPortletAuthenticationToken(
394 HttpServletRequest request, Portlet portlet) {
395
396 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
397 WebKeys.THEME_DISPLAY);
398
399 String portletId = portlet.getPortletId();
400
401 if (!portlet.isAddDefaultResource()) {
402 return false;
403 }
404
405 if (!PropsValues.PORTLET_ADD_DEFAULT_RESOURCE_CHECK_ENABLED) {
406 return true;
407 }
408
409 String namespace = PortalUtil.getPortletNamespace(portletId);
410
411 String strutsAction = ParamUtil.getString(
412 request, namespace + "struts_action");
413
414 if (Validator.isNull(strutsAction)) {
415 strutsAction = ParamUtil.getString(request, "struts_action");
416 }
417
418 String requestPortletAuthenticationToken = ParamUtil.getString(
419 request, "p_p_auth");
420
421 if (Validator.isNull(requestPortletAuthenticationToken)) {
422 HttpServletRequest originalRequest =
423 PortalUtil.getOriginalServletRequest(request);
424
425 requestPortletAuthenticationToken = ParamUtil.getString(
426 originalRequest, "p_p_auth");
427 }
428
429 if (AuthTokenUtil.isValidPortletInvocationToken(
430 request, themeDisplay.getPlid(), portletId, strutsAction,
431 requestPortletAuthenticationToken)) {
432
433 return true;
434 }
435
436 return false;
437 }
438
439 protected boolean isAccessGrantedByPortletOnPage(
440 HttpServletRequest request, Portlet portlet)
441 throws PortalException, SystemException {
442
443 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
444 WebKeys.THEME_DISPLAY);
445
446 Layout layout = themeDisplay.getLayout();
447
448 String portletId = portlet.getPortletId();
449
450 if (layout.isTypePanel() &&
451 isPanelSelectedPortlet(themeDisplay, portletId)) {
452
453 return true;
454 }
455
456 LayoutTypePortlet layoutTypePortlet =
457 themeDisplay.getLayoutTypePortlet();
458
459 if ((layoutTypePortlet != null) &&
460 layoutTypePortlet.hasPortletId(portletId)) {
461
462 return true;
463 }
464
465 return false;
466 }
467
468 protected boolean isAccessGrantedByRuntimePortlet(
469 HttpServletRequest request, Portlet portlet) {
470
471 Boolean renderPortletResource = (Boolean)request.getAttribute(
472 WebKeys.RENDER_PORTLET_RESOURCE);
473
474 if (renderPortletResource != null) {
475 boolean runtimePortlet = renderPortletResource.booleanValue();
476
477 if (runtimePortlet) {
478 return true;
479 }
480 }
481
482 return false;
483 }
484
485 protected boolean isLayoutConfigurationAllowed(
486 HttpServletRequest request, Portlet portlet)
487 throws PortalException, SystemException {
488
489 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
490 WebKeys.THEME_DISPLAY);
491
492 if (!themeDisplay.isSignedIn()) {
493 return false;
494 }
495
496 String portletId = portlet.getPortletId();
497
498 if (!portletId.equals(PortletKeys.LAYOUTS_ADMIN)) {
499 return false;
500 }
501
502 PermissionChecker permissionChecker =
503 themeDisplay.getPermissionChecker();
504
505 Layout layout = themeDisplay.getLayout();
506
507 Group group = layout.getGroup();
508
509 if (group.isSite()) {
510 if (LayoutPermissionUtil.contains(
511 permissionChecker, layout, ActionKeys.CUSTOMIZE) ||
512 LayoutPermissionUtil.contains(
513 permissionChecker, layout, ActionKeys.UPDATE)) {
514
515 return true;
516 }
517 }
518
519 if (group.isCompany()) {
520 if (permissionChecker.isCompanyAdmin()) {
521 return true;
522 }
523 }
524 else if (group.isLayoutPrototype()) {
525 long layoutPrototypeId = group.getClassPK();
526
527 if (LayoutPrototypePermissionUtil.contains(
528 permissionChecker, layoutPrototypeId,
529 ActionKeys.UPDATE)) {
530
531 return true;
532 }
533 }
534 else if (group.isLayoutSetPrototype()) {
535 long layoutSetPrototypeId = group.getClassPK();
536
537 if (LayoutSetPrototypePermissionUtil.contains(
538 permissionChecker, layoutSetPrototypeId,
539 ActionKeys.UPDATE)) {
540
541 return true;
542 }
543 }
544 else if (group.isOrganization()) {
545 long organizationId = group.getOrganizationId();
546
547 if (OrganizationPermissionUtil.contains(
548 permissionChecker, organizationId, ActionKeys.UPDATE)) {
549
550 return true;
551 }
552 }
553 else if (group.isUserGroup()) {
554 long scopeGroupId = themeDisplay.getScopeGroupId();
555
556 if (GroupPermissionUtil.contains(
557 permissionChecker, scopeGroupId, ActionKeys.UPDATE)) {
558
559 return true;
560 }
561 }
562 else if (group.isUser()) {
563 return true;
564 }
565
566 return false;
567 }
568
569 protected boolean isPanelSelectedPortlet(
570 ThemeDisplay themeDisplay, String portletId) {
571
572 Layout layout = themeDisplay.getLayout();
573
574 String panelSelectedPortlets = layout.getTypeSettingsProperty(
575 "panelSelectedPortlets");
576
577 if (Validator.isNotNull(panelSelectedPortlets)) {
578 String[] panelSelectedPortletsArray = StringUtil.split(
579 panelSelectedPortlets);
580
581 return ArrayUtil.contains(panelSelectedPortletsArray, portletId);
582 }
583
584 return false;
585 }
586
587 protected boolean isValidPortletId(String portletId) {
588 for (int i = 0; i < portletId.length(); i++) {
589 char c = portletId.charAt(i);
590
591 if ((c >= CharPool.LOWER_CASE_A) && (c <= CharPool.LOWER_CASE_Z)) {
592 continue;
593 }
594
595 if ((c >= CharPool.UPPER_CASE_A) && (c <= CharPool.UPPER_CASE_Z)) {
596 continue;
597 }
598
599 if ((c >= CharPool.NUMBER_0) && (c <= CharPool.NUMBER_9)) {
600 continue;
601 }
602
603 if (c == CharPool.UNDERLINE) {
604 continue;
605 }
606
607 return false;
608 }
609
610 return true;
611 }
612
613 protected ActionResult processActionException(
614 HttpServletRequest request, HttpServletResponse response,
615 Portlet portlet, PrincipalException e) {
616
617 if (_log.isDebugEnabled()) {
618 _log.debug(e);
619 }
620
621 String url = getOriginalURL(request);
622
623 _log.warn(
624 "Reject process action for " + url + " on " +
625 portlet.getPortletId());
626
627 return ActionResult.EMPTY_ACTION_RESULT;
628 }
629
630 protected void processRenderException(
631 HttpServletRequest request, HttpServletResponse response,
632 Portlet portlet)
633 throws PortletContainerException {
634
635 String portletContent = null;
636
637 if (portlet.isShowPortletAccessDenied()) {
638 portletContent = "/html/portal/portlet_access_denied.jsp";
639 }
640
641 try {
642 if (portletContent != null) {
643 RequestDispatcher requestDispatcher =
644 request.getRequestDispatcher(portletContent);
645
646 requestDispatcher.include(request, response);
647 }
648 }
649 catch (Exception ex) {
650 throw new PortletContainerException(ex);
651 }
652 }
653
654 protected void processServeResourceException(
655 HttpServletRequest request, HttpServletResponse response,
656 Portlet portlet, PrincipalException e) {
657
658 if (_log.isDebugEnabled()) {
659 _log.debug(e);
660 }
661
662 String url = getOriginalURL(request);
663
664 response.setHeader(
665 HttpHeaders.CACHE_CONTROL,
666 HttpHeaders.CACHE_CONTROL_NO_CACHE_VALUE);
667
668 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
669
670 _log.warn(
671 "Reject serveResource for " + url + " on " +
672 portlet.getPortletId());
673 }
674
675 private static Log _log = LogFactoryUtil.getLog(
676 SecurityPortletContainerWrapper.class);
677
678 private PortletContainer _portletContainer;
679
680 }