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