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