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