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   * @see org.eclipse.jetty.security.Password
56   * 
57   */
58  public class HashLoginService extends MappedLoginService
59  {
60      private String _config;
61      private Resource _configResource;
62      private Scanner _scanner;
63      private int _refreshInterval = 0;// default is not to reload
64  
65      /* ------------------------------------------------------------ */
66      public HashLoginService()
67      {
68      }
69  
70      /* ------------------------------------------------------------ */
71      public HashLoginService(String name)
72      {
73          setName(name);
74      }
75      
76      /* ------------------------------------------------------------ */
77      public HashLoginService(String name, String config)
78      {
79          setName(name);
80          setConfig(config);
81      }
82      
83      /* ------------------------------------------------------------ */
84      public String getConfig()
85      {
86          return _config;
87      }
88  
89      /* ------------------------------------------------------------ */
90      public void getConfig(String config)
91      {
92          _config=config;
93      }
94  
95      /* ------------------------------------------------------------ */
96      public Resource getConfigResource()
97      {
98          return _configResource;
99      }
100 
101     /* ------------------------------------------------------------ */
102     /**
103      * Load realm users from properties file. The property file maps usernames
104      * to password specs followed by an optional comma separated list of role
105      * names.
106      * 
107      * @param config Filename or url of user properties file.
108      * @exception java.io.IOException if user properties file could not be
109      *                    loaded
110      */
111     public void setConfig(String config)
112     {
113         _config = config;
114     }
115 
116     /* ------------------------------------------------------------ */
117     public void setRefreshInterval(int msec)
118     {
119         _refreshInterval = msec;
120     }
121 
122     /* ------------------------------------------------------------ */
123     public int getRefreshInterval()
124     {
125         return _refreshInterval;
126     }
127 
128     /* ------------------------------------------------------------ */
129     @Override
130     protected UserIdentity loadUser(String username)
131     {
132         return null;
133     }
134     
135     /* ------------------------------------------------------------ */
136     @Override
137     public void loadUsers() throws IOException
138     {
139         if (_config==null)
140             return;
141         _configResource = Resource.newResource(_config);
142         
143         if (Log.isDebugEnabled()) Log.debug("Load " + this + " from " + _config);
144         Properties properties = new Properties();
145         properties.load(_configResource.getInputStream());
146         Set<String> known = new HashSet<String>();
147 
148         for (Map.Entry<Object, Object> entry : properties.entrySet())
149         {
150             String username = ((String) entry.getKey()).trim();
151             String credentials = ((String) entry.getValue()).trim();
152             String roles = null;
153             int c = credentials.indexOf(',');
154             if (c > 0)
155             {
156                 roles = credentials.substring(c + 1).trim();
157                 credentials = credentials.substring(0, c).trim();
158             }
159 
160             if (username != null && username.length() > 0 && credentials != null && credentials.length() > 0)
161             {
162                 String[] roleArray = IdentityService.NO_ROLES;
163                 if (roles != null && roles.length() > 0)
164                     roleArray = roles.split(",");
165                 known.add(username);
166                 putUser(username,Credential.getCredential(credentials),roleArray);
167             }
168         }
169         
170         Iterator<String> users = _users.keySet().iterator();
171         while(users.hasNext())
172         {
173             String user=users.next();
174             if (!known.contains(user))
175                 users.remove();
176         }
177     }
178 
179 
180     /* ------------------------------------------------------------ */
181     /**
182      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
183      */
184     protected void doStart() throws Exception
185     {
186         super.doStart();
187         
188         if (getRefreshInterval() > 0)
189         {
190             _scanner = new Scanner();
191             _scanner.setScanInterval(getRefreshInterval());
192             List<File> dirList = new ArrayList<File>(1);
193             dirList.add(_configResource.getFile());
194             _scanner.setScanDirs(dirList);
195             _scanner.setFilenameFilter(new FilenameFilter()
196             {
197                 public boolean accept(File dir, String name)
198                 {
199                     File f = new File(dir, name);
200                     try
201                     {
202                         if (f.compareTo(_configResource.getFile()) == 0) return true;
203                     }
204                     catch (IOException e)
205                     {
206                         return false;
207                     }
208 
209                     return false;
210                 }
211 
212             });
213             _scanner.addListener(new BulkListener()
214             {
215                 public void filesChanged(List filenames) throws Exception
216                 {
217                     if (filenames == null) return;
218                     if (filenames.isEmpty()) return;
219                     if (filenames.size() == 1 && filenames.get(0).equals(_config)) loadUsers();
220                 }
221 
222                 public String toString()
223                 {
224                     return "HashLoginService$Scanner";
225                 }
226 
227             });
228             _scanner.setReportExistingFilesOnStartup(false);
229             _scanner.setRecursive(false);
230             _scanner.start();
231         }
232     }
233 
234     /* ------------------------------------------------------------ */
235     /**
236      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
237      */
238     protected void doStop() throws Exception
239     {
240         super.doStop();
241         if (_scanner != null) _scanner.stop();
242         _scanner = null;
243     }
244 
245 
246 }