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