1
2
3
4
5
6
7
8
9
10
11
12
13 package org.abstracthorizon.extend.server.auth.jaas.keystore;
14
15 import java.io.File;
16 import java.io.FileOutputStream;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.OutputStream;
20 import java.lang.reflect.Method;
21 import java.math.BigInteger;
22 import java.net.MalformedURLException;
23 import java.net.URLConnection;
24 import java.security.Key;
25 import java.security.KeyPair;
26 import java.security.KeyPairGenerator;
27 import java.security.KeyStore;
28 import java.security.KeyStoreException;
29 import java.security.NoSuchAlgorithmException;
30 import java.security.NoSuchProviderException;
31 import java.security.Security;
32 import java.security.cert.Certificate;
33 import java.security.cert.CertificateException;
34 import java.util.ArrayList;
35 import java.util.Date;
36 import java.util.Enumeration;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40
41 import javax.security.auth.login.AppConfigurationEntry;
42 import javax.security.auth.login.Configuration;
43
44 import org.bouncycastle.jce.X509Principal;
45 import org.bouncycastle.jce.provider.BouncyCastleProvider;
46 import org.bouncycastle.x509.X509V3CertificateGenerator;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49 import org.springframework.beans.BeansException;
50 import org.springframework.beans.factory.BeanInitializationException;
51 import org.springframework.context.ApplicationContext;
52 import org.springframework.context.ApplicationContextAware;
53 import org.springframework.core.io.Resource;
54
55
56
57
58
59
60
61 public class KeyStoreModuleService implements ApplicationContextAware {
62
63 protected Logger logger = LoggerFactory.getLogger(getClass());
64
65
66 private String keystore;
67
68
69 private String keystorePassword;
70
71
72 private String keystoreType = KeyStore.getDefaultType();
73
74
75 private String keystoreProvider = "";
76
77
78 private String loginContext;
79
80
81 private String controlFlag = "required";
82
83
84 private Configuration configuration;
85
86
87 private Map<String, Object> options = new HashMap<String, Object>();
88
89
90 private ApplicationContext context;
91
92 private Resource keystoreResource;
93
94 static {
95 Security.addProvider(new BouncyCastleProvider());
96 }
97
98
99
100
101 public KeyStoreModuleService() {
102 }
103
104
105
106
107
108 public void start() throws Exception {
109
110 AppConfigurationEntry.LoginModuleControlFlag flag = AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;
111
112 if (AppConfigurationEntry.LoginModuleControlFlag.REQUIRED.toString().indexOf(controlFlag) > 0 ) {
113 flag = AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;
114 } else if( AppConfigurationEntry.LoginModuleControlFlag.REQUISITE.toString().indexOf(controlFlag) > 0 ) {
115 flag = AppConfigurationEntry.LoginModuleControlFlag.REQUISITE;
116 } else if( AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT.toString().indexOf(controlFlag) > 0 ) {
117 flag = AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT;
118 }else if( AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL.toString().indexOf(controlFlag) > 0 ) {
119 flag = AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL;
120 }
121
122 AppConfigurationEntry entry = new AppConfigurationEntry(KeyStoreLoginModule.class.getName(), flag, options);
123
124 AppConfigurationEntry[] list = new AppConfigurationEntry[1];
125 list[0] = entry;
126 Method method = configuration.getClass().getMethod("setAppConfigurationEntry", new Class[]{String.class, list.getClass()});
127 Object[] args = {loginContext, list};
128 method.invoke(configuration, args);
129 logger.info("Set up login context '" + loginContext + "'");
130 }
131
132
133 public void stop() throws Exception {
134 Method method = configuration.getClass().getMethod("removeAppConfigurationEntry", new Class[]{String.class});
135 Object[] args = {loginContext};
136 method.invoke(configuration, args);
137 logger.info("Removed login context '" + loginContext + "'");
138 }
139
140
141
142
143
144
145 public String listUsersString() throws Exception {
146 List<String> u = listUsers();
147 String[] users = new String[u.size()];
148 users = (String[])u.toArray(users);
149
150 StringBuffer res = new StringBuffer();
151 res.append("[");
152 for (int i=0; i<users.length; i++) {
153 if (i > 0) {
154 res.append(", ");
155 }
156 res.append(users[i]);
157 }
158 res.append("]");
159 return res.toString();
160 }
161
162
163
164
165
166
167 public List<String> listUsers() throws Exception {
168 KeyStore keyStore = loadKeyStore();
169 ArrayList<String> users = new ArrayList<String>();
170 Enumeration<String> en = keyStore.aliases();
171 while (en.hasMoreElements()) {
172 users.add(en.nextElement());
173 }
174 return users;
175 }
176
177
178
179
180
181
182
183
184 public void changePassword(String user, String oldPassword, String newPassword) throws Exception {
185 KeyStore keyStore = loadKeyStore();
186 Key key = keyStore.getKey(user, oldPassword.toCharArray());
187
188 Certificate[] certs = keyStore.getCertificateChain(user);
189
190 keyStore.setKeyEntry(user, key, newPassword.toCharArray(), certs);
191 storeKeyStore(keyStore);
192 }
193
194
195
196
197
198
199
200 public void addUser(String user, String passwd) throws Exception {
201 KeyStore keyStore = loadKeyStore();
202
203 String name = "CN="+user+", OU=, O=, L=, ST=, C=";
204
205
206 Security.addProvider(new BouncyCastleProvider());
207
208 X509V3CertificateGenerator generator = new X509V3CertificateGenerator();
209 KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
210 kpGen.initialize(1024);
211 KeyPair pair = kpGen.generateKeyPair();
212
213 generator.setSerialNumber(BigInteger.valueOf(1));
214 generator.setIssuerDN(new X509Principal(name));
215 generator.setNotBefore(new Date());
216 generator.setNotAfter(new Date(System.currentTimeMillis()+1000*60*60*24*365));
217 generator.setSubjectDN(new X509Principal(name));
218 generator.setPublicKey(pair.getPublic());
219 generator.setSignatureAlgorithm("MD5WithRSAEncryption");
220
221 Certificate cert = generator.generate(pair.getPrivate(), "BC");
222
223 keyStore.setKeyEntry(user, pair.getPrivate(), passwd.toCharArray(), new Certificate[]{cert});
224 storeKeyStore(keyStore);
225 }
226
227
228
229
230
231
232 public void removeUser(String user) throws Exception {
233 KeyStore keyStore = loadKeyStore();
234 keyStore.deleteEntry(user);
235 storeKeyStore(keyStore);
236 }
237
238 protected KeyStore loadKeyStore() throws KeyStoreException, NoSuchProviderException, MalformedURLException,
239 IOException, NoSuchAlgorithmException, CertificateException {
240
241 logger.info("Loading keystore from " + keystoreResource.toString() + " for login context '" + loginContext + "'");
242 InputStream keystoreInputStream = keystoreResource.getInputStream();
243 try {
244 KeyStore keyStore;
245 if ((keystoreProvider == null) || (keystoreProvider.length() == 0)) {
246 keyStore = KeyStore.getInstance(keystoreType);
247 } else {
248 keyStore = KeyStore.getInstance(keystoreType, keystoreProvider);
249 }
250
251
252 keyStore.load(keystoreInputStream, keystorePassword.toCharArray());
253 return keyStore;
254
255 } finally {
256 keystoreInputStream.close();
257 }
258 }
259
260
261
262
263
264
265
266
267
268
269
270 protected void storeKeyStore(KeyStore keystore) throws KeyStoreException, NoSuchProviderException, MalformedURLException,
271 IOException, NoSuchAlgorithmException, CertificateException {
272
273 logger.info("Storing keystore to " + keystoreResource.toString() + " for login context '" + loginContext + "'");
274 OutputStream keystoreOutputStream = null;
275 try {
276 File file = keystoreResource.getFile();
277 keystoreOutputStream = new FileOutputStream(file);
278 } catch (IOException e) {
279 URLConnection connection = keystoreResource.getURL().openConnection();
280 connection.setDoOutput(true);
281 keystoreOutputStream = connection.getOutputStream();
282 }
283
284 try {
285 keystore.store(keystoreOutputStream, keystorePassword.toCharArray());
286 } finally {
287 keystoreOutputStream.close();
288 }
289 }
290
291
292
293
294
295 public void setKeyStorePassword(String password) {
296 this.keystorePassword = password;
297 if (password != null) {
298 options.put("keyStorePassword", password);
299 } else {
300 options.remove("keyStorePassword");
301 }
302 }
303
304
305
306
307
308
309 public void setKeyStore(String keystore) throws IOException {
310 this.keystore = keystore;
311
312 if ((keystore != null) && (context != null)) {
313 keystoreResource = context.getResource(keystore);
314 options.put("keyStoreURL", keystoreResource.getURL().toString());
315 } else {
316 keystoreResource = null;
317 options.remove("keyStoreURL");
318 }
319 }
320
321
322
323
324
325 public String getKeyStoreURL() {
326 return keystore;
327 }
328
329
330
331
332
333 public void setKeyStoreType(String type) {
334 keystoreType = type;
335 if (type != null) {
336 options.put("keyStoreType", type);
337 } else {
338 options.remove("keyStoreType");
339 }
340 }
341
342
343
344
345
346 public String getKeyStoreType() {
347 return keystoreType;
348 }
349
350
351
352
353
354 public void setKeyStoreProvider(String provider) {
355 this.keystoreProvider = provider;
356 if (provider != null) {
357 options.put("keyStoreProvider", provider);
358 } else {
359 options.remove("keyStoreProvider");
360 }
361 }
362
363
364
365
366
367 public String getKeyStoreProvider() {
368 return keystoreProvider;
369 }
370
371
372
373
374
375 public void setLoginContext(String loginContext) {
376 this.loginContext = loginContext;
377 }
378
379
380
381
382
383 public String getLoginContext() {
384 return loginContext;
385 }
386
387
388
389
390
391 public void setControlFlag(String controlFlag) {
392 this.controlFlag = controlFlag;
393 }
394
395
396
397
398
399 public String getControlFlag() {
400 return controlFlag;
401 }
402
403
404
405
406
407 public Configuration getConfiguration() {
408 return configuration;
409 }
410
411
412
413
414
415 public void setConfiguration(Configuration configuration) {
416 this.configuration = configuration;
417 }
418
419
420
421
422
423 public void setApplicationContext(ApplicationContext context) throws BeansException {
424 this.context = context;
425 try {
426 setKeyStore(keystore);
427 } catch (IOException e) {
428 throw new BeanInitializationException("Problem setting keystore", e);
429 }
430 }
431 }