1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.security;
15
16 import java.io.IOException;
17 import java.util.Arrays;
18 import java.util.Collection;
19 import java.util.HashSet;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Set;
23 import java.util.concurrent.CopyOnWriteArrayList;
24 import java.util.concurrent.CopyOnWriteArraySet;
25
26 import org.eclipse.jetty.http.PathMap;
27 import org.eclipse.jetty.http.security.Constraint;
28 import org.eclipse.jetty.server.Connector;
29 import org.eclipse.jetty.server.HttpConnection;
30 import org.eclipse.jetty.server.Request;
31 import org.eclipse.jetty.server.Response;
32 import org.eclipse.jetty.server.UserIdentity;
33 import org.eclipse.jetty.util.StringMap;
34
35
36
37
38
39
40
41
42 public class ConstraintSecurityHandler extends SecurityHandler implements ConstraintAware
43 {
44 private final List<ConstraintMapping> _constraintMappings= new CopyOnWriteArrayList<ConstraintMapping>();
45 private final Set<String> _roles = new CopyOnWriteArraySet<String>();
46 private final PathMap _constraintMap = new PathMap();
47 private boolean _strict = true;
48
49
50
51
52
53
54 public boolean isStrict()
55 {
56 return _strict;
57 }
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 public void setStrict(boolean strict)
76 {
77 _strict = strict;
78 }
79
80
81
82
83
84 public List<ConstraintMapping> getConstraintMappings()
85 {
86 return _constraintMappings;
87 }
88
89
90 public Set<String> getRoles()
91 {
92 return _roles;
93 }
94
95
96 @Deprecated
97 public void setConstraintMappings(ConstraintMapping[] constraintMappings)
98 {
99 setConstraintMappings(Arrays.asList(constraintMappings),null);
100 }
101
102
103
104
105
106
107
108
109
110
111 public void setConstraintMappings(List<ConstraintMapping> constraintMappings)
112 {
113 setConstraintMappings(constraintMappings,null);
114 }
115
116
117
118 @Deprecated
119 public void setConstraintMappings(ConstraintMapping[] constraintMappings, Set<String> roles)
120 {
121 setConstraintMappings(Arrays.asList(constraintMappings),roles);
122 }
123
124
125
126
127
128
129
130
131
132
133 public void setConstraintMappings(List<ConstraintMapping> constraintMappings, Set<String> roles)
134 {
135 if (isStarted())
136 throw new IllegalStateException("Started");
137 _constraintMappings.clear();
138 _constraintMappings.addAll(constraintMappings);
139
140 if (roles==null)
141 {
142 roles = new HashSet<String>();
143 for (ConstraintMapping cm : constraintMappings)
144 {
145 String[] cmr = cm.getConstraint().getRoles();
146 if (cmr!=null)
147 {
148 for (String r : cmr)
149 if (!"*".equals(r))
150 roles.add(r);
151 }
152 }
153 }
154 setRoles(roles);
155 }
156
157
158
159
160
161
162
163
164
165 public void setRoles(Set<String> roles)
166 {
167 if (isStarted())
168 throw new IllegalStateException("Started");
169
170 _roles.clear();
171 _roles.addAll(roles);
172 }
173
174
175
176
177
178
179
180 public void addConstraintMapping(ConstraintMapping mapping)
181 {
182 _constraintMappings.add(mapping);
183 if (mapping.getConstraint()!=null && mapping.getConstraint().getRoles()!=null)
184 for (String role : mapping.getConstraint().getRoles())
185 addRole(role);
186
187 if (isStarted())
188 {
189 processContraintMapping(mapping);
190 }
191 }
192
193
194
195
196
197 public void addRole(String role)
198 {
199 boolean modified = _roles.add(role);
200 if (isStarted() && modified && _strict)
201 {
202
203 for (Map<String,RoleInfo> map : (Collection<Map<String,RoleInfo>>)_constraintMap.values())
204 {
205 for (RoleInfo info : map.values())
206 {
207 if (info.isAnyRole())
208 info.addRole(role);
209 }
210 }
211 }
212 }
213
214
215
216
217
218 @Override
219 protected void doStart() throws Exception
220 {
221 _constraintMap.clear();
222 if (_constraintMappings!=null)
223 {
224 for (ConstraintMapping mapping : _constraintMappings)
225 {
226 processContraintMapping(mapping);
227 }
228 }
229 super.doStart();
230 }
231
232 protected void processContraintMapping(ConstraintMapping mapping)
233 {
234 Map<String, RoleInfo> mappings = (Map<String, RoleInfo>)_constraintMap.get(mapping.getPathSpec());
235 if (mappings == null)
236 {
237 mappings = new StringMap();
238 _constraintMap.put(mapping.getPathSpec(),mappings);
239 }
240 RoleInfo allMethodsRoleInfo = mappings.get(null);
241 if (allMethodsRoleInfo != null && allMethodsRoleInfo.isForbidden())
242 return;
243
244 String httpMethod = mapping.getMethod();
245 RoleInfo roleInfo = mappings.get(httpMethod);
246 if (roleInfo == null)
247 {
248 roleInfo = new RoleInfo();
249 mappings.put(httpMethod,roleInfo);
250 if (allMethodsRoleInfo != null)
251 {
252 roleInfo.combine(allMethodsRoleInfo);
253 }
254 }
255 if (roleInfo.isForbidden())
256 return;
257
258 Constraint constraint = mapping.getConstraint();
259 boolean forbidden = constraint.isForbidden();
260 roleInfo.setForbidden(forbidden);
261 if (forbidden)
262 {
263 if (httpMethod == null)
264 {
265 mappings.clear();
266 mappings.put(null,roleInfo);
267 }
268 }
269 else
270 {
271 UserDataConstraint userDataConstraint = UserDataConstraint.get(constraint.getDataConstraint());
272 roleInfo.setUserDataConstraint(userDataConstraint);
273
274 boolean checked = constraint.getAuthenticate();
275 roleInfo.setChecked(checked);
276 if (roleInfo.isChecked())
277 {
278 if (constraint.isAnyRole())
279 {
280 if (_strict)
281 {
282
283 for (String role : _roles)
284 roleInfo.addRole(role);
285 }
286 else
287
288 roleInfo.setAnyRole(true);
289 }
290 else
291 {
292 String[] newRoles = constraint.getRoles();
293 for (String role : newRoles)
294 {
295 if (_strict &&!_roles.contains(role))
296 throw new IllegalArgumentException("Attempt to use undeclared role: " + role + ", known roles: " + _roles);
297 roleInfo.addRole(role);
298 }
299 }
300 }
301 if (httpMethod == null)
302 {
303 for (Map.Entry<String, RoleInfo> entry : mappings.entrySet())
304 {
305 if (entry.getKey() != null)
306 {
307 RoleInfo specific = entry.getValue();
308 specific.combine(roleInfo);
309 }
310 }
311 }
312 }
313 }
314
315 protected Object prepareConstraintInfo(String pathInContext, Request request)
316 {
317 Map<String, RoleInfo> mappings = (Map<String, RoleInfo>)_constraintMap.match(pathInContext);
318
319 if (mappings != null)
320 {
321 String httpMethod = request.getMethod();
322 RoleInfo roleInfo = mappings.get(httpMethod);
323 if (roleInfo == null)
324 roleInfo = mappings.get(null);
325 return roleInfo;
326 }
327
328 return null;
329 }
330
331 protected boolean checkUserDataPermissions(String pathInContext, Request request, Response response, Object constraintInfo) throws IOException
332 {
333 if (constraintInfo == null)
334 return true;
335
336 RoleInfo roleInfo = (RoleInfo)constraintInfo;
337 if (roleInfo.isForbidden())
338 return false;
339
340
341 UserDataConstraint dataConstraint = roleInfo.getUserDataConstraint();
342 if (dataConstraint == null || dataConstraint == UserDataConstraint.None)
343 {
344 return true;
345 }
346 HttpConnection connection = HttpConnection.getCurrentConnection();
347 Connector connector = connection.getConnector();
348
349 if (dataConstraint == UserDataConstraint.Integral)
350 {
351 if (connector.isIntegral(request))
352 return true;
353 if (connector.getConfidentialPort() > 0)
354 {
355 String url = connector.getIntegralScheme() + "://" + request.getServerName() + ":" + connector.getIntegralPort() + request.getRequestURI();
356 if (request.getQueryString() != null)
357 url += "?" + request.getQueryString();
358 response.setContentLength(0);
359 response.sendRedirect(url);
360 }
361 else
362 response.sendError(Response.SC_FORBIDDEN,"!Integral");
363
364 request.setHandled(true);
365 return false;
366 }
367 else if (dataConstraint == UserDataConstraint.Confidential)
368 {
369 if (connector.isConfidential(request))
370 return true;
371
372 if (connector.getConfidentialPort() > 0)
373 {
374 String url = connector.getConfidentialScheme() + "://" + request.getServerName() + ":" + connector.getConfidentialPort()
375 + request.getRequestURI();
376 if (request.getQueryString() != null)
377 url += "?" + request.getQueryString();
378
379 response.setContentLength(0);
380 response.sendRedirect(url);
381 }
382 else
383 response.sendError(Response.SC_FORBIDDEN,"!Confidential");
384
385 request.setHandled(true);
386 return false;
387 }
388 else
389 {
390 throw new IllegalArgumentException("Invalid dataConstraint value: " + dataConstraint);
391 }
392
393 }
394
395 protected boolean isAuthMandatory(Request baseRequest, Response base_response, Object constraintInfo)
396 {
397 if (constraintInfo == null)
398 {
399 return false;
400 }
401 return ((RoleInfo)constraintInfo).isChecked();
402 }
403
404 protected boolean checkWebResourcePermissions(String pathInContext, Request request, Response response, Object constraintInfo, UserIdentity userIdentity)
405 throws IOException
406 {
407 if (constraintInfo == null)
408 {
409 return true;
410 }
411 RoleInfo roleInfo = (RoleInfo)constraintInfo;
412
413 if (!roleInfo.isChecked())
414 {
415 return true;
416 }
417
418 if (roleInfo.isAnyRole() && request.getAuthType()!=null)
419 return true;
420
421 for (String role : roleInfo.getRoles())
422 {
423 if (userIdentity.isUserInRole(role, null))
424 return true;
425 }
426 return false;
427 }
428
429
430 protected void dump(StringBuilder b,String indent)
431 {
432 super.dump(b,indent);
433 b.append(indent).append(" +=roles=").append(_roles).append('\n');
434
435 for (Object path : _constraintMap.keySet())
436 {
437 Object constraint = _constraintMap.get(path);
438 b.append(indent).append(" +=").append(path).append('=').append(constraint).append('\n');
439 }
440 }
441 }