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