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