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