1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.ksb.security.admin.service.impl;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.bouncycastle.jce.X509Principal;
20 import org.bouncycastle.x509.X509V3CertificateGenerator;
21 import org.kuali.rice.core.api.config.property.Config;
22 import org.kuali.rice.core.api.config.property.ConfigContext;
23 import org.kuali.rice.ksb.security.admin.KeyStoreEntryDataContainer;
24 import org.kuali.rice.ksb.security.admin.service.JavaSecurityManagementService;
25 import org.springframework.beans.factory.InitializingBean;
26
27 import java.io.File;
28 import java.io.FileInputStream;
29 import java.io.IOException;
30 import java.security.GeneralSecurityException;
31 import java.security.KeyPair;
32 import java.security.KeyPairGenerator;
33 import java.security.KeyStore;
34 import java.security.KeyStoreException;
35 import java.security.NoSuchAlgorithmException;
36 import java.security.PrivateKey;
37 import java.security.Security;
38 import java.security.UnrecoverableEntryException;
39 import java.security.cert.Certificate;
40 import java.util.ArrayList;
41 import java.util.Calendar;
42 import java.util.Date;
43 import java.util.Enumeration;
44 import java.util.List;
45
46
47
48
49
50
51
52 public class JavaSecurityManagementServiceImpl implements JavaSecurityManagementService, InitializingBean {
53
54 protected final String CLIENT_KEY_GENERATOR_ALGORITHM = "RSA";
55 protected final String CLIENT_SECURE_RANDOM_ALGORITHM = "SHA1PRNG";
56 protected final int CLIENT_KEY_PAIR_KEY_SIZE = 512;
57 private final int CLIENT_CERT_EXPIRATION_DAYS = 9999;
58
59 private static final String MODULE_SHA_RSA_ALGORITHM = "SHA1withRSA";
60 private static final String MODULE_JKS_TYPE = "JKS";
61
62 private String moduleKeyStoreLocation;
63 private String moduleKeyStoreAlias;
64 private String moduleKeyStorePassword;
65
66 private KeyStore moduleKeyStore;
67 private PrivateKey modulePrivateKey;
68
69
70
71
72 public void afterPropertiesSet() throws Exception {
73 if (StringUtils.isEmpty(getModuleKeyStoreLocation())) {
74 setModuleKeyStoreLocation(ConfigContext.getCurrentContextConfig().getKeystoreFile());
75 }
76 if (StringUtils.isEmpty(getModuleKeyStoreAlias())) {
77 setModuleKeyStoreAlias(ConfigContext.getCurrentContextConfig().getKeystoreAlias());
78 }
79 if (StringUtils.isEmpty(getModuleKeyStorePassword())) {
80 setModuleKeyStorePassword(ConfigContext.getCurrentContextConfig().getKeystorePassword());
81 }
82 verifyConfiguration();
83 this.moduleKeyStore = loadKeyStore();
84 this.modulePrivateKey = loadPrivateKey();
85 }
86
87
88
89
90 protected void verifyConfiguration() {
91 if (StringUtils.isEmpty(getModuleKeyStoreLocation())) {
92 throw new RuntimeException("Value for configuration parameter '" + Config.KEYSTORE_FILE + "' could not be found. Please ensure that the keystore is configured properly.");
93 }
94 if (StringUtils.isEmpty(getModuleKeyStoreAlias())) {
95 throw new RuntimeException("Value for configuration parameter '" + Config.KEYSTORE_ALIAS + "' could not be found. Please ensure that the keystore is configured properly.");
96 }
97 if (StringUtils.isEmpty(getModuleKeyStorePassword())) {
98 throw new RuntimeException("Value for configuration parameter '" + Config.KEYSTORE_PASSWORD + "' could not be found. Please ensure that the keystore is configured properly.");
99 }
100 File keystoreFile = new File(getModuleKeyStoreLocation());
101 if (!keystoreFile.exists()) {
102 throw new RuntimeException("Value for configuration parameter '" + Config.KEYSTORE_FILE + "' is invalid. The file does not exist on the filesystem, location was: '" + getModuleKeyStoreLocation() + "'");
103 }
104 if (!keystoreFile.canRead()) {
105 throw new RuntimeException("Value for configuration parameter '" + Config.KEYSTORE_FILE + "' is invalid. The file exists but is not readable (please check permissions), location was: '" + getModuleKeyStoreLocation() + "'");
106 }
107 }
108
109 protected KeyStore loadKeyStore() throws GeneralSecurityException, IOException {
110 KeyStore keyStore = KeyStore.getInstance(getModuleKeyStoreType());
111 FileInputStream stream = null;
112 try {
113 stream = new FileInputStream(getModuleKeyStoreLocation());
114 keyStore.load(stream, getModuleKeyStorePassword().toCharArray());
115 stream.close();
116 } catch (Exception e) {
117 if (stream != null) {
118 try {
119 stream.close();
120 } catch (Exception ignored) {
121 }
122 }
123 }
124 return keyStore;
125 }
126
127 protected PrivateKey loadPrivateKey() throws GeneralSecurityException {
128 return (PrivateKey)getModuleKeyStore().getKey(getModuleKeyStoreAlias(), getModuleKeyStorePassword().toCharArray());
129 }
130
131 public void removeClientCertificate(String alias) throws KeyStoreException {
132 KeyStore moduleKeyStore = getModuleKeyStore();
133 if (!moduleKeyStore.entryInstanceOf(alias, KeyStore.TrustedCertificateEntry.class)) {
134 throw new RuntimeException("Only entries of type " + KeyStoreEntryDataContainer.DISPLAYABLE_ENTRY_TYPES.get(KeyStore.TrustedCertificateEntry.class) + " can be removed");
135 }
136 getModuleKeyStore().deleteEntry(alias);
137 }
138
139 protected void addClientCertificateToModuleKeyStore(String alias, Certificate clientCertificate) throws KeyStoreException {
140 getModuleKeyStore().setEntry(alias, new KeyStore.TrustedCertificateEntry(clientCertificate), null);
141 }
142
143 public boolean isAliasInKeystore(String alias) throws KeyStoreException {
144 return getModuleKeyStore().containsAlias(alias);
145 }
146
147 public String getCertificateAlias(Certificate certificate) throws KeyStoreException {
148 return getModuleKeyStore().getCertificateAlias(certificate);
149 }
150
151 public KeyStore generateClientKeystore(String alias, String clientPassphrase) throws GeneralSecurityException {
152 if (isAliasInKeystore(alias)) {
153 throw new KeyStoreException("Alias '" + alias + "' already exists in module keystore");
154 }
155
156
157 KeyStore ks = null;
158 try {
159
160 KeyPairGenerator keyGen = KeyPairGenerator.getInstance(CLIENT_KEY_GENERATOR_ALGORITHM);
161
162 keyGen.initialize(CLIENT_KEY_PAIR_KEY_SIZE);
163
164 KeyPair pair = keyGen.generateKeyPair();
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189 Certificate cert = generateCertificate(pair, alias);
190 ks = generateKeyStore(cert, pair.getPrivate(), alias, clientPassphrase);
191
192
193 ks.setEntry(getModuleKeyStoreAlias(), new KeyStore.TrustedCertificateEntry(getCertificate(getModuleKeyStoreAlias())), null);
194
195
196 addClientCertificateToModuleKeyStore(alias, cert);
197
198 return ks;
199 } catch (IOException e) {
200 throw new RuntimeException("Could not create new KeyStore",e);
201 }
202 }
203
204 protected Certificate generateCertificate(KeyPair keyPair, String alias) throws GeneralSecurityException {
205
206
207 if( Security.getProvider(org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME) == null) {
208 Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
209 }
210 X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();
211
212 certificateGenerator.setSignatureAlgorithm("MD5WithRSA");
213 certificateGenerator.setSerialNumber(new java.math.BigInteger("1"));
214 X509Principal nameInfo = new X509Principal("CN=" + alias);
215 certificateGenerator.setIssuerDN(nameInfo);
216 certificateGenerator.setSubjectDN(nameInfo);
217 certificateGenerator.setNotBefore(new Date());
218 Calendar c = Calendar.getInstance();
219 c.add(Calendar.DATE, CLIENT_CERT_EXPIRATION_DAYS);
220 certificateGenerator.setNotAfter(c.getTime());
221 certificateGenerator.setPublicKey(keyPair.getPublic());
222 return certificateGenerator.generate(keyPair.getPrivate(), org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME);
223 }
224
225 protected KeyStore generateKeyStore(Certificate cert, PrivateKey privateKey, String alias, String keyStorePassword) throws GeneralSecurityException, IOException {
226 KeyStore ks = KeyStore.getInstance(getModuleKeyStoreType());
227 ks.load(null, keyStorePassword.toCharArray());
228
229 ks.setEntry(alias, new KeyStore.PrivateKeyEntry(privateKey, new Certificate[]{cert}), new KeyStore.PasswordProtection(keyStorePassword.toCharArray()));
230 return ks;
231 }
232
233 public List<KeyStoreEntryDataContainer> getListOfModuleKeyStoreEntries() {
234 List<KeyStoreEntryDataContainer> keyStoreEntries = new ArrayList<KeyStoreEntryDataContainer>();
235 try {
236 KeyStore moduleKeyStore = getModuleKeyStore();
237
238
239 for (Enumeration<String> enumer = moduleKeyStore.aliases(); enumer.hasMoreElements();) {
240 String alias = (String) enumer.nextElement();
241 KeyStoreEntryDataContainer dataContainer = new KeyStoreEntryDataContainer(alias,moduleKeyStore.getCreationDate(alias));
242 KeyStore.PasswordProtection passwordProtection = null;
243 if (moduleKeyStore.isKeyEntry(alias)) {
244 passwordProtection = new KeyStore.PasswordProtection(getModuleKeyStorePassword().toCharArray());
245 }
246 KeyStore.Entry entry = moduleKeyStore.getEntry(alias, passwordProtection);
247 dataContainer.setType(entry.getClass());
248 keyStoreEntries.add(dataContainer);
249 }
250 } catch (KeyStoreException e) {
251 e.printStackTrace();
252 throw new RuntimeException(e);
253 } catch (NoSuchAlgorithmException e) {
254 e.printStackTrace();
255 throw new RuntimeException(e);
256 } catch (UnrecoverableEntryException e) {
257 e.printStackTrace();
258 throw new RuntimeException(e);
259 }
260 return keyStoreEntries;
261 }
262
263 public String getModuleSignatureAlgorithm() {
264 return getModuleAlgorithm();
265 }
266
267
268
269
270 public Certificate getCertificate(String alias) throws KeyStoreException {
271 return getModuleKeyStore().getCertificate(alias);
272 }
273
274 protected String getModuleKeyStoreType() {
275 return MODULE_JKS_TYPE;
276 }
277
278 protected String getModuleAlgorithm() {
279 return MODULE_SHA_RSA_ALGORITHM;
280 }
281
282 public String getModuleKeyStoreLocation() {
283 return this.moduleKeyStoreLocation;
284 }
285
286 public void setModuleKeyStoreLocation(String moduleKeyStoreLocation) {
287 this.moduleKeyStoreLocation = moduleKeyStoreLocation;
288 }
289
290 public String getModuleKeyStoreAlias() {
291 return this.moduleKeyStoreAlias;
292 }
293
294 public void setModuleKeyStoreAlias(String moduleKeyStoreAlias) {
295 this.moduleKeyStoreAlias = moduleKeyStoreAlias;
296 }
297
298 public String getModuleKeyStorePassword() {
299 return this.moduleKeyStorePassword;
300 }
301
302 public void setModuleKeyStorePassword(String moduleKeyStorePassword) {
303 this.moduleKeyStorePassword = moduleKeyStorePassword;
304 }
305
306 public KeyStore getModuleKeyStore() {
307 return this.moduleKeyStore;
308 }
309
310 public PrivateKey getModulePrivateKey() {
311 return this.modulePrivateKey;
312 }
313
314 }