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