View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.security;
20  
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.List;
24  import java.util.Set;
25  
26  import org.eclipse.jetty.security.MappedLoginService.KnownUser;
27  import org.eclipse.jetty.security.PropertyUserStore.UserListener;
28  import org.eclipse.jetty.server.UserIdentity;
29  import org.eclipse.jetty.util.Scanner;
30  import org.eclipse.jetty.util.log.Log;
31  import org.eclipse.jetty.util.log.Logger;
32  import org.eclipse.jetty.util.resource.Resource;
33  import org.eclipse.jetty.util.security.Credential;
34  
35  /* ------------------------------------------------------------ */
36  /**
37   * Properties User Realm.
38   * <p>
39   * An implementation of UserRealm that stores users and roles in-memory in HashMaps.
40   * <p>
41   * Typically these maps are populated by calling the load() method or passing a properties resource to the constructor. The format of the properties file is:
42   * 
43   * <pre>
44   *  username: password [,rolename ...]
45   * </pre>
46   * 
47   * Passwords may be clear text, obfuscated or checksummed. The class com.eclipse.Util.Password should be used to generate obfuscated passwords or password
48   * checksums.
49   * <p>
50   * If DIGEST Authentication is used, the password must be in a recoverable format, either plain text or OBF:.
51   */
52  public class HashLoginService extends MappedLoginService implements UserListener
53  {
54      private static final Logger LOG = Log.getLogger(HashLoginService.class);
55  
56      private PropertyUserStore _propertyUserStore;
57      private String _config;
58      private Resource _configResource;
59      private boolean hotReload = false; // default is not to reload
60      
61      
62      
63      public class HashKnownUser extends KnownUser
64      {
65          String[] _roles;
66          
67          public HashKnownUser(String name, Credential credential)
68          {
69              super(name, credential);
70          }
71          
72          public void setRoles (String[] roles)
73          {
74              _roles = roles;
75          }
76          
77          public String[] getRoles()
78          {
79              return _roles;
80          }
81      }
82  
83      /* ------------------------------------------------------------ */
84      public HashLoginService()
85      {
86      }
87  
88      /* ------------------------------------------------------------ */
89      public HashLoginService(String name)
90      {
91          setName(name);
92      }
93  
94      /* ------------------------------------------------------------ */
95      public HashLoginService(String name, String config)
96      {
97          setName(name);
98          setConfig(config);
99      }
100 
101     /* ------------------------------------------------------------ */
102     public String getConfig()
103     {
104         return _config;
105     }
106 
107     /* ------------------------------------------------------------ */
108     public void getConfig(String config)
109     {
110         _config = config;
111     }
112 
113     /* ------------------------------------------------------------ */
114     public Resource getConfigResource()
115     {
116         return _configResource;
117     }
118 
119     /* ------------------------------------------------------------ */
120     /**
121      * Load realm users from properties file. The property file maps usernames to password specs followed by an optional comma separated list of role names.
122      * 
123      * @param config
124      *            Filename or url of user properties file.
125      */
126     public void setConfig(String config)
127     {
128         _config = config;
129     }
130     
131     /**
132      * Is hot reload enabled on this user store
133      * 
134      * @return true if hot reload was enabled before startup
135      */
136     public boolean isHotReload()
137     {
138         return hotReload;
139     }
140 
141     /**
142      * Enable Hot Reload of the Property File
143      * 
144      * @param enable true to enable, false to disable
145      */
146     public void setHotReload(boolean enable)
147     {
148         if (isRunning())
149         {
150             throw new IllegalStateException("Cannot set hot reload while user store is running");
151         }
152         this.hotReload = enable;
153     }
154 
155     /* ------------------------------------------------------------ */
156     /**
157      * sets the refresh interval (in seconds)
158      * @param sec the refresh interval
159      * @deprecated use {@link #setHotReload(boolean)} instead
160      */
161     @Deprecated
162     public void setRefreshInterval(int sec)
163     {
164     }
165 
166     /* ------------------------------------------------------------ */
167     /**
168      * @return refresh interval in seconds for how often the properties file should be checked for changes
169      * @deprecated use {@link #isHotReload()} instead
170      */
171     @Deprecated
172     public int getRefreshInterval()
173     {
174         return (hotReload)?1:0;
175     }
176 
177     /* ------------------------------------------------------------ */
178     @Override
179     protected UserIdentity loadUser(String username)
180     {
181         return null;
182     }
183 
184     /* ------------------------------------------------------------ */
185     @Override
186     public void loadUsers() throws IOException
187     {
188         // TODO: Consider refactoring MappedLoginService to not have to override with unused methods
189     }
190 
191 
192 
193     @Override
194     protected String[] loadRoleInfo(KnownUser user)
195     {
196         UserIdentity id = _propertyUserStore.getUserIdentity(user.getName());
197         if (id == null)
198             return null;
199 
200 
201         Set<RolePrincipal> roles = id.getSubject().getPrincipals(RolePrincipal.class);
202         if (roles == null)
203             return null;
204 
205         List<String> list = new ArrayList<>();
206         for (RolePrincipal r:roles)
207             list.add(r.getName());
208 
209         return list.toArray(new String[roles.size()]);
210     }
211 
212     @Override
213     protected KnownUser loadUserInfo(String userName)
214     {
215         UserIdentity id = _propertyUserStore.getUserIdentity(userName);
216         if (id != null)
217         {
218             return (KnownUser)id.getUserPrincipal();
219         }
220         
221         return null;
222     }
223     
224     
225 
226     /* ------------------------------------------------------------ */
227     /**
228      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
229      */
230     @Override
231     protected void doStart() throws Exception
232     {
233         super.doStart();
234         
235         if (_propertyUserStore == null)
236         {
237             if(LOG.isDebugEnabled())
238                 LOG.debug("doStart: Starting new PropertyUserStore. PropertiesFile: " + _config + " hotReload: " + hotReload);
239             
240             _propertyUserStore = new PropertyUserStore();
241             _propertyUserStore.setHotReload(hotReload);
242             _propertyUserStore.setConfigPath(_config);
243             _propertyUserStore.registerUserListener(this);
244             _propertyUserStore.start();
245         }
246     }
247 
248     /* ------------------------------------------------------------ */
249     /**
250      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
251      */
252     @Override
253     protected void doStop() throws Exception
254     {
255         super.doStop();
256         if (_propertyUserStore != null)
257             _propertyUserStore.stop();
258         _propertyUserStore = null;
259     }
260     
261     /* ------------------------------------------------------------ */
262     @Override
263     public void update(String userName, Credential credential, String[] roleArray)
264     {
265         if (LOG.isDebugEnabled())
266             LOG.debug("update: " + userName + " Roles: " + roleArray.length);
267        //TODO need to remove and replace the authenticated user?
268     }
269 
270     
271     
272     /* ------------------------------------------------------------ */
273     @Override
274     public void remove(String userName)
275     {
276         if (LOG.isDebugEnabled())
277             LOG.debug("remove: " + userName);
278         removeUser(userName);
279     }
280 }