1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.bitrepository.protocol.security;
23
24 import java.io.BufferedReader;
25 import java.io.ByteArrayInputStream;
26 import java.io.File;
27 import java.io.FileReader;
28 import java.io.IOException;
29 import java.io.UnsupportedEncodingException;
30 import java.security.KeyManagementException;
31 import java.security.KeyStore;
32 import java.security.KeyStoreException;
33 import java.security.NoSuchAlgorithmException;
34 import java.security.PrivateKey;
35 import java.security.Security;
36 import java.security.UnrecoverableKeyException;
37 import java.security.KeyStore.PrivateKeyEntry;
38 import java.security.cert.Certificate;
39 import java.security.cert.CertificateException;
40 import java.security.cert.CertificateExpiredException;
41 import java.security.cert.CertificateFactory;
42 import java.security.cert.CertificateNotYetValidException;
43 import java.security.cert.X509Certificate;
44
45 import javax.net.ssl.KeyManagerFactory;
46 import javax.net.ssl.SSLContext;
47 import javax.net.ssl.TrustManagerFactory;
48
49 import org.bitrepository.common.ArgumentValidator;
50 import org.bitrepository.protocol.security.exception.CertificateUseException;
51 import org.bitrepository.protocol.security.exception.MessageAuthenticationException;
52 import org.bitrepository.protocol.security.exception.MessageSigningException;
53 import org.bitrepository.protocol.security.exception.OperationAuthorizationException;
54 import org.bitrepository.protocol.security.exception.SecurityException;
55 import org.bitrepository.protocol.security.exception.UnregisteredPermissionException;
56 import org.bitrepository.settings.repositorysettings.RepositorySettings;
57 import org.bitrepository.settings.repositorysettings.InfrastructurePermission;
58 import org.bitrepository.settings.repositorysettings.Permission;
59 import org.bitrepository.settings.repositorysettings.PermissionSet;
60 import org.bouncycastle.cms.CMSException;
61 import org.bouncycastle.cms.CMSProcessableByteArray;
62 import org.bouncycastle.cms.CMSSignedData;
63 import org.bouncycastle.cms.SignerInformation;
64 import org.bouncycastle.jce.provider.BouncyCastleProvider;
65 import org.bouncycastle.openssl.PEMReader;
66 import org.bouncycastle.util.encoders.Base64;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
69
70
71
72
73
74
75
76
77
78 public class BasicSecurityManager implements SecurityManager {
79 private final Logger log = LoggerFactory.getLogger(BasicSecurityManager.class);
80
81 private static final String defaultPassword = "123456";
82
83 private final String privateKeyFile;
84
85 private final RepositorySettings repositorySettings;
86
87 private final MessageAuthenticator authenticator;
88
89 private final MessageSigner signer;
90
91 private final OperationAuthorizor authorizer;
92
93 private final PermissionStore permissionStore;
94
95 private static int aliasID = 0;
96
97 private KeyStore keyStore;
98
99 private PrivateKeyEntry privateKeyEntry;
100
101 private final String componentID;
102
103
104
105
106
107
108
109
110
111
112
113 public BasicSecurityManager(RepositorySettings repositorySettings, String privateKeyFile, MessageAuthenticator authenticator,
114 MessageSigner signer, OperationAuthorizor authorizer, PermissionStore permissionStore, String componentID) {
115 ArgumentValidator.checkNotNull(repositorySettings, "repositorySettings");
116 ArgumentValidator.checkNotNull(authenticator, "authenticator");
117 ArgumentValidator.checkNotNull(signer, "signer");
118 ArgumentValidator.checkNotNull(authorizer, "authorizer");
119 ArgumentValidator.checkNotNull(permissionStore, "permissionStore");
120 this.privateKeyFile = privateKeyFile;
121 this.repositorySettings = repositorySettings;
122 this.authenticator = authenticator;
123 this.signer = signer;
124 this.authorizer = authorizer;
125 this.permissionStore = permissionStore;
126 this.componentID = componentID;
127 initialize();
128 }
129
130
131
132
133
134
135
136 public void authenticateMessage(String message, String signature) throws MessageAuthenticationException {
137 if(repositorySettings.getProtocolSettings().isRequireMessageAuthentication()) {
138 if (signature != null) {
139 try {
140 byte[] decodedSig = Base64.decode(signature.getBytes(SecurityModuleConstants.defaultEncodingType));
141 byte[] decodeMessage = message.getBytes(SecurityModuleConstants.defaultEncodingType);
142 authenticator.authenticateMessage(decodeMessage, decodedSig);
143 } catch (UnsupportedEncodingException e) {
144 throw new SecurityException(SecurityModuleConstants.defaultEncodingType + " encoding not supported", e);
145 }
146 } else {
147 throw new MessageAuthenticationException("Received unsigned message, but authentication is required");
148 }
149 }
150 }
151
152
153
154
155
156
157
158 public String signMessage(String message) throws MessageSigningException {
159 if(repositorySettings.getProtocolSettings().isRequireMessageAuthentication()) {
160 try {
161 byte[] signature = signer.signMessage(message.getBytes(SecurityModuleConstants.defaultEncodingType));
162 return new String(Base64.encode(signature));
163 } catch (UnsupportedEncodingException e) {
164 throw new SecurityException(SecurityModuleConstants.defaultEncodingType + " encoding not supported", e);
165 }
166 } else {
167 return null;
168 }
169 }
170
171
172
173
174
175
176
177
178 public void authorizeCertificateUse(String certificateUser, String messageData, String signature)
179 throws CertificateUseException {
180 if(repositorySettings.getProtocolSettings().isRequireOperationAuthorization()) {
181 byte[] decodeSig = Base64.decode(signature.getBytes());
182 CMSSignedData s;
183 try {
184 s = new CMSSignedData(new CMSProcessableByteArray(messageData.getBytes()), decodeSig);
185 } catch (CMSException e) {
186 throw new SecurityException(e.getMessage(), e);
187 }
188
189 SignerInformation signer = (SignerInformation) s.getSignerInfos().getSigners().iterator().next();
190 authorizer.authorizeCertificateUse(certificateUser, signer.getSID());
191 }
192 }
193
194
195
196
197
198
199
200
201 public void authorizeOperation(String operationType, String messageData, String signature)
202 throws OperationAuthorizationException {
203 if(repositorySettings.getProtocolSettings().isRequireOperationAuthorization()) {
204 byte[] decodeSig = Base64.decode(signature.getBytes());
205 CMSSignedData s;
206 try {
207 s = new CMSSignedData(new CMSProcessableByteArray(messageData.getBytes()), decodeSig);
208 } catch (CMSException e) {
209 throw new SecurityException(e.getMessage(), e);
210 }
211
212 SignerInformation signer = (SignerInformation) s.getSignerInfos().getSigners().iterator().next();
213 try {
214 authorizer.authorizeOperation(operationType, signer.getSID());
215 } catch (UnregisteredPermissionException e) {
216 log.info(e.getMessage());
217 }
218
219
220 }
221 }
222
223
224
225
226
227
228
229
230 private void initialize() {
231 Security.addProvider(new BouncyCastleProvider());
232 try {
233 keyStore = KeyStore.getInstance(SecurityModuleConstants.keyStoreType);
234 keyStore.load(null);
235 loadPrivateKey(privateKeyFile);
236 loadInfrastructureCertificates(repositorySettings.getPermissionSet());
237 permissionStore.loadPermissions(repositorySettings.getPermissionSet(), componentID);
238 signer.setPrivateKeyEntry(privateKeyEntry);
239 setupDefaultSSLContext();
240 } catch (Exception e) {
241 throw new SecurityException(e.getMessage(), e);
242 }
243 }
244
245
246
247
248
249 private String getNewAlias() {
250 return "" + aliasID++;
251 }
252
253
254
255
256
257
258
259
260
261 private void loadPrivateKey(String privateKeyFile) throws IOException, KeyStoreException,
262 CertificateExpiredException, CertificateNotYetValidException {
263 PrivateKey privKey = null;
264 X509Certificate privCert = null;
265 if(!(new File(privateKeyFile)).isFile()) {
266 log.info("Key file with private key and certificate does not exist!");
267 return;
268 }
269 BufferedReader bufferedReader = new BufferedReader(new FileReader(privateKeyFile));
270 PEMReader pemReader = new PEMReader(bufferedReader);
271 Object pemObj = pemReader.readObject();
272
273 while(pemObj != null) {
274 if(pemObj instanceof X509Certificate) {
275 log.debug("Certificate for PrivateKeyEntry found");
276 privCert = (X509Certificate) pemObj;
277 } else if(pemObj instanceof PrivateKey) {
278 log.debug("Key for PrivateKeyEntry found");
279 privKey = (PrivateKey) pemObj;
280 } else {
281 log.debug("Got something, thats not X509Certificate or PrivateKey. Class: " + pemObj.getClass().getSimpleName());
282 }
283 pemObj = pemReader.readObject();
284 }
285 pemReader.close();
286 if(privKey == null || privCert == null ) {
287 log.info("No material to create private key entry found!");
288 } else {
289 privCert.checkValidity();
290 privateKeyEntry = new PrivateKeyEntry(privKey, new Certificate[] {privCert});
291 keyStore.setEntry(SecurityModuleConstants.privateKeyAlias, privateKeyEntry,
292 new KeyStore.PasswordProtection(defaultPassword.toCharArray()));
293 }
294 }
295
296
297
298
299
300
301 private void loadInfrastructureCertificates(PermissionSet permissions) throws CertificateException, KeyStoreException {
302 ByteArrayInputStream bs;
303 if(permissions == null) {
304 log.info("The provided PermissionSet is empty. Continuing without permissions!");
305 return;
306 }
307 for(Permission permission : permissions.getPermission()) {
308 if(permission.getInfrastructurePermission().contains(InfrastructurePermission.MESSAGE_BUS_SERVER)) {
309 try {
310 bs = new ByteArrayInputStream(permission.getCertificate().getCertificateData());
311 X509Certificate certificate = (X509Certificate) CertificateFactory.getInstance(
312 SecurityModuleConstants.CertificateType).generateCertificate(bs);
313 keyStore.setEntry(getNewAlias(), new KeyStore.TrustedCertificateEntry(certificate),
314 SecurityModuleConstants.nullProtectionParameter);
315
316 bs.close();
317 } catch (IOException e) {
318
319 }
320 }
321 if(permission.getInfrastructurePermission().contains(InfrastructurePermission.FILE_EXCHANGE_SERVER)) {
322 try {
323 bs = new ByteArrayInputStream(permission.getCertificate().getCertificateData());
324 X509Certificate certificate = (X509Certificate) CertificateFactory.getInstance(
325 SecurityModuleConstants.CertificateType).generateCertificate(bs);
326 keyStore.setEntry(getNewAlias(), new KeyStore.TrustedCertificateEntry(certificate),
327 SecurityModuleConstants.nullProtectionParameter);
328 bs.close();
329 } catch (IOException e) {
330 log.debug("Failed closing ByteArrayInputStream", e);
331 }
332 }
333 }
334 }
335
336
337
338
339
340
341
342
343 private void setupDefaultSSLContext() throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException,
344 KeyManagementException {
345 TrustManagerFactory tmf;
346 KeyManagerFactory kmf;
347 SSLContext context;
348 tmf = TrustManagerFactory.getInstance(SecurityModuleConstants.keyTrustStoreAlgorithm);
349 tmf.init(keyStore);
350 kmf = KeyManagerFactory.getInstance(SecurityModuleConstants.keyTrustStoreAlgorithm);
351 kmf.init(keyStore, defaultPassword.toCharArray());
352 context = SSLContext.getInstance(SecurityModuleConstants.defaultSSLProtocol);
353 context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), SecurityModuleConstants.defaultRandom);
354 SSLContext.setDefault(context);
355 }
356 }