View Javadoc

1   // ========================================================================
2   // Copyright (c) 1996-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  package org.eclipse.jetty.security;
15  
16  import java.io.File;
17  import java.io.FilenameFilter;
18  import java.io.IOException;
19  import java.util.ArrayList;
20  import java.util.HashSet;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.Properties;
25  import java.util.Set;
26  
27  import org.eclipse.jetty.http.security.Credential;
28  import org.eclipse.jetty.server.UserIdentity;
29  import org.eclipse.jetty.util.Scanner;
30  import org.eclipse.jetty.util.Scanner.BulkListener;
31  import org.eclipse.jetty.util.log.Log;
32  import org.eclipse.jetty.util.resource.Resource;
33  
34  /* ------------------------------------------------------------ */
35  /**
36   * Properties User Realm.
37   * 
38   * An implementation of UserRealm that stores users and roles in-memory in
39   * HashMaps.
40   * <P>
41   * Typically these maps are populated by calling the load() method or passing a
42   * properties resource to the constructor. The format of the properties file is:
43   * 
44   * <PRE>
45   *  username: password [,rolename ...]
46   * </PRE>
47   * 
48   * Passwords may be clear text, obfuscated or checksummed. The class
49   * com.eclipse.Util.Password should be used to generate obfuscated passwords or
50   * password checksums.
51   * 
52   * If DIGEST Authentication is used, the password must be in a recoverable
53   * format, either plain text or OBF:.
54   */
55  public class HashLoginService extends MappedLoginService
56  {
57      private String _config;
58      private Resource _configResource;
59      private Scanner _scanner;
60      private int _refreshInterval = 0;// default is not to reload
61  
62      /* ------------------------------------------------------------ */
63      public HashLoginService()
64      {
65      }
66  
67      /* ------------------------------------------------------------ */
68      public HashLoginService(String name)
69      {
70          setName(name);
71      }
72      
73      /* ------------------------------------------------------------ */
74      public HashLoginService(String name, String config)
75      {
76          setName(name);
77          setConfig(config);
78      }
79      
80      /* ------------------------------------------------------------ */
81      public String getConfig()
82      {
83          return _config;
84      }
85  
86      /* ------------------------------------------------------------ */
87      public void getConfig(String config)
88      {
89          _config=config;
90      }
91  
92      /* ------------------------------------------------------------ */
93      public Resource getConfigResource()
94      {
95          return _configResource;
96      }
97  
98      /* ------------------------------------------------------------ */
99      /**
100      * Load realm users from properties file. The property file maps usernames
101      * to password specs followed by an optional comma separated list of role
102      * names.
103      * 
104      * @param config Filename or url of user properties file.
105      */
106     public void setConfig(String config)
107     {
108         _config = config;
109     }
110 
111     /* ------------------------------------------------------------ */
112     public void setRefreshInterval(int msec)
113     {
114         _refreshInterval = msec;
115     }
116 
117     /* ------------------------------------------------------------ */
118     public int getRefreshInterval()
119     {
120         return _refreshInterval;
121     }
122 
123     /* ------------------------------------------------------------ */
124     @Override
125     protected UserIdentity loadUser(String username)
126     {
127         return null;
128     }
129     
130     /* ------------------------------------------------------------ */
131     @Override
132     public void loadUsers() throws IOException
133     {
134         if (_config==null)
135             return;
136         _configResource = Resource.newResource(_config);
137         
138         if (Log.isDebugEnabled()) Log.debug("Load " + this + " from " + _config);
139         Properties properties = new Properties();
140         properties.load(_configResource.getInputStream());
141         Set<String> known = new HashSet<String>();
142 
143         for (Map.Entry<Object, Object> entry : properties.entrySet())
144         {
145             String username = ((String) entry.getKey()).trim();
146             String credentials = ((String) entry.getValue()).trim();
147             String roles = null;
148             int c = credentials.indexOf(',');
149             if (c > 0)
150             {
151                 roles = credentials.substring(c + 1).trim();
152                 credentials = credentials.substring(0, c).trim();
153             }
154 
155             if (username != null && username.length() > 0 && credentials != null && credentials.length() > 0)
156             {
157                 String[] roleArray = IdentityService.NO_ROLES;
158                 if (roles != null && roles.length() > 0)
159                     roleArray = roles.split(",");
160                 known.add(username);
161                 putUser(username,Credential.getCredential(credentials),roleArray);
162             }
163         }
164         
165         Iterator<String> users = _users.keySet().iterator();
166         while(users.hasNext())
167         {
168             String user=users.next();
169             if (!known.contains(user))
170                 users.remove();
171         }
172     }
173 
174 
175     /* ------------------------------------------------------------ */
176     /**
177      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
178      */
179     protected void doStart() throws Exception
180     {
181         super.doStart();
182         
183         if (getRefreshInterval() > 0)
184         {
185             _scanner = new Scanner();
186             _scanner.setScanInterval(getRefreshInterval());
187             List<File> dirList = new ArrayList<File>(1);
188             dirList.add(_configResource.getFile());
189             _scanner.setScanDirs(dirList);
190             _scanner.setFilenameFilter(new FilenameFilter()
191             {
192                 public boolean accept(File dir, String name)
193                 {
194                     File f = new File(dir, name);
195                     try
196                     {
197                         if (f.compareTo(_configResource.getFile()) == 0) return true;
198                     }
199                     catch (IOException e)
200                     {
201                         return false;
202                     }
203 
204                     return false;
205                 }
206 
207             });
208             _scanner.addListener(new BulkListener()
209             {
210                 public void filesChanged(List filenames) throws Exception
211                 {
212                     if (filenames == null) return;
213                     if (filenames.isEmpty()) return;
214                     if (filenames.size() == 1 && filenames.get(0).equals(_config)) loadUsers();
215                 }
216 
217                 public String toString()
218                 {
219                     return "HashLoginService$Scanner";
220                 }
221 
222             });
223             _scanner.setReportExistingFilesOnStartup(false);
224             _scanner.setRecursive(false);
225             _scanner.start();
226         }
227     }
228 
229     /* ------------------------------------------------------------ */
230     /**
231      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
232      */
233     protected void doStop() throws Exception
234     {
235         super.doStop();
236         if (_scanner != null) _scanner.stop();
237         _scanner = null;
238     }
239 
240 
241 }