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.log.Logger;
33  import org.eclipse.jetty.util.resource.Resource;
34  
35  /* ------------------------------------------------------------ */
36  /**
37   * Properties User Realm.
38   * 
39   * An implementation of UserRealm that stores users and roles in-memory in
40   * HashMaps.
41   * <P>
42   * Typically these maps are populated by calling the load() method or passing a
43   * properties resource to the constructor. The format of the properties file is:
44   * 
45   * <PRE>
46   *  username: password [,rolename ...]
47   * </PRE>
48   * 
49   * Passwords may be clear text, obfuscated or checksummed. The class
50   * com.eclipse.Util.Password should be used to generate obfuscated passwords or
51   * password checksums.
52   * 
53   * If DIGEST Authentication is used, the password must be in a recoverable
54   * format, either plain text or OBF:.
55   */
56  public class HashLoginService extends MappedLoginService
57  {
58      private static final Logger LOG = Log.getLogger(HashLoginService.class);
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      */
109     public void setConfig(String config)
110     {
111         _config = config;
112     }
113 
114     /* ------------------------------------------------------------ */
115     public void setRefreshInterval(int msec)
116     {
117         _refreshInterval = msec;
118     }
119 
120     /* ------------------------------------------------------------ */
121     public int getRefreshInterval()
122     {
123         return _refreshInterval;
124     }
125 
126     /* ------------------------------------------------------------ */
127     @Override
128     protected UserIdentity loadUser(String username)
129     {
130         return null;
131     }
132     
133     /* ------------------------------------------------------------ */
134     @Override
135     public void loadUsers() throws IOException
136     {
137         if (_config==null)
138             return;
139         _configResource = Resource.newResource(_config);
140         
141         if (LOG.isDebugEnabled()) LOG.debug("Load " + this + " from " + _config);
142         Properties properties = new Properties();
143         properties.load(_configResource.getInputStream());
144         Set<String> known = new HashSet<String>();
145 
146         for (Map.Entry<Object, Object> entry : properties.entrySet())
147         {
148             String username = ((String) entry.getKey()).trim();
149             String credentials = ((String) entry.getValue()).trim();
150             String roles = null;
151             int c = credentials.indexOf(',');
152             if (c > 0)
153             {
154                 roles = credentials.substring(c + 1).trim();
155                 credentials = credentials.substring(0, c).trim();
156             }
157 
158             if (username != null && username.length() > 0 && credentials != null && credentials.length() > 0)
159             {
160                 String[] roleArray = IdentityService.NO_ROLES;
161                 if (roles != null && roles.length() > 0)
162                     roleArray = roles.split(",");
163                 known.add(username);
164                 putUser(username,Credential.getCredential(credentials),roleArray);
165             }
166         }
167         
168         Iterator<String> users = _users.keySet().iterator();
169         while(users.hasNext())
170         {
171             String user=users.next();
172             if (!known.contains(user))
173                 users.remove();
174         }
175     }
176 
177 
178     /* ------------------------------------------------------------ */
179     /**
180      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
181      */
182     protected void doStart() throws Exception
183     {
184         super.doStart();
185         
186         if (getRefreshInterval() > 0)
187         {
188             _scanner = new Scanner();
189             _scanner.setScanInterval(getRefreshInterval());
190             List<File> dirList = new ArrayList<File>(1);
191             dirList.add(_configResource.getFile());
192             _scanner.setScanDirs(dirList);
193             _scanner.setFilenameFilter(new FilenameFilter()
194             {
195                 public boolean accept(File dir, String name)
196                 {
197                     File f = new File(dir, name);
198                     try
199                     {
200                         if (f.compareTo(_configResource.getFile()) == 0) return true;
201                     }
202                     catch (IOException e)
203                     {
204                         return false;
205                     }
206 
207                     return false;
208                 }
209 
210             });
211             _scanner.addListener(new BulkListener()
212             {
213                 public void filesChanged(List<String> filenames) throws Exception
214                 {
215                     if (filenames == null) return;
216                     if (filenames.isEmpty()) return;
217                     if (filenames.size() == 1)
218                     {
219                         Resource r = Resource.newResource(filenames.get(0));
220                         if (r.getFile().equals(_configResource.getFile()))
221                             loadUsers();
222                     }
223                 }
224 
225                 public String toString()
226                 {
227                     return "HashLoginService$Scanner";
228                 }
229 
230             });
231             _scanner.setReportExistingFilesOnStartup(false);
232             _scanner.setRecursive(false);
233             _scanner.start();
234         }
235     }
236 
237     /* ------------------------------------------------------------ */
238     /**
239      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
240      */
241     protected void doStop() throws Exception
242     {
243         super.doStop();
244         if (_scanner != null) _scanner.stop();
245         _scanner = null;
246     }
247 
248 
249 }