1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.annotations;
15
16 import java.util.ArrayList;
17 import java.util.List;
18
19 import javax.servlet.annotation.HttpConstraint;
20 import javax.servlet.annotation.HttpMethodConstraint;
21 import javax.servlet.annotation.ServletSecurity;
22 import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
23 import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
24
25 import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler;
26 import org.eclipse.jetty.http.security.Constraint;
27 import org.eclipse.jetty.security.ConstraintAware;
28 import org.eclipse.jetty.security.ConstraintMapping;
29 import org.eclipse.jetty.servlet.ServletHolder;
30 import org.eclipse.jetty.servlet.ServletMapping;
31 import org.eclipse.jetty.util.LazyList;
32 import org.eclipse.jetty.util.log.Log;
33 import org.eclipse.jetty.webapp.WebAppContext;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 public class ServletSecurityAnnotationHandler extends AbstractIntrospectableAnnotationHandler
53 {
54
55 private WebAppContext _context;
56
57 public ServletSecurityAnnotationHandler(WebAppContext wac)
58 {
59 super(false);
60 _context = wac;
61 }
62
63
64
65
66 public void doHandle(Class clazz)
67 {
68 if (!(_context.getSecurityHandler() instanceof ConstraintAware))
69 {
70 Log.warn("SecurityHandler not ConstraintAware, skipping security annotation processing");
71 return;
72 }
73
74 ServletSecurity servletSecurity = (ServletSecurity)clazz.getAnnotation(ServletSecurity.class);
75 if (servletSecurity == null)
76 return;
77
78
79
80
81 List<ServletMapping> servletMappings = getServletMappings(clazz.getCanonicalName());
82 List<ConstraintMapping> constraintMappings = ((ConstraintAware)_context.getSecurityHandler()).getConstraintMappings();
83
84 if (constraintsExist(servletMappings, constraintMappings))
85 {
86 Log.warn("Constraints already defined for "+clazz.getName()+", skipping ServletSecurity annotation");
87 return;
88 }
89
90
91 constraintMappings = new ArrayList<ConstraintMapping>();
92
93
94 HttpConstraint defaults = servletSecurity.value();
95
96
97 Constraint defaultConstraint = makeConstraint (clazz,
98 defaults.rolesAllowed(),
99 defaults.value(),
100 defaults.transportGuarantee());
101
102 constraintMappings.addAll(makeMethodMappings(clazz,
103 defaultConstraint,
104 servletMappings,
105 servletSecurity.httpMethodConstraints()));
106
107
108 ConstraintAware securityHandler = (ConstraintAware)_context.getSecurityHandler();
109
110 for (ConstraintMapping m:constraintMappings)
111 securityHandler.addConstraintMapping(m);
112 }
113
114
115
116
117
118
119
120
121
122
123
124
125 protected Constraint makeConstraint (Class servlet, String[] rolesAllowed, EmptyRoleSemantic permitOrDeny, TransportGuarantee transport)
126 {
127 Constraint constraint = new Constraint();
128 if (rolesAllowed == null || rolesAllowed.length==0)
129 {
130 if (permitOrDeny.equals(EmptyRoleSemantic.DENY))
131 {
132
133 constraint.setName(servlet.getName()+"-Deny");
134 constraint.setAuthenticate(true);
135 }
136 else
137 {
138
139 constraint.setAuthenticate(false);
140 constraint.setName(servlet.getName()+"-Permit");
141 }
142 }
143 else
144 {
145
146 constraint.setAuthenticate(true);
147 constraint.setRoles(rolesAllowed);
148 constraint.setName(servlet.getName()+"-RolesAllowed");
149 }
150
151
152 constraint.setDataConstraint((transport.equals(TransportGuarantee.CONFIDENTIAL)?Constraint.DC_CONFIDENTIAL:Constraint.DC_NONE));
153 return constraint;
154 }
155
156
157
158
159
160
161
162
163
164
165
166 protected ConstraintMapping makeConstraintMapping (Constraint constraint, String url, String method, String[] omissions)
167 {
168 ConstraintMapping mapping = new ConstraintMapping();
169 mapping.setConstraint(constraint);
170 mapping.setPathSpec(url);
171 if (method != null)
172 mapping.setMethod(method);
173 if (omissions != null)
174 mapping.setMethodOmissions(omissions);
175 return mapping;
176 }
177
178
179
180
181
182
183
184
185
186
187 protected List<ConstraintMapping> makeMethodMappings (Class servlet, Constraint defaultConstraint, List<ServletMapping> servletMappings, HttpMethodConstraint[] annotations)
188 {
189 List<ConstraintMapping> mappings = new ArrayList<ConstraintMapping>();
190
191
192
193 for (ServletMapping sm : servletMappings)
194 {
195 for (String url : sm.getPathSpecs())
196 {
197
198 ConstraintMapping defaultMapping = makeConstraintMapping(defaultConstraint, url, null, null);
199
200
201 if (annotations != null && annotations.length>0)
202 {
203 List<String> omissions = new ArrayList<String>();
204
205
206 for (int i=0; i < annotations.length;i++)
207 {
208
209 Constraint methodConstraint = makeConstraint(servlet,
210 annotations[i].rolesAllowed(),
211 annotations[i].emptyRoleSemantic(),
212 annotations[i].transportGuarantee());
213
214
215 ConstraintMapping methodConstraintMapping = makeConstraintMapping (methodConstraint,
216 url,annotations[i].value(),
217 null);
218 mappings.add(methodConstraintMapping);
219 omissions.add(annotations[i].value());
220 }
221 defaultMapping.setMethodOmissions(omissions.toArray(new String[0]));
222 }
223
224
225 mappings.add(defaultMapping);
226 }
227 }
228 return mappings;
229 }
230
231
232
233
234
235
236
237
238 protected List<ServletMapping> getServletMappings(String className)
239 {
240 List<ServletMapping> results = new ArrayList<ServletMapping>();
241 ServletMapping[] mappings = _context.getServletHandler().getServletMappings();
242 for (ServletMapping mapping : mappings)
243 {
244
245 ServletHolder holder = _context.getServletHandler().getServlet(mapping.getServletName());
246 if (holder.getClassName().equals(className))
247 results.add(mapping);
248 }
249 return results;
250 }
251
252
253
254
255
256
257
258
259
260 protected boolean constraintsExist (List<ServletMapping> servletMappings, List<ConstraintMapping> constraintMappings)
261 {
262 boolean exists = false;
263
264
265
266 for (ServletMapping mapping : servletMappings)
267 {
268
269 String[] pathSpecs = mapping.getPathSpecs();
270 if (pathSpecs == null)
271 continue;
272
273
274
275
276 for (int i=0; constraintMappings != null && i < constraintMappings.size() && !exists; i++)
277 {
278 for (int j=0; j < pathSpecs.length; j++)
279 {
280 if (pathSpecs[j].equals(constraintMappings.get(i).getPathSpec()))
281 {
282 exists = true;
283 break;
284 }
285 }
286 }
287 }
288 return exists;
289 }
290
291 }