88d8efddee4d1f261a2c9cc0b36eaa1b2040f7f0
[netconf.git] / netconf / sal-netconf-connector / src / main / java / org / opendaylight / netconf / sal / connect / util / NetconfSalKeystoreService.java
1 /*
2  * Copyright (c) 2017 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.netconf.sal.connect.util;
10
11 import com.google.common.util.concurrent.CheckedFuture;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.MoreExecutors;
15 import com.google.common.util.concurrent.SettableFuture;
16 import java.util.List;
17 import java.util.concurrent.Future;
18 import java.util.stream.Collectors;
19 import javax.annotation.Nullable;
20 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddKeystoreEntryInput;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddPrivateKeyInput;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddTrustedCertificateInput;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.Keystore;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.KeystoreBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.NetconfKeystoreService;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveKeystoreEntryInput;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemovePrivateKeyInput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveTrustedCertificateInput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017._private.keys.PrivateKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017._private.keys.PrivateKeyKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.keystore.entry.KeyCredential;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.keystore.entry.KeyCredentialBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.keystore.entry.KeyCredentialKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.trusted.certificates.TrustedCertificate;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.trusted.certificates.TrustedCertificateKey;
41 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
42 import org.opendaylight.yangtools.yang.common.RpcResult;
43 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 public class NetconfSalKeystoreService implements NetconfKeystoreService {
48
49     private static final Logger LOG = LoggerFactory.getLogger(NetconfSalKeystoreService.class);
50
51     private final DataBroker dataBroker;
52     private final AAAEncryptionService encryptionService;
53
54     private final InstanceIdentifier<Keystore> keystoreIid = InstanceIdentifier.create(Keystore.class);
55
56     public NetconfSalKeystoreService(final DataBroker dataBroker,
57                                      final AAAEncryptionService encryptionService) {
58         LOG.info("Starting NETCONF keystore service.");
59
60         this.dataBroker = dataBroker;
61         this.encryptionService = encryptionService;
62
63         initKeystore();
64     }
65
66     private void initKeystore() {
67         final Keystore keystore = new KeystoreBuilder().build();
68
69         final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
70         writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, keystoreIid, keystore);
71
72         final CheckedFuture<Void, TransactionCommitFailedException> submit = writeTransaction.submit();
73
74         try {
75             submit.checkedGet();
76             LOG.debug("init keystore done");
77         } catch (TransactionCommitFailedException exception) {
78             LOG.error("Unable to initialize Netconf key-pair store.", exception);
79         }
80     }
81
82     @Override
83     public Future<RpcResult<Void>> removeKeystoreEntry(final RemoveKeystoreEntryInput input) {
84         LOG.debug("Removing keypairs: {}", input);
85
86         final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
87         final List<String> ids = input.getKeyId();
88
89         for (final String id : ids) {
90             writeTransaction.delete(LogicalDatastoreType.CONFIGURATION,
91                     keystoreIid.child(KeyCredential.class, new KeyCredentialKey(id)));
92         }
93
94         final SettableFuture<RpcResult<Void>> rpcResult = SettableFuture.create();
95
96         final CheckedFuture<Void, TransactionCommitFailedException> submit = writeTransaction.submit();
97         Futures.addCallback(submit, new FutureCallback<Void>() {
98             @Override
99             public void onSuccess(@Nullable final Void result) {
100                 LOG.debug("remove-key-pair success. Input: {}");
101                 final RpcResult<Void> success = RpcResultBuilder.<Void>success().build();
102                 rpcResult.set(success);
103             }
104
105             @Override
106             public void onFailure(final Throwable throwable) {
107                 LOG.warn("remove-key-pair failed. Input: {}", input, throwable);
108                 rpcResult.setException(throwable);
109             }
110         }, MoreExecutors.directExecutor());
111
112         return rpcResult;
113     }
114
115     @Override
116     public Future<RpcResult<Void>> addKeystoreEntry(final AddKeystoreEntryInput input) {
117         LOG.debug("Adding keypairs: {}", input);
118
119         final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
120         final List<KeyCredential> keypairs = input.getKeyCredential().stream().map(keypair ->
121                 new KeyCredentialBuilder(keypair)
122                         .setPrivateKey(encryptionService.encrypt(keypair.getPrivateKey()))
123                         .setPassphrase(encryptionService.encrypt(keypair.getPassphrase()))
124                         .build()).collect(Collectors.toList());
125
126         for (KeyCredential keypair : keypairs) {
127             writeTransaction.merge(LogicalDatastoreType.CONFIGURATION,
128                     keystoreIid.child(KeyCredential.class, keypair.getKey()), keypair);
129         }
130
131         final SettableFuture<RpcResult<Void>> rpcResult = SettableFuture.create();
132
133         final CheckedFuture<Void, TransactionCommitFailedException> submit = writeTransaction.submit();
134         Futures.addCallback(submit, new FutureCallback<Void>() {
135             @Override
136             public void onSuccess(@Nullable final Void result) {
137                 LOG.debug("add-key-pair success. Input: {}");
138                 final RpcResult<Void> success = RpcResultBuilder.<Void>success().build();
139                 rpcResult.set(success);
140             }
141
142             @Override
143             public void onFailure(final Throwable throwable) {
144                 LOG.warn("add-key-pair failed. Input: {}", input, throwable);
145                 rpcResult.setException(throwable);
146             }
147         }, MoreExecutors.directExecutor());
148
149         return rpcResult;
150     }
151
152     @Override
153     public Future<RpcResult<Void>> addTrustedCertificate(AddTrustedCertificateInput input) {
154         final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
155
156         for (TrustedCertificate certificate : input.getTrustedCertificate()) {
157             writeTransaction.merge(LogicalDatastoreType.CONFIGURATION,
158                     keystoreIid.child(TrustedCertificate.class, certificate.getKey()), certificate);
159         }
160
161         final SettableFuture<RpcResult<Void>> rpcResult = SettableFuture.create();
162
163         final CheckedFuture<Void, TransactionCommitFailedException> submit = writeTransaction.submit();
164         Futures.addCallback(submit, new FutureCallback<Void>() {
165             @Override
166             public void onSuccess(@Nullable Void result) {
167                 LOG.debug("add-trusted-certificate success. Input: {}", input);
168                 final RpcResult<Void> success = RpcResultBuilder.<Void>success().build();
169                 rpcResult.set(success);
170             }
171
172             @Override
173             public void onFailure(final Throwable throwable) {
174                 LOG.warn("add-trusted-certificate failed. Input: {}", input, throwable);
175                 rpcResult.setException(throwable);
176             }
177         }, MoreExecutors.directExecutor());
178
179         return rpcResult;
180     }
181
182     @Override
183     public Future<RpcResult<Void>> removeTrustedCertificate(RemoveTrustedCertificateInput input) {
184         final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
185         final List<String> names = input.getName();
186
187         for (final String name : names) {
188             writeTransaction.delete(LogicalDatastoreType.CONFIGURATION,
189                     keystoreIid.child(TrustedCertificate.class, new TrustedCertificateKey(name)));
190         }
191
192         final SettableFuture<RpcResult<Void>> rpcResult = SettableFuture.create();
193
194         final CheckedFuture<Void, TransactionCommitFailedException> submit = writeTransaction.submit();
195         Futures.addCallback(submit, new FutureCallback<Void>() {
196             @Override
197             public void onSuccess(@Nullable Void result) {
198                 LOG.debug("remove-trusted-certificate success. Input: {}", input);
199                 final RpcResult<Void> success = RpcResultBuilder.<Void>success().build();
200                 rpcResult.set(success);
201             }
202
203             @Override
204             public void onFailure(final Throwable throwable) {
205                 LOG.warn("remove-trusted-certificate failed. Input: {}", input, throwable);
206                 rpcResult.setException(throwable);
207             }
208         }, MoreExecutors.directExecutor());
209
210         return rpcResult;
211     }
212
213     @Override
214     public Future<RpcResult<Void>> addPrivateKey(AddPrivateKeyInput input) {
215         final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
216
217         for (PrivateKey key: input.getPrivateKey()) {
218             writeTransaction.merge(LogicalDatastoreType.CONFIGURATION,
219                     keystoreIid.child(PrivateKey.class, key.getKey()), key);
220         }
221
222         final SettableFuture<RpcResult<Void>> rpcResult = SettableFuture.create();
223
224         final CheckedFuture<Void, TransactionCommitFailedException> submit = writeTransaction.submit();
225         Futures.addCallback(submit, new FutureCallback<Void>() {
226             @Override
227             public void onSuccess(@Nullable Void result) {
228                 LOG.debug("add-private-key success. Input: {}", input);
229                 final RpcResult<Void> success = RpcResultBuilder.<Void>success().build();
230                 rpcResult.set(success);
231             }
232
233             @Override
234             public void onFailure(final Throwable throwable) {
235                 LOG.warn("add-private-key failed. Input: {}", input, throwable);
236                 rpcResult.setException(throwable);
237             }
238         }, MoreExecutors.directExecutor());
239
240         return rpcResult;
241     }
242
243     @Override
244     public Future<RpcResult<Void>> removePrivateKey(RemovePrivateKeyInput input) {
245         final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
246         final List<String> names = input.getName();
247
248         for (final String name : names) {
249             writeTransaction.delete(LogicalDatastoreType.CONFIGURATION,
250                     keystoreIid.child(PrivateKey.class, new PrivateKeyKey(name)));
251         }
252
253         final SettableFuture<RpcResult<Void>> rpcResult = SettableFuture.create();
254
255         final CheckedFuture<Void, TransactionCommitFailedException> submit = writeTransaction.submit();
256         Futures.addCallback(submit, new FutureCallback<Void>() {
257             @Override
258             public void onSuccess(@Nullable Void result) {
259                 LOG.debug("remove-private-key success. Input: {}", input);
260                 final RpcResult<Void> success = RpcResultBuilder.<Void>success().build();
261                 rpcResult.set(success);
262             }
263
264             @Override
265             public void onFailure(final Throwable throwable) {
266                 LOG.warn("remove-private-key failed. Input: {}", input, throwable);
267                 rpcResult.setException(throwable);
268             }
269         }, MoreExecutors.directExecutor());
270
271         return rpcResult;
272     }
273 }