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