1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.security;
20
21 import java.io.IOException;
22 import java.security.Principal;
23 import java.util.Collection;
24 import java.util.Enumeration;
25 import java.util.HashMap;
26 import java.util.Map;
27 import java.util.Set;
28
29 import javax.servlet.ServletException;
30 import javax.servlet.http.HttpServletRequest;
31 import javax.servlet.http.HttpServletResponse;
32 import javax.servlet.http.HttpSessionEvent;
33 import javax.servlet.http.HttpSessionListener;
34
35 import org.eclipse.jetty.security.authentication.DeferredAuthentication;
36 import org.eclipse.jetty.server.Authentication;
37 import org.eclipse.jetty.server.Handler;
38 import org.eclipse.jetty.server.HttpChannel;
39 import org.eclipse.jetty.server.Request;
40 import org.eclipse.jetty.server.Response;
41 import org.eclipse.jetty.server.UserIdentity;
42 import org.eclipse.jetty.server.handler.ContextHandler;
43 import org.eclipse.jetty.server.handler.ContextHandler.Context;
44 import org.eclipse.jetty.server.handler.HandlerWrapper;
45 import org.eclipse.jetty.server.session.AbstractSession;
46 import org.eclipse.jetty.util.log.Log;
47 import org.eclipse.jetty.util.log.Logger;
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 public abstract class SecurityHandler extends HandlerWrapper implements Authenticator.AuthConfiguration
64 {
65 private static final Logger LOG = Log.getLogger(SecurityHandler.class);
66
67
68 private boolean _checkWelcomeFiles = false;
69 private Authenticator _authenticator;
70 private Authenticator.Factory _authenticatorFactory=new DefaultAuthenticatorFactory();
71 private String _realmName;
72 private String _authMethod;
73 private final Map<String,String> _initParameters=new HashMap<String,String>();
74 private LoginService _loginService;
75 private IdentityService _identityService;
76 private boolean _renewSession=true;
77 private boolean _discoveredIdentityService = false;
78 private boolean _discoveredLoginService = false;
79
80
81 protected SecurityHandler()
82 {
83 addBean(_authenticatorFactory);
84 }
85
86
87
88
89
90 @Override
91 public IdentityService getIdentityService()
92 {
93 return _identityService;
94 }
95
96
97
98
99
100 public void setIdentityService(IdentityService identityService)
101 {
102 if (isStarted())
103 throw new IllegalStateException("Started");
104 updateBean(_identityService,identityService);
105 _identityService = identityService;
106 }
107
108
109
110
111
112 @Override
113 public LoginService getLoginService()
114 {
115 return _loginService;
116 }
117
118
119
120
121
122 public void setLoginService(LoginService loginService)
123 {
124 if (isStarted())
125 throw new IllegalStateException("Started");
126 updateBean(_loginService,loginService);
127 _loginService = loginService;
128 }
129
130
131
132 public Authenticator getAuthenticator()
133 {
134 return _authenticator;
135 }
136
137
138
139
140
141
142 public void setAuthenticator(Authenticator authenticator)
143 {
144 if (isStarted())
145 throw new IllegalStateException("Started");
146 updateBean(_authenticator,authenticator);
147 _authenticator = authenticator;
148 if (_authenticator!=null)
149 _authMethod=_authenticator.getAuthMethod();
150 }
151
152
153
154
155
156 public Authenticator.Factory getAuthenticatorFactory()
157 {
158 return _authenticatorFactory;
159 }
160
161
162
163
164
165
166 public void setAuthenticatorFactory(Authenticator.Factory authenticatorFactory)
167 {
168 if (isRunning())
169 throw new IllegalStateException("running");
170 updateBean(_authenticatorFactory,authenticatorFactory);
171 _authenticatorFactory = authenticatorFactory;
172 }
173
174
175
176
177
178 @Override
179 public String getRealmName()
180 {
181 return _realmName;
182 }
183
184
185
186
187
188
189 public void setRealmName(String realmName)
190 {
191 if (isRunning())
192 throw new IllegalStateException("running");
193 _realmName = realmName;
194 }
195
196
197
198
199
200 @Override
201 public String getAuthMethod()
202 {
203 return _authMethod;
204 }
205
206
207
208
209
210
211 public void setAuthMethod(String authMethod)
212 {
213 if (isRunning())
214 throw new IllegalStateException("running");
215 _authMethod = authMethod;
216 }
217
218
219
220
221
222 public boolean isCheckWelcomeFiles()
223 {
224 return _checkWelcomeFiles;
225 }
226
227
228
229
230
231
232
233 public void setCheckWelcomeFiles(boolean authenticateWelcomeFiles)
234 {
235 if (isRunning())
236 throw new IllegalStateException("running");
237 _checkWelcomeFiles = authenticateWelcomeFiles;
238 }
239
240
241 @Override
242 public String getInitParameter(String key)
243 {
244 return _initParameters.get(key);
245 }
246
247
248 @Override
249 public Set<String> getInitParameterNames()
250 {
251 return _initParameters.keySet();
252 }
253
254
255
256
257
258
259
260
261 public String setInitParameter(String key, String value)
262 {
263 if (isRunning())
264 throw new IllegalStateException("running");
265 return _initParameters.put(key,value);
266 }
267
268
269 protected LoginService findLoginService()
270 {
271 Collection<LoginService> list = getServer().getBeans(LoginService.class);
272
273 String realm=getRealmName();
274 if (realm!=null)
275 {
276 for (LoginService service : list)
277 if (service.getName()!=null && service.getName().equals(realm))
278 return service;
279 }
280 else if (list.size()==1)
281 return list.iterator().next();
282 return null;
283 }
284
285
286 protected IdentityService findIdentityService()
287 {
288 return getServer().getBean(IdentityService.class);
289 }
290
291
292
293
294 @Override
295 protected void doStart()
296 throws Exception
297 {
298
299 ContextHandler.Context context =ContextHandler.getCurrentContext();
300 if (context!=null)
301 {
302 Enumeration<String> names=context.getInitParameterNames();
303 while (names!=null && names.hasMoreElements())
304 {
305 String name =names.nextElement();
306 if (name.startsWith("org.eclipse.jetty.security.") &&
307 getInitParameter(name)==null)
308 setInitParameter(name,context.getInitParameter(name));
309 }
310
311
312 context.getContextHandler().addEventListener(new HttpSessionListener()
313 {
314 @Override
315 public void sessionDestroyed(HttpSessionEvent se)
316 {
317 }
318
319 @Override
320 public void sessionCreated(HttpSessionEvent se)
321 {
322
323 HttpChannel<?> channel = HttpChannel.getCurrentHttpChannel();
324
325 if (channel == null)
326 return;
327 Request request = channel.getRequest();
328 if (request == null)
329 return;
330
331 if (request.isSecure())
332 {
333 se.getSession().setAttribute(AbstractSession.SESSION_KNOWN_ONLY_TO_AUTHENTICATED, Boolean.TRUE);
334 }
335 }
336 });
337 }
338
339
340
341
342 if (_loginService==null)
343 {
344 setLoginService(findLoginService());
345 _discoveredLoginService = true;
346 }
347
348 if (_identityService==null)
349 {
350 if (_loginService!=null)
351 setIdentityService(_loginService.getIdentityService());
352
353 if (_identityService==null)
354 setIdentityService(findIdentityService());
355
356 if (_identityService==null && _realmName!=null)
357 setIdentityService(new DefaultIdentityService());
358
359 _discoveredIdentityService = true;
360 }
361
362 if (_loginService!=null)
363 {
364 if (_loginService.getIdentityService()==null)
365 _loginService.setIdentityService(_identityService);
366 else if (_loginService.getIdentityService()!=_identityService)
367 throw new IllegalStateException("LoginService has different IdentityService to "+this);
368 }
369
370 Authenticator.Factory authenticatorFactory = getAuthenticatorFactory();
371 if (_authenticator==null && authenticatorFactory!=null && _identityService!=null)
372 setAuthenticator(authenticatorFactory.getAuthenticator(getServer(),ContextHandler.getCurrentContext(),this, _identityService, _loginService));
373
374 if (_authenticator!=null)
375 _authenticator.setConfiguration(this);
376 else if (_realmName!=null)
377 {
378 LOG.warn("No Authenticator for "+this);
379 throw new IllegalStateException("No Authenticator");
380 }
381
382 super.doStart();
383 }
384
385 @Override
386
387 protected void doStop() throws Exception
388 {
389
390 if (_discoveredIdentityService)
391 {
392 removeBean(_identityService);
393 _identityService = null;
394
395 }
396
397 if (_discoveredLoginService)
398 {
399 removeBean(_loginService);
400 _loginService = null;
401 }
402
403 super.doStop();
404 }
405
406
407 protected boolean checkSecurity(Request request)
408 {
409 switch(request.getDispatcherType())
410 {
411 case REQUEST:
412 case ASYNC:
413 return true;
414 case FORWARD:
415 if (isCheckWelcomeFiles() && request.getAttribute("org.eclipse.jetty.server.welcome") != null)
416 {
417 request.removeAttribute("org.eclipse.jetty.server.welcome");
418 return true;
419 }
420 return false;
421 default:
422 return false;
423 }
424 }
425
426
427
428
429
430 public boolean isSessionRenewedOnAuthentication()
431 {
432 return _renewSession;
433 }
434
435
436
437
438
439
440
441 public void setSessionRenewedOnAuthentication(boolean renew)
442 {
443 _renewSession=renew;
444 }
445
446
447
448
449
450
451
452 @Override
453 public void handle(String pathInContext, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
454 {
455 final Response base_response = baseRequest.getResponse();
456 final Handler handler=getHandler();
457
458 if (handler==null)
459 return;
460
461 final Authenticator authenticator = _authenticator;
462
463 if (checkSecurity(baseRequest))
464 {
465 RoleInfo roleInfo = prepareConstraintInfo(pathInContext, baseRequest);
466
467
468 if (!checkUserDataPermissions(pathInContext, baseRequest, base_response, roleInfo))
469 {
470 if (!baseRequest.isHandled())
471 {
472 response.sendError(Response.SC_FORBIDDEN);
473 baseRequest.setHandled(true);
474 }
475 return;
476 }
477
478
479 boolean isAuthMandatory =
480 isAuthMandatory(baseRequest, base_response, roleInfo);
481
482 if (isAuthMandatory && authenticator==null)
483 {
484 LOG.warn("No authenticator for: "+roleInfo);
485 if (!baseRequest.isHandled())
486 {
487 response.sendError(Response.SC_FORBIDDEN);
488 baseRequest.setHandled(true);
489 }
490 return;
491 }
492
493
494 Object previousIdentity = null;
495 try
496 {
497 Authentication authentication = baseRequest.getAuthentication();
498 if (authentication==null || authentication==Authentication.NOT_CHECKED)
499 authentication=authenticator==null?Authentication.UNAUTHENTICATED:authenticator.validateRequest(request, response, isAuthMandatory);
500
501 if (authentication instanceof Authentication.Wrapped)
502 {
503 request=((Authentication.Wrapped)authentication).getHttpServletRequest();
504 response=((Authentication.Wrapped)authentication).getHttpServletResponse();
505 }
506
507 if (authentication instanceof Authentication.ResponseSent)
508 {
509 baseRequest.setHandled(true);
510 }
511 else if (authentication instanceof Authentication.User)
512 {
513 Authentication.User userAuth = (Authentication.User)authentication;
514 baseRequest.setAuthentication(authentication);
515 if (_identityService!=null)
516 previousIdentity = _identityService.associate(userAuth.getUserIdentity());
517
518 if (isAuthMandatory)
519 {
520 boolean authorized=checkWebResourcePermissions(pathInContext, baseRequest, base_response, roleInfo, userAuth.getUserIdentity());
521 if (!authorized)
522 {
523 response.sendError(Response.SC_FORBIDDEN, "!role");
524 baseRequest.setHandled(true);
525 return;
526 }
527 }
528
529 handler.handle(pathInContext, baseRequest, request, response);
530 if (authenticator!=null)
531 authenticator.secureResponse(request, response, isAuthMandatory, userAuth);
532 }
533 else if (authentication instanceof Authentication.Deferred)
534 {
535 DeferredAuthentication deferred= (DeferredAuthentication)authentication;
536 baseRequest.setAuthentication(authentication);
537
538 try
539 {
540 handler.handle(pathInContext, baseRequest, request, response);
541 }
542 finally
543 {
544 previousIdentity = deferred.getPreviousAssociation();
545 }
546
547 if (authenticator!=null)
548 {
549 Authentication auth=baseRequest.getAuthentication();
550 if (auth instanceof Authentication.User)
551 {
552 Authentication.User userAuth = (Authentication.User)auth;
553 authenticator.secureResponse(request, response, isAuthMandatory, userAuth);
554 }
555 else
556 authenticator.secureResponse(request, response, isAuthMandatory, null);
557 }
558 }
559 else
560 {
561 baseRequest.setAuthentication(authentication);
562 if (_identityService!=null)
563 previousIdentity = _identityService.associate(null);
564 handler.handle(pathInContext, baseRequest, request, response);
565 if (authenticator!=null)
566 authenticator.secureResponse(request, response, isAuthMandatory, null);
567 }
568 }
569 catch (ServerAuthException e)
570 {
571
572
573 response.sendError(Response.SC_INTERNAL_SERVER_ERROR, e.getMessage());
574 }
575 finally
576 {
577 if (_identityService!=null)
578 _identityService.disassociate(previousIdentity);
579 }
580 }
581 else
582 handler.handle(pathInContext, baseRequest, request, response);
583 }
584
585
586
587 public static SecurityHandler getCurrentSecurityHandler()
588 {
589 Context context = ContextHandler.getCurrentContext();
590 if (context==null)
591 return null;
592
593 return context.getContextHandler().getChildHandlerByClass(SecurityHandler.class);
594 }
595
596
597 public void logout(Authentication.User user)
598 {
599 LOG.debug("logout {}",user);
600 LoginService login_service=getLoginService();
601 if (login_service!=null)
602 {
603 login_service.logout(user.getUserIdentity());
604 }
605
606 IdentityService identity_service=getIdentityService();
607 if (identity_service!=null)
608 {
609
610 Object previous=null;
611 identity_service.disassociate(previous);
612 }
613 }
614
615
616 protected abstract RoleInfo prepareConstraintInfo(String pathInContext, Request request);
617
618
619 protected abstract boolean checkUserDataPermissions(String pathInContext, Request request, Response response, RoleInfo constraintInfo) throws IOException;
620
621
622 protected abstract boolean isAuthMandatory(Request baseRequest, Response base_response, Object constraintInfo);
623
624
625 protected abstract boolean checkWebResourcePermissions(String pathInContext, Request request, Response response, Object constraintInfo,
626 UserIdentity userIdentity) throws IOException;
627
628
629
630
631 public class NotChecked implements Principal
632 {
633 public String getName()
634 {
635 return null;
636 }
637
638 @Override
639 public String toString()
640 {
641 return "NOT CHECKED";
642 }
643
644 public SecurityHandler getSecurityHandler()
645 {
646 return SecurityHandler.this;
647 }
648 }
649
650
651
652
653 public static final Principal __NO_USER = new Principal()
654 {
655 public String getName()
656 {
657 return null;
658 }
659
660 @Override
661 public String toString()
662 {
663 return "No User";
664 }
665 };
666
667
668
669
670
671
672
673
674
675
676
677 public static final Principal __NOBODY = new Principal()
678 {
679 public String getName()
680 {
681 return "Nobody";
682 }
683
684 @Override
685 public String toString()
686 {
687 return getName();
688 }
689 };
690
691 }