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