1   // ========================================================================
2   // Authors : Van den Broeke Iris, Deville Daniel, Dubois Roger, Greg Wilkins
3   // Copyright (c) 2001 Deville Daniel. All rights reserved.
4   // Permission to use, copy, modify and distribute this software
5   // for non-commercial or commercial purposes and without fee is
6   // hereby granted provided that this copyright notice appears in
7   // all copies.
8   // ========================================================================
9   
10  package org.mortbay.jetty.security;
11  
12  import java.io.BufferedReader;
13  import java.io.IOException;
14  import java.io.InputStreamReader;
15  import java.security.Principal;
16  import java.util.ArrayList;
17  import java.util.HashMap;
18  import java.util.HashSet;
19  import java.util.Map;
20  import java.util.StringTokenizer;
21  
22  import javax.servlet.ServletException;
23  import javax.servlet.http.HttpServletRequest;
24  import javax.servlet.http.HttpServletResponse;
25  
26  import org.mortbay.jetty.Handler;
27  import org.mortbay.jetty.HttpConnection;
28  import org.mortbay.jetty.HttpHeaders;
29  import org.mortbay.jetty.Request;
30  import org.mortbay.jetty.Response;
31  import org.mortbay.jetty.UserRealm;
32  import org.mortbay.jetty.handler.ContextHandler;
33  import org.mortbay.log.Log;
34  import org.mortbay.log.Logger;
35  import org.mortbay.resource.Resource;
36  import org.mortbay.util.StringUtil;
37  import org.mortbay.util.URIUtil;
38  
39  /* ------------------------------------------------------------ */
40  /**
41   * Handler to authenticate access using the Apache's .htaccess files.
42   * 
43   * @author Van den Broeke Iris
44   * @author Deville Daniel
45   * @author Dubois Roger
46   * @author Greg Wilkins
47   * @author Konstantin Metlov
48   * 
49   */
50  public class HTAccessHandler extends ConstraintsSecurityHandler
51  {
52      private Handler protegee;
53      private static Logger log=Log.getLogger(HTAccessHandler.class.getName());
54  
55      String _default=null;
56      String _accessFile=".htaccess";
57  
58      transient HashMap _htCache=new HashMap();
59      
60      /**
61       * DummyPrincipal
62       *
63       * For use when there is no user realm configured.
64       */
65      class DummyPrincipal implements Principal
66      {
67          private String _userName;
68  
69          public DummyPrincipal(String name) 
70          {
71              _userName=name;
72          }
73  
74          public String getName()
75          {
76              return _userName;
77          }
78  
79          public String toString()
80          {
81              return getName();
82          }        
83      }
84  
85  
86      /* ------------------------------------------------------------ */
87      /**
88       * {@inheritDoc}
89       * 
90       * @see org.mortbay.jetty.Handler#handle(java.lang.String,
91       *      javax.servlet.http.HttpServletRequest,
92       *      javax.servlet.http.HttpServletResponse, int)
93       */
94      public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException, ServletException
95      {
96          Request base_request=(request instanceof Request)?(Request)request:HttpConnection.getCurrentConnection().getRequest();
97          Response base_response=(response instanceof Response)?(Response)response:HttpConnection.getCurrentConnection().getResponse();
98  
99          String pathInContext=target;
100 
101         String user=null;
102         String password=null;
103         boolean IPValid=true;
104 
105         if (log.isDebugEnabled())
106             log.debug("HTAccessHandler pathInContext="+pathInContext,null,null);
107 
108         String credentials=request.getHeader(HttpHeaders.AUTHORIZATION);
109 
110         if (credentials!=null)
111         {
112             credentials=credentials.substring(credentials.indexOf(' ')+1);
113             credentials=B64Code.decode(credentials,StringUtil.__ISO_8859_1);
114             int i=credentials.indexOf(':');
115             user=credentials.substring(0,i);
116             password=credentials.substring(i+1);
117 
118             if (log.isDebugEnabled())
119                 log.debug("User="+user+", password="+"******************************".substring(0,password.length()),null,null);
120         }
121 
122         HTAccess ht=null;
123 
124         try
125         {
126             Resource resource=null;
127             String directory=pathInContext.endsWith("/")?pathInContext:URIUtil.parentPath(pathInContext);
128 
129             // Look for htAccess resource
130             while (directory!=null)
131             {
132                 String htPath=directory+_accessFile;
133                 resource=((ContextHandler)getProtegee()).getResource(htPath);
134                 if (log.isDebugEnabled())
135                     log.debug("directory="+directory+" resource="+resource,null,null);
136 
137                 if (resource!=null&&resource.exists()&&!resource.isDirectory())
138                     break;
139                 resource=null;
140                 directory=URIUtil.parentPath(directory);
141             }
142 
143             boolean haveHtAccess=true;
144 
145             // Try default directory
146             if (resource==null&&_default!=null)
147             {
148                 resource=Resource.newResource(_default);
149                 if (!resource.exists()||resource.isDirectory())
150                     haveHtAccess=false;
151             }
152             if (resource==null)
153                 haveHtAccess=false;
154 
155             // prevent access to htaccess files
156             if (pathInContext.endsWith(_accessFile)
157                 // extra security
158                 ||pathInContext.endsWith(_accessFile+"~")||pathInContext.endsWith(_accessFile+".bak"))
159             {
160                 response.sendError(HttpServletResponse.SC_FORBIDDEN);
161                 base_request.setHandled(true);
162                 return;
163             }
164 
165             if (haveHtAccess)
166             {
167                 if (log.isDebugEnabled())
168                     log.debug("HTACCESS="+resource,null,null);
169 
170                 ht=(HTAccess)_htCache.get(resource);
171                 if (ht==null||ht.getLastModified()!=resource.lastModified())
172                 {
173                     ht=new HTAccess(resource);
174                     _htCache.put(resource,ht);
175                     if (log.isDebugEnabled())
176                         log.debug("HTCache loaded "+ht,null,null);
177                 }
178 
179                 // See if there is a config problem
180                 if (ht.isForbidden())
181                 {
182                     log.warn("Mis-configured htaccess: "+ht,null,null);
183                     response.sendError(HttpServletResponse.SC_FORBIDDEN);
184                     base_request.setHandled(true);
185                     return;
186                 }
187 
188                 // first see if we need to handle based on method type
189                 Map methods=ht.getMethods();
190                 if (methods.size()>0&&!methods.containsKey(request.getMethod()))
191                     return; // Nothing to check
192 
193                 // Check the accesss
194                 int satisfy=ht.getSatisfy();
195 
196                 // second check IP address
197                 IPValid=ht.checkAccess("",request.getRemoteAddr());
198                 if (log.isDebugEnabled())
199                     log.debug("IPValid = "+IPValid,null,null);
200 
201                 // If IP is correct and satify is ANY then access is allowed
202                 if (IPValid==true&&satisfy==HTAccess.ANY)
203                     return;
204 
205                 // If IP is NOT correct and satify is ALL then access is
206                 // forbidden
207                 if (IPValid==false&&satisfy==HTAccess.ALL)
208                 {
209                     response.sendError(HttpServletResponse.SC_FORBIDDEN);
210                     base_request.setHandled(true);
211                     return;
212                 }
213 
214                 // set required page
215                 if (!ht.checkAuth(user,password,getUserRealm(),base_request))
216                 {
217                     log.debug("Auth Failed",null,null);
218                     response.setHeader(HttpHeaders.WWW_AUTHENTICATE,"basic realm="+ht.getName());
219                     response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
220                     base_response.complete();
221                     base_request.setHandled(true);
222                     return;
223                 }
224 
225                 // set user
226                 if (user!=null)
227                 {
228                     base_request.setAuthType(Constraint.__BASIC_AUTH);
229                     base_request.setUserPrincipal(getPrincipal(user, getUserRealm()));
230                 }
231             }
232             
233             if (getHandler()!=null)
234             {
235                 getHandler().handle(target,request,response,dispatch);
236             }
237 
238         }
239         catch (Exception ex)
240         {
241             log.warn("Exception",ex);
242             if (ht!=null)
243             {
244                 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
245                 base_request.setHandled(true);
246             }
247         }
248     }
249     
250     /* ------------------------------------------------------------ */
251     /** Get a Principal matching the user.
252      * If there is no user realm, and therefore we are using a
253      * htpassword file instead, then just return a dummy Principal.
254      * @param user
255      * @param realm
256      * @return
257      */
258     public Principal getPrincipal (String user, UserRealm realm)
259     {
260         if (realm==null)
261             return new DummyPrincipal(user);
262         
263         return realm.getPrincipal(user);
264     }
265     /* ------------------------------------------------------------ */
266     /**
267      * set functions for the following .xml administration statements.
268      * 
269      * <Call name="addHandler"> <Arg> <New
270      * class="org.mortbay.http.handler.HTAccessHandler"> <Set
271      * name="Default">./etc/htaccess</Set> <Set name="AccessFile">.htaccess</Set>
272      * </New> </Arg> </Call>
273      * 
274      */
275     public void setDefault(String dir)
276     {
277         _default=dir;
278     }
279 
280     /* ------------------------------------------------------------ */
281     public void setAccessFile(String anArg)
282     {
283         if (anArg==null)
284             _accessFile=".htaccess";
285         else
286             _accessFile=anArg;
287     }
288 
289     /* ------------------------------------------------------------ */
290     /* ------------------------------------------------------------ */
291     /* ------------------------------------------------------------ */
292     private static class HTAccess
293     {
294         // private boolean _debug = false;
295         static final int ANY=0;
296         static final int ALL=1;
297         static final String USER="user";
298         static final String GROUP="group";
299         static final String VALID_USER="valid-user";
300 
301         /* ------------------------------------------------------------ */
302         String _userFile;
303         Resource _userResource;
304         HashMap _users=null;
305         long _userModified;
306 
307         /* ------------------------------------------------------------ */
308         String _groupFile;
309         Resource _groupResource;
310         HashMap _groups=null;
311         long _groupModified;
312 
313         int _satisfy=0;
314         String _type;
315         String _name;
316         HashMap _methods=new HashMap();
317         HashSet _requireEntities=new HashSet();
318         String _requireName;
319         int _order;
320         ArrayList _allowList=new ArrayList();
321         ArrayList _denyList=new ArrayList();
322         long _lastModified;
323         boolean _forbidden=false;
324 
325         /* ------------------------------------------------------------ */
326         public HTAccess(Resource resource)
327         {
328             BufferedReader htin=null;
329             try
330             {
331                 htin=new BufferedReader(new InputStreamReader(resource.getInputStream()));
332                 parse(htin);
333                 _lastModified=resource.lastModified();
334 
335                 if (_userFile!=null)
336                 {
337                     _userResource=Resource.newResource(_userFile);
338                     if (!_userResource.exists())
339                     {
340                         _forbidden=true;
341                         log.warn("Could not find ht user file: "+_userFile,null,null);
342                     }
343                     else if (log.isDebugEnabled())
344                         log.debug("user file: "+_userResource,null,null);
345                 }
346 
347                 if (_groupFile!=null)
348                 {
349                     _groupResource=Resource.newResource(_groupFile);
350                     if (!_groupResource.exists())
351                     {
352                         _forbidden=true;
353                         log.warn("Could not find ht group file: "+_groupResource,null,null);
354                     }
355                     else if (log.isDebugEnabled())
356                         log.debug("group file: "+_groupResource,null,null);
357                 }
358             }
359             catch (IOException e)
360             {
361                 _forbidden=true;
362                 log.warn("LogSupport.EXCEPTION",e);
363             }
364         }
365 
366         /* ------------------------------------------------------------ */
367         public boolean isForbidden()
368         {
369             return _forbidden;
370         }
371 
372         /* ------------------------------------------------------------ */
373         public HashMap getMethods()
374         {
375             return _methods;
376         }
377 
378         /* ------------------------------------------------------------ */
379         public long getLastModified()
380         {
381             return _lastModified;
382         }
383 
384         /* ------------------------------------------------------------ */
385         public Resource getUserResource()
386         {
387             return _userResource;
388         }
389 
390         /* ------------------------------------------------------------ */
391         public Resource getGroupResource()
392         {
393             return _groupResource;
394         }
395 
396         /* ------------------------------------------------------------ */
397         public int getSatisfy()
398         {
399             return (_satisfy);
400         }
401 
402         /* ------------------------------------------------------------ */
403         public String getName()
404         {
405             return _name;
406         }
407 
408         /* ------------------------------------------------------------ */
409         public String getType()
410         {
411             return _type;
412         }
413 
414         /* ------------------------------------------------------------ */
415         public boolean checkAccess(String host, String ip)
416         {
417             String elm;
418             boolean alp=false;
419             boolean dep=false;
420 
421             // if no allows and no deny defined, then return true
422             if (_allowList.size()==0&&_denyList.size()==0)
423                 return (true);
424 
425             // looping for allows
426             for (int i=0; i<_allowList.size(); i++)
427             {
428                 elm=(String)_allowList.get(i);
429                 if (elm.equals("all"))
430                 {
431                     alp=true;
432                     break;
433                 }
434                 else
435                 {
436                     char c=elm.charAt(0);
437                     if (c>='0'&&c<='9')
438                     {
439                         // ip
440                         if (ip.startsWith(elm))
441                         {
442                             alp=true;
443                             break;
444                         }
445                     }
446                     else
447                     {
448                         // hostname
449                         if (host.endsWith(elm))
450                         {
451                             alp=true;
452                             break;
453                         }
454                     }
455                 }
456             }
457 
458             // looping for denies
459             for (int i=0; i<_denyList.size(); i++)
460             {
461                 elm=(String)_denyList.get(i);
462                 if (elm.equals("all"))
463                 {
464                     dep=true;
465                     break;
466                 }
467                 else
468                 {
469                     char c=elm.charAt(0);
470                     if (c>='0'&&c<='9')
471                     { // ip
472                         if (ip.startsWith(elm))
473                         {
474                             dep=true;
475                             break;
476                         }
477                     }
478                     else
479                     { // hostname
480                         if (host.endsWith(elm))
481                         {
482                             dep=true;
483                             break;
484                         }
485                     }
486                 }
487             }
488 
489             if (_order<0) // deny,allow
490                 return !dep||alp;
491             // mutual failure == allow,deny
492             return alp&&!dep;
493         }
494 
495         /* ------------------------------------------------------------ */
496         public boolean checkAuth(String user, String pass, UserRealm realm, Request request)
497         {
498             if (_requireName==null)
499                 return true;
500 
501             // Authenticate with realm
502 
503             Principal principal=realm==null?null:realm.authenticate(user,pass,request);
504             if (principal==null)
505             {
506                 // Have to authenticate the user with the password file
507                 String code=getUserCode(user);
508                 String salt=code!=null?code.substring(0,2):user;
509                 String cred=(user!=null&&pass!=null)?UnixCrypt.crypt(pass,salt):null;
510                 if (code==null||(code.equals("")&&!pass.equals(""))||!code.equals(cred))
511                     return false;
512             }
513 
514             if (_requireName.equalsIgnoreCase(USER))
515             {
516                 if (_requireEntities.contains(user))
517                     return true;
518             }
519             else if (_requireName.equalsIgnoreCase(GROUP))
520             {
521                 ArrayList gps=getUserGroups(user);
522                 if (gps!=null)
523                     for (int g=gps.size(); g-->0;)
524                         if (_requireEntities.contains(gps.get(g)))
525                             return true;
526             }
527             else if (_requireName.equalsIgnoreCase(VALID_USER))
528             {
529                 return true;
530             }
531 
532             return false;
533         }
534 
535         /* ------------------------------------------------------------ */
536         public boolean isAccessLimited()
537         {
538             if (_allowList.size()>0||_denyList.size()>0)
539                 return true;
540             else
541                 return false;
542         }
543 
544         /* ------------------------------------------------------------ */
545         public boolean isAuthLimited()
546         {
547             if (_requireName!=null)
548                 return true;
549             else
550                 return false;
551         }
552 
553         /* ------------------------------------------------------------ */
554         private String getUserCode(String user)
555         {
556             if (_userResource==null)
557                 return null;
558 
559             if (_users==null||_userModified!=_userResource.lastModified())
560             {
561                 if (log.isDebugEnabled())
562                     log.debug("LOAD "+_userResource,null,null);
563                 _users=new HashMap();
564                 BufferedReader ufin=null;
565                 try
566                 {
567                     ufin=new BufferedReader(new InputStreamReader(_userResource.getInputStream()));
568                     _userModified=_userResource.lastModified();
569                     String line;
570                     while ((line=ufin.readLine())!=null)
571                     {
572                         line=line.trim();
573                         if (line.startsWith("#"))
574                             continue;
575                         int spos=line.indexOf(':');
576                         if (spos<0)
577                             continue;
578                         String u=line.substring(0,spos).trim();
579                         String p=line.substring(spos+1).trim();
580                         _users.put(u,p);
581                     }
582                 }
583                 catch (IOException e)
584                 {
585                     log.warn("LogSupport.EXCEPTION",e);
586                 }
587                 finally
588                 {
589                     try
590                     {
591                         if (ufin!=null)
592                             ufin.close();
593                     }
594                     catch (IOException e2)
595                     {
596                         log.warn("LogSupport.EXCEPTION",e2);
597                     }
598                 }
599             }
600 
601             return (String)_users.get(user);
602         }
603 
604         /* ------------------------------------------------------------ */
605         private ArrayList getUserGroups(String group)
606         {
607             if (_groupResource==null)
608                 return null;
609 
610             if (_groups==null||_groupModified!=_groupResource.lastModified())
611             {
612                 if (log.isDebugEnabled())
613                     log.debug("LOAD "+_groupResource,null,null);
614 
615                 _groups=new HashMap();
616                 BufferedReader ufin=null;
617                 try
618                 {
619                     ufin=new BufferedReader(new InputStreamReader(_groupResource.getInputStream()));
620                     _groupModified=_groupResource.lastModified();
621                     String line;
622                     while ((line=ufin.readLine())!=null)
623                     {
624                         line=line.trim();
625                         if (line.startsWith("#")||line.length()==0)
626                             continue;
627 
628                         StringTokenizer tok=new StringTokenizer(line,": \t");
629 
630                         if (!tok.hasMoreTokens())
631                             continue;
632                         String g=tok.nextToken();
633                         if (!tok.hasMoreTokens())
634                             continue;
635                         while (tok.hasMoreTokens())
636                         {
637                             String u=tok.nextToken();
638                             ArrayList gl=(ArrayList)_groups.get(u);
639                             if (gl==null)
640                             {
641                                 gl=new ArrayList();
642                                 _groups.put(u,gl);
643                             }
644                             gl.add(g);
645                         }
646                     }
647                 }
648                 catch (IOException e)
649                 {
650                     log.warn("LogSupport.EXCEPTION",e);
651                 }
652                 finally
653                 {
654                     try
655                     {
656                         if (ufin!=null)
657                             ufin.close();
658                     }
659                     catch (IOException e2)
660                     {
661                         log.warn("LogSupport.EXCEPTION",e2);
662                     }
663                 }
664             }
665 
666             return (ArrayList)_groups.get(group);
667         }
668 
669         /* ------------------------------------------------------------ */
670         public String toString()
671         {
672             StringBuilder buf=new StringBuilder();
673 
674             buf.append("AuthUserFile=");
675             buf.append(_userFile);
676             buf.append(", AuthGroupFile=");
677             buf.append(_groupFile);
678             buf.append(", AuthName=");
679             buf.append(_name);
680             buf.append(", AuthType=");
681             buf.append(_type);
682             buf.append(", Methods=");
683             buf.append(_methods);
684             buf.append(", satisfy=");
685             buf.append(_satisfy);
686             if (_order<0)
687                 buf.append(", order=deny,allow");
688             else if (_order>0)
689                 buf.append(", order=allow,deny");
690             else
691                 buf.append(", order=mutual-failure");
692 
693             buf.append(", Allow from=");
694             buf.append(_allowList);
695             buf.append(", deny from=");
696             buf.append(_denyList);
697             buf.append(", requireName=");
698             buf.append(_requireName);
699             buf.append(" ");
700             buf.append(_requireEntities);
701 
702             return buf.toString();
703         }
704 
705         /* ------------------------------------------------------------ */
706         private void parse(BufferedReader htin) throws IOException
707         {
708             String line;
709             while ((line=htin.readLine())!=null)
710             {
711                 line=line.trim();
712                 if (line.startsWith("#"))
713                     continue;
714                 else if (line.startsWith("AuthUserFile"))
715                 {
716                     _userFile=line.substring(13).trim();
717                 }
718                 else if (line.startsWith("AuthGroupFile"))
719                 {
720                     _groupFile=line.substring(14).trim();
721                 }
722                 else if (line.startsWith("AuthName"))
723                 {
724                     _name=line.substring(8).trim();
725                 }
726                 else if (line.startsWith("AuthType"))
727                 {
728                     _type=line.substring(8).trim();
729                 }
730                 // else if (line.startsWith("<Limit")) {
731                 else if (line.startsWith("<Limit"))
732                 {
733                     int limit=line.length();
734                     int endp=line.indexOf('>');
735                     StringTokenizer tkns;
736 
737                     if (endp<0)
738                         endp=limit;
739                     tkns=new StringTokenizer(line.substring(6,endp));
740                     while (tkns.hasMoreTokens())
741                     {
742                         _methods.put(tkns.nextToken(),Boolean.TRUE);
743                     }
744 
745                     while ((line=htin.readLine())!=null)
746                     {
747                         line=line.trim();
748                         if (line.startsWith("#"))
749                             continue;
750                         else if (line.startsWith("satisfy"))
751                         {
752                             int pos1=7;
753                             limit=line.length();
754                             while ((pos1<limit)&&(line.charAt(pos1)<=' '))
755                                 pos1++;
756                             int pos2=pos1;
757                             while ((pos2<limit)&&(line.charAt(pos2)>' '))
758                                 pos2++;
759                             String l_string=line.substring(pos1,pos2);
760                             if (l_string.equals("all"))
761                                 _satisfy=1;
762                             else if (l_string.equals("any"))
763                                 _satisfy=0;
764                         }
765                         else if (line.startsWith("require"))
766                         {
767                             int pos1=7;
768                             limit=line.length();
769                             while ((pos1<limit)&&(line.charAt(pos1)<=' '))
770                                 pos1++;
771                             int pos2=pos1;
772                             while ((pos2<limit)&&(line.charAt(pos2)>' '))
773                                 pos2++;
774                             _requireName=line.substring(pos1,pos2).toLowerCase();
775                             if (USER.equals(_requireName))
776                                 _requireName=USER;
777                             else if (GROUP.equals(_requireName))
778                                 _requireName=GROUP;
779                             else if (VALID_USER.equals(_requireName))
780                                 _requireName=VALID_USER;
781 
782                             pos1=pos2+1;
783                             if (pos1<limit)
784                             {
785                                 while ((pos1<limit)&&(line.charAt(pos1)<=' '))
786                                     pos1++;
787 
788                                 tkns=new StringTokenizer(line.substring(pos1));
789                                 while (tkns.hasMoreTokens())
790                                 {
791                                     _requireEntities.add(tkns.nextToken());
792                                 }
793                             }
794 
795                         }
796                         else if (line.startsWith("order"))
797                         {
798                             if (log.isDebugEnabled())
799                                 log.debug("orderline="+line+"order="+_order,null,null);
800                             if (line.indexOf("allow,deny")>0)
801                             {
802                                 log.debug("==>allow+deny",null,null);
803                                 _order=1;
804                             }
805                             else if (line.indexOf("deny,allow")>0)
806                             {
807                                 log.debug("==>deny,allow",null,null);
808                                 _order=-1;
809                             }
810                             else if (line.indexOf("mutual-failure")>0)
811                             {
812                                 log.debug("==>mutual",null,null);
813                                 _order=0;
814                             }
815                             else
816                             {
817                             }
818                         }
819                         else if (line.startsWith("allow from"))
820                         {
821                             int pos1=10;
822                             limit=line.length();
823                             while ((pos1<limit)&&(line.charAt(pos1)<=' '))
824                                 pos1++;
825                             if (log.isDebugEnabled())
826                                 log.debug("allow process:"+line.substring(pos1),null,null);
827                             tkns=new StringTokenizer(line.substring(pos1));
828                             while (tkns.hasMoreTokens())
829                             {
830                                 _allowList.add(tkns.nextToken());
831                             }
832                         }
833                         else if (line.startsWith("deny from"))
834                         {
835                             int pos1=9;
836                             limit=line.length();
837                             while ((pos1<limit)&&(line.charAt(pos1)<=' '))
838                                 pos1++;
839                             if (log.isDebugEnabled())
840                                 log.debug("deny process:"+line.substring(pos1),null,null);
841 
842                             tkns=new StringTokenizer(line.substring(pos1));
843                             while (tkns.hasMoreTokens())
844                             {
845                                 _denyList.add(tkns.nextToken());
846                             }
847                         }
848                         else if (line.startsWith("</Limit>"))
849                             break;
850                     }
851                 }
852             }
853         }
854     }
855 
856     /**
857      * Getter for property protegee.
858      * 
859      * @return Returns the protegee.
860      */
861     protected Handler getProtegee()
862     {
863         return this.protegee;
864     }
865 
866     /**
867      * Setter for property protegee.
868      * 
869      * @param protegee
870      *            The protegee to set.
871      */
872     public void setProtegee(Handler protegee)
873     {
874         this.protegee=protegee;
875     }
876 
877 }