KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mortbay > http > SecurityConstraint


1 // ========================================================================
2
// $Id: SecurityConstraint.java,v 1.44 2005/08/13 00:01:24 gregwilkins Exp $
3
// Copyright 200-2004 Mort Bay Consulting Pty. Ltd.
4
// ------------------------------------------------------------------------
5
// Licensed under the Apache License, Version 2.0 (the "License");
6
// you may not use this file except in compliance with the License.
7
// You may obtain a copy of the License at
8
// http://www.apache.org/licenses/LICENSE-2.0
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
// ========================================================================
15

16 package org.mortbay.http;
17
18 import java.io.IOException JavaDoc;
19 import java.io.Serializable JavaDoc;
20 import java.security.Principal JavaDoc;
21 import java.util.Collections JavaDoc;
22 import java.util.List JavaDoc;
23
24 import org.apache.commons.logging.Log;
25 import org.mortbay.log.LogFactory;
26 import org.mortbay.jetty.servlet.FormAuthenticator;
27 import org.mortbay.util.LazyList;
28
29 /* ------------------------------------------------------------ */
30 /** Describe an auth and/or data constraint.
31  *
32  * @version $Revision: 1.44 $
33  * @author Greg Wilkins (gregw)
34  */

35 public class SecurityConstraint implements Cloneable JavaDoc, Serializable JavaDoc
36 {
37     private static Log log= LogFactory.getLog(SecurityConstraint.class);
38
39     /* ------------------------------------------------------------ */
40     public final static String JavaDoc __BASIC_AUTH= "BASIC";
41     public final static String JavaDoc __FORM_AUTH= "FORM";
42     public final static String JavaDoc __DIGEST_AUTH= "DIGEST";
43     public final static String JavaDoc __CERT_AUTH= "CLIENT_CERT";
44     public final static String JavaDoc __CERT_AUTH2= "CLIENT-CERT";
45
46     /* ------------------------------------------------------------ */
47     public final static int DC_UNSET= -1, DC_NONE= 0, DC_INTEGRAL= 1, DC_CONFIDENTIAL= 2;
48
49     /* ------------------------------------------------------------ */
50     public final static String JavaDoc NONE= "NONE";
51     public final static String JavaDoc ANY_ROLE= "*";
52
53     /* ------------------------------------------------------------ */
54     /* ------------------------------------------------------------ */
55     /* ------------------------------------------------------------ */
56     /** Nobody user.
57      * The Nobody UserPrincipal is used to indicate a partial state of
58      * authentication. A request with a Nobody UserPrincipal will be allowed
59      * past all authentication constraints - but will not be considered an
60      * authenticated request. It can be used by Authenticators such as
61      * FormAuthenticator to allow access to logon and error pages within an
62      * authenticated URI tree.
63      */

64     public static class Nobody implements Principal JavaDoc
65     
66     {
67         public String JavaDoc getName()
68         {
69             return "Nobody";
70         }
71     }
72     public final static Nobody __NOBODY= new Nobody();
73
74     /* ------------------------------------------------------------ */
75     private String JavaDoc _name;
76     private Object JavaDoc _methods;
77     private Object JavaDoc _roles;
78     private int _dataConstraint= DC_UNSET;
79     private boolean _anyRole= false;
80     private boolean _authenticate= false;
81
82     private transient List JavaDoc _umMethods;
83     private transient List JavaDoc _umRoles;
84
85     /* ------------------------------------------------------------ */
86     /** Constructor.
87      */

88     public SecurityConstraint()
89     {}
90
91     /* ------------------------------------------------------------ */
92     /** Conveniance Constructor.
93      * @param name
94      * @param role
95      */

96     public SecurityConstraint(String JavaDoc name, String JavaDoc role)
97     {
98         setName(name);
99         addRole(role);
100     }
101
102     /* ------------------------------------------------------------ */
103     /**
104      * @param name
105      */

106     public void setName(String JavaDoc name)
107     {
108         _name= name;
109     }
110
111     /* ------------------------------------------------------------ */
112     /**
113      * @param method
114      */

115     public synchronized void addMethod(String JavaDoc method)
116     {
117         _methods= LazyList.add(_methods, method);
118     }
119
120     /* ------------------------------------------------------------ */
121     public List JavaDoc getMethods()
122     {
123         if (_umMethods == null && _methods != null)
124             _umMethods= Collections.unmodifiableList(LazyList.getList(_methods));
125         return _umMethods;
126     }
127
128     /* ------------------------------------------------------------ */
129     /**
130      * @param method Method name.
131      * @return True if this constraint applies to the method. If no
132      * method has been set, then the constraint applies to all methods.
133      */

134     public boolean forMethod(String JavaDoc method)
135     {
136         if (_methods == null)
137             return true;
138         for (int i= 0; i < LazyList.size(_methods); i++)
139             if (LazyList.get(_methods, i).equals(method))
140                 return true;
141         return false;
142     }
143
144     /* ------------------------------------------------------------ */
145     /**
146      * @param role The rolename. If the rolename is '*' all other
147      * roles are removed and anyRole is set true and subsequent
148      * addRole calls are ignored.
149      * Authenticate is forced true by this call.
150      */

151     public synchronized void addRole(String JavaDoc role)
152     {
153         _authenticate= true;
154         if (ANY_ROLE.equals(role))
155         {
156             _roles= null;
157             _umRoles= null;
158             _anyRole= true;
159         }
160         else if (!_anyRole)
161             _roles= LazyList.add(_roles, role);
162     }
163
164     /* ------------------------------------------------------------ */
165     /**
166      * @return True if any user role is permitted.
167      */

168     public boolean isAnyRole()
169     {
170         return _anyRole;
171     }
172
173     /* ------------------------------------------------------------ */
174     /**
175      * @return List of roles for this constraint.
176      */

177     public List JavaDoc getRoles()
178     {
179         if (_umRoles == null && _roles != null)
180             _umRoles= Collections.unmodifiableList(LazyList.getList(_roles));
181         return _umRoles;
182     }
183
184     /* ------------------------------------------------------------ */
185     /**
186      * @param role
187      * @return True if the constraint contains the role.
188      */

189     public boolean hasRole(String JavaDoc role)
190     {
191         return LazyList.contains(_roles, role);
192     }
193
194     /* ------------------------------------------------------------ */
195     /**
196      * @param authenticate True if users must be authenticated
197      */

198     public void setAuthenticate(boolean authenticate)
199     {
200         _authenticate= authenticate;
201     }
202
203     /* ------------------------------------------------------------ */
204     /**
205      * @return True if the constraint requires request authentication
206      */

207     public boolean getAuthenticate()
208     {
209         return _authenticate;
210     }
211
212     /* ------------------------------------------------------------ */
213     /**
214      * @return True if authentication required but no roles set
215      */

216     public boolean isForbidden()
217     {
218         return _authenticate && !_anyRole && LazyList.size(_roles) == 0;
219     }
220
221     /* ------------------------------------------------------------ */
222     /**
223      * @param c
224      */

225     public void setDataConstraint(int c)
226     {
227         if (c < 0 || c > DC_CONFIDENTIAL)
228             throw new IllegalArgumentException JavaDoc("Constraint out of range");
229         _dataConstraint= c;
230     }
231
232     /* ------------------------------------------------------------ */
233     /**
234      * @return Data constrain indicator: 0=DC+NONE, 1=DC_INTEGRAL & 2=DC_CONFIDENTIAL
235      */

236     public int getDataConstraint()
237     {
238         return _dataConstraint;
239     }
240
241     /* ------------------------------------------------------------ */
242     /**
243      * @return True if a data constraint has been set.
244      */

245     public boolean hasDataConstraint()
246     {
247         return _dataConstraint >= DC_NONE;
248     }
249
250     /* ------------------------------------------------------------ */
251     public Object JavaDoc clone()
252     throws CloneNotSupportedException JavaDoc
253     {
254     SecurityConstraint sc = (SecurityConstraint) super.clone();
255     sc._umMethods=null;
256     sc._umRoles=null;
257     return sc;
258     }
259
260     /* ------------------------------------------------------------ */
261     public String JavaDoc toString()
262     {
263         return "SC{"
264             + _name
265             + ","
266             + _methods
267             + ","
268             + (_anyRole ? "*" : (_roles == null ? "-" : _roles.toString()))
269             + ","
270             + (_dataConstraint == DC_NONE
271                 ? "NONE}"
272                 : (_dataConstraint == DC_INTEGRAL ? "INTEGRAL}" : "CONFIDENTIAL}"));
273     }
274
275     /* ------------------------------------------------------------ */
276     /** Check security contraints
277      * @param constraints
278      * @param authenticator
279      * @param realm
280      * @param pathInContext
281      * @param request
282      * @param response
283      * @return false if the request has failed a security constraint or the authenticator has already sent a response.
284      * @exception HttpException
285      * @exception IOException
286      */

287     public static boolean check(
288         List JavaDoc constraints,
289         Authenticator authenticator,
290         UserRealm realm,
291         String JavaDoc pathInContext,
292         HttpRequest request,
293         HttpResponse response)
294         throws HttpException, IOException JavaDoc
295     {
296         // Combine data and auth constraints
297
int dataConstraint= DC_NONE;
298         Object JavaDoc roles= null;
299         boolean unauthenticated= false;
300         boolean forbidden= false;
301
302         for (int c= 0; c < constraints.size(); c++)
303         {
304             SecurityConstraint sc= (SecurityConstraint)constraints.get(c);
305
306             // Check the method applies
307
if (!sc.forMethod(request.getMethod()))
308                 continue;
309
310             // Combine data constraints.
311
if (dataConstraint > DC_UNSET && sc.hasDataConstraint())
312             {
313                 if (sc.getDataConstraint() > dataConstraint)
314                     dataConstraint= sc.getDataConstraint();
315             }
316             else
317                 dataConstraint= DC_UNSET; // ignore all other data constraints
318

319             // Combine auth constraints.
320
if (!unauthenticated && !forbidden)
321             {
322                 if (sc.getAuthenticate())
323                 {
324                     if (sc.isAnyRole())
325                     {
326                         roles= ANY_ROLE;
327                     }
328                     else
329                     {
330                         List JavaDoc scr= sc.getRoles();
331                         if (scr == null || scr.size() == 0)
332                         {
333                             forbidden= true;
334                             break;
335                         }
336                         else
337                         {
338                             if (roles != ANY_ROLE)
339                             {
340                                 roles= LazyList.addCollection(roles, scr);
341                             }
342                         }
343                     }
344                 }
345                 else
346                     unauthenticated= true;
347             }
348         }
349
350         // Does this forbid everything?
351
if (forbidden &&
352             (!(authenticator instanceof FormAuthenticator) ||
353             !((FormAuthenticator)authenticator).isLoginOrErrorPage(pathInContext)))
354         {
355             HttpContext.sendContextError(response,HttpResponse.__403_Forbidden,null);
356             return false;
357         }
358
359         // Handle data constraint
360
if (dataConstraint > DC_NONE)
361         {
362             HttpConnection connection= request.getHttpConnection();
363             HttpListener listener= connection.getListener();
364
365             switch (dataConstraint)
366             {
367                 case SecurityConstraint.DC_INTEGRAL :
368                     if (listener.isIntegral(connection))
369                         break;
370
371                     if (listener.getIntegralPort() > 0)
372                     {
373                         String JavaDoc url=
374                             listener.getIntegralScheme()
375                                 + "://"
376                                 + request.getHost()
377                                 + ":"
378                                 + listener.getIntegralPort()
379                                 + request.getPath();
380                         if (request.getQuery() != null)
381                             url += "?" + request.getQuery();
382                         response.setContentLength(0);
383                         response.sendRedirect(url);
384                     }
385                     else
386                         HttpContext.sendContextError(response,HttpResponse.__403_Forbidden,null);
387                     return false;
388
389                 case SecurityConstraint.DC_CONFIDENTIAL :
390                     if (listener.isConfidential(connection))
391                         break;
392
393                     if (listener.getConfidentialPort() > 0)
394                     {
395                         String JavaDoc url=
396                             listener.getConfidentialScheme()
397                                 + "://"
398                                 + request.getHost()
399                                 + ":"
400                                 + listener.getConfidentialPort()
401                                 + request.getPath();
402                         if (request.getQuery() != null)
403                             url += "?" + request.getQuery();
404
405                         response.setContentLength(0);
406                         response.sendRedirect(url);
407                     }
408                     else
409                         HttpContext.sendContextError(response,HttpResponse.__403_Forbidden,null);
410                     return false;
411
412                 default :
413                     HttpContext.sendContextError(response,HttpResponse.__403_Forbidden,null);
414                     return false;
415             }
416         }
417
418         // Does it fail a role check?
419
if (!unauthenticated && roles != null)
420         {
421             if (realm == null)
422             {
423                 HttpContext.sendContextError(response,HttpResponse.__500_Internal_Server_Error,"Configuration error");
424                 return false;
425             }
426
427             Principal JavaDoc user= null;
428
429             // Handle pre-authenticated request
430
if (request.getAuthType() != null && request.getAuthUser() != null)
431             {
432                 // TODO - is this still needed???
433
user= request.getUserPrincipal();
434                 if (user == null)
435                     user= realm.authenticate(request.getAuthUser(), null, request);
436                 if (user == null && authenticator != null)
437                     user= authenticator.authenticate(realm, pathInContext, request, response);
438             }
439             else if (authenticator != null)
440             {
441                 // User authenticator.
442
user= authenticator.authenticate(realm, pathInContext, request, response);
443             }
444             else
445             {
446                 // don't know how authenticate
447
log.warn("Mis-configured Authenticator for " + request.getPath());
448                 HttpContext.sendContextError(response,HttpResponse.__500_Internal_Server_Error,"Configuration error");
449             }
450
451             // If we still did not get a user
452
if (user == null)
453                 return false; // Auth challenge or redirection already sent
454
else if (user == __NOBODY)
455                 return true; // The Nobody user indicates authentication in transit.
456

457             if (roles != ANY_ROLE)
458             {
459                 boolean inRole= false;
460                 for (int r= LazyList.size(roles); r-- > 0;)
461                 {
462                     if (realm.isUserInRole(user, (String JavaDoc)LazyList.get(roles, r)))
463                     {
464                         inRole= true;
465                         break;
466                     }
467                 }
468
469                 if (!inRole)
470                 {
471                     log.warn("AUTH FAILURE: role for " + user.getName());
472                     if ("BASIC".equalsIgnoreCase(authenticator.getAuthMethod()))
473                          ((BasicAuthenticator)authenticator).sendChallenge(realm, response);
474                     else
475                         HttpContext.sendContextError(response,HttpResponse.__403_Forbidden,"User not in required role");
476                     return false; // role failed.
477
}
478             }
479         }
480         else
481         {
482             request.setUserPrincipal(HttpRequest.__NOT_CHECKED);
483         }
484
485         return true;
486     }
487     
488 }
489
Popular Tags