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