Rename sal-netconf-connector to netconf-client-mdsal
[netconf.git] / plugins / netconf-client-mdsal / 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 package org.opendaylight.netconf.sal.connect.util;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.ListenableFuture;
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.stream.Collectors;
18 import javax.annotation.PreDestroy;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
21 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
22 import org.opendaylight.mdsal.binding.api.DataBroker;
23 import org.opendaylight.mdsal.binding.api.RpcProviderService;
24 import org.opendaylight.mdsal.binding.api.WriteTransaction;
25 import org.opendaylight.mdsal.common.api.CommitInfo;
26 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddKeystoreEntryInput;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddKeystoreEntryOutput;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddKeystoreEntryOutputBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddPrivateKeyInput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddPrivateKeyOutput;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddPrivateKeyOutputBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddTrustedCertificateInput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddTrustedCertificateOutput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddTrustedCertificateOutputBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.Keystore;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.NetconfKeystoreService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveKeystoreEntryInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveKeystoreEntryOutput;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveKeystoreEntryOutputBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemovePrivateKeyInput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemovePrivateKeyOutput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemovePrivateKeyOutputBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveTrustedCertificateInput;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveTrustedCertificateOutput;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveTrustedCertificateOutputBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017._private.keys.PrivateKey;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017._private.keys.PrivateKeyKey;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.keystore.entry.KeyCredential;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.keystore.entry.KeyCredentialBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.keystore.entry.KeyCredentialKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.trusted.certificates.TrustedCertificate;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.trusted.certificates.TrustedCertificateKey;
54 import org.opendaylight.yangtools.concepts.Registration;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
56 import org.opendaylight.yangtools.yang.common.RpcResult;
57 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
58 import org.osgi.service.component.annotations.Activate;
59 import org.osgi.service.component.annotations.Component;
60 import org.osgi.service.component.annotations.Deactivate;
61 import org.osgi.service.component.annotations.Reference;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64
65 @Singleton
66 @Component(service = { })
67 public final class NetconfSalKeystoreService implements NetconfKeystoreService, AutoCloseable {
68     private static final Logger LOG = LoggerFactory.getLogger(NetconfSalKeystoreService.class);
69     private static final InstanceIdentifier<Keystore> KEYSTORE_IID = InstanceIdentifier.create(Keystore.class);
70
71     // FIXME: we are populating config datastore, but there may be risks with concurrent access. We really should be
72     //        using cluster singleton service here.
73     private final DataBroker dataBroker;
74     private final AAAEncryptionService encryptionService;
75     private final Registration reg;
76
77     @Inject
78     @Activate
79     public NetconfSalKeystoreService(@Reference final DataBroker dataBroker,
80             @Reference final AAAEncryptionService encryptionService, @Reference final RpcProviderService rpcProvider) {
81         this.dataBroker = requireNonNull(dataBroker);
82         this.encryptionService = requireNonNull(encryptionService);
83
84         reg = rpcProvider.registerRpcImplementation(NetconfKeystoreService.class, this);
85         LOG.info("NETCONF keystore service started");
86     }
87
88     @PreDestroy
89     @Deactivate
90     @Override
91     public void close() {
92         reg.close();
93         LOG.info("NETCONF keystore service stopped");
94     }
95
96     @Override
97     public ListenableFuture<RpcResult<RemoveKeystoreEntryOutput>> removeKeystoreEntry(
98             final RemoveKeystoreEntryInput input) {
99         LOG.debug("Removing keypairs: {}", input);
100
101         final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
102
103         for (final String id : input.getKeyId()) {
104             writeTransaction.delete(LogicalDatastoreType.CONFIGURATION,
105                     KEYSTORE_IID.child(KeyCredential.class, new KeyCredentialKey(id)));
106         }
107
108         final SettableFuture<RpcResult<RemoveKeystoreEntryOutput>> rpcResult = SettableFuture.create();
109
110         writeTransaction.commit().addCallback(new FutureCallback<CommitInfo>() {
111             @Override
112             public void onSuccess(final CommitInfo result) {
113                 LOG.debug("remove-key-pair success. Input: {}", input);
114                 rpcResult.set(RpcResultBuilder.success(new RemoveKeystoreEntryOutputBuilder().build()).build());
115             }
116
117             @Override
118             public void onFailure(final Throwable throwable) {
119                 LOG.warn("remove-key-pair failed. Input: {}", input, throwable);
120                 rpcResult.setException(throwable);
121             }
122         }, MoreExecutors.directExecutor());
123
124         return rpcResult;
125     }
126
127     @Override
128     public ListenableFuture<RpcResult<AddKeystoreEntryOutput>> addKeystoreEntry(final AddKeystoreEntryInput input) {
129         LOG.debug("Adding keypairs: {}", input);
130
131         final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
132         final List<KeyCredential> keypairs = input.nonnullKeyCredential().values().stream()
133                 .map(keypair -> new KeyCredentialBuilder(keypair)
134                         .setPrivateKey(encryptionService.encrypt(keypair.getPrivateKey()))
135                         .setPassphrase(encryptionService.encrypt(keypair.getPassphrase()))
136                         .build())
137                 .collect(Collectors.toList());
138
139         for (KeyCredential keypair : keypairs) {
140             writeTransaction.merge(LogicalDatastoreType.CONFIGURATION,
141                     KEYSTORE_IID.child(KeyCredential.class, keypair.key()), keypair);
142         }
143
144         final SettableFuture<RpcResult<AddKeystoreEntryOutput>> rpcResult = SettableFuture.create();
145
146         writeTransaction.commit().addCallback(new FutureCallback<CommitInfo>() {
147             @Override
148             public void onSuccess(final CommitInfo result) {
149                 LOG.debug("add-key-pair success. Input: {}", input);
150                 rpcResult.set(RpcResultBuilder.success(new AddKeystoreEntryOutputBuilder().build()).build());
151             }
152
153             @Override
154             public void onFailure(final Throwable throwable) {
155                 LOG.warn("add-key-pair failed. Input: {}", input, throwable);
156                 rpcResult.setException(throwable);
157             }
158         }, MoreExecutors.directExecutor());
159
160         return rpcResult;
161     }
162
163     @Override
164     public ListenableFuture<RpcResult<AddTrustedCertificateOutput>> addTrustedCertificate(
165             final AddTrustedCertificateInput input) {
166         final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
167
168         for (TrustedCertificate certificate : input.nonnullTrustedCertificate().values()) {
169             writeTransaction.merge(LogicalDatastoreType.CONFIGURATION,
170                     KEYSTORE_IID.child(TrustedCertificate.class, certificate.key()), certificate);
171         }
172
173         final SettableFuture<RpcResult<AddTrustedCertificateOutput>> rpcResult = SettableFuture.create();
174
175         writeTransaction.commit().addCallback(new FutureCallback<CommitInfo>() {
176             @Override
177             public void onSuccess(final CommitInfo result) {
178                 LOG.debug("add-trusted-certificate success. Input: {}", input);
179                 rpcResult.set(RpcResultBuilder.success(new AddTrustedCertificateOutputBuilder().build()).build());
180             }
181
182             @Override
183             public void onFailure(final Throwable throwable) {
184                 LOG.warn("add-trusted-certificate failed. Input: {}", input, throwable);
185                 rpcResult.setException(throwable);
186             }
187         }, MoreExecutors.directExecutor());
188
189         return rpcResult;
190     }
191
192     @Override
193     public ListenableFuture<RpcResult<RemoveTrustedCertificateOutput>> removeTrustedCertificate(
194             final RemoveTrustedCertificateInput input) {
195         final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
196
197         for (final String name : input.getName()) {
198             writeTransaction.delete(LogicalDatastoreType.CONFIGURATION,
199                     KEYSTORE_IID.child(TrustedCertificate.class, new TrustedCertificateKey(name)));
200         }
201
202         final SettableFuture<RpcResult<RemoveTrustedCertificateOutput>> rpcResult = SettableFuture.create();
203
204         writeTransaction.commit().addCallback(new FutureCallback<CommitInfo>() {
205             @Override
206             public void onSuccess(final CommitInfo result) {
207                 LOG.debug("remove-trusted-certificate success. Input: {}", input);
208                 rpcResult.set(RpcResultBuilder.success(new RemoveTrustedCertificateOutputBuilder().build()).build());
209             }
210
211             @Override
212             public void onFailure(final Throwable throwable) {
213                 LOG.warn("remove-trusted-certificate failed. Input: {}", input, throwable);
214                 rpcResult.setException(throwable);
215             }
216         }, MoreExecutors.directExecutor());
217
218         return rpcResult;
219     }
220
221     @Override
222     public ListenableFuture<RpcResult<AddPrivateKeyOutput>> addPrivateKey(final AddPrivateKeyInput input) {
223         final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
224
225         for (PrivateKey key: input.nonnullPrivateKey().values()) {
226             writeTransaction.merge(LogicalDatastoreType.CONFIGURATION,
227                     KEYSTORE_IID.child(PrivateKey.class, key.key()), key);
228         }
229
230         final SettableFuture<RpcResult<AddPrivateKeyOutput>> rpcResult = SettableFuture.create();
231
232         writeTransaction.commit().addCallback(new FutureCallback<CommitInfo>() {
233             @Override
234             public void onSuccess(final CommitInfo result) {
235                 LOG.debug("add-private-key success. Input: {}", input);
236                 rpcResult.set(RpcResultBuilder.success(new AddPrivateKeyOutputBuilder().build()).build());
237             }
238
239             @Override
240             public void onFailure(final Throwable throwable) {
241                 LOG.warn("add-private-key failed. Input: {}", input, throwable);
242                 rpcResult.setException(throwable);
243             }
244         }, MoreExecutors.directExecutor());
245
246         return rpcResult;
247     }
248
249     @Override
250     public ListenableFuture<RpcResult<RemovePrivateKeyOutput>> removePrivateKey(final RemovePrivateKeyInput input) {
251         final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
252
253         for (final String name : input.getName()) {
254             writeTransaction.delete(LogicalDatastoreType.CONFIGURATION,
255                     KEYSTORE_IID.child(PrivateKey.class, new PrivateKeyKey(name)));
256         }
257
258         final SettableFuture<RpcResult<RemovePrivateKeyOutput>> rpcResult = SettableFuture.create();
259
260         writeTransaction.commit().addCallback(new FutureCallback<CommitInfo>() {
261             @Override
262             public void onSuccess(final CommitInfo result) {
263                 LOG.debug("remove-private-key success. Input: {}", input);
264                 rpcResult.set(RpcResultBuilder.success(new RemovePrivateKeyOutputBuilder().build()).build());
265             }
266
267             @Override
268             public void onFailure(final Throwable throwable) {
269                 LOG.warn("remove-private-key failed. Input: {}", input, throwable);
270                 rpcResult.setException(throwable);
271             }
272         }, MoreExecutors.directExecutor());
273
274         return rpcResult;
275     }
276 }