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 }