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
339 if (_loginService!=null)
340 _identityService=_loginService.getIdentityService();
341
342 if (_identityService==null)
343 _identityService=findIdentityService();
344
345 if (_identityService==null && _realmName!=null)
346 _identityService=new DefaultIdentityService();
347 }
348
349 if (_loginService!=null)
350 {
351 if (_loginService.getIdentityService()==null)
352 _loginService.setIdentityService(_identityService);
353 else if (_loginService.getIdentityService()!=_identityService)
354 throw new IllegalStateException("LoginService has different IdentityService to "+this);
355 }
356
357 if (!_loginServiceShared && _loginService instanceof LifeCycle)
358 ((LifeCycle)_loginService).start();
359
360 if (_authenticator==null && _authenticatorFactory!=null && _identityService!=null)
361 {
362 _authenticator=_authenticatorFactory.getAuthenticator(getServer(),ContextHandler.getCurrentContext(),this, _identityService, _loginService);
363 if (_authenticator!=null)
364 _authMethod=_authenticator.getAuthMethod();
365 }
366
367 if (_authenticator==null)
368 {
369 if (_realmName!=null)
370 {
371 LOG.warn("No ServerAuthentication for "+this);
372 throw new IllegalStateException("No ServerAuthentication");
373 }
374 }
375 else
376 {
377 _authenticator.setConfiguration(this);
378 if (_authenticator instanceof LifeCycle)
379 ((LifeCycle)_authenticator).start();
380 }
381
382 super.doStart();
383 }
384
385
386
387
388
389 @Override
390 protected void doStop() throws Exception
391 {
392 super.doStop();
393
394 if (!_loginServiceShared && _loginService instanceof LifeCycle)
395 ((LifeCycle)_loginService).stop();
396
397 }
398
399
400 protected boolean checkSecurity(Request request)
401 {
402 switch(request.getDispatcherType())
403 {
404 case REQUEST:
405 case ASYNC:
406 return true;
407 case FORWARD:
408 if (_checkWelcomeFiles && request.getAttribute("org.eclipse.jetty.server.welcome") != null)
409 {
410 request.removeAttribute("org.eclipse.jetty.server.welcome");
411 return true;
412 }
413 return false;
414 default:
415 return false;
416 }
417 }
418
419
420
421
422
423 public boolean isSessionRenewedOnAuthentication()
424 {
425 return _renewSession;
426 }
427
428
429
430
431
432
433
434 public void setSessionRenewedOnAuthentication(boolean renew)
435 {
436 _renewSession=renew;
437 }
438
439
440
441
442
443
444
445 @Override
446 public void handle(String pathInContext, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
447 {
448 final Response base_response = baseRequest.getResponse();
449 final Handler handler=getHandler();
450
451 if (handler==null)
452 return;
453
454 final Authenticator authenticator = _authenticator;
455
456 if (checkSecurity(baseRequest))
457 {
458 Object constraintInfo = prepareConstraintInfo(pathInContext, baseRequest);
459
460
461 if (!checkUserDataPermissions(pathInContext, baseRequest, base_response, constraintInfo))
462 {
463 if (!baseRequest.isHandled())
464 {
465 response.sendError(Response.SC_FORBIDDEN);
466 baseRequest.setHandled(true);
467 }
468 return;
469 }
470
471
472 boolean isAuthMandatory =
473 isAuthMandatory(baseRequest, base_response, constraintInfo);
474
475 if (isAuthMandatory && authenticator==null)
476 {
477 LOG.warn("No authenticator for: "+constraintInfo);
478 if (!baseRequest.isHandled())
479 {
480 response.sendError(Response.SC_FORBIDDEN);
481 baseRequest.setHandled(true);
482 }
483 return;
484 }
485
486
487 Object previousIdentity = null;
488 try
489 {
490 Authentication authentication = baseRequest.getAuthentication();
491 if (authentication==null || authentication==Authentication.NOT_CHECKED)
492 authentication=authenticator==null?Authentication.UNAUTHENTICATED:authenticator.validateRequest(request, response, isAuthMandatory);
493
494 if (authentication instanceof Authentication.Wrapped)
495 {
496 request=((Authentication.Wrapped)authentication).getHttpServletRequest();
497 response=((Authentication.Wrapped)authentication).getHttpServletResponse();
498 }
499
500 if (authentication instanceof Authentication.ResponseSent)
501 {
502 baseRequest.setHandled(true);
503 }
504 else if (authentication instanceof Authentication.User)
505 {
506 Authentication.User userAuth = (Authentication.User)authentication;
507 baseRequest.setAuthentication(authentication);
508 if (_identityService!=null)
509 previousIdentity = _identityService.associate(userAuth.getUserIdentity());
510
511 if (isAuthMandatory)
512 {
513 boolean authorized=checkWebResourcePermissions(pathInContext, baseRequest, base_response, constraintInfo, userAuth.getUserIdentity());
514 if (!authorized)
515 {
516 response.sendError(Response.SC_FORBIDDEN, "!role");
517 baseRequest.setHandled(true);
518 return;
519 }
520 }
521
522 handler.handle(pathInContext, baseRequest, request, response);
523 if (authenticator!=null)
524 authenticator.secureResponse(request, response, isAuthMandatory, userAuth);
525 }
526 else if (authentication instanceof Authentication.Deferred)
527 {
528 DeferredAuthentication deferred= (DeferredAuthentication)authentication;
529 baseRequest.setAuthentication(authentication);
530
531 try
532 {
533 handler.handle(pathInContext, baseRequest, request, response);
534 }
535 finally
536 {
537 previousIdentity = deferred.getPreviousAssociation();
538 }
539
540 if (authenticator!=null)
541 {
542 Authentication auth=baseRequest.getAuthentication();
543 if (auth instanceof Authentication.User)
544 {
545 Authentication.User userAuth = (Authentication.User)auth;
546 authenticator.secureResponse(request, response, isAuthMandatory, userAuth);
547 }
548 else
549 authenticator.secureResponse(request, response, isAuthMandatory, null);
550 }
551 }
552 else
553 {
554 baseRequest.setAuthentication(authentication);
555 if (_identityService!=null)
556 previousIdentity = _identityService.associate(null);
557 handler.handle(pathInContext, baseRequest, request, response);
558 if (authenticator!=null)
559 authenticator.secureResponse(request, response, isAuthMandatory, null);
560 }
561 }
562 catch (ServerAuthException e)
563 {
564
565
566 response.sendError(Response.SC_INTERNAL_SERVER_ERROR, e.getMessage());
567 }
568 finally
569 {
570 if (_identityService!=null)
571 _identityService.disassociate(previousIdentity);
572 }
573 }
574 else
575 handler.handle(pathInContext, baseRequest, request, response);
576 }
577
578
579
580 public static SecurityHandler getCurrentSecurityHandler()
581 {
582 Context context = ContextHandler.getCurrentContext();
583 if (context==null)
584 return null;
585
586 SecurityHandler security = context.getContextHandler().getChildHandlerByClass(SecurityHandler.class);
587 return security;
588 }
589
590
591 public void logout(Authentication.User user)
592 {
593 LOG.debug("logout {}",user);
594 LoginService login_service=getLoginService();
595 if (login_service!=null)
596 {
597 login_service.logout(user.getUserIdentity());
598 }
599
600 IdentityService identity_service=getIdentityService();
601 if (identity_service!=null)
602 {
603
604 Object previous=null;
605 identity_service.disassociate(previous);
606 }
607 }
608
609
610 protected abstract Object prepareConstraintInfo(String pathInContext, Request request);
611
612
613 protected abstract boolean checkUserDataPermissions(String pathInContext, Request request, Response response, Object constraintInfo) throws IOException;
614
615
616 protected abstract boolean isAuthMandatory(Request baseRequest, Response base_response, Object constraintInfo);
617
618
619 protected abstract boolean checkWebResourcePermissions(String pathInContext, Request request, Response response, Object constraintInfo,
620 UserIdentity userIdentity) throws IOException;
621
622
623
624
625 public class NotChecked implements Principal
626 {
627 public String getName()
628 {
629 return null;
630 }
631
632 @Override
633 public String toString()
634 {
635 return "NOT CHECKED";
636 }
637
638 public SecurityHandler getSecurityHandler()
639 {
640 return SecurityHandler.this;
641 }
642 }
643
644
645
646
647 public static Principal __NO_USER = new Principal()
648 {
649 public String getName()
650 {
651 return null;
652 }
653
654 @Override
655 public String toString()
656 {
657 return "No User";
658 }
659 };
660
661
662
663
664
665
666
667
668
669
670
671 public static Principal __NOBODY = new Principal()
672 {
673 public String getName()
674 {
675 return "Nobody";
676 }
677
678 @Override
679 public String toString()
680 {
681 return getName();
682 }
683 };
684
685 }