08f41b46dbcba57dba058a45118943042a54e076
[netconf.git] / plugins / netconf-client-mdsal / src / test / java / org / opendaylight / netconf / client / mdsal / impl / DefaultSslHandlerFactoryProviderTest.java
1 /*
2  * Copyright (c) 2018 ZTE Corporation. 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 org.hamcrest.CoreMatchers.startsWith;
11 import static org.hamcrest.MatcherAssert.assertThat;
12 import static org.junit.Assert.assertThrows;
13 import static org.junit.Assert.assertTrue;
14 import static org.mockito.ArgumentMatchers.any;
15 import static org.mockito.Mockito.doAnswer;
16 import static org.mockito.Mockito.doReturn;
17
18 import java.security.KeyStoreException;
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.Set;
22 import org.junit.jupiter.api.BeforeEach;
23 import org.junit.jupiter.api.Test;
24 import org.junit.jupiter.api.extension.ExtendWith;
25 import org.mockito.Mock;
26 import org.mockito.junit.jupiter.MockitoExtension;
27 import org.opendaylight.mdsal.binding.api.DataBroker;
28 import org.opendaylight.mdsal.binding.api.DataObjectModification;
29 import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
30 import org.opendaylight.mdsal.binding.api.DataTreeModification;
31 import org.opendaylight.netconf.api.xml.XmlUtil;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.Keystore;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017._private.keys.PrivateKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017._private.keys.PrivateKeyBuilder;
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.trusted.certificates.TrustedCertificate;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.trusted.certificates.TrustedCertificateBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.trusted.certificates.TrustedCertificateKey;
39 import org.opendaylight.yangtools.concepts.Registration;
40 import org.w3c.dom.Document;
41 import org.w3c.dom.Element;
42
43 @ExtendWith(MockitoExtension.class)
44 class DefaultSslHandlerFactoryProviderTest {
45     private static final String XML_ELEMENT_PRIVATE_KEY = "private-key";
46     private static final String XML_ELEMENT_NAME = "name";
47     private static final String XML_ELEMENT_DATA = "data";
48     private static final String XML_ELEMENT_CERT_CHAIN = "certificate-chain";
49     private static final String XML_ELEMENT_TRUSTED_CERT = "trusted-certificate";
50     private static final String XML_ELEMENT_CERT = "certificate";
51
52     @Mock
53     private DataBroker dataBroker;
54     @Mock
55     private Registration listenerRegistration;
56     @Mock
57     private DataTreeModification<Keystore> dataTreeModification1;
58     @Mock
59     private DataTreeModification<Keystore> dataTreeModification2;
60     @Mock
61     private DataObjectModification<Keystore> keystoreObjectModification1;
62     @Mock
63     private DataObjectModification<Keystore> keystoreObjectModification2;
64     @Mock
65     private DataObjectModification<PrivateKey> privateKeyModification;
66     @Mock
67     private DataObjectModification<TrustedCertificate> trustedCertificateModification;
68
69     private DataTreeChangeListener<Keystore> listener;
70
71     @BeforeEach
72     void beforeEach() {
73         doAnswer(inv -> {
74             listener = inv.getArgument(1);
75             return listenerRegistration;
76         }).when(dataBroker).registerTreeChangeListener(any(), any());
77     }
78
79     @Test
80     void testKeystoreAdapterInit() throws Exception {
81         try (var keystoreAdapter = new DefaultSslHandlerFactoryProvider(dataBroker)) {
82             final var ex = assertThrows(KeyStoreException.class, () -> keystoreAdapter.getJavaKeyStore(Set.of()));
83             assertThat(ex.getMessage(), startsWith("No keystore private key found"));
84         }
85     }
86
87     @Test
88     void testWritePrivateKey() throws Exception {
89         doReturn(keystoreObjectModification1).when(dataTreeModification1).getRootNode();
90         doReturn(List.of(privateKeyModification)).when(keystoreObjectModification1)
91             .getModifiedChildren(PrivateKey.class);
92         doReturn(DataObjectModification.ModificationType.WRITE).when(privateKeyModification).modificationType();
93
94         final var privateKey = getPrivateKey();
95         doReturn(privateKey).when(privateKeyModification).dataAfter();
96
97         try (var keystoreAdapter = new DefaultSslHandlerFactoryProvider(dataBroker)) {
98             listener.onDataTreeChanged(List.of(dataTreeModification1));
99
100             final var keyStore = keystoreAdapter.getJavaKeyStore(Set.of());
101             assertTrue(keyStore.containsAlias(privateKey.getName()));
102         }
103     }
104
105     @Test
106     void testWritePrivateKeyAndTrustedCertificate() throws Exception {
107         // Prepare PrivateKey configuration
108         doReturn(keystoreObjectModification1).when(dataTreeModification1).getRootNode();
109
110         doReturn(List.of(privateKeyModification)).when(keystoreObjectModification1)
111             .getModifiedChildren(PrivateKey.class);
112         doReturn(DataObjectModification.ModificationType.WRITE).when(privateKeyModification).modificationType();
113
114         final var privateKey = getPrivateKey();
115         doReturn(privateKey).when(privateKeyModification).dataAfter();
116
117         // Prepare TrustedCertificate configuration
118         doReturn(keystoreObjectModification2).when(dataTreeModification2).getRootNode();
119
120         doReturn(List.of()).when(keystoreObjectModification2).getModifiedChildren(PrivateKey.class);
121         doReturn(List.of(trustedCertificateModification)).when(keystoreObjectModification2)
122             .getModifiedChildren(TrustedCertificate.class);
123         doReturn(DataObjectModification.ModificationType.WRITE).when(trustedCertificateModification).modificationType();
124
125         final var trustedCertificate = getTrustedCertificate();
126         doReturn(trustedCertificate).when(trustedCertificateModification).dataAfter();
127
128         try (var keystoreAdapter = new DefaultSslHandlerFactoryProvider(dataBroker)) {
129             // Apply configurations
130             listener.onDataTreeChanged(List.of(dataTreeModification1, dataTreeModification2));
131
132             // Check result
133             final var keyStore = keystoreAdapter.getJavaKeyStore(Set.of());
134             assertTrue(keyStore.containsAlias(privateKey.getName()));
135             assertTrue(keyStore.containsAlias(trustedCertificate.getName()));
136         }
137     }
138
139     private static PrivateKey getPrivateKey() throws Exception {
140         final var privateKeys = new ArrayList<PrivateKey>();
141         final var document = readKeystoreXML();
142         final var nodeList = document.getElementsByTagName(XML_ELEMENT_PRIVATE_KEY);
143         for (int i = 0; i < nodeList.getLength(); i++) {
144             if (nodeList.item(i) instanceof Element element) {
145                 final var keyName = element.getElementsByTagName(XML_ELEMENT_NAME).item(0).getTextContent();
146                 final var keyData = element.getElementsByTagName(XML_ELEMENT_DATA).item(0).getTextContent();
147                 final var certNodes = element.getElementsByTagName(XML_ELEMENT_CERT_CHAIN);
148                 final var certChain = new ArrayList<String>();
149                 for (int j = 0; j < certNodes.getLength(); j++) {
150                     if (certNodes.item(j) instanceof Element certNode) {
151                         certChain.add(certNode.getTextContent());
152                     }
153                 }
154
155                 privateKeys.add(new PrivateKeyBuilder()
156                     .withKey(new PrivateKeyKey(keyName))
157                     .setName(keyName)
158                     .setData(keyData)
159                     .setCertificateChain(certChain)
160                     .build());
161             }
162         }
163
164         return privateKeys.get(0);
165     }
166
167     private static TrustedCertificate getTrustedCertificate() throws Exception {
168         final var trustedCertificates = new ArrayList<TrustedCertificate>();
169         final var document = readKeystoreXML();
170         final var nodeList = document.getElementsByTagName(XML_ELEMENT_TRUSTED_CERT);
171         for (int i = 0; i < nodeList.getLength(); i++) {
172             if (nodeList.item(i) instanceof Element element) {
173                 final var certName = element.getElementsByTagName(XML_ELEMENT_NAME).item(0).getTextContent();
174                 final var certData = element.getElementsByTagName(XML_ELEMENT_CERT).item(0).getTextContent();
175
176                 trustedCertificates.add(new TrustedCertificateBuilder()
177                     .withKey(new TrustedCertificateKey(certName))
178                     .setName(certName)
179                     .setCertificate(certData)
180                     .build());
181             }
182         }
183
184         return trustedCertificates.get(0);
185     }
186
187     private static Document readKeystoreXML() throws Exception {
188         return XmlUtil.readXmlToDocument(
189             DefaultSslHandlerFactoryProviderTest.class.getResourceAsStream("/netconf-keystore.xml"));
190     }
191 }