BUG-9261: introduce netconf keystore service
[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.Keystore;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.KeystoreBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.NetconfKeystoreService;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveKeystoreEntryInput;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.keystore.entry.KeyCredential;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.keystore.entry.KeyCredentialBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.keystore.entry.KeyCredentialKey;
33 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
34 import org.opendaylight.yangtools.yang.common.RpcResult;
35 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 public class NetconfSalKeystoreService implements NetconfKeystoreService {
40
41     private static final Logger LOG = LoggerFactory.getLogger(NetconfSalKeystoreService.class);
42
43     private final DataBroker dataBroker;
44     private final AAAEncryptionService encryptionService;
45
46     private final InstanceIdentifier<Keystore> keystoreIid = InstanceIdentifier.create(Keystore.class);
47
48     public NetconfSalKeystoreService(final DataBroker dataBroker,
49                                      final AAAEncryptionService encryptionService) {
50         LOG.info("Starting NETCONF keystore service.");
51
52         this.dataBroker = dataBroker;
53         this.encryptionService = encryptionService;
54
55         initKeystore();
56     }
57
58     private void initKeystore() {
59         final Keystore keystore = new KeystoreBuilder().build();
60
61         final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
62         writeTransaction.merge(LogicalDatastoreType.OPERATIONAL, keystoreIid, keystore);
63
64         final CheckedFuture<Void, TransactionCommitFailedException> submit = writeTransaction.submit();
65
66         try {
67             submit.checkedGet();
68             LOG.debug("init keystore done");
69         } catch (TransactionCommitFailedException exception) {
70             LOG.error("Unable to initialize Netconf key-pair store.", exception);
71         }
72     }
73
74     @Override
75     public Future<RpcResult<Void>> removeKeystoreEntry(final RemoveKeystoreEntryInput input) {
76         LOG.debug("Removing keypairs: {}", input);
77
78         final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
79         final List<String> ids = input.getKeyId();
80
81         for (final String id : ids) {
82             writeTransaction.delete(LogicalDatastoreType.OPERATIONAL,
83                     keystoreIid.child(KeyCredential.class, new KeyCredentialKey(id)));
84         }
85
86         final SettableFuture<RpcResult<Void>> rpcResult = SettableFuture.create();
87
88         final CheckedFuture<Void, TransactionCommitFailedException> submit = writeTransaction.submit();
89         Futures.addCallback(submit, new FutureCallback<Void>() {
90             @Override
91             public void onSuccess(@Nullable final Void result) {
92                 LOG.debug("remove-key-pair success. Input: {}");
93                 final RpcResult<Void> success = RpcResultBuilder.<Void>success().build();
94                 rpcResult.set(success);
95             }
96
97             @Override
98             public void onFailure(final Throwable throwable) {
99                 LOG.warn("remove-key-pair failed. Input: {}", input, throwable);
100                 rpcResult.setException(throwable);
101             }
102         }, MoreExecutors.directExecutor());
103
104         return rpcResult;
105     }
106
107     @Override
108     public Future<RpcResult<Void>> addKeystoreEntry(final AddKeystoreEntryInput input) {
109         LOG.debug("Adding keypairs: {}", input);
110
111         final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
112         final List<KeyCredential> keypairs = input.getKeyCredential().stream().map(keypair ->
113                 new KeyCredentialBuilder(keypair)
114                         .setPrivateKey(encryptionService.encrypt(keypair.getPrivateKey()))
115                         .setPassphrase(encryptionService.encrypt(keypair.getPassphrase()))
116                         .build()).collect(Collectors.toList());
117
118         for (KeyCredential keypair : keypairs) {
119             writeTransaction.merge(LogicalDatastoreType.OPERATIONAL,
120                     keystoreIid.child(KeyCredential.class, keypair.getKey()), keypair);
121         }
122
123         final SettableFuture<RpcResult<Void>> rpcResult = SettableFuture.create();
124
125         final CheckedFuture<Void, TransactionCommitFailedException> submit = writeTransaction.submit();
126         Futures.addCallback(submit, new FutureCallback<Void>() {
127             @Override
128             public void onSuccess(@Nullable final Void result) {
129                 LOG.debug("add-key-pair success. Input: {}");
130                 final RpcResult<Void> success = RpcResultBuilder.<Void>success().build();
131                 rpcResult.set(success);
132             }
133
134             @Override
135             public void onFailure(final Throwable throwable) {
136                 LOG.warn("add-key-pair failed. Input: {}", input, throwable);
137                 rpcResult.setException(throwable);
138             }
139         }, MoreExecutors.directExecutor());
140
141         return rpcResult;
142     }
143 }