<description>Legacy NETCONF keystore</description>
<dependencies>
+ <dependency>
+ <groupId>org.opendaylight.aaa</groupId>
+ <artifactId>aaa-encrypt-service</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-binding-api</artifactId>
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-common-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-singleton-api</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>concepts</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>netconf-api</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.aaa.encrypt.AAAEncryptionService;
import org.opendaylight.mdsal.binding.api.DataBroker;
import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
+import org.opendaylight.mdsal.binding.api.RpcProviderService;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.singleton.api.ClusterSingletonServiceProvider;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.Keystore;
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.trusted.certificates.TrustedCertificate;
private final SecurityHelper securityHelper = new SecurityHelper();
private @Nullable Registration configListener;
+ private @Nullable Registration rpcSingleton;
- protected final void start(final DataBroker dataBroker) {
+ protected final void start(final DataBroker dataBroker, final RpcProviderService rpcProvider,
+ final ClusterSingletonServiceProvider cssProvider, final AAAEncryptionService encryptionService) {
if (configListener == null) {
configListener = dataBroker.registerTreeChangeListener(
DataTreeIdentifier.of(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Keystore.class)),
new ConfigListener(this));
+ LOG.debug("NETCONF keystore configuration listener started");
}
+ if (rpcSingleton == null) {
+ rpcSingleton = cssProvider.registerClusterSingletonService(
+ new RpcSingleton(dataBroker, rpcProvider, encryptionService));
+ LOG.debug("NETCONF keystore configuration singleton registered");
+ }
+ LOG.info("NETCONF keystore service started");
}
protected final void stop() {
+ final var singleton = rpcSingleton;
+ if (singleton != null) {
+ rpcSingleton = null;
+ singleton.close();
+ }
final var listener = configListener;
if (listener != null) {
configListener = null;
--- /dev/null
+/*
+ * Copyright (c) 2024 PANTHEON.tech, s.r.o. 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.keystore.legacy;
+
+import static java.util.Objects.requireNonNull;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.WriteTransaction;
+
+abstract class AbstractRpc {
+ private final DataBroker dataBroker;
+
+ AbstractRpc(final DataBroker dataBroker) {
+ this.dataBroker = requireNonNull(dataBroker);
+ }
+
+ final @NonNull WriteTransaction newTransaction() {
+ return dataBroker.newWriteOnlyTransaction();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2024 PANTHEON.tech, s.r.o. 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.keystore.legacy;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.util.ArrayList;
+import java.util.Base64;
+import org.opendaylight.aaa.encrypt.AAAEncryptionService;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddKeystoreEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddKeystoreEntryInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddKeystoreEntryOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddKeystoreEntryOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.Keystore;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.keystore.entry.KeyCredential;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.keystore.entry.KeyCredentialBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class DefaultAddKeystoreEntry extends AbstractRpc implements AddKeystoreEntry {
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultAddKeystoreEntry.class);
+
+ private final AAAEncryptionService encryptionService;
+
+ DefaultAddKeystoreEntry(final DataBroker dataBroker, final AAAEncryptionService encryptionService) {
+ super(dataBroker);
+ this.encryptionService = requireNonNull(encryptionService);
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<AddKeystoreEntryOutput>> invoke(final AddKeystoreEntryInput input) {
+ final var plain = input.getKeyCredential();
+ if (plain == null || plain.isEmpty()) {
+ return RpcResultBuilder.success(new AddKeystoreEntryOutputBuilder().build()).buildFuture();
+ }
+
+ LOG.debug("Adding keypairs: {}", plain);
+ final var encrypted = new ArrayList<KeyCredential>(plain.size());
+ for (var credential : plain.values()) {
+ final var keyId = credential.getKeyId();
+ try {
+ encrypted.add(new KeyCredentialBuilder(credential)
+ .setPrivateKey(encryptString(credential.getPrivateKey()))
+ .setPassphrase(encryptString(credential.getPassphrase()))
+ .build());
+ } catch (GeneralSecurityException e) {
+ LOG.debug("Cannot decrypt key credential {}}", credential, e);
+ return RpcResultBuilder.<AddKeystoreEntryOutput>failed()
+ .withError(ErrorType.APPLICATION, "Failed to decrypt key " + keyId, e)
+ .buildFuture();
+ }
+ }
+
+ final var tx = newTransaction();
+ for (var keypair : encrypted) {
+ tx.put(LogicalDatastoreType.CONFIGURATION,
+ InstanceIdentifier.create(Keystore.class).child(KeyCredential.class, keypair.key()), keypair);
+ }
+
+ return tx.commit().transform(commitInfo -> {
+ LOG.debug("Updated keypairs: {}", plain.keySet());
+ return RpcResultBuilder.success(new AddKeystoreEntryOutputBuilder().build()).build();
+ }, MoreExecutors.directExecutor());
+ }
+
+ private String encryptString(final String plain) throws GeneralSecurityException {
+ return Base64.getEncoder().encodeToString(encryptionService.encrypt(plain.getBytes(StandardCharsets.UTF_8)));
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2024 PANTHEON.tech, s.r.o. 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.keystore.legacy;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddPrivateKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddPrivateKeyInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddPrivateKeyOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddPrivateKeyOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.Keystore;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017._private.keys.PrivateKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class DefaultAddPrivateKey extends AbstractRpc implements AddPrivateKey {
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultAddPrivateKey.class);
+
+ DefaultAddPrivateKey(final DataBroker dataBroker) {
+ super(dataBroker);
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<AddPrivateKeyOutput>> invoke(final AddPrivateKeyInput input) {
+ final var keys = input.getPrivateKey();
+ if (keys == null || keys.isEmpty()) {
+ return RpcResultBuilder.success(new AddPrivateKeyOutputBuilder().build()).buildFuture();
+ }
+
+ LOG.debug("Adding private keys: {}", keys);
+ final var tx = newTransaction();
+ for (var key : keys.values()) {
+ tx.put(LogicalDatastoreType.CONFIGURATION,
+ InstanceIdentifier.create(Keystore.class).child(PrivateKey.class, key.key()), key);
+ }
+
+ return tx.commit().transform(commitInfo -> {
+ LOG.debug("Added private keys: {}", keys.keySet());
+ return RpcResultBuilder.success(new AddPrivateKeyOutputBuilder().build()).build();
+ }, MoreExecutors.directExecutor());
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2024 PANTHEON.tech, s.r.o. 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.keystore.legacy;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddTrustedCertificate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddTrustedCertificateInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddTrustedCertificateOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddTrustedCertificateOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.Keystore;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.trusted.certificates.TrustedCertificate;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class DefaultAddTrustedCertificate extends AbstractRpc implements AddTrustedCertificate {
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultAddTrustedCertificate.class);
+
+ DefaultAddTrustedCertificate(final DataBroker dataBroker) {
+ super(dataBroker);
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<AddTrustedCertificateOutput>> invoke(final AddTrustedCertificateInput input) {
+ final var certs = input.getTrustedCertificate();
+ if (certs == null || certs.isEmpty()) {
+ return RpcResultBuilder.success(new AddTrustedCertificateOutputBuilder().build()).buildFuture();
+ }
+
+ LOG.debug("Updating trusted certificates: {}", certs);
+ final var tx = newTransaction();
+ for (var certificate : certs.values()) {
+ tx.put(LogicalDatastoreType.CONFIGURATION,
+ InstanceIdentifier.create(Keystore.class).child(TrustedCertificate.class, certificate.key()),
+ certificate);
+ }
+
+ return tx.commit().transform(commitInfo -> {
+ LOG.debug("Updated trusted certificates: {}", certs.keySet());
+ return RpcResultBuilder.success(new AddTrustedCertificateOutputBuilder().build()).build();
+ }, MoreExecutors.directExecutor());
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2024 PANTHEON.tech, s.r.o. 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.keystore.legacy;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.util.stream.Collectors;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.Keystore;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveKeystoreEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveKeystoreEntryInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveKeystoreEntryOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveKeystoreEntryOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.keystore.entry.KeyCredential;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.keystore.entry.KeyCredentialKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class DefaultRemoveKeystoreEntry extends AbstractRpc implements RemoveKeystoreEntry {
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultRemoveKeystoreEntry.class);
+
+ DefaultRemoveKeystoreEntry(final DataBroker dataBroker) {
+ super(dataBroker);
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<RemoveKeystoreEntryOutput>> invoke(final RemoveKeystoreEntryInput input) {
+ final var keyIds = input.getKeyId();
+ if (keyIds == null || keyIds.isEmpty()) {
+ return RpcResultBuilder.success(new RemoveKeystoreEntryOutputBuilder().build()).buildFuture();
+ }
+
+ final var keys = keyIds.stream().map(KeyCredentialKey::new).collect(Collectors.toSet());
+ LOG.debug("Removing keypairs: {}", keys);
+ final var tx = newTransaction();
+ for (var key : keys) {
+ tx.delete(LogicalDatastoreType.CONFIGURATION,
+ InstanceIdentifier.create(Keystore.class).child(KeyCredential.class, key));
+ }
+
+ return tx.commit().transform(commitInfo -> {
+ LOG.debug("Removed keypairs: {}", keys);
+ return RpcResultBuilder.success(new RemoveKeystoreEntryOutputBuilder().build()).build();
+ }, MoreExecutors.directExecutor());
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2024 PANTHEON.tech, s.r.o. 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.keystore.legacy;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.util.stream.Collectors;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.Keystore;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemovePrivateKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemovePrivateKeyInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemovePrivateKeyOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemovePrivateKeyOutputBuilder;
+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.PrivateKeyKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class DefaultRemovePrivateKey extends AbstractRpc implements RemovePrivateKey {
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultRemovePrivateKey.class);
+
+ DefaultRemovePrivateKey(final DataBroker dataBroker) {
+ super(dataBroker);
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<RemovePrivateKeyOutput>> invoke(final RemovePrivateKeyInput input) {
+ final var names = input.getName();
+ if (names == null || names.isEmpty()) {
+ return RpcResultBuilder.success(new RemovePrivateKeyOutputBuilder().build()).buildFuture();
+ }
+
+ final var keys = names.stream().map(PrivateKeyKey::new).collect(Collectors.toSet());
+ LOG.debug("Removing private keys: {}", keys);
+
+
+ final var tx = newTransaction();
+ for (var key : keys) {
+ tx.delete(LogicalDatastoreType.CONFIGURATION,
+ InstanceIdentifier.create(Keystore.class).child(PrivateKey.class, key));
+ }
+
+ return tx.commit().transform(commitInfo -> {
+ LOG.debug("Removed trusted keys: {}", keys);
+ return RpcResultBuilder.success(new RemovePrivateKeyOutputBuilder().build()).build();
+ }, MoreExecutors.directExecutor());
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2024 PANTHEON.tech, s.r.o. 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.keystore.legacy;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.util.stream.Collectors;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.Keystore;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveTrustedCertificate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveTrustedCertificateInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveTrustedCertificateOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveTrustedCertificateOutputBuilder;
+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.TrustedCertificateKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class DefaultRemoveTrustedCertificate extends AbstractRpc implements RemoveTrustedCertificate {
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultRemoveTrustedCertificate.class);
+
+ DefaultRemoveTrustedCertificate(final DataBroker dataBroker) {
+ super(dataBroker);
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<RemoveTrustedCertificateOutput>> invoke(
+ final RemoveTrustedCertificateInput input) {
+ final var names = input.getName();
+ if (names == null || names.isEmpty()) {
+ return RpcResultBuilder.success(new RemoveTrustedCertificateOutputBuilder().build()).buildFuture();
+ }
+
+ final var keys = names.stream().map(TrustedCertificateKey::new).collect(Collectors.toSet());
+ LOG.debug("Removing trusted certificates: {}", keys);
+ final var tx = newTransaction();
+ for (var key : keys) {
+ tx.delete(LogicalDatastoreType.CONFIGURATION,
+ InstanceIdentifier.create(Keystore.class).child(TrustedCertificate.class, key));
+ }
+
+ return tx.commit().transform(commitInfo -> {
+ LOG.debug("Removed trusted certificates: {}", keys);
+ return RpcResultBuilder.success(new RemoveTrustedCertificateOutputBuilder().build()).build();
+ }, MoreExecutors.directExecutor());
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2024 PANTHEON.tech, s.r.o. 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.keystore.legacy;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableClassToInstanceMap;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.aaa.encrypt.AAAEncryptionService;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.RpcProviderService;
+import org.opendaylight.mdsal.singleton.api.ClusterSingletonService;
+import org.opendaylight.mdsal.singleton.api.ServiceGroupIdentifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddKeystoreEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddPrivateKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddTrustedCertificate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveKeystoreEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemovePrivateKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveTrustedCertificate;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.Rpc;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class RpcSingleton implements ClusterSingletonService {
+ private static final Logger LOG = LoggerFactory.getLogger(RpcSingleton.class);
+ private static final @NonNull ServiceGroupIdentifier SGI = new ServiceGroupIdentifier("netconf-keystore-rpc");
+
+ private final AAAEncryptionService encryptionService;
+ private final RpcProviderService rpcProvider;
+ private final DataBroker dataBroker;
+
+ private Registration reg;
+
+ RpcSingleton(final DataBroker dataBroker, final RpcProviderService rpcProvider,
+ final AAAEncryptionService encryptionService) {
+ this.dataBroker = requireNonNull(dataBroker);
+ this.rpcProvider = requireNonNull(rpcProvider);
+ this.encryptionService = requireNonNull(encryptionService);
+ }
+
+ @Override
+ public ServiceGroupIdentifier getIdentifier() {
+ return SGI;
+ }
+
+ @Override
+ public void instantiateServiceInstance() {
+ if (reg != null) {
+ LOG.warn("Instiatiating while already running, very weird", new Throwable());
+ return;
+ }
+
+ LOG.debug("Registering RPC implementations");
+ reg = rpcProvider.registerRpcImplementations(ImmutableClassToInstanceMap.<Rpc<?, ?>>builder()
+ .put(AddKeystoreEntry.class, new DefaultAddKeystoreEntry(dataBroker, encryptionService))
+ .put(RemoveKeystoreEntry.class, new DefaultRemoveKeystoreEntry(dataBroker))
+ .put(AddPrivateKey.class, new DefaultAddPrivateKey(dataBroker))
+ .put(RemovePrivateKey.class, new DefaultRemovePrivateKey(dataBroker))
+ .put(AddTrustedCertificate.class, new DefaultAddTrustedCertificate(dataBroker))
+ .put(RemoveTrustedCertificate.class, new DefaultRemoveTrustedCertificate(dataBroker))
+ .build());
+ LOG.info("This node is now owning NETCONF keystore configuration");
+ }
+
+ @Override
+ public ListenableFuture<?> closeServiceInstance() {
+ if (reg != null) {
+ LOG.debug("Unregistering RPC implementations");
+ reg.close();
+ reg = null;
+ LOG.info("This node is no longer owning NETCONF keystore configuration");
+ }
+ return Futures.immediateVoidFuture();
+ }
+}
--- /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.keystore.legacy;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.opendaylight.mdsal.common.api.CommitInfo.emptyFluentFuture;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.opendaylight.aaa.encrypt.AAAEncryptionService;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.RpcProviderService;
+import org.opendaylight.mdsal.binding.api.WriteTransaction;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.netconf.api.xml.XmlUtil;
+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.concepts.ObjectRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+@ExtendWith(MockitoExtension.class)
+class NetconfKeystoreRpcsTest {
+ 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";
+
+ private static Document KEYSTORE;
+
+ @Mock
+ private WriteTransaction writeTx;
+ @Mock
+ private DataBroker dataBroker;
+ @Mock
+ private AAAEncryptionService encryptionService;
+ @Mock
+ private RpcProviderService rpcProvider;
+ @Mock
+ private ObjectRegistration<?> rpcReg;
+
+ @BeforeAll
+ static void beforeAll() throws Exception {
+ KEYSTORE = XmlUtil.readXmlToDocument(
+ NetconfKeystoreRpcsTest.class.getResourceAsStream("/netconf-keystore.xml"));
+ }
+
+ @BeforeEach
+ void beforeEach() {
+ doReturn(writeTx).when(dataBroker).newWriteOnlyTransaction();
+ }
+
+ @Test
+ void testAddPrivateKey() throws Exception {
+ doReturn(emptyFluentFuture()).when(writeTx).commit();
+
+ final var rpc = new DefaultAddPrivateKey(dataBroker);
+ final var input = getPrivateKeyInput();
+ rpc.invoke(input).get();
+
+ verify(writeTx, times(input.nonnullPrivateKey().size()))
+ .put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(DataObject.class));
+ }
+
+ private static AddPrivateKeyInput getPrivateKeyInput() throws Exception {
+ final var privateKeys = new HashMap<PrivateKeyKey, PrivateKey>();
+ final var nodeList = KEYSTORE.getElementsByTagName(XML_ELEMENT_PRIVATE_KEY);
+ for (int i = 0; i < nodeList.getLength(); i++) {
+ if (nodeList.item(i) instanceof Element element) {
+ final var keyName = element.getElementsByTagName(XML_ELEMENT_NAME).item(0).getTextContent();
+ final var keyData = element.getElementsByTagName(XML_ELEMENT_DATA).item(0).getTextContent();
+ final var certNodes = element.getElementsByTagName(XML_ELEMENT_CERT_CHAIN);
+ final var certChain = new ArrayList<String>();
+ for (int j = 0; j < certNodes.getLength(); j++) {
+ if (certNodes.item(j) instanceof Element certElement) {
+ certChain.add(certElement.getTextContent());
+ }
+ }
+
+ final var key = new PrivateKeyKey(keyName);
+ privateKeys.put(key, new PrivateKeyBuilder()
+ .withKey(key)
+ .setData(keyData)
+ .setCertificateChain(certChain)
+ .build());
+ }
+ }
+
+ return new AddPrivateKeyInputBuilder().setPrivateKey(privateKeys).build();
+ }
+
+ @Test
+ void testAddTrustedCertificate() throws Exception {
+ doReturn(emptyFluentFuture()).when(writeTx).commit();
+
+ final var rpc = new DefaultAddTrustedCertificate(dataBroker);
+ final var input = getTrustedCertificateInput();
+ rpc.invoke(input).get();
+
+ verify(writeTx, times(input.nonnullTrustedCertificate().size()))
+ .put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(DataObject.class));
+ }
+
+ private static AddTrustedCertificateInput getTrustedCertificateInput() throws Exception {
+ final var trustedCertificates = new HashMap<TrustedCertificateKey, TrustedCertificate>();
+ final var nodeList = KEYSTORE.getElementsByTagName(XML_ELEMENT_TRUSTED_CERT);
+ for (int i = 0; i < nodeList.getLength(); i++) {
+ if (nodeList.item(i) instanceof Element element) {
+ final var certName = element.getElementsByTagName(XML_ELEMENT_NAME).item(0).getTextContent();
+ final var certData = element.getElementsByTagName(XML_ELEMENT_CERT).item(0).getTextContent();
+
+ final var key = new TrustedCertificateKey(certName);
+ trustedCertificates.put(key, new TrustedCertificateBuilder()
+ .withKey(key)
+ .setName(certName)
+ .setCertificate(certData)
+ .build());
+ }
+ }
+
+ return new AddTrustedCertificateInputBuilder().setTrustedCertificate(trustedCertificates).build();
+ }
+}
--- /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
import javax.inject.Inject;
import javax.inject.Singleton;
import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.aaa.encrypt.AAAEncryptionService;
import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.RpcProviderService;
+import org.opendaylight.mdsal.singleton.api.ClusterSingletonServiceProvider;
import org.opendaylight.netconf.client.SslHandlerFactory;
import org.opendaylight.netconf.client.mdsal.api.SslHandlerFactoryProvider;
import org.opendaylight.netconf.keystore.legacy.AbstractNetconfKeystore;
@Inject
@Activate
- public DefaultSslHandlerFactoryProvider(@Reference final DataBroker dataBroker) {
- start(dataBroker);
+ public DefaultSslHandlerFactoryProvider(@Reference final DataBroker dataBroker,
+ @Reference final RpcProviderService rpcProvider,
+ @Reference final ClusterSingletonServiceProvider cssProvider,
+ @Reference final AAAEncryptionService encryptionService) {
+ start(dataBroker, rpcProvider, cssProvider, encryptionService);
}
@Deactivate
+++ /dev/null
-/*
- * Copyright (c) 2017 Cisco Systems, Inc. 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.client.mdsal.impl;
-
-import static java.util.Objects.requireNonNull;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableClassToInstanceMap;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
-import com.google.common.util.concurrent.SettableFuture;
-import java.nio.charset.StandardCharsets;
-import java.security.GeneralSecurityException;
-import java.util.ArrayList;
-import java.util.Base64;
-import javax.annotation.PreDestroy;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import org.opendaylight.aaa.encrypt.AAAEncryptionService;
-import org.opendaylight.mdsal.binding.api.DataBroker;
-import org.opendaylight.mdsal.binding.api.RpcProviderService;
-import org.opendaylight.mdsal.binding.api.WriteTransaction;
-import org.opendaylight.mdsal.common.api.CommitInfo;
-import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
-import org.opendaylight.mdsal.dom.api.DefaultDOMRpcException;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddKeystoreEntry;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddKeystoreEntryInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddKeystoreEntryOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddKeystoreEntryOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddPrivateKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddPrivateKeyInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddPrivateKeyOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddPrivateKeyOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddTrustedCertificate;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddTrustedCertificateInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddTrustedCertificateOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.AddTrustedCertificateOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.Keystore;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveKeystoreEntry;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveKeystoreEntryInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveKeystoreEntryOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveKeystoreEntryOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemovePrivateKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemovePrivateKeyInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemovePrivateKeyOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemovePrivateKeyOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveTrustedCertificate;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveTrustedCertificateInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveTrustedCertificateOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.RemoveTrustedCertificateOutputBuilder;
-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.PrivateKeyKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.keystore.entry.KeyCredential;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.keystore.entry.KeyCredentialBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.keystore.entry.KeyCredentialKey;
-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.TrustedCertificateKey;
-import org.opendaylight.yangtools.concepts.Registration;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.Rpc;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
-import org.osgi.service.component.annotations.Activate;
-import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Deactivate;
-import org.osgi.service.component.annotations.Reference;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Singleton
-@Component(service = { })
-public final class NetconfSalKeystoreRpcs implements AutoCloseable {
- private static final Logger LOG = LoggerFactory.getLogger(NetconfSalKeystoreRpcs.class);
- private static final InstanceIdentifier<Keystore> KEYSTORE_IID = InstanceIdentifier.create(Keystore.class);
-
- // FIXME: we are populating config datastore, but there may be risks with concurrent access. We really should be
- // using cluster singleton service here.
- private final DataBroker dataBroker;
- private final AAAEncryptionService encryptionService;
- private final Registration reg;
-
- @Inject
- @Activate
- public NetconfSalKeystoreRpcs(@Reference final DataBroker dataBroker,
- @Reference final AAAEncryptionService encryptionService, @Reference final RpcProviderService rpcProvider) {
- this.dataBroker = requireNonNull(dataBroker);
- this.encryptionService = requireNonNull(encryptionService);
-
- reg = rpcProvider.registerRpcImplementations(ImmutableClassToInstanceMap.<Rpc<?, ?>>builder()
- .put(RemoveKeystoreEntry.class, this::removeKeystoreEntry)
- .put(AddKeystoreEntry.class, this::addKeystoreEntry)
- .put(AddTrustedCertificate.class, this::addTrustedCertificate)
- .put(RemoveTrustedCertificate.class, this::removeTrustedCertificate)
- .put(AddPrivateKey.class, this::addPrivateKey)
- .put(RemovePrivateKey.class, this::removePrivateKey)
- .build());
- LOG.info("NETCONF keystore service started");
- }
-
- @PreDestroy
- @Deactivate
- @Override
- public void close() {
- reg.close();
- LOG.info("NETCONF keystore service stopped");
- }
-
- private ListenableFuture<RpcResult<RemoveKeystoreEntryOutput>> removeKeystoreEntry(
- final RemoveKeystoreEntryInput input) {
- LOG.debug("Removing keypairs: {}", input);
-
- final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
-
- for (final String id : input.getKeyId()) {
- writeTransaction.delete(LogicalDatastoreType.CONFIGURATION,
- KEYSTORE_IID.child(KeyCredential.class, new KeyCredentialKey(id)));
- }
-
- final SettableFuture<RpcResult<RemoveKeystoreEntryOutput>> rpcResult = SettableFuture.create();
-
- writeTransaction.commit().addCallback(new FutureCallback<CommitInfo>() {
- @Override
- public void onSuccess(final CommitInfo result) {
- LOG.debug("remove-key-pair success. Input: {}", input);
- rpcResult.set(RpcResultBuilder.success(new RemoveKeystoreEntryOutputBuilder().build()).build());
- }
-
- @Override
- public void onFailure(final Throwable throwable) {
- LOG.warn("remove-key-pair failed. Input: {}", input, throwable);
- rpcResult.setException(throwable);
- }
- }, MoreExecutors.directExecutor());
-
- return rpcResult;
- }
-
- private ListenableFuture<RpcResult<AddKeystoreEntryOutput>> addKeystoreEntry(final AddKeystoreEntryInput input) {
- LOG.debug("Adding keypairs: {}", input);
-
- final var plain = input.nonnullKeyCredential();
- final var encrypted = new ArrayList<KeyCredential>(plain.size());
- for (var credential : plain.values()) {
- try {
- encrypted.add(new KeyCredentialBuilder(credential)
- .setPrivateKey(encryptString(credential.getPrivateKey()))
- .setPassphrase(encryptString(credential.getPassphrase()))
- .build());
- } catch (GeneralSecurityException e) {
- return Futures.immediateFailedFuture(new DefaultDOMRpcException("Failed to decrypt " + credential, e));
- }
- }
-
- final var writeTransaction = dataBroker.newWriteOnlyTransaction();
- for (var keypair : encrypted) {
- writeTransaction.merge(LogicalDatastoreType.CONFIGURATION,
- KEYSTORE_IID.child(KeyCredential.class, keypair.key()), keypair);
- }
-
- final var rpcResult = SettableFuture.<RpcResult<AddKeystoreEntryOutput>>create();
- writeTransaction.commit().addCallback(new FutureCallback<CommitInfo>() {
- @Override
- public void onSuccess(final CommitInfo result) {
- LOG.debug("add-key-pair success. Input: {}", input);
- rpcResult.set(RpcResultBuilder.success(new AddKeystoreEntryOutputBuilder().build()).build());
- }
-
- @Override
- public void onFailure(final Throwable throwable) {
- LOG.warn("add-key-pair failed. Input: {}", input, throwable);
- rpcResult.setException(throwable);
- }
- }, MoreExecutors.directExecutor());
- return rpcResult;
- }
-
- private String encryptString(final String plain) throws GeneralSecurityException {
- return Base64.getEncoder().encodeToString(encryptionService.encrypt(plain.getBytes(StandardCharsets.UTF_8)));
- }
-
- @VisibleForTesting
- ListenableFuture<RpcResult<AddTrustedCertificateOutput>> addTrustedCertificate(
- final AddTrustedCertificateInput input) {
- final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
-
- for (TrustedCertificate certificate : input.nonnullTrustedCertificate().values()) {
- writeTransaction.merge(LogicalDatastoreType.CONFIGURATION,
- KEYSTORE_IID.child(TrustedCertificate.class, certificate.key()), certificate);
- }
-
- final SettableFuture<RpcResult<AddTrustedCertificateOutput>> rpcResult = SettableFuture.create();
-
- writeTransaction.commit().addCallback(new FutureCallback<CommitInfo>() {
- @Override
- public void onSuccess(final CommitInfo result) {
- LOG.debug("add-trusted-certificate success. Input: {}", input);
- rpcResult.set(RpcResultBuilder.success(new AddTrustedCertificateOutputBuilder().build()).build());
- }
-
- @Override
- public void onFailure(final Throwable throwable) {
- LOG.warn("add-trusted-certificate failed. Input: {}", input, throwable);
- rpcResult.setException(throwable);
- }
- }, MoreExecutors.directExecutor());
-
- return rpcResult;
- }
-
- private ListenableFuture<RpcResult<RemoveTrustedCertificateOutput>> removeTrustedCertificate(
- final RemoveTrustedCertificateInput input) {
- final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
-
- for (final String name : input.getName()) {
- writeTransaction.delete(LogicalDatastoreType.CONFIGURATION,
- KEYSTORE_IID.child(TrustedCertificate.class, new TrustedCertificateKey(name)));
- }
-
- final SettableFuture<RpcResult<RemoveTrustedCertificateOutput>> rpcResult = SettableFuture.create();
-
- writeTransaction.commit().addCallback(new FutureCallback<CommitInfo>() {
- @Override
- public void onSuccess(final CommitInfo result) {
- LOG.debug("remove-trusted-certificate success. Input: {}", input);
- rpcResult.set(RpcResultBuilder.success(new RemoveTrustedCertificateOutputBuilder().build()).build());
- }
-
- @Override
- public void onFailure(final Throwable throwable) {
- LOG.warn("remove-trusted-certificate failed. Input: {}", input, throwable);
- rpcResult.setException(throwable);
- }
- }, MoreExecutors.directExecutor());
-
- return rpcResult;
- }
-
- @VisibleForTesting
- ListenableFuture<RpcResult<AddPrivateKeyOutput>> addPrivateKey(final AddPrivateKeyInput input) {
- final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
-
- for (PrivateKey key: input.nonnullPrivateKey().values()) {
- writeTransaction.merge(LogicalDatastoreType.CONFIGURATION,
- KEYSTORE_IID.child(PrivateKey.class, key.key()), key);
- }
-
- final SettableFuture<RpcResult<AddPrivateKeyOutput>> rpcResult = SettableFuture.create();
-
- writeTransaction.commit().addCallback(new FutureCallback<CommitInfo>() {
- @Override
- public void onSuccess(final CommitInfo result) {
- LOG.debug("add-private-key success. Input: {}", input);
- rpcResult.set(RpcResultBuilder.success(new AddPrivateKeyOutputBuilder().build()).build());
- }
-
- @Override
- public void onFailure(final Throwable throwable) {
- LOG.warn("add-private-key failed. Input: {}", input, throwable);
- rpcResult.setException(throwable);
- }
- }, MoreExecutors.directExecutor());
-
- return rpcResult;
- }
-
- private ListenableFuture<RpcResult<RemovePrivateKeyOutput>> removePrivateKey(final RemovePrivateKeyInput input) {
- final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
-
- for (final String name : input.getName()) {
- writeTransaction.delete(LogicalDatastoreType.CONFIGURATION,
- KEYSTORE_IID.child(PrivateKey.class, new PrivateKeyKey(name)));
- }
-
- final SettableFuture<RpcResult<RemovePrivateKeyOutput>> rpcResult = SettableFuture.create();
-
- writeTransaction.commit().addCallback(new FutureCallback<CommitInfo>() {
- @Override
- public void onSuccess(final CommitInfo result) {
- LOG.debug("remove-private-key success. Input: {}", input);
- rpcResult.set(RpcResultBuilder.success(new RemovePrivateKeyOutputBuilder().build()).build());
- }
-
- @Override
- public void onFailure(final Throwable throwable) {
- LOG.warn("remove-private-key failed. Input: {}", input, throwable);
- rpcResult.setException(throwable);
- }
- }, MoreExecutors.directExecutor());
-
- return rpcResult;
- }
-}
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
+import org.opendaylight.aaa.encrypt.AAAEncryptionService;
import org.opendaylight.mdsal.binding.api.DataBroker;
import org.opendaylight.mdsal.binding.api.DataObjectModification;
import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
import org.opendaylight.mdsal.binding.api.DataTreeModification;
+import org.opendaylight.mdsal.binding.api.RpcProviderService;
+import org.opendaylight.mdsal.singleton.api.ClusterSingletonServiceProvider;
import org.opendaylight.netconf.api.xml.XmlUtil;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.Keystore;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017._private.keys.PrivateKey;
@Mock
private DataBroker dataBroker;
@Mock
+ private RpcProviderService rpcProvider;
+ @Mock
+ private ClusterSingletonServiceProvider cssProvider;
+ @Mock
+ private AAAEncryptionService encryptionService;
+ @Mock
private Registration listenerRegistration;
@Mock
private DataTreeModification<Keystore> dataTreeModification1;
}).when(dataBroker).registerTreeChangeListener(any(), any());
}
+ private DefaultSslHandlerFactoryProvider newProvider() {
+ return new DefaultSslHandlerFactoryProvider(dataBroker, rpcProvider, cssProvider, encryptionService);
+ }
+
@Test
void testKeystoreAdapterInit() throws Exception {
- try (var keystoreAdapter = new DefaultSslHandlerFactoryProvider(dataBroker)) {
+ try (var keystoreAdapter = newProvider()) {
final var ex = assertThrows(KeyStoreException.class, () -> keystoreAdapter.getJavaKeyStore(Set.of()));
assertThat(ex.getMessage(), startsWith("No keystore private key found"));
}
final var privateKey = getPrivateKey();
doReturn(privateKey).when(privateKeyModification).dataAfter();
- try (var keystoreAdapter = new DefaultSslHandlerFactoryProvider(dataBroker)) {
+ try (var keystoreAdapter = newProvider()) {
listener.onDataTreeChanged(List.of(dataTreeModification1));
final var keyStore = keystoreAdapter.getJavaKeyStore(Set.of());
final var trustedCertificate = getTrustedCertificate();
doReturn(trustedCertificate).when(trustedCertificateModification).dataAfter();
- try (var keystoreAdapter = new DefaultSslHandlerFactoryProvider(dataBroker)) {
+ try (var keystoreAdapter = newProvider()) {
// Apply configurations
listener.onDataTreeChanged(List.of(dataTreeModification1, dataTreeModification2));
+++ /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.client.mdsal.impl;
-
-import static org.mockito.ArgumentMatchers.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 static org.opendaylight.mdsal.common.api.CommitInfo.emptyFluentFuture;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-import org.opendaylight.aaa.encrypt.AAAEncryptionService;
-import org.opendaylight.mdsal.binding.api.DataBroker;
-import org.opendaylight.mdsal.binding.api.RpcProviderService;
-import org.opendaylight.mdsal.binding.api.WriteTransaction;
-import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
-import org.opendaylight.netconf.api.xml.XmlUtil;
-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.concepts.ObjectRegistration;
-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;
-
-@RunWith(MockitoJUnitRunner.StrictStubs.class)
-public class NetconfSalKeystoreRpcsTest {
- 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;
- @Mock
- private RpcProviderService rpcProvider;
- @Mock
- private ObjectRegistration<?> rpcReg;
-
- @Before
- public void setUp() {
- doReturn(writeTx).when(dataBroker).newWriteOnlyTransaction();
- doNothing().when(writeTx)
- .merge(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(DataObject.class));
- doReturn(rpcReg).when(rpcProvider).registerRpcImplementations(any());
- doNothing().when(rpcReg).close();
- }
-
- @Test
- public void testAddPrivateKey() throws Exception {
- doReturn(emptyFluentFuture()).when(writeTx).commit();
- try (var keystoreService = new NetconfSalKeystoreRpcs(dataBroker, encryptionService, rpcProvider)) {
- final AddPrivateKeyInput input = getPrivateKeyInput();
- keystoreService.addPrivateKey(input).get();
-
- verify(writeTx, times(input.nonnullPrivateKey().size()))
- .merge(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(DataObject.class));
- }
- }
-
- @Test
- public void testAddTrustedCertificate() throws Exception {
- doReturn(emptyFluentFuture()).when(writeTx).commit();
- try (var keystoreService = new NetconfSalKeystoreRpcs(dataBroker, encryptionService, rpcProvider)) {
- final var input = getTrustedCertificateInput();
- keystoreService.addTrustedCertificate(input).get();
-
- verify(writeTx, times(input.nonnullTrustedCertificate().size()))
- .merge(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(DataObject.class));
- }
- }
-
- private AddPrivateKeyInput getPrivateKeyInput() throws Exception {
- final Map<PrivateKeyKey, PrivateKey> privateKeys = new HashMap<>();
- 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 PrivateKeyKey key = new PrivateKeyKey(keyName);
- privateKeys.put(key, new PrivateKeyBuilder()
- .withKey(key)
- .setData(keyData)
- .setCertificateChain(certChain)
- .build());
- }
-
- return new AddPrivateKeyInputBuilder().setPrivateKey(privateKeys).build();
- }
-
- private AddTrustedCertificateInput getTrustedCertificateInput() throws Exception {
- final Map<TrustedCertificateKey, TrustedCertificate> trustedCertificates = new HashMap<>();
- 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 TrustedCertificateKey key = new TrustedCertificateKey(certName);
- trustedCertificates.put(key, new TrustedCertificateBuilder()
- .withKey(key)
- .setName(certName)
- .setCertificate(certData)
- .build());
- }
-
- return new AddTrustedCertificateInputBuilder().setTrustedCertificate(trustedCertificates).build();
- }
-
- private Document readKeystoreXML() throws Exception {
- return XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/netconf-keystore.xml"));
- }
-}