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.resiliency.spi.SPIUtil;
025 import com.liferay.portal.kernel.security.pacl.DoPrivileged;
026 import com.liferay.portal.kernel.servlet.HttpHeaders;
027 import com.liferay.portal.kernel.servlet.TempAttributesServletRequest;
028 import com.liferay.portal.kernel.struts.LastPath;
029 import com.liferay.portal.kernel.util.CharPool;
030 import com.liferay.portal.kernel.util.GetterUtil;
031 import com.liferay.portal.model.Layout;
032 import com.liferay.portal.model.LayoutType;
033 import com.liferay.portal.model.LayoutTypeAccessPolicy;
034 import com.liferay.portal.model.LayoutTypePortlet;
035 import com.liferay.portal.model.Portlet;
036 import com.liferay.portal.security.auth.AuthTokenUtil;
037 import com.liferay.portal.security.auth.PrincipalException;
038 import com.liferay.portal.theme.ThemeDisplay;
039 import com.liferay.portal.util.PortalUtil;
040 import com.liferay.portal.util.PropsValues;
041 import com.liferay.portal.util.WebKeys;
042
043 import java.util.List;
044 import java.util.Map;
045
046 import javax.portlet.Event;
047
048 import javax.servlet.RequestDispatcher;
049 import javax.servlet.http.HttpServletRequest;
050 import javax.servlet.http.HttpServletResponse;
051
052
056 @DoPrivileged
057 public class SecurityPortletContainerWrapper implements PortletContainer {
058
059 public static PortletContainer createSecurityPortletContainerWrapper(
060 PortletContainer portletContainer) {
061
062 if (!SPIUtil.isSPI()) {
063 portletContainer = new SecurityPortletContainerWrapper(
064 portletContainer);
065 }
066
067 return portletContainer;
068 }
069
070 public SecurityPortletContainerWrapper(PortletContainer portletContainer) {
071 _portletContainer = portletContainer;
072 }
073
074 @Override
075 public void preparePortlet(HttpServletRequest request, Portlet portlet)
076 throws PortletContainerException {
077
078 _portletContainer.preparePortlet(request, portlet);
079 }
080
081 @Override
082 public ActionResult processAction(
083 HttpServletRequest request, HttpServletResponse response,
084 Portlet portlet)
085 throws PortletContainerException {
086
087 try {
088 HttpServletRequest ownerLayoutRequest =
089 getOwnerLayoutRequestWrapper(request, portlet);
090
091 checkAction(ownerLayoutRequest, portlet);
092
093 return _portletContainer.processAction(request, response, portlet);
094 }
095 catch (PrincipalException pe) {
096 return processActionException(request, response, portlet, pe);
097 }
098 catch (PortletContainerException pce) {
099 throw pce;
100 }
101 catch (Exception e) {
102 throw new PortletContainerException(e);
103 }
104 }
105
106 @Override
107 public List<Event> processEvent(
108 HttpServletRequest request, HttpServletResponse response,
109 Portlet portlet, Layout layout, Event event)
110 throws PortletContainerException {
111
112 return _portletContainer.processEvent(
113 request, response, portlet, layout, event);
114 }
115
116 @Override
117 public void render(
118 HttpServletRequest request, HttpServletResponse response,
119 Portlet portlet)
120 throws PortletContainerException {
121
122 try {
123 checkRender(request, portlet);
124
125 _portletContainer.render(request, response, portlet);
126 }
127 catch (PrincipalException pe) {
128 processRenderException(request, response, portlet);
129 }
130 catch (PortletContainerException pce) {
131 throw pce;
132 }
133 catch (Exception e) {
134 throw new PortletContainerException(e);
135 }
136 }
137
138 @Override
139 public void serveResource(
140 HttpServletRequest request, HttpServletResponse response,
141 Portlet portlet)
142 throws PortletContainerException {
143
144 try {
145 HttpServletRequest ownerLayoutRequest =
146 getOwnerLayoutRequestWrapper(request, portlet);
147
148 checkResource(ownerLayoutRequest, portlet);
149
150 _portletContainer.serveResource(request, response, portlet);
151 }
152 catch (PrincipalException pe) {
153 processServeResourceException(request, response, portlet, pe);
154 }
155 catch (PortletContainerException pce) {
156 throw pce;
157 }
158 catch (Exception e) {
159 throw new PortletContainerException(e);
160 }
161 }
162
163 protected void check(HttpServletRequest request, Portlet portlet)
164 throws Exception {
165
166 if (portlet == null) {
167 return;
168 }
169
170 if (!isValidPortletId(portlet.getPortletId())) {
171 if (_log.isWarnEnabled()) {
172 _log.warn("Invalid portlet ID " + portlet.getPortletId());
173 }
174
175 throw new PrincipalException(
176 "Invalid portlet ID " + portlet.getPortletId());
177 }
178
179 if (portlet.isUndeployedPortlet()) {
180 return;
181 }
182
183 Layout layout = (Layout)request.getAttribute(WebKeys.LAYOUT);
184
185 LayoutType layoutType = layout.getLayoutType();
186
187 LayoutTypeAccessPolicy layoutTypeAccessPolicy =
188 layoutType.getLayoutTypeAccessPolicy();
189
190 layoutTypeAccessPolicy.checkAccessAllowedToPortlet(
191 request, layout, portlet);
192 }
193
194 protected void checkAction(HttpServletRequest request, Portlet portlet)
195 throws Exception {
196
197 checkCSRFProtection(request, portlet);
198
199 check(request, portlet);
200 }
201
202 protected void checkCSRFProtection(
203 HttpServletRequest request, Portlet portlet)
204 throws PortalException {
205
206 Map<String, String> initParams = portlet.getInitParams();
207
208 boolean checkAuthToken = GetterUtil.getBoolean(
209 initParams.get("check-auth-token"), true);
210
211 if (checkAuthToken) {
212 AuthTokenUtil.checkCSRFToken(
213 request, SecurityPortletContainerWrapper.class.getName());
214 }
215 }
216
217 protected void checkRender(HttpServletRequest request, Portlet portlet)
218 throws Exception {
219
220 check(request, portlet);
221 }
222
223 protected void checkResource(HttpServletRequest request, Portlet portlet)
224 throws Exception {
225
226 check(request, portlet);
227 }
228
229 protected String getOriginalURL(HttpServletRequest request) {
230 LastPath lastPath = (LastPath)request.getAttribute(WebKeys.LAST_PATH);
231
232 if (lastPath == null) {
233 return String.valueOf(request.getRequestURI());
234 }
235
236 String portalURL = PortalUtil.getPortalURL(request);
237
238 return portalURL.concat(
239 lastPath.getContextPath()).concat(lastPath.getPath());
240 }
241
242 protected HttpServletRequest getOwnerLayoutRequestWrapper(
243 HttpServletRequest request, Portlet portlet)
244 throws Exception {
245
246 if (!PropsValues.PORTLET_EVENT_DISTRIBUTION_LAYOUT_SET ||
247 PropsValues.PORTLET_CROSS_LAYOUT_INVOCATION_MODE.equals("render")) {
248
249 return request;
250 }
251
252 Layout ownerLayout = null;
253 LayoutTypePortlet ownerLayoutTypePortlet = null;
254
255 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
256 WebKeys.THEME_DISPLAY);
257
258 Layout requestLayout = (Layout)request.getAttribute(WebKeys.LAYOUT);
259
260 List<LayoutTypePortlet> layoutTypePortlets =
261 PortletContainerUtil.getLayoutTypePortlets(requestLayout);
262
263 for (LayoutTypePortlet layoutTypePortlet : layoutTypePortlets) {
264 if (layoutTypePortlet.hasPortletId(portlet.getPortletId())) {
265 ownerLayoutTypePortlet = layoutTypePortlet;
266
267 ownerLayout = layoutTypePortlet.getLayout();
268
269 break;
270 }
271 }
272
273 if (ownerLayout == null) {
274 return request;
275 }
276
277 Layout currentLayout = themeDisplay.getLayout();
278
279 if (currentLayout.equals(ownerLayout)) {
280 return request;
281 }
282
283 ThemeDisplay themeDisplayClone = (ThemeDisplay)themeDisplay.clone();
284
285 themeDisplayClone.setLayout(ownerLayout);
286 themeDisplayClone.setLayoutTypePortlet(ownerLayoutTypePortlet);
287
288 TempAttributesServletRequest tempAttributesServletRequest =
289 new TempAttributesServletRequest(request);
290
291 tempAttributesServletRequest.setTempAttribute(
292 WebKeys.LAYOUT, ownerLayout);
293 tempAttributesServletRequest.setTempAttribute(
294 WebKeys.THEME_DISPLAY, themeDisplayClone);
295
296 return tempAttributesServletRequest;
297 }
298
299 protected boolean isValidPortletId(String portletId) {
300 for (int i = 0; i < portletId.length(); i++) {
301 char c = portletId.charAt(i);
302
303 if ((c >= CharPool.LOWER_CASE_A) && (c <= CharPool.LOWER_CASE_Z)) {
304 continue;
305 }
306
307 if ((c >= CharPool.UPPER_CASE_A) && (c <= CharPool.UPPER_CASE_Z)) {
308 continue;
309 }
310
311 if ((c >= CharPool.NUMBER_0) && (c <= CharPool.NUMBER_9)) {
312 continue;
313 }
314
315 if ((c == CharPool.POUND) || (c == CharPool.UNDERLINE)) {
316 continue;
317 }
318
319 return false;
320 }
321
322 return true;
323 }
324
325 protected ActionResult processActionException(
326 HttpServletRequest request, HttpServletResponse response,
327 Portlet portlet, PrincipalException pe) {
328
329 if (_log.isDebugEnabled()) {
330 _log.debug(pe);
331 }
332
333 String url = getOriginalURL(request);
334
335 if (_log.isWarnEnabled()) {
336 _log.warn(
337 String.format(
338 "User %s is not allowed to access URL %s and portlet %s",
339 PortalUtil.getUserId(request), url,
340 portlet.getPortletId()));
341 }
342
343 return ActionResult.EMPTY_ACTION_RESULT;
344 }
345
346 protected void processRenderException(
347 HttpServletRequest request, HttpServletResponse response,
348 Portlet portlet)
349 throws PortletContainerException {
350
351 String portletContent = null;
352
353 if (portlet.isShowPortletAccessDenied()) {
354 portletContent = "/html/portal/portlet_access_denied.jsp";
355 }
356
357 try {
358 if (portletContent != null) {
359 RequestDispatcher requestDispatcher =
360 request.getRequestDispatcher(portletContent);
361
362 requestDispatcher.include(request, response);
363 }
364 }
365 catch (Exception e) {
366 throw new PortletContainerException(e);
367 }
368 }
369
370 protected void processServeResourceException(
371 HttpServletRequest request, HttpServletResponse response,
372 Portlet portlet, PrincipalException pe) {
373
374 if (_log.isDebugEnabled()) {
375 _log.debug(pe);
376 }
377
378 String url = getOriginalURL(request);
379
380 response.setHeader(
381 HttpHeaders.CACHE_CONTROL,
382 HttpHeaders.CACHE_CONTROL_NO_CACHE_VALUE);
383
384 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
385
386 if (_log.isWarnEnabled()) {
387 _log.warn(
388 "Reject serveResource for " + url + " on " +
389 portlet.getPortletId());
390 }
391 }
392
393 private static final Log _log = LogFactoryUtil.getLog(
394 SecurityPortletContainerWrapper.class);
395
396 private final PortletContainer _portletContainer;
397
398 }