001
014
015 package com.liferay.portal.security.auth;
016
017 import com.liferay.portal.kernel.concurrent.ConcurrentHashSet;
018 import com.liferay.portal.kernel.portlet.LiferayPortletURL;
019 import com.liferay.portal.kernel.portlet.bridges.mvc.MVCActionCommand;
020 import com.liferay.portal.kernel.portlet.bridges.mvc.MVCRenderCommand;
021 import com.liferay.portal.kernel.portlet.bridges.mvc.MVCResourceCommand;
022 import com.liferay.portal.kernel.security.auth.BaseAuthTokenWhitelist;
023 import com.liferay.portal.kernel.security.pacl.DoPrivileged;
024 import com.liferay.portal.kernel.util.ParamUtil;
025 import com.liferay.portal.kernel.util.StringPool;
026 import com.liferay.portal.kernel.util.StringUtil;
027 import com.liferay.portal.kernel.util.Validator;
028 import com.liferay.portal.kernel.util.WebKeys;
029 import com.liferay.portal.model.Portlet;
030 import com.liferay.portal.model.PortletConstants;
031 import com.liferay.portal.theme.ThemeDisplay;
032 import com.liferay.portal.util.PortalUtil;
033 import com.liferay.registry.Registry;
034 import com.liferay.registry.RegistryUtil;
035 import com.liferay.registry.ServiceReference;
036 import com.liferay.registry.ServiceTracker;
037 import com.liferay.registry.ServiceTrackerCustomizer;
038 import com.liferay.registry.util.StringPlus;
039
040 import java.util.List;
041 import java.util.Map;
042 import java.util.Set;
043
044 import javax.portlet.ActionRequest;
045 import javax.portlet.PortletRequest;
046
047 import javax.servlet.http.HttpServletRequest;
048
049
052 @DoPrivileged
053 public class MVCPortletAuthTokenWhitelist extends BaseAuthTokenWhitelist {
054
055 public MVCPortletAuthTokenWhitelist() {
056 trackWhitelistServices(
057 "auth.token.ignore.mvc.action", MVCActionCommand.class,
058 _portletCSRFWhitelist);
059 trackWhitelistServices(
060 "portlet.add.default.resource.check.whitelist.mvc.action",
061 MVCActionCommand.class, _portletInvocationWhitelistAction);
062 trackWhitelistServices(
063 "portlet.add.default.resource.check.whitelist.mvc.action",
064 MVCRenderCommand.class, _portletInvocationWhitelistRender);
065 trackWhitelistServices(
066 "portlet.add.default.resource.check.whitelist.mvc.action",
067 MVCResourceCommand.class, _portletInvocationWhitelistResource);
068 }
069
070 @Override
071 public boolean isPortletCSRFWhitelisted(
072 HttpServletRequest request, Portlet portlet) {
073
074 String portletId = portlet.getPortletId();
075
076 String[] mvcActionCommandNames = getMVCActionCommandNames(
077 request, portletId);
078
079 return _containsAll(
080 portletId, _portletCSRFWhitelist, mvcActionCommandNames);
081 }
082
083 @Override
084 public boolean isPortletInvocationWhitelisted(
085 HttpServletRequest request, Portlet portlet) {
086
087 String portletId = portlet.getPortletId();
088
089 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
090 WebKeys.THEME_DISPLAY);
091
092 if (themeDisplay.isLifecycleAction()) {
093 String[] mvcActionCommandNames = getMVCActionCommandNames(
094 request, portletId);
095
096 return _containsAll(
097 portletId, _portletInvocationWhitelistAction,
098 mvcActionCommandNames);
099 }
100
101 else if (themeDisplay.isLifecycleRender()) {
102 String namespace = PortalUtil.getPortletNamespace(portletId);
103
104 String mvcRenderCommandName = ParamUtil.getString(
105 request, namespace + "mvcRenderCommandName");
106
107 return _contains(
108 portletId, _portletInvocationWhitelistRender,
109 mvcRenderCommandName);
110 }
111
112 else if (themeDisplay.isLifecycleResource()) {
113 String ppid = ParamUtil.getString(request, "p_p_id");
114
115 if (!portletId.equals(ppid)) {
116 return false;
117 }
118
119 String mvcResourceCommandName = ParamUtil.getString(
120 request, "p_p_resource_id");
121
122 return _contains(
123 portletId, _portletInvocationWhitelistResource,
124 mvcResourceCommandName);
125 }
126
127 return false;
128 }
129
130 @Override
131 public boolean isPortletURLCSRFWhitelisted(
132 LiferayPortletURL liferayPortletURL) {
133
134 String[] mvcActionCommandNames = getMVCActionCommandNames(
135 liferayPortletURL);
136
137 return _containsAll(
138 liferayPortletURL.getPortletId(), _portletCSRFWhitelist,
139 mvcActionCommandNames);
140 }
141
142 @Override
143 public boolean isPortletURLPortletInvocationWhitelisted(
144 LiferayPortletURL liferayPortletURL) {
145
146 String portletId = liferayPortletURL.getPortletId();
147
148 String lifecycle = liferayPortletURL.getLifecycle();
149
150 if (lifecycle.equals(PortletRequest.ACTION_PHASE)) {
151 String[] mvcActionCommandNames = getMVCActionCommandNames(
152 liferayPortletURL);
153
154 return _containsAll(
155 portletId, _portletInvocationWhitelistAction,
156 mvcActionCommandNames);
157 }
158
159 else if (lifecycle.equals(PortletRequest.RENDER_PHASE)) {
160 String mvcRenderCommandName = liferayPortletURL.getParameter(
161 "mvcRenderCommandName");
162
163 return _contains(
164 portletId, _portletInvocationWhitelistRender,
165 mvcRenderCommandName);
166 }
167
168 else if (lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
169 String mvcResourceCommandName = liferayPortletURL.getResourceID();
170
171 return _contains(
172 portletId, _portletInvocationWhitelistResource,
173 mvcResourceCommandName);
174 }
175
176 return false;
177 }
178
179 protected String[] getMVCActionCommandNames(
180 HttpServletRequest request, String portletId) {
181
182 String namespace = PortalUtil.getPortletNamespace(portletId);
183
184 String[] actionNames = ParamUtil.getParameterValues(
185 request, namespace + ActionRequest.ACTION_NAME);
186
187 String actions = StringUtil.merge(actionNames);
188
189 return StringUtil.split(actions);
190 }
191
192 protected String[] getMVCActionCommandNames(
193 LiferayPortletURL liferayPortletURL) {
194
195 Map<String, String[]> parameterMap =
196 liferayPortletURL.getParameterMap();
197
198 String[] actionNames = parameterMap.get(ActionRequest.ACTION_NAME);
199
200 String actions = StringUtil.merge(actionNames);
201
202 return StringUtil.split(actions);
203 }
204
205 protected String getWhitelistValue(
206 String portletName, String whitelistAction) {
207
208 return portletName + StringPool.POUND + whitelistAction;
209 }
210
211 protected void trackWhitelistServices(
212 String whitelistName, Class<?> serviceClass, Set<String> whiteList) {
213
214 Registry registry = RegistryUtil.getRegistry();
215
216 ServiceTracker<Object, Object> serviceTracker = registry.trackServices(
217 registry.getFilter(
218 "(&(&(" + whitelistName + "=*)(javax.portlet.name=*))" +
219 "(objectClass=" + serviceClass.getName() + "))"),
220 new TokenWhitelistTrackerCustomizer(whiteList));
221
222 serviceTracker.open();
223
224 serviceTrackers.add(serviceTracker);
225 }
226
227 private boolean _contains(
228 String portletId, Set<String> whitelist, String item) {
229
230 if (Validator.isBlank(item)) {
231 return false;
232 }
233
234 String rootPortletId = PortletConstants.getRootPortletId(portletId);
235
236 return whitelist.contains(getWhitelistValue(rootPortletId, item));
237 }
238
239 private boolean _containsAll(
240 String portletId, Set<String> whitelist, String[] items) {
241
242 if (items.length == 0) {
243 return false;
244 }
245
246 String rootPortletId = PortletConstants.getRootPortletId(portletId);
247
248 for (String action : items) {
249 if (!whitelist.contains(getWhitelistValue(rootPortletId, action))) {
250 return false;
251 }
252 }
253
254 return true;
255 }
256
257 private final Set<String> _portletCSRFWhitelist = new ConcurrentHashSet<>();
258 private final Set<String> _portletInvocationWhitelistAction =
259 new ConcurrentHashSet<>();
260 private final Set<String> _portletInvocationWhitelistRender =
261 new ConcurrentHashSet<>();
262 private final Set<String> _portletInvocationWhitelistResource =
263 new ConcurrentHashSet<>();
264
265 private class TokenWhitelistTrackerCustomizer
266 implements ServiceTrackerCustomizer<Object, Object> {
267
268 public TokenWhitelistTrackerCustomizer(Set<String> whitelist) {
269 _whitelist = whitelist;
270 }
271
272 @Override
273 public Object addingService(ServiceReference<Object> serviceReference) {
274 List<String> whitelistActions = StringPlus.asList(
275 serviceReference.getProperty("mvc.command.name"));
276
277 List<String> portletNames = StringPlus.asList(
278 serviceReference.getProperty("javax.portlet.name"));
279
280 for (String portletName : portletNames) {
281 for (String whitelistAction : whitelistActions) {
282 _whitelist.add(
283 getWhitelistValue(portletName, whitelistAction));
284 }
285 }
286
287 Registry registry = RegistryUtil.getRegistry();
288
289 return registry.getService(serviceReference);
290 }
291
292 @Override
293 public void modifiedService(
294 ServiceReference<Object> serviceReference, Object object) {
295
296 removedService(serviceReference, object);
297
298 addingService(serviceReference);
299 }
300
301 @Override
302 public void removedService(
303 ServiceReference<Object> serviceReference, Object object) {
304
305 List<String> whitelistActions = StringPlus.asList(
306 serviceReference.getProperty("mvc.command.name"));
307
308 List<String> portletNames = StringPlus.asList(
309 serviceReference.getProperty("javax.portlet.name"));
310
311 for (String portletName : portletNames) {
312 for (String whitelistAction : whitelistActions) {
313 _whitelist.remove(
314 getWhitelistValue(portletName, whitelistAction));
315 }
316 }
317 }
318
319 private final Set<String> _whitelist;
320
321 }
322
323 }