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         // TODO Auto-generated method stub
133         return null;
134     }
135     
136     /* ------------------------------------------------------------ */
137     @Override
138     public void loadUsers() throws IOException
139     {
140         if (_config==null)
141             return;
142         _configResource = Resource.newResource(_config);
143         
144         if (Log.isDebugEnabled()) Log.debug("Load " + this + " from " + _config);
145         Properties properties = new Properties();
146         properties.load(_configResource.getInputStream());
147         Set<String> known = new HashSet<String>();
148 
149         for (Map.Entry<Object, Object> entry : properties.entrySet())
150         {
151             String username = ((String) entry.getKey()).trim();
152             String credentials = ((String) entry.getValue()).trim();
153             String roles = null;
154             int c = credentials.indexOf(',');
155             if (c > 0)
156             {
157                 roles = credentials.substring(c + 1).trim();
158                 credentials = credentials.substring(0, c).trim();
159             }
160 
161             if (username != null && username.length() > 0 && credentials != null && credentials.length() > 0)
162             {
163                 String[] roleArray = IdentityService.NO_ROLES;
164                 if (roles != null && roles.length() > 0)
165                     roleArray = roles.split(",");
166                 known.add(username);
167                 putUser(username,Credential.getCredential(credentials),roleArray);
168             }
169         }
170         
171         Iterator<String> users = _users.keySet().iterator();
172         while(users.hasNext())
173         {
174             String user=users.next();
175             if (!known.contains(user))
176                 users.remove();
177         }
178     }
179 
180 
181     /* ------------------------------------------------------------ */
182     /**
183      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
184      */
185     protected void doStart() throws Exception
186     {
187         super.doStart();
188         
189         if (getRefreshInterval() > 0)
190         {
191             _scanner = new Scanner();
192             _scanner.setScanInterval(getRefreshInterval());
193             List<File> dirList = new ArrayList<File>(1);
194             dirList.add(_configResource.getFile());
195             _scanner.setScanDirs(dirList);
196             _scanner.setFilenameFilter(new FilenameFilter()
197             {
198                 public boolean accept(File dir, String name)
199                 {
200                     File f = new File(dir, name);
201                     try
202                     {
203                         if (f.compareTo(_configResource.getFile()) == 0) return true;
204                     }
205                     catch (IOException e)
206                     {
207                         return false;
208                     }
209 
210                     return false;
211                 }
212 
213             });
214             _scanner.addListener(new BulkListener()
215             {
216                 public void filesChanged(List filenames) throws Exception
217                 {
218                     if (filenames == null) return;
219                     if (filenames.isEmpty()) return;
220                     if (filenames.size() == 1 && filenames.get(0).equals(_config)) loadUsers();
221                 }
222 
223                 public String toString()
224                 {
225                     return "HashLoginService$Scanner";
226                 }
227 
228             });
229             _scanner.setReportExistingFilesOnStartup(false);
230             _scanner.setRecursive(false);
231             _scanner.start();
232         }
233     }
234 
235     /* ------------------------------------------------------------ */
236     /**
237      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
238      */
239     protected void doStop() throws Exception
240     {
241         super.doStop();
242         if (_scanner != null) _scanner.stop();
243         _scanner = null;
244     }
245 
246 
247 }