--- /dev/null
+/*
+ * Copyright (c) 2018 ZTE Corporation. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.connect.netconf.util;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.util.concurrent.Futures;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.aaa.encrypt.AAAEncryptionService;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.netconf.sal.connect.util.NetconfSalKeystoreService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddPrivateKeyInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddPrivateKeyInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddTrustedCertificateInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddTrustedCertificateInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017._private.keys.PrivateKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017._private.keys.PrivateKeyBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017._private.keys.PrivateKeyKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.trusted.certificates.TrustedCertificate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.trusted.certificates.TrustedCertificateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.trusted.certificates.TrustedCertificateKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class NetconfSalKeystoreServiceTest {
+ private static final String XML_ELEMENT_PRIVATE_KEY = "private-key";
+ private static final String XML_ELEMENT_NAME = "name";
+ private static final String XML_ELEMENT_DATA = "data";
+ private static final String XML_ELEMENT_CERT_CHAIN = "certificate-chain";
+ private static final String XML_ELEMENT_TRUSTED_CERT = "trusted-certificate";
+ private static final String XML_ELEMENT_CERT = "certificate";
+
+ @Mock
+ private WriteTransaction writeTx;
+ @Mock
+ private DataBroker dataBroker;
+ @Mock
+ private AAAEncryptionService encryptionService;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ doReturn(writeTx).when(dataBroker).newWriteOnlyTransaction();
+ doNothing().when(writeTx)
+ .merge(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(DataObject.class));
+ }
+
+ @Test
+ public void testAddPrivateKey() throws Exception {
+ doReturn(Futures.<Void, TransactionCommitFailedException>immediateCheckedFuture(null)).when(writeTx).submit();
+ NetconfSalKeystoreService keystoreService = new NetconfSalKeystoreService(dataBroker, encryptionService);
+
+ final AddPrivateKeyInput input = getPrivateKeyInput();
+ keystoreService.addPrivateKey(input);
+
+ verify(writeTx, times(input.getPrivateKey().size() + 1))
+ .merge(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(DataObject.class));
+ }
+
+ @Test
+ public void testAddTrustedCertificate() throws Exception {
+ doReturn(Futures.<Void, TransactionCommitFailedException>immediateCheckedFuture(null)).when(writeTx).submit();
+ NetconfSalKeystoreService keystoreService = new NetconfSalKeystoreService(dataBroker, encryptionService);
+
+ final AddTrustedCertificateInput input = getTrustedCertificateInput();
+ keystoreService.addTrustedCertificate(input);
+
+ verify(writeTx, times(input.getTrustedCertificate().size() + 1))
+ .merge(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(DataObject.class));
+ }
+
+ private AddPrivateKeyInput getPrivateKeyInput() throws Exception {
+ final List<PrivateKey> privateKeys = new ArrayList<>();
+ final Document document = readKeystoreXML();
+ final NodeList nodeList = document.getElementsByTagName(XML_ELEMENT_PRIVATE_KEY);
+ for (int i = 0; i < nodeList.getLength(); i++) {
+ final Node node = nodeList.item(i);
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ continue;
+ }
+ final Element element = (Element)node;
+ final String keyName = element.getElementsByTagName(XML_ELEMENT_NAME).item(0).getTextContent();
+ final String keyData = element.getElementsByTagName(XML_ELEMENT_DATA).item(0).getTextContent();
+ final NodeList certNodes = element.getElementsByTagName(XML_ELEMENT_CERT_CHAIN);
+ final List<String> certChain = new ArrayList<>();
+ for (int j = 0; j < certNodes.getLength(); j++) {
+ final Node certNode = certNodes.item(j);
+ if (certNode.getNodeType() != Node.ELEMENT_NODE) {
+ continue;
+ }
+ certChain.add(certNode.getTextContent());
+ }
+
+ final PrivateKey privateKey = new PrivateKeyBuilder()
+ .setKey(new PrivateKeyKey(keyName))
+ .setName(keyName)
+ .setData(keyData)
+ .setCertificateChain(certChain)
+ .build();
+ privateKeys.add(privateKey);
+ }
+
+ return new AddPrivateKeyInputBuilder().setPrivateKey(privateKeys).build();
+ }
+
+ private AddTrustedCertificateInput getTrustedCertificateInput() throws Exception {
+ final List<TrustedCertificate> trustedCertificates = new ArrayList<>();
+ final Document document = readKeystoreXML();
+ final NodeList nodeList = document.getElementsByTagName(XML_ELEMENT_TRUSTED_CERT);
+ for (int i = 0; i < nodeList.getLength(); i++) {
+ final Node node = nodeList.item(i);
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ continue;
+ }
+ final Element element = (Element)node;
+ final String certName = element.getElementsByTagName(XML_ELEMENT_NAME).item(0).getTextContent();
+ final String certData = element.getElementsByTagName(XML_ELEMENT_CERT).item(0).getTextContent();
+
+ final TrustedCertificate certificate = new TrustedCertificateBuilder()
+ .setKey(new TrustedCertificateKey(certName))
+ .setName(certName)
+ .setCertificate(certData)
+ .build();
+ trustedCertificates.add(certificate);
+ }
+
+ return new AddTrustedCertificateInputBuilder().setTrustedCertificate(trustedCertificates).build();
+ }
+
+ private Document readKeystoreXML() throws Exception {
+ return XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/netconf-keystore.xml"));
+ }
+}
--- /dev/null
+<keystore xmlns="urn:opendaylight:netconf:keystore">\r
+ <private-key>\r
+ <name>test_private_key</name>\r
+ <data>MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCxrZcfyb8hPfiA\r
+Sa1FNqboboPfgOv6E6KJpqpsgbowbEGnw6fOJnx9otfrVmAP86YUT6i+nuPwNG/b\r
+I5YHqxd+OMllmvt0DX1tbtHMirx0wFcVXfk4hruDEMWzsUTohrpiQFTrq/kb9Dr4\r
+FxO+/Ddt+YMmUhu1WGPAhOun2VErwGF6HuYfBMji3QvSzS0Hn9Fez1/nY88CzQrz\r
+lPUH7FMVYIP/rzovKJT/5Bnj+YiiNMKYuPoyvBmyPylFeCvAhF5uyGDjLGYDkscQ\r
+MzFDu44ebtcnVK9BZUxgWUDVwm5FjDSDjdcWKla7N46ykITvyBelm96oY38KkNaV\r
+6x/e/4KZAgMBAAECggEBAJdNO2PWaOvl2bdlBifqYjeL5MBvCIPsNH0DcBz2W5bg\r
+mQhDlKH4JArYoQXGiAcNdF/Xddrdcz0ZaicyJpBhIaBauyXK1FX/JtAJjp6fhdvl\r
+7kJDw/ZexU7W+YQLcKKSGCWSor4NtBQZ5h1diXMZVBpSX1xCj1Xd7xQCHKrSZEzc\r
+Geqx7ew1jkkHL+K6MunyQrY2fb6snWkyGEJf3VyjRjzzNubmF7dR7p+fo6NpeTD4\r
+ywEAenkTtw55gwtz2q5pTV3I11ZJHcFjfbLY3SONz86x5FwNODVzaTrLN0JAvkXz\r
+1LqeZbGRnKQ2/emlX1Gt9z8AzlissqJS8JgvQNm+AAECgYEA5bIEJfFDDvBWFPbh\r
+gp5QmX9v9n2jRRX6mEdRPMIbfLfh9NAg3dc5l+yxQaAzSJHrOxe2eciwUGNhE5yb\r
+Spub9o66ZSjAB58GzMI3LIrMUWufp5Ua7ztl3SuMhoTPlAMuqe69q4RMC0KUW9aE\r
+LF4fs2fAm62dv15Z0pOsnR0CdSkCgYEAxgaVD055iAutKXSugI63hvP0T6DAHcnQ\r
+rgdPUT4uCQGibnqUPRbcnNkBNxORRmap12K39B0QQ0eZTpdKNYmWOSnvNSBwiJ6r\r
+ZRCF7UCqArub3nrONSYXXfd+szVjlYgB0paiOUtzEtt7s+JYV2+KswIAx0QwjynX\r
+OPLVAF4tX/ECgYEAtPirwgUzU2rSN9RH2vTHBhlc6nUUlVL6zM2r2NYKeBoc4hi1\r
+PHPdQbDP+6evoCavkjBdqdgP6lZSXvRNedveZsUPYLJZkeeeoOcIN4Tn8+J6uLuG\r
+rCQ9XqN4JWgwcCqNsn+SWrdyfpCneTArlRVXnq9JFp8UoXlCBeIp5uO7UvkCgYEA\r
+kE7Vq4zlldXkf/RvAnJ+nhMDtE+SEWMz9s6O58anZ5rQUzBy/L2/UXH2p7tTv/kq\r
+xjJDmdrgMhdoSlSIGNHGLqw3jQCx4W23u3O6FXZtLoanhQ77XNIAb1Lf+xrqEltF\r
+8MAjQhuQpWpbEHDfLgC0E9Ve2dgAhyPXmsGjpZv79xECgYAjX+cUFoexgkzhilSc\r
+xyI2GI46IZ1NIFBCMuTMSTkEpBotO1ooUT4ZrR2mdIsoc3O5X5y63ZI1CWMwfd4u\r
+buB0qy91s1i4AMW3JlB/jOX++y7YVwUX2aHHHl9fljFJBYqSxUatPDSuo0r42SXq\r
+sD2PXwX43X/g2QxQhP2l9nfSmg==</data>\r
+ <certificate-chain>MIIDgTCCAmmgAwIBAgIEb3Rj1DANBgkqhkiG9w0BAQsFADBxMQswCQYDVQQGEwJD\r
+TjEQMA4GA1UECBMHSklBTkdTVTEQMA4GA1UEBxMHTkFOSklORzEVMBMGA1UEChMM\r
+b3BlbmRheWxpZ2h0MRAwDgYDVQQLEwduZXRjb25mMRUwEwYDVQQDEwxvcGVuZGF5\r
+bGlnaHQwHhcNMTcxMTIwMDkyNDM3WhcNMjcxMTE4MDkyNDM3WjBxMQswCQYDVQQG\r
+EwJDTjEQMA4GA1UECBMHSklBTkdTVTEQMA4GA1UEBxMHTkFOSklORzEVMBMGA1UE\r
+ChMMb3BlbmRheWxpZ2h0MRAwDgYDVQQLEwduZXRjb25mMRUwEwYDVQQDEwxvcGVu\r
+ZGF5bGlnaHQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxrZcfyb8h\r
+PfiASa1FNqboboPfgOv6E6KJpqpsgbowbEGnw6fOJnx9otfrVmAP86YUT6i+nuPw\r
+NG/bI5YHqxd+OMllmvt0DX1tbtHMirx0wFcVXfk4hruDEMWzsUTohrpiQFTrq/kb\r
+9Dr4FxO+/Ddt+YMmUhu1WGPAhOun2VErwGF6HuYfBMji3QvSzS0Hn9Fez1/nY88C\r
+zQrzlPUH7FMVYIP/rzovKJT/5Bnj+YiiNMKYuPoyvBmyPylFeCvAhF5uyGDjLGYD\r
+kscQMzFDu44ebtcnVK9BZUxgWUDVwm5FjDSDjdcWKla7N46ykITvyBelm96oY38K\r
+kNaV6x/e/4KZAgMBAAGjITAfMB0GA1UdDgQWBBTjjrH57CtARfDWvpmkmv7lGL/2\r
+rDANBgkqhkiG9w0BAQsFAAOCAQEApzyNLC/jh5UhWh9VvQW19Fbn9zTcSiCRtgwf\r
+eUXpQPukLfL0eDOK0kBLIvN8lQtu7nH/3aYTaZwHMOpahDfSe2Q0eZPxr9hX7Hlo\r
+kVOtQ88iW3c/KUF7TVjC16eBeNqvMsBCZ45j0al3QxP40iFPvO576HxRLuYKaB3k\r
++CNI6bn1m5SKoToQgbQbqrALFE3zud7iaUSiLAPSCLBqvEg50pLbbxc6nHXmHjqp\r
+alTeRo89Ph0k0jnHzsW+GlefH4MGS3E2MZG0i1jh/+JoTC6DV2g/vNI4Yry7YFa0\r
+WCCnuFcJwlvd12rkxiNI78buwMzEGcOU16wXeDRJxOM+UbF9xA==</certificate-chain>\r
+ </private-key>\r
+ <trusted-certificate>\r
+ <name>test_trusted_cert</name>\r
+ <certificate>MIIECTCCAvGgAwIBAgIBCDANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UEBhMCQ1ox\r
+FjAUBgNVBAgMDVNvdXRoIE1vcmF2aWExDTALBgNVBAcMBEJybm8xDzANBgNVBAoM\r
+BkNFU05FVDEMMAoGA1UECwwDVE1DMRMwEQYDVQQDDApleGFtcGxlIENBMSIwIAYJ\r
+KoZIhvcNAQkBFhNleGFtcGxlY2FAbG9jYWxob3N0MB4XDTE1MDczMDA3MjU1MFoX\r
+DTM1MDcyNTA3MjU1MFowgYUxCzAJBgNVBAYTAkNaMRYwFAYDVQQIDA1Tb3V0aCBN\r
+b3JhdmlhMQ8wDQYDVQQKDAZDRVNORVQxDDAKBgNVBAsMA1RNQzEXMBUGA1UEAwwO\r
+ZXhhbXBsZSBzZXJ2ZXIxJjAkBgkqhkiG9w0BCQEWF2V4YW1wbGVzZXJ2ZXJAbG9j\r
+YWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsdI1TBjzX1Pg\r
+QXFuPCw5/kQwU7qkrhirMcFAXhI8EoXepPa9fKAVuMjHW32P6nNzDpnhFe0YGdNl\r
+oIEN3hJJ87cVOqj4o7zZMbq3zVG2L8As7MTA8tYXm2fSC/0rIxxRRemcGUXM0q+4\r
+LEACjZj2pOKonaivF5VbhgNjPCO1Jj/TamUc0aViE577C9L9EiObGM+bGbabWk/K\r
+WKLsvxUc+sKZXaJ7psTVgpggJAkUszlmwOQgFiMSR53E9/CAkQYhzGVCmH44Vs6H\r
+zs3RZjOTbce4wr4ongiA5LbPeSNSCFjy9loKpaE1rtOjkNBVdiNPCQTmLuODXUTK\r
+gkeL+9v/OwIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVu\r
+U1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQU83qEtQDFzDvLoaII\r
+vqiU6k7j1uswHwYDVR0jBBgwFoAUc1YQIqjZsHVwlea0AB4N+ilNI2gwDQYJKoZI\r
+hvcNAQELBQADggEBAJ+QOLi4gPWGofMkLTqSsbv5xRvTw0xa/sJnEeiejtygAu3o\r
+McAsyevSH9EYVPCANxzISPzd9SFaO56HxWgcxLn9vi8ZNvo2wIp9zucNu285ced1\r
+K/2nDZfBmvBxXnj/n7spwqOyuoIc8sR7P7YyI806Qsfhk3ybNZE5UHJFZKDRQKvR\r
+J1t4nk9saeo87kIuNEDfYNdwYZzRfXoGJ5qIJQK+uJJv9noaIhfFowDW/G14Ji5p\r
+Vh/YtvnOPh7aBjOj8jmzk8MqzK+TZgT7GWu48Nd/NaV8g/DNg9hlN047LaNsJly3\r
+NX3+VBlpMnA4rKwl1OnmYSirIVh9RJqNwqe6k/k=</certificate>\r
+ </trusted-certificate>\r
+</keystore>\r