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