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
466 if (authenticator != null)
467 authenticator.prepareRequest(baseRequest);
468
469 RoleInfo roleInfo = prepareConstraintInfo(pathInContext, baseRequest);
470
471
472 if (!checkUserDataPermissions(pathInContext, baseRequest, base_response, roleInfo))
473 {
474 if (!baseRequest.isHandled())
475 {
476 response.sendError(Response.SC_FORBIDDEN);
477 baseRequest.setHandled(true);
478 }
479 return;
480 }
481
482
483 boolean isAuthMandatory =
484 isAuthMandatory(baseRequest, base_response, roleInfo);
485
486 if (isAuthMandatory && authenticator==null)
487 {
488 LOG.warn("No authenticator for: "+roleInfo);
489 if (!baseRequest.isHandled())
490 {
491 response.sendError(Response.SC_FORBIDDEN);
492 baseRequest.setHandled(true);
493 }
494 return;
495 }
496
497
498 Object previousIdentity = null;
499 try
500 {
501 Authentication authentication = baseRequest.getAuthentication();
502 if (authentication==null || authentication==Authentication.NOT_CHECKED)
503 authentication=authenticator==null?Authentication.UNAUTHENTICATED:authenticator.validateRequest(request, response, isAuthMandatory);
504
505 if (authentication instanceof Authentication.Wrapped)
506 {
507 request=((Authentication.Wrapped)authentication).getHttpServletRequest();
508 response=((Authentication.Wrapped)authentication).getHttpServletResponse();
509 }
510
511 if (authentication instanceof Authentication.ResponseSent)
512 {
513 baseRequest.setHandled(true);
514 }
515 else if (authentication instanceof Authentication.User)
516 {
517 Authentication.User userAuth = (Authentication.User)authentication;
518 baseRequest.setAuthentication(authentication);
519 if (_identityService!=null)
520 previousIdentity = _identityService.associate(userAuth.getUserIdentity());
521
522 if (isAuthMandatory)
523 {
524 boolean authorized=checkWebResourcePermissions(pathInContext, baseRequest, base_response, roleInfo, userAuth.getUserIdentity());
525 if (!authorized)
526 {
527 response.sendError(Response.SC_FORBIDDEN, "!role");
528 baseRequest.setHandled(true);
529 return;
530 }
531 }
532
533 handler.handle(pathInContext, baseRequest, request, response);
534 if (authenticator!=null)
535 authenticator.secureResponse(request, response, isAuthMandatory, userAuth);
536 }
537 else if (authentication instanceof Authentication.Deferred)
538 {
539 DeferredAuthentication deferred= (DeferredAuthentication)authentication;
540 baseRequest.setAuthentication(authentication);
541
542 try
543 {
544 handler.handle(pathInContext, baseRequest, request, response);
545 }
546 finally
547 {
548 previousIdentity = deferred.getPreviousAssociation();
549 }
550
551 if (authenticator!=null)
552 {
553 Authentication auth=baseRequest.getAuthentication();
554 if (auth instanceof Authentication.User)
555 {
556 Authentication.User userAuth = (Authentication.User)auth;
557 authenticator.secureResponse(request, response, isAuthMandatory, userAuth);
558 }
559 else
560 authenticator.secureResponse(request, response, isAuthMandatory, null);
561 }
562 }
563 else
564 {
565 baseRequest.setAuthentication(authentication);
566 if (_identityService!=null)
567 previousIdentity = _identityService.associate(null);
568 handler.handle(pathInContext, baseRequest, request, response);
569 if (authenticator!=null)
570 authenticator.secureResponse(request, response, isAuthMandatory, null);
571 }
572 }
573 catch (ServerAuthException e)
574 {
575
576
577 response.sendError(Response.SC_INTERNAL_SERVER_ERROR, e.getMessage());
578 }
579 finally
580 {
581 if (_identityService!=null)
582 _identityService.disassociate(previousIdentity);
583 }
584 }
585 else
586 handler.handle(pathInContext, baseRequest, request, response);
587 }
588
589
590
591 public static SecurityHandler getCurrentSecurityHandler()
592 {
593 Context context = ContextHandler.getCurrentContext();
594 if (context==null)
595 return null;
596
597 return context.getContextHandler().getChildHandlerByClass(SecurityHandler.class);
598 }
599
600
601 public void logout(Authentication.User user)
602 {
603 LOG.debug("logout {}",user);
604 LoginService login_service=getLoginService();
605 if (login_service!=null)
606 {
607 login_service.logout(user.getUserIdentity());
608 }
609
610 IdentityService identity_service=getIdentityService();
611 if (identity_service!=null)
612 {
613
614 Object previous=null;
615 identity_service.disassociate(previous);
616 }
617 }
618
619
620 protected abstract RoleInfo prepareConstraintInfo(String pathInContext, Request request);
621
622
623 protected abstract boolean checkUserDataPermissions(String pathInContext, Request request, Response response, RoleInfo constraintInfo) throws IOException;
624
625
626 protected abstract boolean isAuthMandatory(Request baseRequest, Response base_response, Object constraintInfo);
627
628
629 protected abstract boolean checkWebResourcePermissions(String pathInContext, Request request, Response response, Object constraintInfo,
630 UserIdentity userIdentity) throws IOException;
631
632
633
634
635 public class NotChecked implements Principal
636 {
637 public String getName()
638 {
639 return null;
640 }
641
642 @Override
643 public String toString()
644 {
645 return "NOT CHECKED";
646 }
647
648 public SecurityHandler getSecurityHandler()
649 {
650 return SecurityHandler.this;
651 }
652 }
653
654
655
656
657 public static final Principal __NO_USER = new Principal()
658 {
659 public String getName()
660 {
661 return null;
662 }
663
664 @Override
665 public String toString()
666 {
667 return "No User";
668 }
669 };
670
671
672
673
674
675
676
677
678
679
680
681 public static final Principal __NOBODY = new Principal()
682 {
683 public String getName()
684 {
685 return "Nobody";
686 }
687
688 @Override
689 public String toString()
690 {
691 return getName();
692 }
693 };
694
695 }