1
2
3
4
5
6
7
8
9
10
11
12
13 package org.abstracthorizon.danube.auth.jaas.memory;
14
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.io.OutputStream;
18 import java.lang.reflect.Method;
19 import java.net.URI;
20 import java.net.URISyntaxException;
21 import java.net.URLConnection;
22 import java.security.MessageDigest;
23 import java.security.NoSuchAlgorithmException;
24 import java.security.Security;
25 import java.security.cert.CertificateException;
26 import java.util.ArrayList;
27 import java.util.Enumeration;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Properties;
33 import java.util.Set;
34
35 import javax.security.auth.login.AppConfigurationEntry;
36 import javax.security.auth.login.Configuration;
37
38 import org.bouncycastle.jce.provider.BouncyCastleProvider;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42
43
44
45
46
47
48 public class PropertiesModuleService {
49
50 protected Logger logger = LoggerFactory.getLogger(getClass());
51
52
53 private String loginContext;
54
55
56 private String controlFlag = "required";
57
58
59 private Configuration configuration;
60
61
62 private Map<String, Object> options = new HashMap<String, Object>();
63
64
65 private String propertiesURI;
66
67
68 private Properties properties = new Properties();
69
70 static {
71 Security.addProvider(new BouncyCastleProvider());
72 }
73
74
75
76
77 public PropertiesModuleService() {
78 }
79
80
81
82
83
84 public void start() throws Exception {
85
86 AppConfigurationEntry.LoginModuleControlFlag flag = AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;
87
88 if (AppConfigurationEntry.LoginModuleControlFlag.REQUIRED.toString().indexOf(controlFlag) > 0 ) {
89 flag = AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;
90 } else if( AppConfigurationEntry.LoginModuleControlFlag.REQUISITE.toString().indexOf(controlFlag) > 0 ) {
91 flag = AppConfigurationEntry.LoginModuleControlFlag.REQUISITE;
92 } else if( AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT.toString().indexOf(controlFlag) > 0 ) {
93 flag = AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT;
94 }else if( AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL.toString().indexOf(controlFlag) > 0 ) {
95 flag = AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL;
96 }
97
98
99 options.put("properties", properties);
100 AppConfigurationEntry entry = new AppConfigurationEntry(PropertiesLoginModule.class.getName(), flag, options);
101
102 AppConfigurationEntry[] list = new AppConfigurationEntry[1];
103 list[0] = entry;
104 Method method = configuration.getClass().getMethod("setAppConfigurationEntry", new Class[]{String.class, list.getClass()});
105 Object[] args = {loginContext, list};
106 method.invoke(configuration, args);
107 logger.info("Set up login context '" + loginContext + "'");
108 }
109
110
111 public void stop() throws Exception {
112 Method method = configuration.getClass().getMethod("removeAppConfigurationEntry", new Class[]{String.class});
113 Object[] args = {loginContext};
114 method.invoke(configuration, args);
115 logger.info("Removed login context '" + loginContext + "'");
116 }
117
118
119
120
121
122
123 public String listUsersString() throws Exception {
124 List<String> u = listUsers();
125 String[] users = new String[u.size()];
126 users = (String[])u.toArray(users);
127
128 StringBuffer res = new StringBuffer();
129 res.append("[");
130 for (int i=0; i<users.length; i++) {
131 if (i > 0) {
132 res.append(", ");
133 }
134 res.append(users[i]);
135 }
136 res.append("]");
137 return res.toString();
138 }
139
140
141
142
143
144
145 public List<String> listUsers() throws Exception {
146 ArrayList<String> users = new ArrayList<String>();
147 Enumeration<?> en = properties.propertyNames();
148 while (en.hasMoreElements()) {
149 users.add((String)en.nextElement());
150 }
151 return users;
152 }
153
154
155
156
157
158
159
160
161 public void changePassword(String user, String oldPassword, String newPassword) throws Exception {
162 newPassword = generateMD5Hash(newPassword);
163 String line = properties.getProperty(user);
164 if (line != null) {
165 int i = line.indexOf(',');
166 if (i < 0) {
167 properties.setProperty(user, newPassword);
168 } else {
169 properties.setProperty(user, newPassword + line.substring(i));
170 }
171 }
172 storeProperties();
173 }
174
175
176
177
178
179
180
181 public void addUser(String user, String passwd) throws Exception {
182 properties.setProperty(user, generateMD5Hash(passwd));
183 storeProperties();
184 }
185
186
187
188
189
190
191 public void removeUser(String user) throws Exception {
192 properties.remove(user);
193 storeProperties();
194 }
195
196 public Set<String> getUserRoles(String user) {
197 String line = properties.getProperty(user);
198 if (line == null) {
199 return null;
200 }
201 Set<String> res = new HashSet<String>();
202 String[] roles = line.split(",");
203 for (int i = 1; i < roles.length; i++) {
204 res.add(roles[i]);
205 }
206 return res;
207 }
208
209 public String[] getUserRolesAsArray(String user) {
210 String line = properties.getProperty(user);
211 if (line == null) {
212 return null;
213 }
214 String[] roles = line.split(",");
215 String[] res = new String[roles.length - 1];
216 if (roles.length > 1) {
217 System.arraycopy(roles, 1, res, 0, roles.length - 1);
218 }
219 return res;
220 }
221
222 public void loadProperties() throws CertificateException, IOException, URISyntaxException {
223 if (propertiesURI != null) {
224 logger.info("Loading properties from " + propertiesURI.toString() + " for login context '" + loginContext + "'");
225 InputStream keystoreInputStream = new URI(propertiesURI).toURL().openStream();
226 try {
227 properties.load(keystoreInputStream);
228 } finally {
229 keystoreInputStream.close();
230 }
231 }
232 }
233
234 public void storeProperties() throws IOException, URISyntaxException {
235
236 if ((properties != null) && (propertiesURI != null)) {
237
238 logger.info("Storing properties to " + propertiesURI.toString() + " for login context '" + loginContext + "'");
239 OutputStream keystoreOutputStream = null;
240 URLConnection connection = new URI(propertiesURI).toURL().openConnection();
241 connection.setDoOutput(true);
242 keystoreOutputStream = connection.getOutputStream();
243
244 try {
245 properties.store(keystoreOutputStream, "For login context " + loginContext);
246 } finally {
247 keystoreOutputStream.close();
248 }
249 }
250 }
251
252
253
254
255
256
257 public String getPropertiesURI() {
258 return propertiesURI;
259 }
260
261
262
263
264
265 public void setPropertesURI(String uri) {
266 propertiesURI = uri;
267 }
268
269
270
271
272
273 public void setLoginContext(String loginContext) {
274 this.loginContext = loginContext;
275 }
276
277
278
279
280
281 public String getLoginContext() {
282 return loginContext;
283 }
284
285
286
287
288
289 public void setControlFlag(String controlFlag) {
290 this.controlFlag = controlFlag;
291 }
292
293
294
295
296
297 public String getControlFlag() {
298 return controlFlag;
299 }
300
301
302
303
304
305 public Configuration getConfiguration() {
306 return configuration;
307 }
308
309
310
311
312
313 public void setConfiguration(Configuration configuration) {
314 this.configuration = configuration;
315 }
316
317 public Properties getProperties() {
318 return properties;
319 }
320
321 public void setProperties(Properties properties) {
322 this.properties = properties;
323 }
324
325 public static String generateMD5Hash(String password) throws NoSuchAlgorithmException {
326 return generateHash("MD5", password);
327 }
328 public static String generateHash(String algorithm, String password) throws NoSuchAlgorithmException {
329 MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
330 StringBuilder res = new StringBuilder();
331 res.append("{MD5}");
332 byte[] bytes = messageDigest.digest(password.getBytes());
333 String h = null;
334 int i;
335 for (byte b : bytes) {
336 i = (int)b;
337 if (i < 0) {
338 i = - i + 127;
339 }
340 h = Integer.toString(i, 16);
341 if (h.length() < 2) {
342 res.append('0').append(h);
343 } else {
344 res.append(h);
345 }
346 }
347 return res.toString();
348
349 }
350 }