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.security.Principal;
18 import java.util.Enumeration;
19 import java.util.HashMap;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Set;
23
24 import javax.servlet.ServletException;
25 import javax.servlet.http.HttpServletRequest;
26 import javax.servlet.http.HttpServletResponse;
27
28 import org.eclipse.jetty.security.authentication.DeferredAuthentication;
29 import org.eclipse.jetty.server.Authentication;
30 import org.eclipse.jetty.server.Handler;
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.server.handler.ContextHandler;
35 import org.eclipse.jetty.server.handler.HandlerWrapper;
36 import org.eclipse.jetty.util.component.LifeCycle;
37 import org.eclipse.jetty.util.log.Log;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 public abstract class SecurityHandler extends HandlerWrapper implements Authenticator.Configuration
54 {
55
56 private boolean _checkWelcomeFiles = false;
57 private Authenticator _authenticator;
58 private Authenticator.Factory _authenticatorFactory=new DefaultAuthenticatorFactory();
59 private String _realmName;
60 private String _authMethod;
61 private final Map<String,String> _initParameters=new HashMap<String,String>();
62 private LoginService _loginService;
63 private boolean _loginServiceShared;
64 private IdentityService _identityService;
65
66
67 protected SecurityHandler()
68 {
69 }
70
71
72
73
74
75 public IdentityService getIdentityService()
76 {
77 return _identityService;
78 }
79
80
81
82
83
84 public void setIdentityService(IdentityService identityService)
85 {
86 if (isStarted())
87 throw new IllegalStateException("Started");
88 _identityService = identityService;
89 }
90
91
92
93
94
95 public LoginService getLoginService()
96 {
97 return _loginService;
98 }
99
100
101
102
103
104 public void setLoginService(LoginService loginService)
105 {
106 if (isStarted())
107 throw new IllegalStateException("Started");
108 _loginService = loginService;
109 _loginServiceShared=false;
110 }
111
112
113
114 public Authenticator getAuthenticator()
115 {
116 return _authenticator;
117 }
118
119
120
121
122
123
124 public void setAuthenticator(Authenticator authenticator)
125 {
126 if (isStarted())
127 throw new IllegalStateException("Started");
128 _authenticator = authenticator;
129 }
130
131
132
133
134
135 public Authenticator.Factory getAuthenticatorFactory()
136 {
137 return _authenticatorFactory;
138 }
139
140
141
142
143
144
145 public void setAuthenticatorFactory(Authenticator.Factory authenticatorFactory)
146 {
147 if (isRunning())
148 throw new IllegalStateException("running");
149 _authenticatorFactory = authenticatorFactory;
150 }
151
152
153
154
155
156 public String getRealmName()
157 {
158 return _realmName;
159 }
160
161
162
163
164
165
166 public void setRealmName(String realmName)
167 {
168 if (isRunning())
169 throw new IllegalStateException("running");
170 _realmName = realmName;
171 }
172
173
174
175
176
177 public String getAuthMethod()
178 {
179 return _authMethod;
180 }
181
182
183
184
185
186
187 public void setAuthMethod(String authMethod)
188 {
189 if (isRunning())
190 throw new IllegalStateException("running");
191 _authMethod = authMethod;
192 }
193
194
195
196
197
198 public boolean isCheckWelcomeFiles()
199 {
200 return _checkWelcomeFiles;
201 }
202
203
204
205
206
207
208
209 public void setCheckWelcomeFiles(boolean authenticateWelcomeFiles)
210 {
211 if (isRunning())
212 throw new IllegalStateException("running");
213 _checkWelcomeFiles = authenticateWelcomeFiles;
214 }
215
216
217 public String getInitParameter(String key)
218 {
219 return _initParameters.get(key);
220 }
221
222
223 public Set<String> getInitParameterNames()
224 {
225 return _initParameters.keySet();
226 }
227
228
229
230
231
232
233
234
235 public String setInitParameter(String key, String value)
236 {
237 if (isRunning())
238 throw new IllegalStateException("running");
239 return _initParameters.put(key,value);
240 }
241
242
243
244 protected LoginService findLoginService()
245 {
246 List<LoginService> list = getServer().getBeans(LoginService.class);
247
248 for (LoginService service : list)
249 if (service.getName()!=null && service.getName().equals(getRealmName()))
250 return service;
251 if (list.size()>0)
252 return list.get(0);
253 return null;
254 }
255
256
257 protected IdentityService findIdentityService()
258 {
259 return getServer().getBean(IdentityService.class);
260 }
261
262
263
264
265 @Override
266 protected void doStart()
267 throws Exception
268 {
269
270 ContextHandler.Context context =ContextHandler.getCurrentContext();
271 if (context!=null)
272 {
273 Enumeration<String> names=context.getInitParameterNames();
274 while (names!=null && names.hasMoreElements())
275 {
276 String name =names.nextElement();
277 if (name.startsWith("org.eclipse.jetty.security.") &&
278 getInitParameter(name)==null)
279 setInitParameter(name,context.getInitParameter(name));
280 }
281 }
282
283
284
285
286 if (_loginService==null)
287 {
288 _loginService=findLoginService();
289 if (_loginService!=null)
290 _loginServiceShared=true;
291 }
292
293 if (_identityService==null)
294 {
295 if (_loginService!=null)
296 _identityService=_loginService.getIdentityService();
297
298 if (_identityService==null)
299 _identityService=findIdentityService();
300
301 if (_identityService==null && _realmName!=null)
302 _identityService=new DefaultIdentityService();
303 }
304
305 if (_loginService!=null)
306 {
307 if (_loginService.getIdentityService()==null)
308 _loginService.setIdentityService(_identityService);
309 else if (_loginService.getIdentityService()!=_identityService)
310 throw new IllegalStateException("LoginService has different IdentityService to "+this);
311 }
312
313 if (!_loginServiceShared && _loginService instanceof LifeCycle)
314 ((LifeCycle)_loginService).start();
315
316 if (_authenticator==null && _authenticatorFactory!=null && _identityService!=null)
317 {
318 _authenticator=_authenticatorFactory.getAuthenticator(getServer(),ContextHandler.getCurrentContext(),this, _identityService, _loginService);
319 if (_authenticator!=null)
320 _authMethod=_authenticator.getAuthMethod();
321 }
322
323 if (_authenticator==null)
324 {
325 if (_realmName!=null)
326 {
327 Log.warn("No ServerAuthentication for "+this);
328 throw new IllegalStateException("No ServerAuthentication");
329 }
330 }
331 else
332 {
333 _authenticator.setConfiguration(this);
334 if (_authenticator instanceof LifeCycle)
335 ((LifeCycle)_authenticator).start();
336 }
337
338 super.doStart();
339 }
340
341
342
343
344
345 @Override
346 protected void doStop() throws Exception
347 {
348 super.doStop();
349
350 if (!_loginServiceShared && _loginService instanceof LifeCycle)
351 ((LifeCycle)_loginService).stop();
352
353 }
354
355
356 protected boolean checkSecurity(Request request)
357 {
358 switch(request.getDispatcherType())
359 {
360 case REQUEST:
361 case ASYNC:
362 return true;
363 case FORWARD:
364 if (_checkWelcomeFiles && request.getAttribute("org.eclipse.jetty.server.welcome") != null)
365 {
366 request.removeAttribute("org.eclipse.jetty.server.welcome");
367 return true;
368 }
369 return false;
370 default:
371 return false;
372 }
373 }
374
375
376
377
378
379
380
381 public void handle(String pathInContext, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
382 {
383 final Response base_response = baseRequest.getResponse();
384 final Handler handler=getHandler();
385
386 if (handler==null)
387 return;
388
389 final Authenticator authenticator = _authenticator;
390
391 if (authenticator!=null && checkSecurity(baseRequest))
392 {
393 Object constraintInfo = prepareConstraintInfo(pathInContext, baseRequest);
394
395
396 if (!checkUserDataPermissions(pathInContext, baseRequest, base_response, constraintInfo))
397 {
398 if (!baseRequest.isHandled())
399 {
400 response.sendError(Response.SC_FORBIDDEN);
401 baseRequest.setHandled(true);
402 }
403 return;
404 }
405
406
407 boolean isAuthMandatory =
408 isAuthMandatory(baseRequest, base_response, constraintInfo);
409
410
411 Object previousIdentity = null;
412 try
413 {
414 Authentication authentication = baseRequest.getAuthentication();
415 if (authentication==null || authentication==Authentication.NOT_CHECKED)
416 authentication=authenticator.validateRequest(request, response, isAuthMandatory);
417
418 if (authentication instanceof Authentication.Wrapped)
419 {
420 request=((Authentication.Wrapped)authentication).getHttpServletRequest();
421 response=((Authentication.Wrapped)authentication).getHttpServletResponse();
422 }
423
424 if (authentication instanceof Authentication.ResponseSent)
425 {
426 baseRequest.setHandled(true);
427 }
428 else if (authentication instanceof Authentication.User)
429 {
430 Authentication.User userAuth = (Authentication.User)authentication;
431 baseRequest.setAuthentication(authentication);
432 previousIdentity = _identityService.associate(userAuth.getUserIdentity());
433
434 if (isAuthMandatory)
435 {
436 boolean authorized=checkWebResourcePermissions(pathInContext, baseRequest, base_response, constraintInfo, userAuth.getUserIdentity());
437 if (!authorized)
438 {
439 response.sendError(Response.SC_FORBIDDEN, "!role");
440 baseRequest.setHandled(true);
441 return;
442 }
443 }
444
445 handler.handle(pathInContext, baseRequest, request, response);
446 authenticator.secureResponse(request, response, isAuthMandatory, userAuth);
447 }
448 else if (authentication instanceof Authentication.Deferred)
449 {
450 DeferredAuthentication deferred= (DeferredAuthentication)authentication;
451 deferred.setIdentityService(_identityService);
452 baseRequest.setAuthentication(authentication);
453
454 try
455 {
456 handler.handle(pathInContext, baseRequest, request, response);
457 }
458 finally
459 {
460 previousIdentity = deferred.getPreviousAssociation();
461 deferred.setIdentityService(null);
462 }
463
464 Authentication auth=baseRequest.getAuthentication();
465 if (auth instanceof Authentication.User)
466 {
467 Authentication.User userAuth = (Authentication.User)auth;
468 authenticator.secureResponse(request, response, isAuthMandatory, userAuth);
469 }
470 else
471 authenticator.secureResponse(request, response, isAuthMandatory, null);
472 }
473 else
474 {
475 baseRequest.setAuthentication(authentication);
476 previousIdentity = _identityService.associate(null);
477 handler.handle(pathInContext, baseRequest, request, response);
478 authenticator.secureResponse(request, response, isAuthMandatory, null);
479 }
480 }
481 catch (ServerAuthException e)
482 {
483
484
485 response.sendError(Response.SC_INTERNAL_SERVER_ERROR, e.getMessage());
486 }
487 finally
488 {
489 _identityService.disassociate(previousIdentity);
490 }
491 }
492 else
493 handler.handle(pathInContext, baseRequest, request, response);
494 }
495
496
497
498 protected abstract Object prepareConstraintInfo(String pathInContext, Request request);
499
500
501 protected abstract boolean checkUserDataPermissions(String pathInContext, Request request, Response response, Object constraintInfo) throws IOException;
502
503
504 protected abstract boolean isAuthMandatory(Request baseRequest, Response base_response, Object constraintInfo);
505
506
507 protected abstract boolean checkWebResourcePermissions(String pathInContext, Request request, Response response, Object constraintInfo,
508 UserIdentity userIdentity) throws IOException;
509
510
511
512
513 public class NotChecked implements Principal
514 {
515 public String getName()
516 {
517 return null;
518 }
519
520 public String toString()
521 {
522 return "NOT CHECKED";
523 }
524
525 public SecurityHandler getSecurityHandler()
526 {
527 return SecurityHandler.this;
528 }
529 }
530
531
532
533
534 public static Principal __NO_USER = new Principal()
535 {
536 public String getName()
537 {
538 return null;
539 }
540
541 public String toString()
542 {
543 return "No User";
544 }
545 };
546
547
548
549
550
551
552
553
554
555
556
557 public static Principal __NOBODY = new Principal()
558 {
559 public String getName()
560 {
561 return "Nobody";
562 }
563
564 public String toString()
565 {
566 return getName();
567 }
568 };
569
570
571 }