1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.security;
15
16 import java.io.IOException;
17 import java.security.Principal;
18 import java.util.Enumeration;
19 import java.util.HashMap;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Set;
23
24 import javax.servlet.ServletException;
25 import javax.servlet.http.HttpServletRequest;
26 import javax.servlet.http.HttpServletResponse;
27
28 import org.eclipse.jetty.security.authentication.DeferredAuthentication;
29 import org.eclipse.jetty.server.Authentication;
30 import org.eclipse.jetty.server.Handler;
31 import org.eclipse.jetty.server.HttpConnection;
32 import org.eclipse.jetty.server.Request;
33 import org.eclipse.jetty.server.Response;
34 import org.eclipse.jetty.server.UserIdentity;
35 import org.eclipse.jetty.server.handler.ContextHandler;
36 import org.eclipse.jetty.server.handler.HandlerWrapper;
37 import org.eclipse.jetty.util.component.LifeCycle;
38 import org.eclipse.jetty.util.log.Log;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public abstract class SecurityHandler extends HandlerWrapper implements Authenticator.Configuration
55 {
56
57 private boolean _checkWelcomeFiles = false;
58 private Authenticator _authenticator;
59 private Authenticator.Factory _authenticatorFactory=new DefaultAuthenticatorFactory();
60 private String _realmName;
61 private String _authMethod;
62 private final Map<String,String> _initParameters=new HashMap<String,String>();
63 private LoginService _loginService;
64 private boolean _loginServiceShared;
65 private IdentityService _identityService;
66
67
68 protected SecurityHandler()
69 {
70 }
71
72
73
74
75
76 public IdentityService getIdentityService()
77 {
78 return _identityService;
79 }
80
81
82
83
84
85 public void setIdentityService(IdentityService identityService)
86 {
87 if (isStarted())
88 throw new IllegalStateException("Started");
89 _identityService = identityService;
90 }
91
92
93
94
95
96 public LoginService getLoginService()
97 {
98 return _loginService;
99 }
100
101
102
103
104
105 public void setLoginService(LoginService loginService)
106 {
107 if (isStarted())
108 throw new IllegalStateException("Started");
109 _loginService = loginService;
110 _loginServiceShared=false;
111 }
112
113
114
115 public Authenticator getAuthenticator()
116 {
117 return _authenticator;
118 }
119
120
121
122
123
124
125 public void setAuthenticator(Authenticator authenticator)
126 {
127 if (isStarted())
128 throw new IllegalStateException("Started");
129 _authenticator = authenticator;
130 }
131
132
133
134
135
136 public Authenticator.Factory getAuthenticatorFactory()
137 {
138 return _authenticatorFactory;
139 }
140
141
142
143
144
145
146 public void setAuthenticatorFactory(Authenticator.Factory authenticatorFactory)
147 {
148 if (isRunning())
149 throw new IllegalStateException("running");
150 _authenticatorFactory = authenticatorFactory;
151 }
152
153
154
155
156
157 public String getRealmName()
158 {
159 return _realmName;
160 }
161
162
163
164
165
166
167 public void setRealmName(String realmName)
168 {
169 if (isRunning())
170 throw new IllegalStateException("running");
171 _realmName = realmName;
172 }
173
174
175
176
177
178 public String getAuthMethod()
179 {
180 return _authMethod;
181 }
182
183
184
185
186
187
188 public void setAuthMethod(String authMethod)
189 {
190 if (isRunning())
191 throw new IllegalStateException("running");
192 _authMethod = authMethod;
193 }
194
195
196
197
198
199 public boolean isCheckWelcomeFiles()
200 {
201 return _checkWelcomeFiles;
202 }
203
204
205
206
207
208
209
210 public void setCheckWelcomeFiles(boolean authenticateWelcomeFiles)
211 {
212 if (isRunning())
213 throw new IllegalStateException("running");
214 _checkWelcomeFiles = authenticateWelcomeFiles;
215 }
216
217
218 public String getInitParameter(String key)
219 {
220 return _initParameters.get(key);
221 }
222
223
224 public Set<String> getInitParameterNames()
225 {
226 return _initParameters.keySet();
227 }
228
229
230
231
232
233
234
235
236 public String setInitParameter(String key, String value)
237 {
238 if (isRunning())
239 throw new IllegalStateException("running");
240 return _initParameters.put(key,value);
241 }
242
243
244
245 protected LoginService findLoginService()
246 {
247 List<LoginService> list = getServer().getBeans(LoginService.class);
248
249 for (LoginService service : list)
250 if (service.getName()!=null && service.getName().equals(getRealmName()))
251 return service;
252 if (list.size()>0)
253 return list.get(0);
254 return null;
255 }
256
257
258 protected IdentityService findIdentityService()
259 {
260 List<IdentityService> services = getServer().getBeans(IdentityService.class);
261 if (services!=null && services.size()>0)
262 return services.get(0);
263 return null;
264 }
265
266
267
268
269 protected void doStart()
270 throws Exception
271 {
272
273 ContextHandler.Context context =ContextHandler.getCurrentContext();
274 if (context!=null)
275 {
276 Enumeration<String> names=context.getInitParameterNames();
277 while (names!=null && names.hasMoreElements())
278 {
279 String name =names.nextElement();
280 if (name.startsWith("org.eclipse.jetty.security.") &&
281 getInitParameter(name)==null)
282 setInitParameter(name,context.getInitParameter(name));
283 }
284 }
285
286
287
288
289 if (_loginService==null)
290 {
291 _loginService=findLoginService();
292 if (_loginService!=null)
293 _loginServiceShared=true;
294 }
295
296 if (_identityService==null)
297 {
298 if (_loginService!=null)
299 _identityService=_loginService.getIdentityService();
300
301 if (_identityService==null)
302 _identityService=findIdentityService();
303
304 if (_identityService==null && _realmName!=null)
305 _identityService=new DefaultIdentityService();
306 }
307
308 if (_loginService!=null)
309 {
310 if (_loginService.getIdentityService()==null)
311 _loginService.setIdentityService(_identityService);
312 else if (_loginService.getIdentityService()!=_identityService)
313 throw new IllegalStateException("LoginService has different IdentityService to "+this);
314 }
315
316 if (!_loginServiceShared && _loginService instanceof LifeCycle)
317 ((LifeCycle)_loginService).start();
318
319 if (_authenticator==null && _authenticatorFactory!=null && _identityService!=null)
320 {
321 _authenticator=_authenticatorFactory.getAuthenticator(getServer(),ContextHandler.getCurrentContext(),this, _identityService, _loginService);
322 if (_authenticator!=null)
323 _authMethod=_authenticator.getAuthMethod();
324 }
325
326 if (_authenticator==null)
327 {
328 if (_realmName!=null)
329 {
330 Log.warn("No ServerAuthentication for "+this);
331 throw new IllegalStateException("No ServerAuthentication");
332 }
333 }
334 else
335 {
336 _authenticator.setConfiguration(this);
337 if (_authenticator instanceof LifeCycle)
338 ((LifeCycle)_authenticator).start();
339 }
340
341 super.doStart();
342 }
343
344
345
346
347
348 @Override
349 protected void doStop() throws Exception
350 {
351 super.doStop();
352
353 if (!_loginServiceShared && _loginService instanceof LifeCycle)
354 ((LifeCycle)_loginService).stop();
355
356 }
357
358 protected boolean checkSecurity(Request request)
359 {
360 switch(request.getDispatcherType())
361 {
362 case REQUEST:
363 case ASYNC:
364 return true;
365 case FORWARD:
366 if (_checkWelcomeFiles && request.getAttribute("org.eclipse.jetty.server.welcome") != null)
367 {
368 request.removeAttribute("org.eclipse.jetty.server.welcome");
369 return true;
370 }
371 return false;
372 default:
373 return false;
374 }
375 }
376
377
378
379
380
381
382
383 public void handle(String pathInContext, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
384 {
385 final Response base_response = baseRequest.getResponse();
386 final Handler handler=getHandler();
387
388 if (handler==null)
389 return;
390
391 final Authenticator authenticator = _authenticator;
392
393 if (authenticator!=null && checkSecurity(baseRequest))
394 {
395 Object constraintInfo = prepareConstraintInfo(pathInContext, baseRequest);
396
397
398 if (!checkUserDataPermissions(pathInContext, baseRequest, base_response, constraintInfo))
399 {
400 if (!baseRequest.isHandled())
401 {
402 response.sendError(Response.SC_FORBIDDEN);
403 baseRequest.setHandled(true);
404 }
405 return;
406 }
407
408
409 boolean isAuthMandatory =
410 isAuthMandatory(baseRequest, base_response, constraintInfo);
411
412
413 Object previousIdentity = null;
414 try
415 {
416 Authentication authentication = baseRequest.getAuthentication();
417 if (authentication==null || authentication==Authentication.NOT_CHECKED)
418 authentication=authenticator.validateRequest(request, response, isAuthMandatory);
419
420 if (authentication instanceof Authentication.Wrapped)
421 {
422 request=((Authentication.Wrapped)authentication).getHttpServletRequest();
423 response=((Authentication.Wrapped)authentication).getHttpServletResponse();
424 }
425
426 if (authentication instanceof Authentication.ResponseSent)
427 {
428 baseRequest.setHandled(true);
429 }
430 else if (authentication instanceof Authentication.User)
431 {
432 Authentication.User userAuth = (Authentication.User)authentication;
433 baseRequest.setAuthentication(authentication);
434 previousIdentity = _identityService.associate(userAuth.getUserIdentity());
435
436 if (isAuthMandatory)
437 {
438 boolean authorized=checkWebResourcePermissions(pathInContext, baseRequest, base_response, constraintInfo, userAuth.getUserIdentity());
439 if (!authorized)
440 {
441 response.sendError(Response.SC_FORBIDDEN, "!role");
442 baseRequest.setHandled(true);
443 return;
444 }
445 }
446
447 handler.handle(pathInContext, baseRequest, request, response);
448 authenticator.secureResponse(request, response, isAuthMandatory, userAuth);
449 }
450 else if (authentication instanceof Authentication.Deferred)
451 {
452 DeferredAuthentication deferred= (DeferredAuthentication)authentication;
453 deferred.setIdentityService(_identityService);
454 baseRequest.setAuthentication(authentication);
455
456 try
457 {
458 handler.handle(pathInContext, baseRequest, request, response);
459 }
460 finally
461 {
462 previousIdentity = deferred.getPreviousAssociation();
463 deferred.setIdentityService(null);
464 }
465
466 Authentication auth=baseRequest.getAuthentication();
467 if (auth instanceof Authentication.User)
468 {
469 Authentication.User userAuth = (Authentication.User)auth;
470 authenticator.secureResponse(request, response, isAuthMandatory, userAuth);
471 }
472 else
473 authenticator.secureResponse(request, response, isAuthMandatory, null);
474 }
475 else
476 {
477 baseRequest.setAuthentication(authentication);
478 previousIdentity = _identityService.associate(null);
479 handler.handle(pathInContext, baseRequest, request, response);
480 authenticator.secureResponse(request, response, isAuthMandatory, null);
481 }
482 }
483 catch (ServerAuthException e)
484 {
485
486
487 response.sendError(Response.SC_INTERNAL_SERVER_ERROR, e.getMessage());
488 }
489 finally
490 {
491 _identityService.disassociate(previousIdentity);
492 }
493 }
494 else
495 handler.handle(pathInContext, baseRequest, request, response);
496 }
497
498
499
500 protected abstract Object prepareConstraintInfo(String pathInContext, Request request);
501
502
503 protected abstract boolean checkUserDataPermissions(String pathInContext, Request request, Response response, Object constraintInfo) throws IOException;
504
505
506 protected abstract boolean isAuthMandatory(Request baseRequest, Response base_response, Object constraintInfo);
507
508
509 protected abstract boolean checkWebResourcePermissions(String pathInContext, Request request, Response response, Object constraintInfo,
510 UserIdentity userIdentity) throws IOException;
511
512
513
514
515 public class NotChecked implements Principal
516 {
517 public String getName()
518 {
519 return null;
520 }
521
522 public String toString()
523 {
524 return "NOT CHECKED";
525 }
526
527 public SecurityHandler getSecurityHandler()
528 {
529 return SecurityHandler.this;
530 }
531 }
532
533
534
535
536 public static Principal __NO_USER = new Principal()
537 {
538 public String getName()
539 {
540 return null;
541 }
542
543 public String toString()
544 {
545 return "No User";
546 }
547 };
548
549
550
551
552
553
554
555
556
557
558
559 public static Principal __NOBODY = new Principal()
560 {
561 public String getName()
562 {
563 return "Nobody";
564 }
565
566 public String toString()
567 {
568 return getName();
569 }
570 };
571
572
573 }