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